mirror of
https://github.com/madari-media/madari-oss.git
synced 2026-01-11 22:40:23 +00:00
fix: small changes
This commit is contained in:
parent
46571852de
commit
fdd0e772cd
74 changed files with 1681 additions and 2414 deletions
7
.gitignore
vendored
7
.gitignore
vendored
|
|
@ -49,3 +49,10 @@ app.*.map.json
|
|||
|
||||
.env
|
||||
node_modules
|
||||
|
||||
# Rust related
|
||||
.cargo/
|
||||
target/
|
||||
|
||||
# Generated messages
|
||||
*/**/messages/
|
||||
|
|
|
|||
957
Cargo.lock
generated
Normal file
957
Cargo.lock
generated
Normal file
|
|
@ -0,0 +1,957 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.24.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
|
||||
dependencies = [
|
||||
"gimli",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "adler2"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
|
||||
|
||||
[[package]]
|
||||
name = "allo-isolate"
|
||||
version = "0.1.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f67642eb6773fb42a95dd3b348c305ee18dee6642274c6b412d67e985e3befc"
|
||||
dependencies = [
|
||||
"atomic",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.95"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04"
|
||||
|
||||
[[package]]
|
||||
name = "async-channel"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35"
|
||||
dependencies = [
|
||||
"concurrent-queue",
|
||||
"event-listener",
|
||||
"futures-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-oneshot"
|
||||
version = "0.5.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae47de2a02d543205f3f5457a90b6ecbc9494db70557bd29590ec8f1ddff5463"
|
||||
dependencies = [
|
||||
"futures-micro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "644dd749086bf3771a2fbc5f256fdb982d53f011c7d5d560304eafeecebce79d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atomic"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c59bdb34bc650a32731b31bd8f0829cc15d24a708ee31559e0bb34f2bc320cba"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.74"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
"object",
|
||||
"rustc-demangle",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.22.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36"
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c3d1b2e905a3a7b00a6141adb0e4c0bb941d11caf55349d863942a1cc44e3c9"
|
||||
dependencies = [
|
||||
"shlex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "concurrent-queue"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
|
||||
|
||||
[[package]]
|
||||
name = "env_home"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c7f84e12ccf0a7ddc17a6c41c93326024c42920d7ee630d04950e6926645c0fe"
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "event-listener"
|
||||
version = "2.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.0.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "form_urlencoded"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
|
||||
dependencies = [
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-executor",
|
||||
"futures-io",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
|
||||
|
||||
[[package]]
|
||||
name = "futures-executor"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-micro"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b460264b3593d68b16a7bc35f7bc226ddfebdf9a1c8db1ed95d5cc6b7168c826"
|
||||
dependencies = [
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"futures-macro",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"memchr",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.31.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
|
||||
|
||||
[[package]]
|
||||
name = "home"
|
||||
version = "0.5.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf"
|
||||
dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hub"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"log",
|
||||
"messages",
|
||||
"prost",
|
||||
"rinf",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
|
||||
dependencies = [
|
||||
"unicode-bidi",
|
||||
"unicode-normalization",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.77"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.169"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||
|
||||
[[package]]
|
||||
name = "messages"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e02e0c66a1c30e448db540072c1b3811859ebeac2671f96bba20ed7932210205"
|
||||
dependencies = [
|
||||
"async-channel",
|
||||
"async-oneshot",
|
||||
"async-trait",
|
||||
"futures",
|
||||
"once_cell",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3b1c9bd4fe1f0f8b387f6eb9eb3b4a1aa26185e5750efb9140301703f62cd1b"
|
||||
dependencies = [
|
||||
"adler2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.36.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.20.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e"
|
||||
|
||||
[[package]]
|
||||
name = "os-thread-local"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd7fc7fa9ea7dc8907f9b10e730106ed0011926e7f5abb382530ac91d1af2b7c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
|
||||
|
||||
[[package]]
|
||||
name = "pin-utils"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.93"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prost"
|
||||
version = "0.13.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"prost-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prost-derive"
|
||||
version = "0.13.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"itertools",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "protoc-prebuilt"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4d85d4641fe3b8c6e853dfd09fe35379bc6b6e66bd692ac29ed4f7087de69ed5"
|
||||
dependencies = [
|
||||
"ureq",
|
||||
"zip",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rinf"
|
||||
version = "7.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37f9c0095f302b63d3e7641454abdd9996cafb737526f949c7c89695a1e6bdc6"
|
||||
dependencies = [
|
||||
"allo-isolate",
|
||||
"home",
|
||||
"js-sys",
|
||||
"os-thread-local",
|
||||
"protoc-prebuilt",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"which",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ring"
|
||||
version = "0.17.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e75ec5e92c4d8aede845126adc388046234541629e76029599ed35a003c7ed24"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"getrandom",
|
||||
"libc",
|
||||
"untrusted",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls"
|
||||
version = "0.23.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "47796c98c480fce5406ef69d1c76378375492c3b0a0de587be0c1d9feb12f395"
|
||||
dependencies = [
|
||||
"log",
|
||||
"once_cell",
|
||||
"ring",
|
||||
"rustls-pki-types",
|
||||
"rustls-webpki",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pki-types"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c"
|
||||
|
||||
[[package]]
|
||||
name = "rustls-webpki"
|
||||
version = "0.102.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9"
|
||||
dependencies = [
|
||||
"ring",
|
||||
"rustls-pki-types",
|
||||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4"
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.98"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "022db8904dfa342efe721985167e9fcd16c29b226db4397ed752a761cfce81e8"
|
||||
dependencies = [
|
||||
"tinyvec_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec_macros"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.43.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"pin-project-lite",
|
||||
"tokio-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-macros"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
version = "0.1.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956"
|
||||
dependencies = [
|
||||
"tinyvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "untrusted"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
|
||||
|
||||
[[package]]
|
||||
name = "ureq"
|
||||
version = "2.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02d1a66277ed75f640d608235660df48c8e3c19f3b4edb6a263315626cc3c01d"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"log",
|
||||
"once_cell",
|
||||
"rustls",
|
||||
"rustls-pki-types",
|
||||
"url",
|
||||
"webpki-roots",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"idna",
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"rustversion",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-futures"
|
||||
version = "0.4.50"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
"once_cell",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.77"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webpki-roots"
|
||||
version = "0.26.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2210b291f7ea53617fbafcc4939f10914214ec15aace5ba62293a668f322c5c9"
|
||||
dependencies = [
|
||||
"rustls-pki-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "which"
|
||||
version = "7.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2774c861e1f072b3aadc02f8ba886c26ad6321567ecc294c935434cad06f1283"
|
||||
dependencies = [
|
||||
"either",
|
||||
"env_home",
|
||||
"rustix",
|
||||
"winsafe",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.59.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "winsafe"
|
||||
version = "0.0.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904"
|
||||
|
||||
[[package]]
|
||||
name = "zeroize"
|
||||
version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
|
||||
|
||||
[[package]]
|
||||
name = "zip"
|
||||
version = "0.6.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"crc32fast",
|
||||
"crossbeam-utils",
|
||||
"flate2",
|
||||
]
|
||||
8
Cargo.toml
Normal file
8
Cargo.toml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
# This file is used for telling Rust-related tools
|
||||
# where various Rust crates are.
|
||||
# This also unifies `./target` output folder and
|
||||
# various Rust configurations.
|
||||
|
||||
[workspace]
|
||||
members = ["./native/*"]
|
||||
resolver = "2"
|
||||
52
README.md
52
README.md
|
|
@ -7,14 +7,9 @@ An open-source media manager app built with Flutter, designed to stream videos f
|
|||
- **Cross-Platform Support**: Works on Android, iOS supported by Flutter.
|
||||
- **Open Source**: Contributions are welcome!
|
||||
|
||||
|
||||
## TODO
|
||||
|
||||
- [ ] Update dialog
|
||||
|
||||
## Screenshots
|
||||
|
||||
<img src="readme/image/home.jpg" width="250" title="Home Page">
|
||||
<img alt="Application Screenshot" src="https://downloads.madari.media/madari_app_images/madari_5.jpeg" width="250" title="Home Page">
|
||||
|
||||
## Getting Started
|
||||
|
||||
|
|
@ -48,9 +43,52 @@ This application is designed to be an open source media player that can process
|
|||
|
||||
The developers of Madari:
|
||||
|
||||
Do not host, develop, or distribute any content
|
||||
Do not host, develop, or distribute any content
|
||||
Do not endorse or promote copyright infringement or illegal activities
|
||||
Are not responsible for third-party add-ons or content accessed through them
|
||||
Expect users to respect intellectual property rights and their local laws
|
||||
|
||||
Users are solely responsible for the add-ons they install and content they access through the application.
|
||||
|
||||
## Using Rust Inside Flutter
|
||||
|
||||
This project leverages Flutter for GUI and Rust for the backend logic,
|
||||
utilizing the capabilities of the
|
||||
[Rinf](https://pub.dev/packages/rinf) framework.
|
||||
|
||||
To run and build this app, you need to have
|
||||
[Flutter SDK](https://docs.flutter.dev/get-started/install)
|
||||
and [Rust toolchain](https://www.rust-lang.org/tools/install)
|
||||
installed on your system.
|
||||
You can check that your system is ready with the commands below.
|
||||
Note that all the Flutter subcomponents should be installed.
|
||||
|
||||
```shell
|
||||
rustc --version
|
||||
flutter doctor
|
||||
```
|
||||
|
||||
You also need to have the CLI tool for Rinf ready.
|
||||
|
||||
```shell
|
||||
cargo install rinf
|
||||
```
|
||||
|
||||
Messages sent between Dart and Rust are implemented using Protobuf.
|
||||
If you have newly cloned the project repository
|
||||
or made changes to the `.proto` files in the `./messages` directory,
|
||||
run the following command:
|
||||
|
||||
```shell
|
||||
rinf message
|
||||
```
|
||||
|
||||
Now you can run and build this app just like any other Flutter projects.
|
||||
|
||||
```shell
|
||||
flutter run
|
||||
```
|
||||
|
||||
For detailed instructions on writing Rust and Flutter together,
|
||||
please refer to Rinf's [documentation](https://rinf.cunarist.com).
|
||||
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -136,6 +136,8 @@ PODS:
|
|||
- permission_handler_apple (9.3.0):
|
||||
- Flutter
|
||||
- PromisesObjC (2.4.0)
|
||||
- rinf (0.1.0):
|
||||
- Flutter
|
||||
- SDWebImage (5.20.0):
|
||||
- SDWebImage/Core (= 5.20.0)
|
||||
- SDWebImage/Core (5.20.0)
|
||||
|
|
@ -190,6 +192,7 @@ DEPENDENCIES:
|
|||
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
|
||||
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
|
||||
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
|
||||
- rinf (from `.symlinks/plugins/rinf/ios`)
|
||||
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
|
||||
- sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`)
|
||||
- sqlite3_flutter_libs (from `.symlinks/plugins/sqlite3_flutter_libs/darwin`)
|
||||
|
|
@ -248,6 +251,8 @@ EXTERNAL SOURCES:
|
|||
:path: ".symlinks/plugins/path_provider_foundation/darwin"
|
||||
permission_handler_apple:
|
||||
:path: ".symlinks/plugins/permission_handler_apple/ios"
|
||||
rinf:
|
||||
:path: ".symlinks/plugins/rinf/ios"
|
||||
shared_preferences_foundation:
|
||||
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
|
||||
sqflite_darwin:
|
||||
|
|
@ -293,6 +298,7 @@ SPEC CHECKSUMS:
|
|||
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
|
||||
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
|
||||
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
|
||||
rinf: 75ee395a39eedbc6aa8c7698ad04faa0f47753c6
|
||||
SDWebImage: 73c6079366fea25fa4bb9640d5fb58f0893facd8
|
||||
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
|
||||
sqflite_darwin: 5a7236e3b501866c1c9befc6771dfd73ffb8702d
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:madari_client/features/pocketbase/service/pocketbase.service.dart';
|
||||
import 'package:madari_client/features/video_player/container/state/video_settings.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import '../features/settings/service/selected_profile.dart';
|
||||
import '../features/theme/provider/theme_provider.dart';
|
||||
import 'app_router.dart';
|
||||
|
||||
|
|
@ -25,31 +24,33 @@ class _AppDefaultState extends State<AppDefault> {
|
|||
void initState() {
|
||||
_router = createRouterDesktop();
|
||||
|
||||
if (AppPocketBaseService.instance.pb.authStore.isValid) {
|
||||
SelectedProfileService.instance.initialize();
|
||||
}
|
||||
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Consumer<ThemeProvider>(
|
||||
builder: (context, themeProvider, child) {
|
||||
final theme = themeProvider.getTheme();
|
||||
|
||||
return ChangeNotifierProvider(
|
||||
create: (context) => VideoSettingsProvider(),
|
||||
child: MaterialApp.router(
|
||||
routerConfig: _router,
|
||||
title: "Madari",
|
||||
theme: theme.copyWith(
|
||||
textTheme: GoogleFonts.exo2TextTheme(theme.textTheme),
|
||||
),
|
||||
debugShowCheckedModeBanner: false, // comes in the way of the search
|
||||
),
|
||||
);
|
||||
return Shortcuts(
|
||||
shortcuts: <LogicalKeySet, Intent>{
|
||||
LogicalKeySet(LogicalKeyboardKey.select): const ActivateIntent(),
|
||||
},
|
||||
child: Consumer<ThemeProvider>(
|
||||
builder: (context, themeProvider, child) {
|
||||
final theme = themeProvider.getTheme();
|
||||
|
||||
return ChangeNotifierProvider(
|
||||
create: (context) => VideoSettingsProvider(),
|
||||
child: MaterialApp.router(
|
||||
routerConfig: _router,
|
||||
title: "Madari",
|
||||
theme: theme.copyWith(
|
||||
textTheme: GoogleFonts.exo2TextTheme(theme.textTheme),
|
||||
),
|
||||
debugShowCheckedModeBanner:
|
||||
false, // comes in the way of the search
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import 'package:go_router/go_router.dart';
|
|||
import 'package:madari_client/features/downloads/pages/downloads_page.dart';
|
||||
import 'package:madari_client/features/offline_ratings/pages/offline_ratings.dart';
|
||||
import 'package:madari_client/features/settings/pages/profile_page.dart';
|
||||
import 'package:madari_engine/madari_engine.dart';
|
||||
|
||||
import '../features/accounts/pages/external_account.dart';
|
||||
import '../features/auth/pages/forget_password_page.dart';
|
||||
|
|
@ -14,7 +15,6 @@ import '../features/layout/widgets/scaffold_with_nav.dart';
|
|||
import '../features/library/container/create_list_widget.dart';
|
||||
import '../features/library/pages/library.page.dart';
|
||||
import '../features/library/pages/list_detail_page.dart';
|
||||
import '../features/library/types/library_types.dart';
|
||||
import '../features/pocketbase/service/pocketbase.service.dart';
|
||||
import '../features/settings/pages/appearance_page.dart';
|
||||
import '../features/settings/pages/change_password_page.dart';
|
||||
|
|
@ -27,7 +27,6 @@ import '../features/settings/pages/subprofiles_page.dart';
|
|||
import '../features/streamio_addons/pages/stremio_addons_page.dart';
|
||||
import '../features/video_player/container/video_player.dart';
|
||||
import '../features/widgetter/plugins/stremio/pages/streamio_item_viewer.dart';
|
||||
import '../features/zeku/pages/integration_page.dart';
|
||||
|
||||
final GlobalKey<NavigatorState> _rootNavigatorKey = GlobalKey<NavigatorState>();
|
||||
final GlobalKey<StatefulNavigationShellState> _shellNavigatorKey =
|
||||
|
|
@ -46,7 +45,7 @@ final GlobalKey<NavigatorState> _exploreNavigatorKey =
|
|||
GoRouter createRouterDesktop() {
|
||||
return GoRouter(
|
||||
navigatorKey: _rootNavigatorKey,
|
||||
initialLocation: '/',
|
||||
initialLocation: '/profile',
|
||||
refreshListenable: ValueNotifier(
|
||||
AppPocketBaseService.instance.pb.authStore.onChange,
|
||||
),
|
||||
|
|
@ -83,10 +82,6 @@ GoRouter createRouterDesktop() {
|
|||
path: "/downloads",
|
||||
builder: (context, state) => const DownloadsPage(),
|
||||
),
|
||||
GoRoute(
|
||||
path: "/settings/integration",
|
||||
builder: (context, state) => const IntegrationPage(),
|
||||
),
|
||||
StatefulShellRoute.indexedStack(
|
||||
key: _shellNavigatorKey,
|
||||
builder: (context, state, navigationShell) {
|
||||
|
|
|
|||
|
|
@ -1,234 +0,0 @@
|
|||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../service/zeku_service.dart';
|
||||
|
||||
class ServicesGrid extends StatefulWidget {
|
||||
const ServicesGrid({super.key});
|
||||
|
||||
@override
|
||||
State<ServicesGrid> createState() => _ServicesGridState();
|
||||
}
|
||||
|
||||
class _ServicesGridState extends State<ServicesGrid> {
|
||||
final _zekuService = ZekuService();
|
||||
late Future<List<ZekuServiceItem>> _servicesFuture;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_servicesFuture = _zekuService.getServices();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
|
||||
return FutureBuilder<List<ZekuServiceItem>>(
|
||||
future: _servicesFuture,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
return Center(
|
||||
child: CircularProgressIndicator(
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (snapshot.hasError) {
|
||||
return Center(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.error_outline,
|
||||
color: theme.colorScheme.error,
|
||||
size: 48,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
'Failed to load services',
|
||||
style: theme.textTheme.titleMedium?.copyWith(
|
||||
color: theme.colorScheme.error,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'${snapshot.error}',
|
||||
style: theme.textTheme.titleMedium?.copyWith(
|
||||
color: theme.colorScheme.error,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_servicesFuture = _zekuService.getServices();
|
||||
});
|
||||
},
|
||||
child: const Text('Retry'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
final services = snapshot.data ?? [];
|
||||
|
||||
if (services.isEmpty) {
|
||||
return Center(
|
||||
child: Text(
|
||||
'No services available',
|
||||
style: theme.textTheme.titleMedium?.copyWith(
|
||||
color: theme.colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return ListView.builder(
|
||||
padding: const EdgeInsets.all(0),
|
||||
itemCount: services.length,
|
||||
itemBuilder: (context, index) {
|
||||
final service = services[index];
|
||||
return ServiceCard(
|
||||
service: service,
|
||||
onRefresh: () {
|
||||
setState(() {
|
||||
_servicesFuture = _zekuService.getServices();
|
||||
});
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ServiceCard extends StatefulWidget {
|
||||
final ZekuServiceItem service;
|
||||
final VoidCallback onRefresh;
|
||||
|
||||
const ServiceCard({
|
||||
super.key,
|
||||
required this.service,
|
||||
required this.onRefresh,
|
||||
});
|
||||
|
||||
@override
|
||||
State<ServiceCard> createState() => _ServiceCardState();
|
||||
}
|
||||
|
||||
class _ServiceCardState extends State<ServiceCard> {
|
||||
authenticate() async {
|
||||
await ZekuService.instance.authenticate();
|
||||
|
||||
showAdaptiveDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
title: const Text("Authenticated?"),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: const Text("Cancel"),
|
||||
),
|
||||
TextButton(
|
||||
child: const Text("Refresh"),
|
||||
onPressed: () {
|
||||
widget.onRefresh();
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
disconnect(String service) async {
|
||||
await ZekuService.instance.removeSession(service);
|
||||
widget.onRefresh();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
|
||||
return Card(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Row(
|
||||
children: [
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: SizedBox(
|
||||
width: 60,
|
||||
height: 60,
|
||||
child: CachedNetworkImage(
|
||||
imageUrl: widget.service.logo,
|
||||
fit: BoxFit.cover,
|
||||
placeholder: (context, url) => Center(
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2,
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
),
|
||||
errorWidget: (context, url, error) => Container(
|
||||
color: theme.colorScheme.surfaceContainerHighest,
|
||||
child: Icon(
|
||||
Icons.image_not_supported,
|
||||
color: theme.colorScheme.onSurfaceVariant,
|
||||
size: 24,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
widget.service.name,
|
||||
style: theme.textTheme.titleMedium?.copyWith(
|
||||
color: theme.colorScheme.onSurface,
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
widget.service.website,
|
||||
style: theme.textTheme.bodyMedium?.copyWith(
|
||||
color: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
if (widget.service.enabled) {
|
||||
disconnect(widget.service.name);
|
||||
} else {
|
||||
authenticate();
|
||||
}
|
||||
},
|
||||
child: widget.service.enabled
|
||||
? const Text("Disconnect")
|
||||
: const Text("Authenticate"),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:madari_client/features/accounts/container/trakt.container.dart';
|
||||
|
||||
import '../../settings/widget/setting_wrapper.dart';
|
||||
|
||||
|
|
@ -14,8 +13,8 @@ class ExternalAccount extends StatelessWidget {
|
|||
appBar: AppBar(
|
||||
title: const Text("External Accounts"),
|
||||
),
|
||||
body: const SettingWrapper(
|
||||
child: ServicesGrid(),
|
||||
body: SettingWrapper(
|
||||
child: Container(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,114 +0,0 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
import 'package:madari_client/features/pocketbase/service/pocketbase.service.dart';
|
||||
import 'package:madari_client/features/settings/service/selected_profile.dart';
|
||||
import 'package:url_launcher/url_launcher_string.dart';
|
||||
|
||||
part 'zeku_service.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
class ZekuServiceItem {
|
||||
final String name;
|
||||
final String logo;
|
||||
final String website;
|
||||
final bool enabled;
|
||||
|
||||
ZekuServiceItem({
|
||||
required this.name,
|
||||
required this.logo,
|
||||
required this.website,
|
||||
required this.enabled,
|
||||
});
|
||||
|
||||
factory ZekuServiceItem.fromJson(Map<String, dynamic> json) {
|
||||
return _$ZekuServiceItemFromJson(json);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => _$ZekuServiceItemToJson(this);
|
||||
}
|
||||
|
||||
class ZekuService {
|
||||
static final ZekuService _instance = ZekuService._internal();
|
||||
final pocketbase = AppPocketBaseService.instance.pb;
|
||||
final String endpoint =
|
||||
kDebugMode ? 'http://100.64.0.1:3001' : 'https://zeku.madari.media';
|
||||
|
||||
authenticate() async {
|
||||
final result = await http.get(
|
||||
Uri.parse(
|
||||
"$endpoint/${SelectedProfileService.instance.selectedProfileId}/session",
|
||||
),
|
||||
headers: {
|
||||
"Authorization":
|
||||
"Bearer ${AppPocketBaseService.instance.pb.authStore.token}",
|
||||
},
|
||||
);
|
||||
|
||||
final res = jsonDecode(result.body);
|
||||
|
||||
final id = res["data"]["id"];
|
||||
|
||||
await launchUrlString(
|
||||
"$endpoint/$id/trakt/auth",
|
||||
);
|
||||
}
|
||||
|
||||
disconnect() async {}
|
||||
|
||||
factory ZekuService() {
|
||||
return _instance;
|
||||
}
|
||||
|
||||
ZekuService._internal();
|
||||
|
||||
static ZekuService get instance => _instance;
|
||||
|
||||
final List<ZekuServiceItem> _services = [];
|
||||
|
||||
Future<List<ZekuServiceItem>> getServices() async {
|
||||
try {
|
||||
final result = await http.get(
|
||||
Uri.parse(
|
||||
"$endpoint/${SelectedProfileService.instance.selectedProfileId}/services",
|
||||
),
|
||||
headers: {
|
||||
"Authorization":
|
||||
"Bearer ${AppPocketBaseService.instance.pb.authStore.token}",
|
||||
},
|
||||
);
|
||||
|
||||
final bodyParsed = jsonDecode(result.body);
|
||||
|
||||
final List<ZekuServiceItem> returnValue = [];
|
||||
|
||||
for (final item in bodyParsed["data"]) {
|
||||
returnValue.add(ZekuServiceItem.fromJson(item));
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
} catch (e) {
|
||||
throw Exception('Failed to fetch services: $e');
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> removeSession(String service) async {
|
||||
final result = await http.get(
|
||||
Uri.parse(
|
||||
"$endpoint/${SelectedProfileService.instance.selectedProfileId}/${service.toLowerCase()}/revoke",
|
||||
),
|
||||
headers: {
|
||||
"Authorization":
|
||||
"Bearer ${AppPocketBaseService.instance.pb.authStore.token}",
|
||||
},
|
||||
);
|
||||
|
||||
if (result.statusCode != 200) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:madari_client/features/streamio_addons/service/stremio_addon_service.dart';
|
||||
import 'package:pocketbase/pocketbase.dart';
|
||||
|
||||
|
|
@ -17,6 +17,7 @@ class SignInPage extends StatefulWidget {
|
|||
|
||||
class _SignInPageState extends State<SignInPage>
|
||||
with SingleTickerProviderStateMixin {
|
||||
final _logger = Logger("SignInPage");
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
final _emailController = TextEditingController();
|
||||
final _passwordController = TextEditingController();
|
||||
|
|
@ -195,18 +196,7 @@ class _SignInPageState extends State<SignInPage>
|
|||
|
||||
return Scaffold(
|
||||
backgroundColor: colorScheme.surface,
|
||||
body: RawKeyboardListener(
|
||||
focusNode: FocusNode(),
|
||||
onKey: (RawKeyEvent event) {
|
||||
if (event is RawKeyDownEvent) {
|
||||
if (event.logicalKey == LogicalKeyboardKey.select) {
|
||||
// Handle select button press based on current focus
|
||||
if (_signInButtonFocusNode.hasFocus) {
|
||||
_signIn();
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
body: SafeArea(
|
||||
child: Stack(
|
||||
children: [
|
||||
Positioned(
|
||||
|
|
@ -461,7 +451,12 @@ class _SignInPageState extends State<SignInPage>
|
|||
if (mounted) {
|
||||
context.go('/profile');
|
||||
}
|
||||
} on ClientException catch (e) {
|
||||
} on ClientException catch (e, stack) {
|
||||
_logger.warning(
|
||||
"Failed to login",
|
||||
e,
|
||||
stack,
|
||||
);
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
|
|||
import 'package:go_router/go_router.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:madari_client/consts/data.dart';
|
||||
import 'package:madari_client/features/settings/service/selected_profile.dart';
|
||||
import 'package:madari_client/features/streamio_addons/extension/query_extension.dart';
|
||||
import 'package:madari_client/features/streamio_addons/service/stremio_addon_service.dart';
|
||||
import 'package:pocketbase/pocketbase.dart';
|
||||
|
|
@ -468,10 +467,10 @@ class _SignUpPageState extends State<SignUpPage>
|
|||
|
||||
await pocketbase.collection('users').create(body: userData);
|
||||
|
||||
await pocketbase.collection('users').authWithPassword(
|
||||
_emailController.text.trim(),
|
||||
_passwordController.text,
|
||||
);
|
||||
await AppPocketBaseService.instance.engine.authService.signInWithEmail(
|
||||
email: _emailController.text.trim(),
|
||||
password: _passwordController.text.trim(),
|
||||
);
|
||||
|
||||
final profile = await pocketbase.collection('account_profile').create(
|
||||
body: {
|
||||
|
|
@ -481,7 +480,8 @@ class _SignUpPageState extends State<SignUpPage>
|
|||
},
|
||||
);
|
||||
|
||||
await SelectedProfileService.instance.setSelectedProfile(profile.id);
|
||||
await AppPocketBaseService.instance.engine.profileService
|
||||
.setCurrentProfile(profile.id);
|
||||
|
||||
for (final defaultAddon in defaultAppAddons) {
|
||||
final manifest = await StremioAddonService.instance
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import 'package:cached_query_flutter/cached_query_flutter.dart';
|
|||
import 'package:cached_storage/cached_storage.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:madari_client/features/settings/service/selected_profile.dart';
|
||||
import 'package:media_kit/media_kit.dart';
|
||||
import 'package:universal_platform/universal_platform.dart';
|
||||
import 'package:window_manager/window_manager.dart';
|
||||
|
|
@ -19,7 +18,6 @@ Future startupApp() async {
|
|||
|
||||
await AppPocketBaseService.ensureInitialized();
|
||||
await AppTheme().ensureInitialized();
|
||||
await SelectedProfileService.instance.initialize();
|
||||
|
||||
final pb = AppPocketBaseService.instance.pb;
|
||||
final userCollection = pb.collection("users");
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ import 'package:flex_color_picker/flex_color_picker.dart';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:madari_client/features/streamio_addons/extension/query_extension.dart';
|
||||
import 'package:madari_client/features/streamio_addons/models/stremio_base_types.dart';
|
||||
import 'package:madari_client/features/streamio_addons/service/stremio_addon_service.dart';
|
||||
import 'package:madari_client/utils/array-extension.dart';
|
||||
import 'package:madari_engine/madari_engine.dart';
|
||||
|
||||
import '../../widgetter/plugins/stremio/widgets/catalog_grid_full.dart';
|
||||
import '../../widgetter/plugins/stremio/widgets/error_card.dart';
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ import 'package:flutter/material.dart';
|
|||
import 'package:madari_client/features/streamio_addons/extension/query_extension.dart';
|
||||
import 'package:madari_client/features/streamio_addons/service/stremio_addon_service.dart';
|
||||
import 'package:madari_client/features/widgetter/plugins/stremio/widgets/error_card.dart';
|
||||
import 'package:madari_engine/madari_engine.dart';
|
||||
|
||||
import '../../streamio_addons/models/stremio_base_types.dart';
|
||||
import '../containers/explore_addon.dart';
|
||||
|
||||
class ExplorePage extends StatefulWidget {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import 'dart:async';
|
|||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:madari_client/features/settings/service/selected_profile.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:universal_platform/universal_platform.dart';
|
||||
|
||||
|
|
@ -26,8 +25,6 @@ class HomePage extends StatefulWidget {
|
|||
class _HomePageState extends State<HomePage> {
|
||||
final _state = GlobalKey<LayoutManagerState>();
|
||||
|
||||
late StreamSubscription<String?> _selectedProfile;
|
||||
|
||||
Widget _buildLogo() {
|
||||
return Image.asset(
|
||||
'assets/icon/icon_mini.png',
|
||||
|
|
@ -38,18 +35,12 @@ class _HomePageState extends State<HomePage> {
|
|||
|
||||
@override
|
||||
void initState() {
|
||||
_selectedProfile =
|
||||
SelectedProfileService.instance.selectedProfileStream.listen((data) {
|
||||
_state.currentState?.refresh();
|
||||
});
|
||||
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
_selectedProfile.cancel();
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
|||
|
|
@ -1,76 +0,0 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../models/navigation.model.dart';
|
||||
|
||||
class TVNavigation extends StatefulWidget {
|
||||
final List<NavigationItem> items;
|
||||
final String currentLocation;
|
||||
final ValueChanged<int> onNavigate;
|
||||
final bool isTV;
|
||||
|
||||
const TVNavigation({
|
||||
super.key,
|
||||
required this.items,
|
||||
required this.currentLocation,
|
||||
required this.onNavigate,
|
||||
this.isTV = false,
|
||||
});
|
||||
|
||||
@override
|
||||
State<TVNavigation> createState() => _TVNavigationState();
|
||||
}
|
||||
|
||||
class _TVNavigationState extends State<TVNavigation> {
|
||||
bool _isExpanded = true;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
|
||||
return AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
width: _isExpanded ? 240.0 : 72.0,
|
||||
child: Drawer(
|
||||
elevation: 0,
|
||||
child: Column(
|
||||
crossAxisAlignment: _isExpanded
|
||||
? CrossAxisAlignment.start
|
||||
: CrossAxisAlignment.center,
|
||||
children: [
|
||||
if (!widget.isTV)
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: IconButton(
|
||||
icon: Icon(
|
||||
_isExpanded ? Icons.chevron_left : Icons.chevron_right),
|
||||
onPressed: () => setState(() => _isExpanded = !_isExpanded),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: ListView(
|
||||
children: widget.items.map((item) {
|
||||
final isSelected =
|
||||
widget.currentLocation.startsWith(item.path);
|
||||
return ListTile(
|
||||
selected: isSelected,
|
||||
leading: Icon(
|
||||
isSelected ? item.selectedIcon ?? item.icon : item.icon,
|
||||
color: isSelected ? theme.colorScheme.primary : null,
|
||||
),
|
||||
title: _isExpanded ? Text(item.label) : null,
|
||||
onTap: () => widget.onNavigate(0),
|
||||
autofocus: widget.isTV && isSelected,
|
||||
selectedTileColor:
|
||||
theme.colorScheme.primaryContainer.withValues(
|
||||
alpha: 0.2,
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,9 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:madari_engine/madari_engine.dart';
|
||||
|
||||
import '../../streamio_addons/models/stremio_base_types.dart';
|
||||
import '../service/list_service.dart';
|
||||
import '../types/library_types.dart';
|
||||
import '../../pocketbase/service/pocketbase.service.dart';
|
||||
|
||||
class AddToListButton extends StatefulWidget {
|
||||
final Meta meta;
|
||||
|
|
@ -57,7 +56,8 @@ class _AddToListButtonState extends State<AddToListButton> {
|
|||
try {
|
||||
setState(() => _isLoading = true);
|
||||
|
||||
final lists = await ListsService.instance.getLists();
|
||||
final lists =
|
||||
await AppPocketBaseService.instance.engine.listService.getLists();
|
||||
_existingList = lists.cast<ListModel?>().firstWhere(
|
||||
(list) =>
|
||||
list?.name.toLowerCase() == widget.listName?.toLowerCase(),
|
||||
|
|
@ -65,8 +65,8 @@ class _AddToListButtonState extends State<AddToListButton> {
|
|||
);
|
||||
|
||||
if (_existingList != null) {
|
||||
final items =
|
||||
await ListsService.instance.getListItems(_existingList!.id);
|
||||
final items = await AppPocketBaseService.instance.engine.listService
|
||||
.getListItems(_existingList!.id);
|
||||
final existingItem = items.cast<ListItemModel?>().firstWhere(
|
||||
(item) => item?.imdbId == widget.meta.imdbId,
|
||||
orElse: () => null,
|
||||
|
|
@ -89,7 +89,8 @@ class _AddToListButtonState extends State<AddToListButton> {
|
|||
Future<void> _loadLists() async {
|
||||
try {
|
||||
setState(() => _isLoading = true);
|
||||
_lists = await ListsService.instance.getLists();
|
||||
_lists =
|
||||
await AppPocketBaseService.instance.engine.listService.getLists();
|
||||
setState(() => _isLoading = false);
|
||||
} catch (e) {
|
||||
_logger.severe('Error loading lists', e);
|
||||
|
|
@ -102,7 +103,8 @@ class _AddToListButtonState extends State<AddToListButton> {
|
|||
try {
|
||||
setState(() => _isLoading = true);
|
||||
|
||||
final lists = await ListsService.instance.getLists();
|
||||
final lists =
|
||||
await AppPocketBaseService.instance.engine.listService.getLists();
|
||||
ListModel? list = lists.cast<ListModel?>().firstWhere(
|
||||
(list) => list?.name.toLowerCase() == listName.toLowerCase(),
|
||||
orElse: () => null,
|
||||
|
|
@ -113,9 +115,11 @@ class _AddToListButtonState extends State<AddToListButton> {
|
|||
name: listName,
|
||||
description: '',
|
||||
);
|
||||
await ListsService.instance.createList(request);
|
||||
await AppPocketBaseService.instance.engine.listService
|
||||
.createList(request);
|
||||
|
||||
final updatedLists = await ListsService.instance.getLists();
|
||||
final updatedLists =
|
||||
await AppPocketBaseService.instance.engine.listService.getLists();
|
||||
list = updatedLists.firstWhere(
|
||||
(l) => l.name.toLowerCase() == listName.toLowerCase(),
|
||||
);
|
||||
|
|
@ -159,7 +163,8 @@ class _AddToListButtonState extends State<AddToListButton> {
|
|||
0.0,
|
||||
);
|
||||
|
||||
await ListsService.instance.addListItem(list.id, item);
|
||||
await AppPocketBaseService.instance.engine.listService
|
||||
.addListItem(list.id, item);
|
||||
|
||||
if (context.mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
|
|
@ -192,7 +197,8 @@ class _AddToListButtonState extends State<AddToListButton> {
|
|||
BuildContext context, String itemId, ListModel list) async {
|
||||
try {
|
||||
setState(() => _isLoading = true);
|
||||
await ListsService.instance.removeListItem(list.id, itemId);
|
||||
await AppPocketBaseService.instance.engine.listService
|
||||
.removeListItem(list.id, itemId);
|
||||
|
||||
if (context.mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:madari_engine/madari_engine.dart';
|
||||
|
||||
import '../../pocketbase/service/pocketbase.service.dart';
|
||||
import '../service/list_service.dart';
|
||||
import '../service/trakt_service.dart';
|
||||
import '../types/library_types.dart';
|
||||
|
||||
class CreateListPage extends StatefulWidget {
|
||||
const CreateListPage({super.key});
|
||||
|
|
@ -57,7 +56,8 @@ class _CreateListPageState extends State<CreateListPage> {
|
|||
name: _nameController.text,
|
||||
description: _descriptionController.text,
|
||||
);
|
||||
await ListsService.instance.createList(request);
|
||||
await AppPocketBaseService.instance.engine.listService
|
||||
.createList(request);
|
||||
if (mounted) {
|
||||
context.pop(true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,12 +3,11 @@ import 'dart:async';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:madari_client/features/settings/service/selected_profile.dart';
|
||||
import 'package:madari_client/features/settings/widget/setting_wrapper.dart';
|
||||
import 'package:madari_engine/madari_engine.dart';
|
||||
|
||||
import '../service/list_service.dart';
|
||||
import '../../pocketbase/service/pocketbase.service.dart';
|
||||
import '../service/trakt_service.dart';
|
||||
import '../types/library_types.dart';
|
||||
|
||||
class LibraryPage extends StatefulWidget {
|
||||
const LibraryPage({super.key});
|
||||
|
|
@ -29,11 +28,6 @@ class _LibraryPageState extends State<LibraryPage> {
|
|||
void initState() {
|
||||
super.initState();
|
||||
_loadLists();
|
||||
|
||||
_item =
|
||||
SelectedProfileService.instance.selectedProfileStream.listen((item) {
|
||||
_loadLists();
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
@ -46,7 +40,8 @@ class _LibraryPageState extends State<LibraryPage> {
|
|||
Future<void> _loadLists() async {
|
||||
try {
|
||||
setState(() => _isLoading = true);
|
||||
final lists = await ListsService.instance.getLists();
|
||||
final lists =
|
||||
await AppPocketBaseService.instance.engine.listService.getLists();
|
||||
setState(() {
|
||||
_lists = lists;
|
||||
_isLoading = false;
|
||||
|
|
@ -60,7 +55,8 @@ class _LibraryPageState extends State<LibraryPage> {
|
|||
Future<void> _refreshLists() async {
|
||||
try {
|
||||
setState(() => _isRefreshing = true);
|
||||
final lists = await ListsService.instance.getLists();
|
||||
final lists =
|
||||
await AppPocketBaseService.instance.engine.listService.getLists();
|
||||
setState(() {
|
||||
_lists = lists;
|
||||
_isRefreshing = false;
|
||||
|
|
@ -73,7 +69,7 @@ class _LibraryPageState extends State<LibraryPage> {
|
|||
|
||||
Future<void> _deleteList(String listId) async {
|
||||
try {
|
||||
await ListsService.instance.deleteList(listId);
|
||||
await AppPocketBaseService.instance.engine.listService.deleteList(listId);
|
||||
_loadLists();
|
||||
} catch (e) {
|
||||
_logger.severe('Error deleting list', e);
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:madari_client/features/pocketbase/service/pocketbase.service.dart';
|
||||
import 'package:madari_client/features/widgetter/plugins/stremio/utils/size.dart';
|
||||
import 'package:madari_engine/madari_engine.dart';
|
||||
|
||||
import '../service/list_service.dart';
|
||||
import '../service/trakt_service.dart';
|
||||
import '../types/library_types.dart';
|
||||
|
||||
class ListDetailsPage extends StatefulWidget {
|
||||
final ListModel list;
|
||||
|
|
@ -35,7 +35,8 @@ class _ListDetailsPageState extends State<ListDetailsPage> {
|
|||
Future<void> _loadItems() async {
|
||||
try {
|
||||
setState(() => _isLoading = true);
|
||||
final items = await ListsService.instance.getListItems(widget.list.id);
|
||||
final items = await AppPocketBaseService.instance.engine.listService
|
||||
.getListItems(widget.list.id);
|
||||
setState(() {
|
||||
_items = items;
|
||||
_isLoading = false;
|
||||
|
|
@ -64,7 +65,8 @@ class _ListDetailsPageState extends State<ListDetailsPage> {
|
|||
|
||||
Future<void> _removeItem(ListItemModel item) async {
|
||||
try {
|
||||
await ListsService.instance.removeListItem(widget.list.id, item.id);
|
||||
await AppPocketBaseService.instance.engine.listService
|
||||
.removeListItem(widget.list.id, item.id);
|
||||
_loadItems();
|
||||
} catch (e) {
|
||||
_logger.severe('Error removing list item', e);
|
||||
|
|
|
|||
|
|
@ -1,114 +0,0 @@
|
|||
import 'package:logging/logging.dart';
|
||||
|
||||
import '../../pocketbase/service/pocketbase.service.dart';
|
||||
import '../../settings/service/selected_profile.dart';
|
||||
import '../types/library_types.dart';
|
||||
|
||||
class ListsService {
|
||||
static final ListsService instance = ListsService._internal();
|
||||
final _logger = Logger('ListsService');
|
||||
|
||||
ListsService._internal();
|
||||
|
||||
Future<List<ListModel>> getLists() async {
|
||||
try {
|
||||
final records =
|
||||
await AppPocketBaseService.instance.pb.collection('list').getFullList(
|
||||
filter:
|
||||
"account_profile = '${SelectedProfileService.instance.selectedProfileId}'",
|
||||
);
|
||||
return records
|
||||
.map((record) => ListModel.fromJson(record.toJson()))
|
||||
.toList();
|
||||
} catch (e) {
|
||||
_logger.severe('Error fetching lists', e);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> createList(CreateListRequest request) async {
|
||||
try {
|
||||
await AppPocketBaseService.instance.pb.collection('list').create(
|
||||
body: request.toJson(),
|
||||
);
|
||||
} catch (e) {
|
||||
_logger.severe('Error creating list', e);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> importTraktList(ListModel traktList) async {
|
||||
try {
|
||||
await AppPocketBaseService.instance.pb.collection('list').create(
|
||||
body: traktList.toJson(),
|
||||
);
|
||||
} catch (e) {
|
||||
_logger.severe('Error importing Trakt list', e);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> updateList(String id, UpdateListRequest request) async {
|
||||
try {
|
||||
await AppPocketBaseService.instance.pb.collection('list').update(
|
||||
id,
|
||||
body: request.toJson(),
|
||||
);
|
||||
} catch (e) {
|
||||
_logger.severe('Error updating list', e);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> deleteList(String id) async {
|
||||
try {
|
||||
await AppPocketBaseService.instance.pb.collection('list').delete(id);
|
||||
} catch (e) {
|
||||
_logger.severe('Error deleting list', e);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> addListItem(String listId, ListItemModel item) async {
|
||||
try {
|
||||
final itemData = item.toJson();
|
||||
itemData['list'] = listId;
|
||||
|
||||
await AppPocketBaseService.instance.pb.collection('list_item').create(
|
||||
body: itemData,
|
||||
);
|
||||
} catch (e) {
|
||||
_logger.severe('Error adding list item', e);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<ListItemModel>> getListItems(String listId) async {
|
||||
try {
|
||||
final records = await AppPocketBaseService.instance.pb
|
||||
.collection('list_item')
|
||||
.getFullList(
|
||||
filter: 'list = "$listId"',
|
||||
sort: '-created',
|
||||
);
|
||||
|
||||
return records
|
||||
.map((record) => ListItemModel.fromJson(record.toJson()))
|
||||
.toList();
|
||||
} catch (e) {
|
||||
_logger.severe('Error fetching list items', e);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> removeListItem(String listId, String itemId) async {
|
||||
try {
|
||||
await AppPocketBaseService.instance.pb
|
||||
.collection('list_item')
|
||||
.delete(itemId);
|
||||
} catch (e) {
|
||||
_logger.severe('Error removing list item', e);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,8 +5,7 @@ import 'package:http/http.dart' as http;
|
|||
import 'package:logging/logging.dart';
|
||||
|
||||
import '../../pocketbase/service/pocketbase.service.dart';
|
||||
import '../types/library_types.dart';
|
||||
import 'list_service.dart';
|
||||
import '../../widgetter/plugins/stremio/models/cast_info.dart';
|
||||
|
||||
final _logger = Logger('TraktService');
|
||||
|
||||
|
|
@ -142,7 +141,7 @@ class TraktService {
|
|||
final items = await getListItems(listId);
|
||||
|
||||
for (final item in items) {
|
||||
await ListsService.instance.addListItem(
|
||||
await AppPocketBaseService.instance.engine.listService.addListItem(
|
||||
listId,
|
||||
ListItemModel(
|
||||
id: '',
|
||||
|
|
|
|||
|
|
@ -1,148 +1 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:madari_client/features/settings/service/selected_profile.dart';
|
||||
|
||||
import '../../pocketbase/service/pocketbase.service.dart';
|
||||
|
||||
class ListModel {
|
||||
final String id;
|
||||
final String name;
|
||||
final String description;
|
||||
final int order;
|
||||
final bool sync;
|
||||
final String? traktListId;
|
||||
|
||||
ListModel({
|
||||
required this.id,
|
||||
required this.name,
|
||||
required this.description,
|
||||
required this.order,
|
||||
required this.sync,
|
||||
this.traktListId,
|
||||
});
|
||||
|
||||
factory ListModel.fromJson(Map<String, dynamic> json) {
|
||||
return ListModel(
|
||||
id: json['id'],
|
||||
name: json['name'],
|
||||
description: json['description'],
|
||||
order: json['order'],
|
||||
sync: json['sync'],
|
||||
traktListId: json['trakt_list_id'],
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'id': id,
|
||||
'name': name,
|
||||
'description': description,
|
||||
'order': order,
|
||||
'sync': sync,
|
||||
'trakt_list_id': traktListId,
|
||||
};
|
||||
}
|
||||
|
||||
ListModel copyWith({
|
||||
String? name,
|
||||
String? description,
|
||||
int? order,
|
||||
bool? sync,
|
||||
String? traktListId,
|
||||
}) {
|
||||
return ListModel(
|
||||
id: id,
|
||||
name: name ?? this.name,
|
||||
description: description ?? this.description,
|
||||
order: order ?? this.order,
|
||||
sync: sync ?? this.sync,
|
||||
traktListId: traktListId ?? this.traktListId,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ListItemModel {
|
||||
final String id;
|
||||
final String type;
|
||||
final String imdbId;
|
||||
final Map<String, dynamic> ids;
|
||||
final String title;
|
||||
final String description;
|
||||
final String poster;
|
||||
final double rating;
|
||||
|
||||
ListItemModel({
|
||||
required this.id,
|
||||
required this.type,
|
||||
required this.imdbId,
|
||||
required this.ids,
|
||||
required this.title,
|
||||
required this.description,
|
||||
required this.poster,
|
||||
required this.rating,
|
||||
});
|
||||
|
||||
factory ListItemModel.fromJson(Map<String, dynamic> json) {
|
||||
return ListItemModel(
|
||||
id: json['id'],
|
||||
type: json['type'],
|
||||
imdbId: json['imdb_id'],
|
||||
ids: json['ids'] is String ? jsonDecode(json['ids']) : json['ids'],
|
||||
title: json['title'],
|
||||
description: json['description'],
|
||||
poster: json['poster'],
|
||||
rating: (json['rating'] as num).toDouble(),
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'id': id,
|
||||
'type': type,
|
||||
'imdb_id': imdbId,
|
||||
'ids': ids is String ? ids : jsonEncode(ids),
|
||||
'title': title,
|
||||
'description': description,
|
||||
'poster': poster,
|
||||
'rating': rating,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class CreateListRequest {
|
||||
final String name;
|
||||
final String description;
|
||||
|
||||
CreateListRequest({
|
||||
required this.name,
|
||||
required this.description,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'name': name,
|
||||
'description': description,
|
||||
'order': 0,
|
||||
'sync': false,
|
||||
'user': AppPocketBaseService.instance.pb.authStore.record!.id,
|
||||
'account_profile': SelectedProfileService.instance.selectedProfileId,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class UpdateListRequest {
|
||||
final String name;
|
||||
final String description;
|
||||
|
||||
UpdateListRequest({
|
||||
required this.name,
|
||||
required this.description,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'name': name,
|
||||
'description': description,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:madari_engine/madari_engine.dart';
|
||||
import 'package:pocketbase/pocketbase.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
|
|
@ -8,6 +9,7 @@ class AppPocketBaseService {
|
|||
static AppPocketBaseService? _instance;
|
||||
|
||||
late final PocketBase pb;
|
||||
late final MadariEngine engine;
|
||||
|
||||
static AppPocketBaseService get instance {
|
||||
if (_instance == null) {
|
||||
|
|
@ -37,5 +39,6 @@ class AppPocketBaseService {
|
|||
kDebugMode ? 'http://100.64.0.1:8090' : 'https://api-v2.madari.media',
|
||||
authStore: authStore,
|
||||
);
|
||||
engine = MadariEngine(pb: pb);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,9 +3,7 @@ import 'dart:async';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:madari_client/features/pocketbase/service/pocketbase.service.dart';
|
||||
import 'package:pocketbase/pocketbase.dart';
|
||||
|
||||
import '../service/selected_profile.dart';
|
||||
import 'package:madari_engine/madari_engine.dart';
|
||||
|
||||
class FullProfileSelectorPage extends StatefulWidget {
|
||||
const FullProfileSelectorPage({super.key});
|
||||
|
|
@ -16,34 +14,26 @@ class FullProfileSelectorPage extends StatefulWidget {
|
|||
}
|
||||
|
||||
class _FullProfileSelectorPageState extends State<FullProfileSelectorPage> {
|
||||
final _selectedProfileService = SelectedProfileService.instance;
|
||||
|
||||
late Future<ResultList<RecordModel>> _future;
|
||||
|
||||
late StreamSubscription<String?> _listener;
|
||||
late Future<List<UserProfile>> _future;
|
||||
final profileService = AppPocketBaseService.instance.engine.profileService;
|
||||
String? selectedProfileId;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
_future = AppPocketBaseService.instance.pb
|
||||
.collection('account_profile')
|
||||
.getList();
|
||||
_future =
|
||||
AppPocketBaseService.instance.engine.profileService.getAllProfiles();
|
||||
|
||||
_listener = _selectedProfileService.selectedProfileStream.listen((item) {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_future = AppPocketBaseService.instance.pb
|
||||
.collection('account_profile')
|
||||
.getList();
|
||||
});
|
||||
}
|
||||
AppPocketBaseService.instance.engine.profileService
|
||||
.getCurrentProfile()
|
||||
.then((item) {
|
||||
if (item != null) selectedProfileId = item.id;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_listener.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
|
|
@ -128,16 +118,11 @@ class _FullProfileSelectorPageState extends State<FullProfileSelectorPage> {
|
|||
|
||||
if (!snapshot.hasData) {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator());
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
}
|
||||
|
||||
final profiles = snapshot.data!.items;
|
||||
|
||||
if (_selectedProfileService.selectedProfileId == null &&
|
||||
profiles.isNotEmpty) {
|
||||
_selectedProfileService
|
||||
.setSelectedProfile(profiles[0].id);
|
||||
}
|
||||
final profiles = snapshot.data;
|
||||
|
||||
return GridView.builder(
|
||||
padding: EdgeInsets.all(padding),
|
||||
|
|
@ -148,147 +133,118 @@ class _FullProfileSelectorPageState extends State<FullProfileSelectorPage> {
|
|||
crossAxisSpacing: spacing,
|
||||
mainAxisExtent: isDesktop ? 200 : 160,
|
||||
),
|
||||
itemCount: profiles.length,
|
||||
itemCount: profiles!.length,
|
||||
itemBuilder: (context, index) {
|
||||
final profile = profiles[index];
|
||||
|
||||
return StreamBuilder<String?>(
|
||||
stream:
|
||||
_selectedProfileService.selectedProfileStream,
|
||||
builder: (context, snapshot) {
|
||||
final isSelected = snapshot.data == profile.id;
|
||||
final isSelected = snapshot.data == profile.id;
|
||||
|
||||
return InkWell(
|
||||
onTap: () async {
|
||||
final currentSelectedId =
|
||||
_selectedProfileService
|
||||
.selectedProfileId;
|
||||
final newSelectedId =
|
||||
currentSelectedId == profile.id
|
||||
? profile.id
|
||||
: profile.id;
|
||||
await _selectedProfileService
|
||||
.setSelectedProfile(newSelectedId);
|
||||
return InkWell(
|
||||
onTap: () async {
|
||||
profileService.setCurrentProfile(profile.id);
|
||||
|
||||
if (context.mounted) context.push("/");
|
||||
},
|
||||
if (context.mounted) context.push("/");
|
||||
},
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
color: isSelected
|
||||
? colorScheme.primaryContainer
|
||||
.withOpacity(0.3)
|
||||
: Colors.transparent,
|
||||
border: Border.all(
|
||||
color: isSelected
|
||||
? colorScheme.primary
|
||||
: colorScheme.outlineVariant,
|
||||
width: isSelected ? 2 : 1,
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.center,
|
||||
color: isSelected
|
||||
? colorScheme.primaryContainer
|
||||
.withOpacity(0.3)
|
||||
: Colors.transparent,
|
||||
border: Border.all(
|
||||
color: isSelected
|
||||
? colorScheme.primary
|
||||
: colorScheme.outlineVariant,
|
||||
width: isSelected ? 2 : 1,
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
if (profile.data['profile_image'] !=
|
||||
null &&
|
||||
profile.data['profile_image'] !=
|
||||
"")
|
||||
CircleAvatar(
|
||||
radius: avatarSize,
|
||||
backgroundImage: NetworkImage(
|
||||
AppPocketBaseService
|
||||
.instance.pb.files
|
||||
.getUrl(
|
||||
profile,
|
||||
profile.data[
|
||||
'profile_image'],
|
||||
)
|
||||
.toString(),
|
||||
),
|
||||
)
|
||||
else
|
||||
CircleAvatar(
|
||||
radius: avatarSize,
|
||||
backgroundColor: isSelected
|
||||
? colorScheme.primary
|
||||
: colorScheme
|
||||
.surfaceVariant,
|
||||
child: Text(
|
||||
profile.data['name'][0]
|
||||
.toUpperCase(),
|
||||
style: TextStyle(
|
||||
color: isSelected
|
||||
? colorScheme.onPrimary
|
||||
: colorScheme
|
||||
.onSurfaceVariant,
|
||||
fontSize: avatarSize * 0.75,
|
||||
fontWeight: isSelected
|
||||
? FontWeight.bold
|
||||
: FontWeight.normal,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (isSelected)
|
||||
Positioned(
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(
|
||||
isDesktop ? 6 : 4),
|
||||
decoration: BoxDecoration(
|
||||
color: colorScheme.primary,
|
||||
shape: BoxShape.circle,
|
||||
border: Border.all(
|
||||
color:
|
||||
colorScheme.surface,
|
||||
width: 2,
|
||||
),
|
||||
),
|
||||
child: Icon(
|
||||
Icons.check,
|
||||
color:
|
||||
colorScheme.onPrimary,
|
||||
size: isDesktop ? 24 : 20,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: isDesktop ? 16 : 8,
|
||||
),
|
||||
child: Text(
|
||||
profile.data['name'],
|
||||
style: (isDesktop
|
||||
? theme.textTheme.titleLarge
|
||||
: theme
|
||||
.textTheme.titleMedium)
|
||||
?.copyWith(
|
||||
color: isSelected
|
||||
? colorScheme.primary
|
||||
: null,
|
||||
fontWeight: isSelected
|
||||
? FontWeight.bold
|
||||
: null,
|
||||
if (profile.profileImage != null)
|
||||
CircleAvatar(
|
||||
radius: avatarSize,
|
||||
backgroundImage: NetworkImage(
|
||||
profile.profileImage!,
|
||||
),
|
||||
)
|
||||
else
|
||||
CircleAvatar(
|
||||
radius: avatarSize,
|
||||
backgroundColor: isSelected
|
||||
? colorScheme.primary
|
||||
: colorScheme
|
||||
.surfaceContainerHighest,
|
||||
child: Text(
|
||||
profile.name[0].toUpperCase(),
|
||||
style: TextStyle(
|
||||
color: isSelected
|
||||
? colorScheme.onPrimary
|
||||
: colorScheme
|
||||
.onSurfaceVariant,
|
||||
fontSize: avatarSize * 0.75,
|
||||
fontWeight: isSelected
|
||||
? FontWeight.bold
|
||||
: FontWeight.normal,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (isSelected)
|
||||
Positioned(
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(
|
||||
isDesktop ? 6 : 4),
|
||||
decoration: BoxDecoration(
|
||||
color: colorScheme.primary,
|
||||
shape: BoxShape.circle,
|
||||
border: Border.all(
|
||||
color: colorScheme.surface,
|
||||
width: 2,
|
||||
),
|
||||
),
|
||||
child: Icon(
|
||||
Icons.check,
|
||||
color: colorScheme.onPrimary,
|
||||
size: isDesktop ? 24 : 20,
|
||||
),
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
const SizedBox(height: 16),
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: isDesktop ? 16 : 8,
|
||||
),
|
||||
child: Text(
|
||||
profile.name,
|
||||
style: (isDesktop
|
||||
? theme.textTheme.titleLarge
|
||||
: theme.textTheme.titleMedium)
|
||||
?.copyWith(
|
||||
color: isSelected
|
||||
? colorScheme.primary
|
||||
: null,
|
||||
fontWeight: isSelected
|
||||
? FontWeight.bold
|
||||
: null,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ import 'package:cached_query/cached_query.dart';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:madari_client/features/home/pages/home_page.dart';
|
||||
import 'package:madari_client/features/settings/service/selected_profile.dart';
|
||||
import 'package:madari_client/features/widgetter/plugins/stremio/utils/size.dart';
|
||||
import 'package:pocketbase/pocketbase.dart';
|
||||
|
||||
import '../../pocketbase/service/pocketbase.service.dart';
|
||||
import '../../widgetter/plugin_base.dart';
|
||||
|
|
@ -31,25 +31,35 @@ class _LayoutPageState extends State<LayoutPage> with TickerProviderStateMixin {
|
|||
final double _minCellWidth = 150;
|
||||
final ScrollController _scrollController = ScrollController();
|
||||
bool _isLoading = false;
|
||||
final appProfile = AppPocketBaseService.instance.engine.profileService;
|
||||
|
||||
final query = Query(
|
||||
key: "home_layout",
|
||||
queryFn: () async {
|
||||
return await AppPocketBaseService.instance.pb
|
||||
.collection('home_layout')
|
||||
.getFullList(
|
||||
sort: 'order',
|
||||
filter:
|
||||
'profiles = \'${SelectedProfileService.instance.selectedProfileId}\'',
|
||||
);
|
||||
},
|
||||
);
|
||||
Query<List<RecordModel>>? query;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_logger.info('Initializing LayoutPage');
|
||||
|
||||
(() async {
|
||||
final query = await AppPocketBaseService.instance.engine.profileService
|
||||
.getCurrentProfile();
|
||||
|
||||
this.query = Query(
|
||||
key: "home_layout${query!.id}",
|
||||
queryFn: () async {
|
||||
return await AppPocketBaseService.instance.pb
|
||||
.collection('home_layout')
|
||||
.getFullList(
|
||||
sort: 'order',
|
||||
filter:
|
||||
'profiles = \'${(await appProfile.getCurrentProfile())!.id}\'',
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
setState(() {});
|
||||
})();
|
||||
|
||||
loadData();
|
||||
}
|
||||
|
||||
|
|
@ -135,7 +145,7 @@ class _LayoutPageState extends State<LayoutPage> with TickerProviderStateMixin {
|
|||
newWidget,
|
||||
);
|
||||
|
||||
query.refetch();
|
||||
query?.refetch();
|
||||
|
||||
if (success) {
|
||||
await loadData();
|
||||
|
|
@ -159,7 +169,7 @@ class _LayoutPageState extends State<LayoutPage> with TickerProviderStateMixin {
|
|||
layoutWidgets.remove(widget);
|
||||
});
|
||||
await HomeLayoutService.instance.updateLayoutOrder(layoutWidgets);
|
||||
query.refetch();
|
||||
query?.refetch();
|
||||
_showSuccess('Removed widget successfully');
|
||||
} else {
|
||||
_showError('Failed to remove widget. Please try again.');
|
||||
|
|
@ -195,7 +205,7 @@ class _LayoutPageState extends State<LayoutPage> with TickerProviderStateMixin {
|
|||
final success =
|
||||
await HomeLayoutService.instance.saveLayoutWidget(newWidget);
|
||||
|
||||
query.refetch();
|
||||
query?.refetch();
|
||||
if (success) {
|
||||
successCount++;
|
||||
}
|
||||
|
|
@ -229,7 +239,7 @@ class _LayoutPageState extends State<LayoutPage> with TickerProviderStateMixin {
|
|||
|
||||
final success =
|
||||
await HomeLayoutService.instance.updateLayoutOrder(layoutWidgets);
|
||||
query.refetch();
|
||||
query?.refetch();
|
||||
if (!success) {
|
||||
_showError('Failed to save new order. Please try again.');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import 'package:flutter/services.dart';
|
|||
import 'package:go_router/go_router.dart';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:madari_client/features/settings/service/selected_profile.dart';
|
||||
|
||||
import '../../pocketbase/service/pocketbase.service.dart';
|
||||
import '../widget/language_selector.dart';
|
||||
|
|
@ -108,10 +107,6 @@ class _ProfilePageState extends State<ProfilePage> {
|
|||
.update(user.id, body: data);
|
||||
}
|
||||
|
||||
SelectedProfileService.instance.setSelectedProfile(
|
||||
SelectedProfileService.instance.selectedProfileId,
|
||||
);
|
||||
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('Profile updated successfully')),
|
||||
|
|
@ -169,8 +164,10 @@ class _ProfilePageState extends State<ProfilePage> {
|
|||
),
|
||||
),
|
||||
filled: true,
|
||||
fillColor:
|
||||
Theme.of(context).colorScheme.surfaceVariant.withOpacity(0.3),
|
||||
fillColor: Theme.of(context)
|
||||
.colorScheme
|
||||
.surfaceContainerHighest
|
||||
.withOpacity(0.3),
|
||||
hoverColor: Theme.of(context).colorScheme.onSurface.withOpacity(0.08),
|
||||
focusColor: Theme.of(context).colorScheme.onSurface.withOpacity(0.12),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -2,12 +2,9 @@ import 'dart:async';
|
|||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:madari_client/features/pocketbase/service/pocketbase.service.dart';
|
||||
import 'package:pocketbase/src/dtos/record_model.dart';
|
||||
import 'package:pocketbase/src/dtos/result_list.dart';
|
||||
import 'package:madari_engine/madari_engine.dart';
|
||||
import 'package:shimmer/shimmer.dart';
|
||||
|
||||
import '../../service/selected_profile.dart';
|
||||
|
||||
class ProfileSelector extends StatefulWidget {
|
||||
const ProfileSelector({super.key});
|
||||
|
||||
|
|
@ -16,37 +13,33 @@ class ProfileSelector extends StatefulWidget {
|
|||
}
|
||||
|
||||
class _ProfileSelectorState extends State<ProfileSelector> {
|
||||
final _selectedProfileService = SelectedProfileService.instance;
|
||||
final profileService = AppPocketBaseService.instance.engine.profileService;
|
||||
late Future<List<UserProfile>> _future;
|
||||
late String selectedProfileId;
|
||||
|
||||
late Future<ResultList<RecordModel>> _future;
|
||||
|
||||
late StreamSubscription<String?> _listener;
|
||||
late StreamSubscription<bool> _listenerNew;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
_future = AppPocketBaseService.instance.pb
|
||||
.collection('account_profile')
|
||||
.getList();
|
||||
_future = profileService.getAllProfiles();
|
||||
|
||||
_listener = _selectedProfileService.selectedProfileStream.listen(
|
||||
(item) {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_future = AppPocketBaseService.instance.pb
|
||||
.collection('account_profile')
|
||||
.getList();
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
_listenerNew = profileService.onProfileUpdate.listen((item) {
|
||||
setState(() {
|
||||
_future = profileService.getAllProfiles();
|
||||
});
|
||||
});
|
||||
|
||||
profileService.getCurrentProfile().then((item) {
|
||||
selectedProfileId = item!.id;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
_listener.cancel();
|
||||
_listenerNew.cancel();
|
||||
}
|
||||
|
||||
Widget _buildShimmerLoading() {
|
||||
|
|
@ -115,7 +108,7 @@ class _ProfileSelectorState extends State<ProfileSelector> {
|
|||
return _buildShimmerLoading();
|
||||
}
|
||||
|
||||
final profiles = snapshot.data!.items;
|
||||
final profiles = snapshot.data!;
|
||||
|
||||
return GridView.builder(
|
||||
shrinkWrap: true,
|
||||
|
|
@ -131,89 +124,76 @@ class _ProfileSelectorState extends State<ProfileSelector> {
|
|||
itemBuilder: (context, index) {
|
||||
final profile = profiles[index];
|
||||
|
||||
return StreamBuilder<String?>(
|
||||
stream: _selectedProfileService.selectedProfileStream,
|
||||
builder: (context, snapshot) {
|
||||
final isSelected = snapshot.data == profile.id;
|
||||
final isSelected = selectedProfileId == profile.id;
|
||||
|
||||
return InkWell(
|
||||
onTap: () async {
|
||||
final currentSelectedId =
|
||||
_selectedProfileService.selectedProfileId;
|
||||
final newSelectedId = currentSelectedId == profile.id
|
||||
? profile.id
|
||||
: profile.id;
|
||||
await _selectedProfileService
|
||||
.setSelectedProfile(newSelectedId);
|
||||
},
|
||||
return InkWell(
|
||||
onTap: () async {
|
||||
profileService.setCurrentProfile(profile.id);
|
||||
|
||||
setState(() {
|
||||
selectedProfileId = profile.id;
|
||||
});
|
||||
},
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
color: isSelected
|
||||
? colorScheme.primaryContainer.withOpacity(0.3)
|
||||
: Colors.transparent,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
color: isSelected
|
||||
? colorScheme.primaryContainer.withOpacity(0.3)
|
||||
: Colors.transparent,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
if (profile.data['profile_image'] != null &&
|
||||
profile.data['profile_image'] != "")
|
||||
CircleAvatar(
|
||||
radius: 24,
|
||||
backgroundImage: NetworkImage(
|
||||
AppPocketBaseService.instance.pb.files
|
||||
.getUrl(
|
||||
profile,
|
||||
profile.data['profile_image'],
|
||||
)
|
||||
.toString(),
|
||||
),
|
||||
)
|
||||
else
|
||||
CircleAvatar(
|
||||
radius: 24,
|
||||
backgroundColor: isSelected
|
||||
? colorScheme.primary
|
||||
: colorScheme.surfaceVariant,
|
||||
child: Text(
|
||||
profile.data['name'][0].toUpperCase(),
|
||||
style: TextStyle(
|
||||
color: isSelected
|
||||
? colorScheme.onPrimary
|
||||
: colorScheme.onSurfaceVariant,
|
||||
fontSize: 18,
|
||||
fontWeight: isSelected
|
||||
? FontWeight.bold
|
||||
: FontWeight.normal,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4),
|
||||
child: Text(
|
||||
profile.data['name'],
|
||||
style: theme.textTheme.bodySmall?.copyWith(
|
||||
color: isSelected ? colorScheme.primary : null,
|
||||
fontWeight: isSelected ? FontWeight.bold : null,
|
||||
if (profile.profileImage != null)
|
||||
CircleAvatar(
|
||||
radius: 24,
|
||||
backgroundImage: NetworkImage(
|
||||
profile.profileImage!,
|
||||
),
|
||||
)
|
||||
else
|
||||
CircleAvatar(
|
||||
radius: 24,
|
||||
backgroundColor: isSelected
|
||||
? colorScheme.primary
|
||||
: colorScheme.surfaceContainerHighest,
|
||||
child: Text(
|
||||
profile.name[0].toUpperCase(),
|
||||
style: TextStyle(
|
||||
color: isSelected
|
||||
? colorScheme.onPrimary
|
||||
: colorScheme.onSurfaceVariant,
|
||||
fontSize: 18,
|
||||
fontWeight: isSelected
|
||||
? FontWeight.bold
|
||||
: FontWeight.normal,
|
||||
),
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
const SizedBox(height: 4),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4),
|
||||
child: Text(
|
||||
profile.name,
|
||||
style: theme.textTheme.bodySmall?.copyWith(
|
||||
color: isSelected ? colorScheme.primary : null,
|
||||
fontWeight: isSelected ? FontWeight.bold : null,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ import 'package:flutter/material.dart';
|
|||
import 'package:go_router/go_router.dart';
|
||||
import 'package:madari_client/features/pocketbase/service/pocketbase.service.dart';
|
||||
import 'package:madari_client/features/settings/pages/settings/profile_selector.dart';
|
||||
import 'package:madari_client/features/settings/service/selected_profile.dart';
|
||||
|
||||
class SettingsPage extends StatelessWidget {
|
||||
const SettingsPage({
|
||||
|
|
@ -48,7 +47,6 @@ class SettingsPage extends StatelessWidget {
|
|||
deleteStorage: true,
|
||||
);
|
||||
AppPocketBaseService.instance.pb.authStore.clear();
|
||||
SelectedProfileService.instance.setSelectedProfile(null);
|
||||
context.go("/signin");
|
||||
},
|
||||
),
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import 'package:pocketbase/pocketbase.dart';
|
|||
|
||||
import '../../pocketbase/service/pocketbase.service.dart';
|
||||
import '../service/account_profile_service.dart';
|
||||
import '../service/selected_profile.dart';
|
||||
import '../widget/profile_dialog.dart';
|
||||
|
||||
class SubprofilesPage extends StatefulWidget {
|
||||
|
|
@ -20,29 +19,32 @@ class SubprofilesPage extends StatefulWidget {
|
|||
class _SubprofilesPageState extends State<SubprofilesPage> {
|
||||
final _logger = Logger('SubprofilesPage');
|
||||
final _profileService = AccountProfileService.instance;
|
||||
final _selectedProfileService = SelectedProfileService.instance;
|
||||
final _selectedProfileService =
|
||||
AppPocketBaseService.instance.engine.profileService;
|
||||
List<RecordModel> _profiles = [];
|
||||
bool _isLoading = true;
|
||||
String? _error;
|
||||
Timer? _retryTimer;
|
||||
int _retryAttempts = 0;
|
||||
static const int _maxRetryAttempts = 3;
|
||||
|
||||
late final StreamSubscription<String?> _selectedProfileSubscription;
|
||||
String? selectedProfile;
|
||||
late StreamSubscription<bool> _listener;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_selectedProfileSubscription = _selectedProfileService.selectedProfileStream
|
||||
.listen((_) => setState(() {}));
|
||||
_loadProfiles();
|
||||
|
||||
_listener = _selectedProfileService.onProfileUpdate.listen((item) async {
|
||||
selectedProfile = (await _selectedProfileService.getCurrentProfile())!.id;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_selectedProfileSubscription.cancel();
|
||||
_retryTimer?.cancel();
|
||||
super.dispose();
|
||||
_listener.cancel();
|
||||
}
|
||||
|
||||
Future<void> _loadProfiles({bool isRetry = false}) async {
|
||||
|
|
@ -56,10 +58,6 @@ class _SubprofilesPageState extends State<SubprofilesPage> {
|
|||
|
||||
final profiles = await _profileService.getProfiles();
|
||||
|
||||
_selectedProfileService.setSelectedProfile(
|
||||
_selectedProfileService.selectedProfileId,
|
||||
);
|
||||
|
||||
if (!mounted) return;
|
||||
|
||||
setState(() {
|
||||
|
|
@ -113,10 +111,11 @@ class _SubprofilesPageState extends State<SubprofilesPage> {
|
|||
|
||||
Future<void> _handleProfileSelection(RecordModel profile) async {
|
||||
try {
|
||||
final currentSelectedId = _selectedProfileService.selectedProfileId;
|
||||
final currentSelectedId =
|
||||
(await _selectedProfileService.getCurrentProfile())!.id;
|
||||
final newSelectedId =
|
||||
currentSelectedId == profile.id ? profile.id : profile.id;
|
||||
await _selectedProfileService.setSelectedProfile(newSelectedId);
|
||||
await _selectedProfileService.setCurrentProfile(newSelectedId);
|
||||
|
||||
if (!mounted) return;
|
||||
} catch (e, stackTrace) {
|
||||
|
|
@ -200,7 +199,6 @@ class _SubprofilesPageState extends State<SubprofilesPage> {
|
|||
Widget _buildProfileCard(RecordModel profile) {
|
||||
return ProfileCard(
|
||||
profile: profile,
|
||||
selectedProfileId: _selectedProfileService.selectedProfileId,
|
||||
onTap: () => _handleProfileSelection(profile),
|
||||
onEdit: () => _showProfileDialog(context, profile: profile),
|
||||
onDelete: () => _showDeleteDialog(profile),
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ class AccountProfileService {
|
|||
static final AccountProfileService instance =
|
||||
AccountProfileService._internal();
|
||||
final _logger = Logger('AccountProfileService');
|
||||
final profileService = AppPocketBaseService.instance.engine.profileService;
|
||||
|
||||
AccountProfileService._internal();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,51 +0,0 @@
|
|||
import 'package:logging/logging.dart';
|
||||
import 'package:rxdart/rxdart.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
class SelectedProfileService {
|
||||
static final SelectedProfileService instance =
|
||||
SelectedProfileService._internal();
|
||||
final _logger = Logger('SelectedProfileService');
|
||||
|
||||
static const String _selectedProfileKey = 'selected_profile_id';
|
||||
final _selectedProfileSubject = BehaviorSubject<String?>();
|
||||
|
||||
SharedPreferences? _prefs;
|
||||
|
||||
SelectedProfileService._internal();
|
||||
|
||||
Future<void> initialize() async {
|
||||
try {
|
||||
_prefs = await SharedPreferences.getInstance();
|
||||
final storedId = _prefs?.getString(_selectedProfileKey);
|
||||
_selectedProfileSubject.add(storedId);
|
||||
_logger.info('Initialized with stored profile ID: $storedId');
|
||||
} catch (e, stack) {
|
||||
_logger.severe('Error initializing SelectedProfileService', e, stack);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
String? get selectedProfileId => _selectedProfileSubject.valueOrNull;
|
||||
|
||||
Stream<String?> get selectedProfileStream => _selectedProfileSubject.stream;
|
||||
|
||||
Future<void> setSelectedProfile(String? profileId) async {
|
||||
try {
|
||||
if (profileId != null) {
|
||||
await _prefs?.setString(_selectedProfileKey, profileId);
|
||||
} else {
|
||||
await _prefs?.remove(_selectedProfileKey);
|
||||
}
|
||||
_selectedProfileSubject.add(profileId);
|
||||
_logger.info('Selected profile updated: $profileId');
|
||||
} catch (e, stack) {
|
||||
_logger.severe('Error setting selected profile', e, stack);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
_selectedProfileSubject.close();
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,7 +1,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:madari_engine/madari_engine.dart';
|
||||
|
||||
import '../../settings/widget/setting_wrapper.dart';
|
||||
import '../models/stremio_base_types.dart';
|
||||
import '../service/stremio_addon_service.dart';
|
||||
import '../widget/add_addon_sheet.dart';
|
||||
import '../widget/stremio_addons_list.dart';
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@ import 'package:logging/logging.dart';
|
|||
import 'package:madari_client/data/db.dart';
|
||||
import 'package:madari_client/features/streamio_addons/extension/query_extension.dart';
|
||||
import 'package:madari_client/utils/array-extension.dart';
|
||||
import 'package:madari_engine/madari_engine.dart';
|
||||
import 'package:pocketbase/pocketbase.dart';
|
||||
|
||||
import '../../pocketbase/service/pocketbase.service.dart';
|
||||
import '../../widgetter/plugins/stremio/models/cast_info.dart';
|
||||
import '../models/stremio_base_types.dart';
|
||||
|
||||
typedef OnStreamCallback = void Function(
|
||||
List<VideoStream>? items,
|
||||
|
|
@ -22,6 +22,7 @@ class StremioAddonService {
|
|||
final _logger = Logger('StremioAddonService');
|
||||
|
||||
static final StremioAddonService instance = StremioAddonService._internal();
|
||||
|
||||
final _manifestQueryConfig = QueryConfig(
|
||||
cacheDuration: const Duration(hours: 8),
|
||||
);
|
||||
|
|
@ -586,13 +587,3 @@ enum ConnectionFilterType {
|
|||
text,
|
||||
options,
|
||||
}
|
||||
|
||||
class ConnectionFilterItem {
|
||||
final String title;
|
||||
final dynamic value;
|
||||
|
||||
ConnectionFilterItem({
|
||||
required this.title,
|
||||
required this.value,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import 'package:cached_query_flutter/cached_query_flutter.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:madari_client/features/streamio_addons/extension/query_extension.dart';
|
||||
import 'package:madari_engine/madari_engine.dart';
|
||||
import 'package:pocketbase/pocketbase.dart';
|
||||
|
||||
import '../models/stremio_base_types.dart';
|
||||
import '../service/stremio_addon_service.dart';
|
||||
|
||||
class AddAddonSheet extends StatefulWidget {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../models/stremio_base_types.dart';
|
||||
import 'package:madari_engine/madari_engine.dart';
|
||||
|
||||
class ManifestPreview extends StatelessWidget {
|
||||
final StremioManifest manifest;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import 'package:cached_query_flutter/cached_query_flutter.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:madari_engine/madari_engine.dart';
|
||||
import 'package:shimmer/shimmer.dart';
|
||||
|
||||
import '../models/stremio_base_types.dart';
|
||||
import '../pages/stremio_addons_page.dart';
|
||||
import 'add_addon_sheet.dart';
|
||||
|
||||
|
|
|
|||
|
|
@ -28,13 +28,6 @@ class _AlwaysOnTopButtonState extends State<AlwaysOnTopButton> {
|
|||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
|
||||
windowManager.setAlwaysOnTop(false);
|
||||
windowManager.setTitleBarStyle(TitleBarStyle.normal);
|
||||
setState(() {
|
||||
alwaysOnTop = false;
|
||||
});
|
||||
windowManager.setVisibleOnAllWorkspaces(false);
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
|||
|
|
@ -4,12 +4,12 @@ import 'package:madari_client/features/video_player/container/options/settings_s
|
|||
import 'package:madari_client/features/video_player/container/state/video_settings.dart';
|
||||
import 'package:madari_client/features/video_player/container/video_mobile.dart';
|
||||
import 'package:madari_client/features/video_player/container/video_play.dart';
|
||||
import 'package:madari_engine/madari_engine.dart' as types;
|
||||
import 'package:media_kit_video/media_kit_video.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:rxdart/rxdart.dart';
|
||||
import 'package:universal_platform/universal_platform.dart';
|
||||
|
||||
import '../../streamio_addons/models/stremio_base_types.dart' as types;
|
||||
import '../widgets/video_selector.dart';
|
||||
import 'options/always_on_top.dart';
|
||||
import 'options/audio_track_selector.dart';
|
||||
|
|
|
|||
|
|
@ -5,11 +5,11 @@ import 'package:go_router/go_router.dart';
|
|||
import 'package:madari_client/features/video_player/container/options/settings_sheet.dart';
|
||||
import 'package:madari_client/features/video_player/container/state/video_settings.dart';
|
||||
import 'package:madari_client/features/video_player/container/video_play.dart';
|
||||
import 'package:madari_engine/madari_engine.dart' as types;
|
||||
import 'package:media_kit_video/media_kit_video.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:rxdart/src/subjects/behavior_subject.dart';
|
||||
|
||||
import '../../streamio_addons/models/stremio_base_types.dart' as types;
|
||||
import '../widgets/video_selector.dart';
|
||||
import 'options/audio_track_selector.dart';
|
||||
import 'options/scale_option.dart';
|
||||
|
|
|
|||
|
|
@ -6,13 +6,14 @@ import 'package:madari_client/features/video_player/container/native.dart';
|
|||
import 'package:madari_client/features/video_player/container/state/video_settings.dart';
|
||||
import 'package:madari_client/features/video_player/container/video_desktop.dart';
|
||||
import 'package:madari_client/features/video_player/container/video_mobile.dart';
|
||||
import 'package:madari_engine/madari_engine.dart';
|
||||
import 'package:media_kit/media_kit.dart';
|
||||
import 'package:media_kit_video/media_kit_video.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:rxdart/src/subjects/behavior_subject.dart';
|
||||
import 'package:universal_platform/universal_platform.dart';
|
||||
import 'package:window_manager/window_manager.dart';
|
||||
|
||||
import '../../streamio_addons/models/stremio_base_types.dart';
|
||||
import '../service/video_eventer_default_track.dart';
|
||||
|
||||
typedef OnVideoChangeCallback = Future<bool> Function(
|
||||
|
|
@ -130,6 +131,12 @@ class _VideoPlayState extends State<VideoPlay> {
|
|||
_settings.removeListener(_onSettingsChanged);
|
||||
setter.dispose();
|
||||
player.dispose();
|
||||
|
||||
if (UniversalPlatform.isDesktop) {
|
||||
windowManager.setAlwaysOnTop(false);
|
||||
windowManager.setTitleBarStyle(TitleBarStyle.normal);
|
||||
windowManager.setVisibleOnAllWorkspaces(false);
|
||||
}
|
||||
}
|
||||
|
||||
late int selectedVideo = widget.index;
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@ import 'package:flutter/services.dart';
|
|||
import 'package:logging/logging.dart';
|
||||
import 'package:madari_client/features/settings/model/playback_settings_model.dart';
|
||||
import 'package:madari_client/features/settings/service/playback_setting_service.dart';
|
||||
import 'package:madari_client/features/streamio_addons/models/stremio_base_types.dart';
|
||||
import 'package:madari_client/features/video_player/container/video_play.dart';
|
||||
import 'package:madari_client/features/widgetter/plugins/stremio/containers/streamio_background.dart';
|
||||
import 'package:madari_engine/madari_engine.dart';
|
||||
import 'package:rxdart/rxdart.dart';
|
||||
|
||||
class VideoPlayer extends StatefulWidget {
|
||||
|
|
|
|||
|
|
@ -2,11 +2,10 @@ import 'package:cached_network_image/cached_network_image.dart';
|
|||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:madari_client/features/video_player/container/video_play.dart';
|
||||
import 'package:madari_engine/madari_engine.dart';
|
||||
import 'package:media_kit_video/media_kit_video.dart';
|
||||
import 'package:rxdart/src/subjects/behavior_subject.dart';
|
||||
|
||||
import '../../streamio_addons/models/stremio_base_types.dart';
|
||||
|
||||
class SeasonSource extends StatefulWidget {
|
||||
final Meta meta;
|
||||
final bool isMobile;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:cached_query/cached_query.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:madari_client/features/settings/service/selected_profile.dart';
|
||||
import 'package:madari_client/features/streamio_addons/extension/query_extension.dart';
|
||||
import 'package:madari_client/features/widgetter/plugin_base.dart';
|
||||
import 'package:madari_client/features/widgetter/plugins/stremio/widgets/catalog_featured_shimmer.dart';
|
||||
|
|
@ -32,16 +33,24 @@ class LayoutManagerState extends State<LayoutManager> {
|
|||
List<HomeLayoutModel> _layouts = [];
|
||||
List<HomeLayoutModel> _filteredLayouts = [];
|
||||
bool _isLoading = true;
|
||||
final profileService = AppPocketBaseService.instance.engine.profileService;
|
||||
|
||||
late StreamSubscription<bool> _listener;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_loadLayouts();
|
||||
|
||||
_listener = profileService.onProfileUpdate.listen((_) {
|
||||
refresh();
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_scrollController.dispose();
|
||||
_listener.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
|
|
@ -65,9 +74,10 @@ class LayoutManagerState extends State<LayoutManager> {
|
|||
}) async {
|
||||
try {
|
||||
_logger.info('Loading layouts');
|
||||
print((await profileService.getCurrentProfile())!.id);
|
||||
final query = Query(
|
||||
key:
|
||||
"home_layout_${SelectedProfileService.instance.selectedProfileId}${widget.hasSearch}",
|
||||
"home_layout_${(await profileService.getCurrentProfile())!.id}${widget.hasSearch}",
|
||||
config: QueryConfig(
|
||||
ignoreCacheDuration: refresh,
|
||||
cacheDuration: const Duration(hours: 8),
|
||||
|
|
@ -79,7 +89,7 @@ class LayoutManagerState extends State<LayoutManager> {
|
|||
.getFullList(
|
||||
sort: 'order',
|
||||
filter:
|
||||
"profiles = '${SelectedProfileService.instance.selectedProfileId}'",
|
||||
"profiles = '${(await profileService.getCurrentProfile())!.id}'",
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ import 'package:logging/logging.dart';
|
|||
import 'package:madari_client/features/external_player/service/external_player.dart';
|
||||
import 'package:madari_client/features/settings/service/playback_setting_service.dart';
|
||||
import 'package:madari_client/features/streamio_addons/extension/query_extension.dart';
|
||||
import 'package:madari_engine/madari_engine.dart';
|
||||
|
||||
import '../../../../streamio_addons/models/stremio_base_types.dart';
|
||||
import '../../../../streamio_addons/service/stremio_addon_service.dart';
|
||||
|
||||
final _logger = Logger('StreamioStreamList');
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:madari_client/features/streamio_addons/models/stremio_base_types.dart';
|
||||
import 'package:madari_client/utils/array-extension.dart';
|
||||
import 'package:madari_engine/madari_engine.dart';
|
||||
import 'package:universal_platform/universal_platform.dart';
|
||||
|
||||
import '../../../../library/container/add_to_list_button.dart';
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:madari_engine/madari_engine.dart';
|
||||
import 'package:universal_platform/universal_platform.dart';
|
||||
|
||||
import '../../../../streamio_addons/models/stremio_base_types.dart';
|
||||
import 'cast_info.dart';
|
||||
|
||||
class StreamioCastSection extends StatelessWidget {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:madari_client/features/streamio_addons/models/stremio_base_types.dart';
|
||||
import 'package:madari_engine/madari_engine.dart';
|
||||
|
||||
final _logger = Logger('StreamioEpisodeList');
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:madari_engine/madari_engine.dart';
|
||||
import 'package:universal_platform/universal_platform.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
import '../../../../streamio_addons/models/stremio_base_types.dart';
|
||||
|
||||
final _logger = Logger('StreamioTrailerSection');
|
||||
|
||||
class StreamioTrailerSection extends StatelessWidget {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:madari_client/features/streamio_addons/models/stremio_base_types.dart';
|
||||
import 'package:madari_engine/madari_engine.dart';
|
||||
|
||||
class StremioVideoList extends StatelessWidget {
|
||||
final List<Video>? videos;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:madari_client/features/streamio_addons/models/stremio_base_types.dart';
|
||||
import 'package:madari_client/features/widgetter/plugins/stremio/containers/streamio_background.dart';
|
||||
import 'package:madari_client/features/widgetter/plugins/stremio/containers/streamio_cast_section.dart';
|
||||
import 'package:madari_client/features/widgetter/plugins/stremio/containers/streamio_trailer_section.dart';
|
||||
import 'package:madari_client/features/widgetter/plugins/stremio/containers/streamio_video_list.dart';
|
||||
import 'package:madari_engine/madari_engine.dart';
|
||||
|
||||
final _logger = Logger('StreamioViewerContent');
|
||||
|
||||
|
|
|
|||
|
|
@ -1,94 +1 @@
|
|||
import 'package:madari_client/features/streamio_addons/models/stremio_base_types.dart';
|
||||
|
||||
enum ContentType { movie, series, channel, tv }
|
||||
|
||||
class SocialLinks {
|
||||
final String? instagram;
|
||||
final String? twitter;
|
||||
final String? facebook;
|
||||
final String? website;
|
||||
|
||||
const SocialLinks({
|
||||
this.instagram,
|
||||
this.twitter,
|
||||
this.facebook,
|
||||
this.website,
|
||||
});
|
||||
|
||||
factory SocialLinks.fromJson(Map<String, dynamic> json) {
|
||||
return SocialLinks(
|
||||
instagram: json['instagram'] as String?,
|
||||
twitter: json['twitter'] as String?,
|
||||
facebook: json['facebook'] as String?,
|
||||
website: json['website'] as String?,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'instagram': instagram,
|
||||
'twitter': twitter,
|
||||
'facebook': facebook,
|
||||
'website': website,
|
||||
};
|
||||
}
|
||||
|
||||
class CastMember {
|
||||
final String id;
|
||||
final String name;
|
||||
final String? profilePath;
|
||||
final String? biography;
|
||||
final String? birthDate;
|
||||
final String? birthPlace;
|
||||
final SocialLinks socialLinks;
|
||||
final List<Meta> knownFor;
|
||||
final double? popularity;
|
||||
final String? department;
|
||||
final String? character;
|
||||
|
||||
const CastMember({
|
||||
required this.id,
|
||||
required this.name,
|
||||
this.profilePath,
|
||||
this.biography,
|
||||
this.birthDate,
|
||||
this.birthPlace,
|
||||
this.socialLinks = const SocialLinks(),
|
||||
this.knownFor = const [],
|
||||
this.popularity,
|
||||
this.department,
|
||||
this.character,
|
||||
});
|
||||
|
||||
factory CastMember.fromJson(Map<String, dynamic> json) {
|
||||
return CastMember(
|
||||
id: json['id'] as String,
|
||||
name: json['name'] as String,
|
||||
profilePath: json['profilePath'] as String?,
|
||||
biography: json['biography'] as String?,
|
||||
birthDate: json['birthDate'] as String?,
|
||||
birthPlace: json['birthPlace'] as String?,
|
||||
socialLinks: SocialLinks.fromJson(json['socialLinks'] ?? {}),
|
||||
knownFor: (json['knownFor'] as List<dynamic>?)
|
||||
?.map((e) => Meta.fromJson(e as Map<String, dynamic>))
|
||||
.toList() ??
|
||||
[],
|
||||
popularity: json['popularity'] as double?,
|
||||
department: json['department'] as String?,
|
||||
character: json['character'] as String?,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'id': id,
|
||||
'name': name,
|
||||
'profile_path': profilePath,
|
||||
'biography': biography,
|
||||
'birth_date': birthDate,
|
||||
'birth_place': birthPlace,
|
||||
'social_links': socialLinks.toJson(),
|
||||
'known_for': knownFor.map((e) => e.toJson()).toList(),
|
||||
'popularity': popularity,
|
||||
'department': department,
|
||||
'character': character,
|
||||
};
|
||||
}
|
||||
export 'package:madari_engine/madari_engine.dart';
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import 'package:cached_query_flutter/cached_query_flutter.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:madari_client/features/streamio_addons/models/stremio_base_types.dart';
|
||||
import 'package:madari_client/features/streamio_addons/service/stremio_addon_service.dart';
|
||||
import 'package:madari_engine/madari_engine.dart';
|
||||
|
||||
import '../containers/shimmer.dart';
|
||||
import '../containers/streamio_viewer_content.dart';
|
||||
|
|
|
|||
|
|
@ -2,10 +2,9 @@ import 'dart:math' as math;
|
|||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:madari_engine/madari_engine.dart';
|
||||
import 'package:universal_platform/universal_platform.dart';
|
||||
|
||||
import '../../../../streamio_addons/models/stremio_base_types.dart';
|
||||
|
||||
class CatalogFeatured extends StatefulWidget {
|
||||
final List<Meta> meta;
|
||||
final VoidCallback? onTap;
|
||||
|
|
|
|||
|
|
@ -11,10 +11,9 @@ import 'package:madari_client/features/widgetter/plugin_base.dart';
|
|||
import 'package:madari_client/features/widgetter/plugins/stremio/widgets/catalog_featured.dart';
|
||||
import 'package:madari_client/features/widgetter/plugins/stremio/widgets/stremio_card.dart';
|
||||
import 'package:madari_client/utils/array-extension.dart';
|
||||
import 'package:madari_engine/madari_engine.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:shimmer/shimmer.dart';
|
||||
|
||||
import '../../../../streamio_addons/models/stremio_base_types.dart';
|
||||
import '../../../../streamio_addons/service/stremio_addon_service.dart';
|
||||
import '../../../interface/widgets.dart';
|
||||
import '../../../service/home_layout_service.dart';
|
||||
|
|
@ -137,31 +136,9 @@ class _CatalogGridState extends State<CatalogGrid> implements Refreshable {
|
|||
Widget _buildShimmerCard(BuildContext context, StremioCardSize cardSize) {
|
||||
final theme = Theme.of(context);
|
||||
|
||||
return Container(
|
||||
margin: const EdgeInsets.only(right: 12),
|
||||
child: Shimmer.fromColors(
|
||||
baseColor: theme.brightness == Brightness.light
|
||||
? Colors.grey[300]!
|
||||
: Colors.grey[800]!,
|
||||
highlightColor: theme.brightness == Brightness.light
|
||||
? Colors.grey[100]!
|
||||
: Colors.grey[700]!,
|
||||
child: Container(
|
||||
width: cardSize.width,
|
||||
height: cardSize.height,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
color: Colors.red,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: theme.shadowColor.withOpacity(0.1),
|
||||
blurRadius: 4,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
return PulseLoadingCard(
|
||||
width: cardSize.width,
|
||||
height: cardSize.height,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -508,3 +485,78 @@ class _CatalogGridState extends State<CatalogGrid> implements Refreshable {
|
|||
return _query.refetch();
|
||||
}
|
||||
}
|
||||
|
||||
class PulseLoadingCard extends StatefulWidget {
|
||||
final double width;
|
||||
final double height;
|
||||
|
||||
const PulseLoadingCard({
|
||||
super.key,
|
||||
required this.width,
|
||||
required this.height,
|
||||
});
|
||||
|
||||
@override
|
||||
State<PulseLoadingCard> createState() => _PulseLoadingCardState();
|
||||
}
|
||||
|
||||
class _PulseLoadingCardState extends State<PulseLoadingCard>
|
||||
with SingleTickerProviderStateMixin {
|
||||
late AnimationController _controller;
|
||||
late Animation<double> _animation;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_controller = AnimationController(
|
||||
duration: const Duration(milliseconds: 1500),
|
||||
vsync: this,
|
||||
)..repeat(reverse: true);
|
||||
|
||||
_animation = Tween<double>(
|
||||
begin: 0.5,
|
||||
end: 1.0,
|
||||
).animate(CurvedAnimation(
|
||||
parent: _controller,
|
||||
curve: Curves.easeInOut,
|
||||
));
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
final baseColor = theme.brightness == Brightness.light
|
||||
? Colors.grey[300]!
|
||||
: Colors.grey[800]!;
|
||||
|
||||
return Container(
|
||||
margin: const EdgeInsets.only(right: 12),
|
||||
child: AnimatedBuilder(
|
||||
animation: _animation,
|
||||
builder: (context, child) {
|
||||
return Container(
|
||||
width: widget.width,
|
||||
height: widget.height,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
color: baseColor.withOpacity(_animation.value),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: theme.shadowColor.withOpacity(0.1),
|
||||
blurRadius: 4,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ import 'package:flutter/material.dart';
|
|||
import 'package:go_router/go_router.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:madari_client/features/widgetter/plugins/stremio/widgets/stremio_card.dart';
|
||||
import 'package:madari_engine/madari_engine.dart';
|
||||
import 'package:shimmer/shimmer.dart';
|
||||
|
||||
import '../../../../streamio_addons/models/stremio_base_types.dart';
|
||||
import '../utils/size.dart';
|
||||
|
||||
typedef GetQuery = InfiniteQuery<List<Meta>, int> Function();
|
||||
|
|
|
|||
|
|
@ -2,8 +2,7 @@ import 'package:cached_network_image/cached_network_image.dart';
|
|||
import 'package:cached_network_image_platform_interface/cached_network_image_platform_interface.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
import '../../../../streamio_addons/models/stremio_base_types.dart';
|
||||
import 'package:madari_engine/madari_engine.dart';
|
||||
|
||||
typedef ImageCallback = Function(String? image);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import 'package:cached_query_flutter/cached_query_flutter.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:madari_client/features/settings/service/selected_profile.dart';
|
||||
import 'package:pocketbase/pocketbase.dart';
|
||||
import 'package:rxdart/subjects.dart';
|
||||
|
||||
|
|
@ -12,6 +11,7 @@ final _logger = Logger('HomeLayoutService');
|
|||
class HomeLayoutService {
|
||||
static final HomeLayoutService instance = HomeLayoutService._internal();
|
||||
HomeLayoutService._internal();
|
||||
final profileService = AppPocketBaseService.instance.engine.profileService;
|
||||
|
||||
final BehaviorSubject refreshWidgets = BehaviorSubject();
|
||||
|
||||
|
|
@ -23,7 +23,7 @@ class HomeLayoutService {
|
|||
.getFullList(
|
||||
sort: 'order',
|
||||
filter:
|
||||
'profiles = \'${SelectedProfileService.instance.selectedProfileId}\'',
|
||||
'profiles = \'${(await profileService.getCurrentProfile())!.id}\'',
|
||||
);
|
||||
|
||||
return records
|
||||
|
|
@ -36,10 +36,6 @@ class HomeLayoutService {
|
|||
}
|
||||
|
||||
void clearCache() {
|
||||
SelectedProfileService.instance.setSelectedProfile(
|
||||
SelectedProfileService.instance.selectedProfileId,
|
||||
);
|
||||
|
||||
CachedQuery.instance.invalidateCache(filterFn: (item, key) {
|
||||
return key.startsWith("home_layout");
|
||||
});
|
||||
|
|
@ -49,7 +45,7 @@ class HomeLayoutService {
|
|||
try {
|
||||
_logger.info('Saving layout widget: ${widget.pluginId}');
|
||||
await AppPocketBaseService.instance.pb.collection('home_layout').create(
|
||||
body: widget.toJson(),
|
||||
body: await widget.toJson(),
|
||||
);
|
||||
clearCache();
|
||||
return true;
|
||||
|
|
@ -148,14 +144,16 @@ class LayoutWidgetConfig {
|
|||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
Future<Map<String, dynamic>> toJson() async {
|
||||
return {
|
||||
'title': title,
|
||||
'config': config,
|
||||
'order': order,
|
||||
'plugin_id': pluginId,
|
||||
'type': widgetType,
|
||||
'profiles': SelectedProfileService.instance.selectedProfileId,
|
||||
'profiles': (await AppPocketBaseService.instance.engine.profileService
|
||||
.getCurrentProfile())!
|
||||
.id,
|
||||
'user': AppPocketBaseService.instance.pb.authStore.record!.id,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +0,0 @@
|
|||
class Integration {
|
||||
final String id;
|
||||
|
||||
Integration({
|
||||
required this.id,
|
||||
});
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class IntegrationPage extends StatelessWidget {
|
||||
const IntegrationPage({
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text("Integrations"),
|
||||
),
|
||||
body: ListView(
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: () {},
|
||||
child: const Text("Choose account"),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:rinf/rinf.dart';
|
||||
|
||||
import './messages/all.dart';
|
||||
import 'app/app.dart';
|
||||
import 'features/common/utils/startup_app.dart';
|
||||
import 'features/logger/service/logger.service.dart';
|
||||
|
|
@ -8,6 +10,7 @@ import 'features/theme/theme/app_theme.dart';
|
|||
import 'features/widgetter/state/widget_state_provider.dart';
|
||||
|
||||
void main() async {
|
||||
await initializeRust(assignRustSignal);
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
setupLogger();
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
|
|||
|
||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||
media_kit_native_event_loop
|
||||
rinf
|
||||
)
|
||||
|
||||
set(PLUGIN_BUNDLED_LIBRARIES)
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ PODS:
|
|||
- path_provider_foundation (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- rinf (0.1.0):
|
||||
- FlutterMacOS
|
||||
- screen_retriever_macos (0.0.1):
|
||||
- FlutterMacOS
|
||||
- shared_preferences_foundation (0.0.1):
|
||||
|
|
@ -68,6 +70,7 @@ DEPENDENCIES:
|
|||
- media_kit_video (from `Flutter/ephemeral/.symlinks/plugins/media_kit_video/macos`)
|
||||
- package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`)
|
||||
- path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`)
|
||||
- rinf (from `Flutter/ephemeral/.symlinks/plugins/rinf/macos`)
|
||||
- screen_retriever_macos (from `Flutter/ephemeral/.symlinks/plugins/screen_retriever_macos/macos`)
|
||||
- shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`)
|
||||
- sqflite_darwin (from `Flutter/ephemeral/.symlinks/plugins/sqflite_darwin/darwin`)
|
||||
|
|
@ -102,6 +105,8 @@ EXTERNAL SOURCES:
|
|||
:path: Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos
|
||||
path_provider_foundation:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin
|
||||
rinf:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/rinf/macos
|
||||
screen_retriever_macos:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/screen_retriever_macos/macos
|
||||
shared_preferences_foundation:
|
||||
|
|
@ -129,6 +134,7 @@ SPEC CHECKSUMS:
|
|||
OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94
|
||||
package_info_plus: 12f1c5c2cfe8727ca46cbd0b26677728972d9a5b
|
||||
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
|
||||
rinf: 4ecc3f564099eabf18209471f569e1a5b8c7b6b3
|
||||
screen_retriever_macos: 776e0fa5d42c6163d2bf772d22478df4b302b161
|
||||
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
|
||||
sqflite_darwin: 5a7236e3b501866c1c9befc6771dfd73ffb8702d
|
||||
|
|
|
|||
19
messages/torrent.proto
Normal file
19
messages/torrent.proto
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
syntax = "proto3";
|
||||
package torrent;
|
||||
|
||||
// [RUST-SIGNAL]
|
||||
message ServerEngine {
|
||||
ServerStatus status = 1;
|
||||
int32 port = 2;
|
||||
}
|
||||
|
||||
// [DART-SIGNAL]
|
||||
message ServerAction {
|
||||
ServerStatus status = 1;
|
||||
string path = 2;
|
||||
}
|
||||
|
||||
enum ServerStatus {
|
||||
Active = 0;
|
||||
Stop = 1;
|
||||
}
|
||||
18
native/hub/Cargo.toml
Normal file
18
native/hub/Cargo.toml
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
[package]
|
||||
name = "hub"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
crate-type = ["lib", "cdylib", "staticlib"]
|
||||
|
||||
[dependencies]
|
||||
rinf = "7.1.1"
|
||||
prost = "0.13.0"
|
||||
tokio = { version = "1", features = ["rt", "macros"] }
|
||||
log = "0.4.25"
|
||||
messages = "0.3.1"
|
||||
|
||||
# Uncomment below to target the web.
|
||||
# tokio_with_wasm = { version = "0.7.2", features = ["rt", "macros"] }
|
||||
# wasm-bindgen = "0.2.95"
|
||||
18
native/hub/src/lib.rs
Normal file
18
native/hub/src/lib.rs
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
use log::{info, warn};
|
||||
use rinf::debug_print;
|
||||
|
||||
mod messages;
|
||||
mod torrent_server;
|
||||
|
||||
// use tokio_with_wasm::alias as tokio; // web
|
||||
|
||||
rinf::write_interface!();
|
||||
|
||||
#[tokio::main(flavor = "current_thread")]
|
||||
async fn main() {
|
||||
tokio::spawn(torrent_server::communicate());
|
||||
|
||||
debug_print!("Hello world");
|
||||
|
||||
rinf::dart_shutdown().await;
|
||||
}
|
||||
112
native/hub/src/torrent_server.rs
Normal file
112
native/hub/src/torrent_server.rs
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
use crate::messages::*;
|
||||
use messages::prelude::*;
|
||||
use rinf::debug_print;
|
||||
|
||||
struct StartServer;
|
||||
struct StopServer;
|
||||
|
||||
struct TorrentServer {
|
||||
state: ServerStatus,
|
||||
}
|
||||
|
||||
impl Actor for TorrentServer {}
|
||||
|
||||
#[async_trait]
|
||||
impl Handler<StartServer> for TorrentServer {
|
||||
type Result = Result<(), String>;
|
||||
|
||||
async fn handle(&mut self, _: StartServer, ctx: &Context<Self>) -> Self::Result {
|
||||
self.handle_start().await
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Handler<StopServer> for TorrentServer {
|
||||
type Result = Result<(), String>;
|
||||
|
||||
async fn handle(&mut self, _: StopServer, ctx: &Context<Self>) -> Self::Result {
|
||||
self.handle_stop().await
|
||||
}
|
||||
}
|
||||
|
||||
impl TorrentServer {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
state: ServerStatus::Stop,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start() -> Address<Self> {
|
||||
let context = Context::new();
|
||||
let actor = Self::new();
|
||||
let addr = context.address();
|
||||
tokio::spawn(context.run(actor));
|
||||
addr
|
||||
}
|
||||
|
||||
async fn handle_start(&mut self) -> Result<(), String> {
|
||||
match self.state {
|
||||
ServerStatus::Active => {
|
||||
debug_print!("Server already active");
|
||||
Ok(())
|
||||
}
|
||||
ServerStatus::Stop => {
|
||||
self.start_server().await?;
|
||||
self.state = ServerStatus::Active;
|
||||
debug_print!("Server activated");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_stop(&mut self) -> Result<(), String> {
|
||||
match self.state {
|
||||
ServerStatus::Stop => {
|
||||
debug_print!("Server already stopped");
|
||||
Ok(())
|
||||
}
|
||||
ServerStatus::Active => {
|
||||
self.stop_server().await?;
|
||||
self.state = ServerStatus::Stop;
|
||||
debug_print!("Server deactivated");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn start_server(&mut self) -> Result<(), String> {
|
||||
ServerEngine { status: 0, port: 1212 }.send_signal_to_dart();
|
||||
debug_print!("started server");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn stop_server(&mut self) -> Result<(), String> {
|
||||
ServerEngine { status: 1, port: 1212 }.send_signal_to_dart();
|
||||
debug_print!("stopped server");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn communicate() {
|
||||
let receiver = ServerAction::get_dart_signal_receiver();
|
||||
let mut server = TorrentServer::start();
|
||||
|
||||
while let Some(dart_signal) = receiver.recv().await {
|
||||
let message: ServerAction = dart_signal.message;
|
||||
|
||||
let status = ServerStatus::try_from(message.status);
|
||||
|
||||
match status.unwrap() {
|
||||
ServerStatus::Active => {
|
||||
if let Err(e) = server.send(StartServer).await {
|
||||
debug_print!("Failed to start server: {}", e);
|
||||
}
|
||||
}
|
||||
ServerStatus::Stop => {
|
||||
if let Err(e) = server.send(StopServer).await {
|
||||
debug_print!("Failed to stop server: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
32
pubspec.lock
32
pubspec.lock
|
|
@ -246,6 +246,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
chalkdart:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: chalkdart
|
||||
sha256: "08c910ee341fcdd1e46f20ddce59b13c1d85f5d97f2fd2f12014c46ede670e40"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.2"
|
||||
characters:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
@ -721,10 +729,10 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: http
|
||||
sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010
|
||||
sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.2"
|
||||
version: "1.3.0"
|
||||
http_multi_server:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
@ -901,6 +909,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.3-main.0"
|
||||
madari_engine:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: madari_engine
|
||||
sha256: ba432da6be58a82395082559aa1d0b633230455ec4e71792ede107f419bffb89
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.6"
|
||||
markdown:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
@ -1216,7 +1232,7 @@ packages:
|
|||
source: hosted
|
||||
version: "6.0.1"
|
||||
protobuf:
|
||||
dependency: transitive
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: protobuf
|
||||
sha256: "68645b24e0716782e58948f8467fd42a880f255096a821f9e7d0ec625b00c84d"
|
||||
|
|
@ -1255,6 +1271,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.1.0"
|
||||
rinf:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: rinf
|
||||
sha256: b221072fd5d2a30f8244ee04d4991230b9bb8640cf991bb8d1f16894192d617b
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.1.1"
|
||||
riverpod:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
@ -1837,5 +1861,5 @@ packages:
|
|||
source: hosted
|
||||
version: "3.1.2"
|
||||
sdks:
|
||||
dart: ">=3.5.3 <4.0.0"
|
||||
dart: ">=3.6.0 <4.0.0"
|
||||
flutter: ">=3.27.0"
|
||||
|
|
|
|||
|
|
@ -55,6 +55,9 @@ dependencies:
|
|||
permission_handler: ^11.3.1
|
||||
android_intent_plus: ^5.2.1
|
||||
flex_color_picker: ^3.7.0
|
||||
rinf: ^7.1.1
|
||||
protobuf: ^3.1.0
|
||||
madari_engine: ^1.0.6
|
||||
|
||||
dependency_overrides:
|
||||
media_kit:
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 927 KiB |
|
|
@ -18,6 +18,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
|
|||
|
||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||
media_kit_native_event_loop
|
||||
rinf
|
||||
)
|
||||
|
||||
set(PLUGIN_BUNDLED_LIBRARIES)
|
||||
|
|
|
|||
Loading…
Reference in a new issue