Phase 8: Export/Import des flux (T8.7-T8.8) - PROJET COMPLÉTÉ À 100%
ccd9183 parent: ed3f0cc modified
Cargo.lock +249 -2 | @@ -353,6 +353,18 @@ dependencies = [ | ||
| 353 | 353 | "syn 2.0.118", |
| 354 | 354 | ] |
| 355 | 355 | |
| 356 | +[[package]] | |
| 357 | +name = "atk-sys" | |
| 358 | +version = "0.18.2" | |
| 359 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 360 | +checksum = "c5e48b684b0ca77d2bbadeef17424c2ea3c897d44d566a1617e7e8f30614d086" | |
| 361 | +dependencies = [ | |
| 362 | + "glib-sys", | |
| 363 | + "gobject-sys", | |
| 364 | + "libc", | |
| 365 | + "system-deps", | |
| 366 | +] | |
| 367 | + | |
| 356 | 368 | [[package]] |
| 357 | 369 | name = "atom_syndication" |
| 358 | 370 | version = "0.12.9" |
| @@ -528,6 +540,16 @@ version = "1.12.0" | ||
| 528 | 540 | source = "registry+https://github.com/rust-lang/crates.io-index" |
| 529 | 541 | checksum = "8ae3f5d315924270530207e2a68396c3cc547f6dca3fbdca317cfb1a51edb593" |
| 530 | 542 | |
| 543 | +[[package]] | |
| 544 | +name = "cairo-sys-rs" | |
| 545 | +version = "0.18.2" | |
| 546 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 547 | +checksum = "685c9fa8e590b8b3d678873528d83411db17242a73fccaed827770ea0fedda51" | |
| 548 | +dependencies = [ | |
| 549 | + "libc", | |
| 550 | + "system-deps", | |
| 551 | +] | |
| 552 | + | |
| 531 | 553 | [[package]] |
| 532 | 554 | name = "calloop" |
| 533 | 555 | version = "0.10.6" |
| @@ -560,6 +582,16 @@ version = "1.1.0" | ||
| 560 | 582 | source = "registry+https://github.com/rust-lang/crates.io-index" |
| 561 | 583 | checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" |
| 562 | 584 | |
| 585 | +[[package]] | |
| 586 | +name = "cfg-expr" | |
| 587 | +version = "0.15.8" | |
| 588 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 589 | +checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" | |
| 590 | +dependencies = [ | |
| 591 | + "smallvec", | |
| 592 | + "target-lexicon", | |
| 593 | +] | |
| 594 | + | |
| 563 | 595 | [[package]] |
| 564 | 596 | name = "cfg-if" |
| 565 | 597 | version = "1.0.4" |
| @@ -1251,6 +1283,36 @@ dependencies = [ | ||
| 1251 | 1283 | "slab", |
| 1252 | 1284 | ] |
| 1253 | 1285 | |
| 1286 | +[[package]] | |
| 1287 | +name = "gdk-pixbuf-sys" | |
| 1288 | +version = "0.18.0" | |
| 1289 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 1290 | +checksum = "3f9839ea644ed9c97a34d129ad56d38a25e6756f99f3a88e15cd39c20629caf7" | |
| 1291 | +dependencies = [ | |
| 1292 | + "gio-sys", | |
| 1293 | + "glib-sys", | |
| 1294 | + "gobject-sys", | |
| 1295 | + "libc", | |
| 1296 | + "system-deps", | |
| 1297 | +] | |
| 1298 | + | |
| 1299 | +[[package]] | |
| 1300 | +name = "gdk-sys" | |
| 1301 | +version = "0.18.2" | |
| 1302 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 1303 | +checksum = "5c2d13f38594ac1e66619e188c6d5a1adb98d11b2fcf7894fc416ad76aa2f3f7" | |
| 1304 | +dependencies = [ | |
| 1305 | + "cairo-sys-rs", | |
| 1306 | + "gdk-pixbuf-sys", | |
| 1307 | + "gio-sys", | |
| 1308 | + "glib-sys", | |
| 1309 | + "gobject-sys", | |
| 1310 | + "libc", | |
| 1311 | + "pango-sys", | |
| 1312 | + "pkg-config", | |
| 1313 | + "system-deps", | |
| 1314 | +] | |
| 1315 | + | |
| 1254 | 1316 | [[package]] |
| 1255 | 1317 | name = "generic-array" |
| 1256 | 1318 | version = "0.14.7" |
| @@ -1305,6 +1367,19 @@ dependencies = [ | ||
| 1305 | 1367 | "r-efi 6.0.0", |
| 1306 | 1368 | ] |
| 1307 | 1369 | |
| 1370 | +[[package]] | |
| 1371 | +name = "gio-sys" | |
| 1372 | +version = "0.18.1" | |
| 1373 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 1374 | +checksum = "37566df850baf5e4cb0dfb78af2e4b9898d817ed9263d1090a2df958c64737d2" | |
| 1375 | +dependencies = [ | |
| 1376 | + "glib-sys", | |
| 1377 | + "gobject-sys", | |
| 1378 | + "libc", | |
| 1379 | + "system-deps", | |
| 1380 | + "winapi", | |
| 1381 | +] | |
| 1382 | + | |
| 1308 | 1383 | [[package]] |
| 1309 | 1384 | name = "gl_generator" |
| 1310 | 1385 | version = "0.14.0" |
| @@ -1316,6 +1391,16 @@ dependencies = [ | ||
| 1316 | 1391 | "xml-rs", |
| 1317 | 1392 | ] |
| 1318 | 1393 | |
| 1394 | +[[package]] | |
| 1395 | +name = "glib-sys" | |
| 1396 | +version = "0.18.1" | |
| 1397 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 1398 | +checksum = "063ce2eb6a8d0ea93d2bf8ba1957e78dbab6be1c2220dd3daca57d5a9d869898" | |
| 1399 | +dependencies = [ | |
| 1400 | + "libc", | |
| 1401 | + "system-deps", | |
| 1402 | +] | |
| 1403 | + | |
| 1319 | 1404 | [[package]] |
| 1320 | 1405 | name = "glow" |
| 1321 | 1406 | version = "0.12.3" |
| @@ -1392,6 +1477,35 @@ dependencies = [ | ||
| 1392 | 1477 | "gl_generator", |
| 1393 | 1478 | ] |
| 1394 | 1479 | |
| 1480 | +[[package]] | |
| 1481 | +name = "gobject-sys" | |
| 1482 | +version = "0.18.0" | |
| 1483 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 1484 | +checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44" | |
| 1485 | +dependencies = [ | |
| 1486 | + "glib-sys", | |
| 1487 | + "libc", | |
| 1488 | + "system-deps", | |
| 1489 | +] | |
| 1490 | + | |
| 1491 | +[[package]] | |
| 1492 | +name = "gtk-sys" | |
| 1493 | +version = "0.18.2" | |
| 1494 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 1495 | +checksum = "8f29a1c21c59553eb7dd40e918be54dccd60c52b049b75119d5d96ce6b624414" | |
| 1496 | +dependencies = [ | |
| 1497 | + "atk-sys", | |
| 1498 | + "cairo-sys-rs", | |
| 1499 | + "gdk-pixbuf-sys", | |
| 1500 | + "gdk-sys", | |
| 1501 | + "gio-sys", | |
| 1502 | + "glib-sys", | |
| 1503 | + "gobject-sys", | |
| 1504 | + "libc", | |
| 1505 | + "pango-sys", | |
| 1506 | + "system-deps", | |
| 1507 | +] | |
| 1508 | + | |
| 1395 | 1509 | [[package]] |
| 1396 | 1510 | name = "h2" |
| 1397 | 1511 | version = "0.3.27" |
| @@ -1417,6 +1531,12 @@ version = "0.17.1" | ||
| 1417 | 1531 | source = "registry+https://github.com/rust-lang/crates.io-index" |
| 1418 | 1532 | checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" |
| 1419 | 1533 | |
| 1534 | +[[package]] | |
| 1535 | +name = "heck" | |
| 1536 | +version = "0.5.0" | |
| 1537 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 1538 | +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" | |
| 1539 | + | |
| 1420 | 1540 | [[package]] |
| 1421 | 1541 | name = "hermit-abi" |
| 1422 | 1542 | version = "0.3.9" |
| @@ -2122,6 +2242,17 @@ dependencies = [ | ||
| 2122 | 2242 | "malloc_buf", |
| 2123 | 2243 | ] |
| 2124 | 2244 | |
| 2245 | +[[package]] | |
| 2246 | +name = "objc-foundation" | |
| 2247 | +version = "0.1.1" | |
| 2248 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 2249 | +checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" | |
| 2250 | +dependencies = [ | |
| 2251 | + "block", | |
| 2252 | + "objc", | |
| 2253 | + "objc_id", | |
| 2254 | +] | |
| 2255 | + | |
| 2125 | 2256 | [[package]] |
| 2126 | 2257 | name = "objc-sys" |
| 2127 | 2258 | version = "0.2.0-beta.2" |
| @@ -2221,6 +2352,15 @@ dependencies = [ | ||
| 2221 | 2352 | "objc2-core-foundation", |
| 2222 | 2353 | ] |
| 2223 | 2354 | |
| 2355 | +[[package]] | |
| 2356 | +name = "objc_id" | |
| 2357 | +version = "0.1.1" | |
| 2358 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 2359 | +checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" | |
| 2360 | +dependencies = [ | |
| 2361 | + "objc", | |
| 2362 | +] | |
| 2363 | + | |
| 2224 | 2364 | [[package]] |
| 2225 | 2365 | name = "once_cell" |
| 2226 | 2366 | version = "1.21.4" |
| @@ -2299,6 +2439,18 @@ dependencies = [ | ||
| 2299 | 2439 | "ttf-parser", |
| 2300 | 2440 | ] |
| 2301 | 2441 | |
| 2442 | +[[package]] | |
| 2443 | +name = "pango-sys" | |
| 2444 | +version = "0.18.0" | |
| 2445 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 2446 | +checksum = "436737e391a843e5933d6d9aa102cb126d501e815b83601365a948a518555dc5" | |
| 2447 | +dependencies = [ | |
| 2448 | + "glib-sys", | |
| 2449 | + "gobject-sys", | |
| 2450 | + "libc", | |
| 2451 | + "system-deps", | |
| 2452 | +] | |
| 2453 | + | |
| 2302 | 2454 | [[package]] |
| 2303 | 2455 | name = "parking" |
| 2304 | 2456 | version = "2.2.1" |
| @@ -2443,7 +2595,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2443 | 2595 | checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" |
| 2444 | 2596 | dependencies = [ |
| 2445 | 2597 | "once_cell", |
| 2446 | - "toml_edit", | |
| 2598 | + "toml_edit 0.19.15", | |
| 2447 | 2599 | ] |
| 2448 | 2600 | |
| 2449 | 2601 | [[package]] |
| @@ -2620,6 +2772,29 @@ dependencies = [ | ||
| 2620 | 2772 | "winreg", |
| 2621 | 2773 | ] |
| 2622 | 2774 | |
| 2775 | +[[package]] | |
| 2776 | +name = "rfd" | |
| 2777 | +version = "0.12.1" | |
| 2778 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 2779 | +checksum = "3c9e7b57df6e8472152674607f6cc68aa14a748a3157a857a94f516e11aeacc2" | |
| 2780 | +dependencies = [ | |
| 2781 | + "block", | |
| 2782 | + "dispatch", | |
| 2783 | + "glib-sys", | |
| 2784 | + "gobject-sys", | |
| 2785 | + "gtk-sys", | |
| 2786 | + "js-sys", | |
| 2787 | + "log", | |
| 2788 | + "objc", | |
| 2789 | + "objc-foundation", | |
| 2790 | + "objc_id", | |
| 2791 | + "raw-window-handle", | |
| 2792 | + "wasm-bindgen", | |
| 2793 | + "wasm-bindgen-futures", | |
| 2794 | + "web-sys", | |
| 2795 | + "windows-sys 0.48.0", | |
| 2796 | +] | |
| 2797 | + | |
| 2623 | 2798 | [[package]] |
| 2624 | 2799 | name = "rss" |
| 2625 | 2800 | version = "2.1.0" |
| @@ -2645,6 +2820,7 @@ dependencies = [ | ||
| 2645 | 2820 | "md5", |
| 2646 | 2821 | "pathdiff", |
| 2647 | 2822 | "reqwest", |
| 2823 | + "rfd", | |
| 2648 | 2824 | "rss", |
| 2649 | 2825 | "serde", |
| 2650 | 2826 | "serde_json", |
| @@ -2836,6 +3012,15 @@ dependencies = [ | ||
| 2836 | 3012 | "syn 2.0.118", |
| 2837 | 3013 | ] |
| 2838 | 3014 | |
| 3015 | +[[package]] | |
| 3016 | +name = "serde_spanned" | |
| 3017 | +version = "0.6.9" | |
| 3018 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 3019 | +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" | |
| 3020 | +dependencies = [ | |
| 3021 | + "serde", | |
| 3022 | +] | |
| 3023 | + | |
| 2839 | 3024 | [[package]] |
| 2840 | 3025 | name = "serde_urlencoded" |
| 2841 | 3026 | version = "0.7.1" |
| @@ -3045,6 +3230,25 @@ dependencies = [ | ||
| 3045 | 3230 | "libc", |
| 3046 | 3231 | ] |
| 3047 | 3232 | |
| 3233 | +[[package]] | |
| 3234 | +name = "system-deps" | |
| 3235 | +version = "6.2.2" | |
| 3236 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 3237 | +checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" | |
| 3238 | +dependencies = [ | |
| 3239 | + "cfg-expr", | |
| 3240 | + "heck", | |
| 3241 | + "pkg-config", | |
| 3242 | + "toml", | |
| 3243 | + "version-compare", | |
| 3244 | +] | |
| 3245 | + | |
| 3246 | +[[package]] | |
| 3247 | +name = "target-lexicon" | |
| 3248 | +version = "0.12.16" | |
| 3249 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 3250 | +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" | |
| 3251 | + | |
| 3048 | 3252 | [[package]] |
| 3049 | 3253 | name = "tempfile" |
| 3050 | 3254 | version = "3.27.0" |
| @@ -3173,11 +3377,26 @@ dependencies = [ | ||
| 3173 | 3377 | "tokio", |
| 3174 | 3378 | ] |
| 3175 | 3379 | |
| 3380 | +[[package]] | |
| 3381 | +name = "toml" | |
| 3382 | +version = "0.8.23" | |
| 3383 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 3384 | +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" | |
| 3385 | +dependencies = [ | |
| 3386 | + "serde", | |
| 3387 | + "serde_spanned", | |
| 3388 | + "toml_datetime", | |
| 3389 | + "toml_edit 0.22.27", | |
| 3390 | +] | |
| 3391 | + | |
| 3176 | 3392 | [[package]] |
| 3177 | 3393 | name = "toml_datetime" |
| 3178 | 3394 | version = "0.6.11" |
| 3179 | 3395 | source = "registry+https://github.com/rust-lang/crates.io-index" |
| 3180 | 3396 | checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" |
| 3397 | +dependencies = [ | |
| 3398 | + "serde", | |
| 3399 | +] | |
| 3181 | 3400 | |
| 3182 | 3401 | [[package]] |
| 3183 | 3402 | name = "toml_edit" |
| @@ -3187,7 +3406,20 @@ checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" | ||
| 3187 | 3406 | dependencies = [ |
| 3188 | 3407 | "indexmap", |
| 3189 | 3408 | "toml_datetime", |
| 3190 | - "winnow", | |
| 3409 | + "winnow 0.5.40", | |
| 3410 | +] | |
| 3411 | + | |
| 3412 | +[[package]] | |
| 3413 | +name = "toml_edit" | |
| 3414 | +version = "0.22.27" | |
| 3415 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 3416 | +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" | |
| 3417 | +dependencies = [ | |
| 3418 | + "indexmap", | |
| 3419 | + "serde", | |
| 3420 | + "serde_spanned", | |
| 3421 | + "toml_datetime", | |
| 3422 | + "winnow 0.7.15", | |
| 3191 | 3423 | ] |
| 3192 | 3424 | |
| 3193 | 3425 | [[package]] |
| @@ -3304,6 +3536,12 @@ version = "0.8.2" | ||
| 3304 | 3536 | source = "registry+https://github.com/rust-lang/crates.io-index" |
| 3305 | 3537 | checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" |
| 3306 | 3538 | |
| 3539 | +[[package]] | |
| 3540 | +name = "version-compare" | |
| 3541 | +version = "0.2.1" | |
| 3542 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 3543 | +checksum = "03c2856837ef78f57382f06b2b8563a2f512f7185d732608fd9176cb3b8edf0e" | |
| 3544 | + | |
| 3307 | 3545 | [[package]] |
| 3308 | 3546 | name = "version_check" |
| 3309 | 3547 | version = "0.9.5" |
| @@ -4004,6 +4242,15 @@ dependencies = [ | ||
| 4004 | 4242 | "memchr", |
| 4005 | 4243 | ] |
| 4006 | 4244 | |
| 4245 | +[[package]] | |
| 4246 | +name = "winnow" | |
| 4247 | +version = "0.7.15" | |
| 4248 | +source = "registry+https://github.com/rust-lang/crates.io-index" | |
| 4249 | +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" | |
| 4250 | +dependencies = [ | |
| 4251 | + "memchr", | |
| 4252 | +] | |
| 4253 | + | |
| 4007 | 4254 | [[package]] |
| 4008 | 4255 | name = "winreg" |
| 4009 | 4256 | version = "0.50.0" |
| @@ -353,6 +353,18 @@ dependencies = [ | |||
| 353 | "syn 2.0.118", | 353 | "syn 2.0.118", |
| 354 | ] | 354 | ] |
| 355 | 355 | ||
| 356 | +[[package]] | ||
| 357 | +name = "atk-sys" | ||
| 358 | +version = "0.18.2" | ||
| 359 | +source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 360 | +checksum = "c5e48b684b0ca77d2bbadeef17424c2ea3c897d44d566a1617e7e8f30614d086" | ||
| 361 | +dependencies = [ | ||
| 362 | + "glib-sys", | ||
| 363 | + "gobject-sys", | ||
| 364 | + "libc", | ||
| 365 | + "system-deps", | ||
| 366 | +] | ||
| 367 | + | ||
| 356 | [[package]] | 368 | [[package]] |
| 357 | name = "atom_syndication" | 369 | name = "atom_syndication" |
| 358 | version = "0.12.9" | 370 | version = "0.12.9" |
| @@ -528,6 +540,16 @@ version = "1.12.0" | |||
| 528 | source = "registry+https://github.com/rust-lang/crates.io-index" | 540 | source = "registry+https://github.com/rust-lang/crates.io-index" |
| 529 | checksum = "8ae3f5d315924270530207e2a68396c3cc547f6dca3fbdca317cfb1a51edb593" | 541 | checksum = "8ae3f5d315924270530207e2a68396c3cc547f6dca3fbdca317cfb1a51edb593" |
| 530 | 542 | ||
| 543 | +[[package]] | ||
| 544 | +name = "cairo-sys-rs" | ||
| 545 | +version = "0.18.2" | ||
| 546 | +source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 547 | +checksum = "685c9fa8e590b8b3d678873528d83411db17242a73fccaed827770ea0fedda51" | ||
| 548 | +dependencies = [ | ||
| 549 | + "libc", | ||
| 550 | + "system-deps", | ||
| 551 | +] | ||
| 552 | + | ||
| 531 | [[package]] | 553 | [[package]] |
| 532 | name = "calloop" | 554 | name = "calloop" |
| 533 | version = "0.10.6" | 555 | version = "0.10.6" |
| @@ -560,6 +582,16 @@ version = "1.1.0" | |||
| 560 | source = "registry+https://github.com/rust-lang/crates.io-index" | 582 | source = "registry+https://github.com/rust-lang/crates.io-index" |
| 561 | checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" | 583 | checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" |
| 562 | 584 | ||
| 585 | +[[package]] | ||
| 586 | +name = "cfg-expr" | ||
| 587 | +version = "0.15.8" | ||
| 588 | +source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 589 | +checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" | ||
| 590 | +dependencies = [ | ||
| 591 | + "smallvec", | ||
| 592 | + "target-lexicon", | ||
| 593 | +] | ||
| 594 | + | ||
| 563 | [[package]] | 595 | [[package]] |
| 564 | name = "cfg-if" | 596 | name = "cfg-if" |
| 565 | version = "1.0.4" | 597 | version = "1.0.4" |
| @@ -1251,6 +1283,36 @@ dependencies = [ | |||
| 1251 | "slab", | 1283 | "slab", |
| 1252 | ] | 1284 | ] |
| 1253 | 1285 | ||
| 1286 | +[[package]] | ||
| 1287 | +name = "gdk-pixbuf-sys" | ||
| 1288 | +version = "0.18.0" | ||
| 1289 | +source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1290 | +checksum = "3f9839ea644ed9c97a34d129ad56d38a25e6756f99f3a88e15cd39c20629caf7" | ||
| 1291 | +dependencies = [ | ||
| 1292 | + "gio-sys", | ||
| 1293 | + "glib-sys", | ||
| 1294 | + "gobject-sys", | ||
| 1295 | + "libc", | ||
| 1296 | + "system-deps", | ||
| 1297 | +] | ||
| 1298 | + | ||
| 1299 | +[[package]] | ||
| 1300 | +name = "gdk-sys" | ||
| 1301 | +version = "0.18.2" | ||
| 1302 | +source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1303 | +checksum = "5c2d13f38594ac1e66619e188c6d5a1adb98d11b2fcf7894fc416ad76aa2f3f7" | ||
| 1304 | +dependencies = [ | ||
| 1305 | + "cairo-sys-rs", | ||
| 1306 | + "gdk-pixbuf-sys", | ||
| 1307 | + "gio-sys", | ||
| 1308 | + "glib-sys", | ||
| 1309 | + "gobject-sys", | ||
| 1310 | + "libc", | ||
| 1311 | + "pango-sys", | ||
| 1312 | + "pkg-config", | ||
| 1313 | + "system-deps", | ||
| 1314 | +] | ||
| 1315 | + | ||
| 1254 | [[package]] | 1316 | [[package]] |
| 1255 | name = "generic-array" | 1317 | name = "generic-array" |
| 1256 | version = "0.14.7" | 1318 | version = "0.14.7" |
| @@ -1305,6 +1367,19 @@ dependencies = [ | |||
| 1305 | "r-efi 6.0.0", | 1367 | "r-efi 6.0.0", |
| 1306 | ] | 1368 | ] |
| 1307 | 1369 | ||
| 1370 | +[[package]] | ||
| 1371 | +name = "gio-sys" | ||
| 1372 | +version = "0.18.1" | ||
| 1373 | +source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1374 | +checksum = "37566df850baf5e4cb0dfb78af2e4b9898d817ed9263d1090a2df958c64737d2" | ||
| 1375 | +dependencies = [ | ||
| 1376 | + "glib-sys", | ||
| 1377 | + "gobject-sys", | ||
| 1378 | + "libc", | ||
| 1379 | + "system-deps", | ||
| 1380 | + "winapi", | ||
| 1381 | +] | ||
| 1382 | + | ||
| 1308 | [[package]] | 1383 | [[package]] |
| 1309 | name = "gl_generator" | 1384 | name = "gl_generator" |
| 1310 | version = "0.14.0" | 1385 | version = "0.14.0" |
| @@ -1316,6 +1391,16 @@ dependencies = [ | |||
| 1316 | "xml-rs", | 1391 | "xml-rs", |
| 1317 | ] | 1392 | ] |
| 1318 | 1393 | ||
| 1394 | +[[package]] | ||
| 1395 | +name = "glib-sys" | ||
| 1396 | +version = "0.18.1" | ||
| 1397 | +source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1398 | +checksum = "063ce2eb6a8d0ea93d2bf8ba1957e78dbab6be1c2220dd3daca57d5a9d869898" | ||
| 1399 | +dependencies = [ | ||
| 1400 | + "libc", | ||
| 1401 | + "system-deps", | ||
| 1402 | +] | ||
| 1403 | + | ||
| 1319 | [[package]] | 1404 | [[package]] |
| 1320 | name = "glow" | 1405 | name = "glow" |
| 1321 | version = "0.12.3" | 1406 | version = "0.12.3" |
| @@ -1392,6 +1477,35 @@ dependencies = [ | |||
| 1392 | "gl_generator", | 1477 | "gl_generator", |
| 1393 | ] | 1478 | ] |
| 1394 | 1479 | ||
| 1480 | +[[package]] | ||
| 1481 | +name = "gobject-sys" | ||
| 1482 | +version = "0.18.0" | ||
| 1483 | +source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1484 | +checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44" | ||
| 1485 | +dependencies = [ | ||
| 1486 | + "glib-sys", | ||
| 1487 | + "libc", | ||
| 1488 | + "system-deps", | ||
| 1489 | +] | ||
| 1490 | + | ||
| 1491 | +[[package]] | ||
| 1492 | +name = "gtk-sys" | ||
| 1493 | +version = "0.18.2" | ||
| 1494 | +source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1495 | +checksum = "8f29a1c21c59553eb7dd40e918be54dccd60c52b049b75119d5d96ce6b624414" | ||
| 1496 | +dependencies = [ | ||
| 1497 | + "atk-sys", | ||
| 1498 | + "cairo-sys-rs", | ||
| 1499 | + "gdk-pixbuf-sys", | ||
| 1500 | + "gdk-sys", | ||
| 1501 | + "gio-sys", | ||
| 1502 | + "glib-sys", | ||
| 1503 | + "gobject-sys", | ||
| 1504 | + "libc", | ||
| 1505 | + "pango-sys", | ||
| 1506 | + "system-deps", | ||
| 1507 | +] | ||
| 1508 | + | ||
| 1395 | [[package]] | 1509 | [[package]] |
| 1396 | name = "h2" | 1510 | name = "h2" |
| 1397 | version = "0.3.27" | 1511 | version = "0.3.27" |
| @@ -1417,6 +1531,12 @@ version = "0.17.1" | |||
| 1417 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1531 | source = "registry+https://github.com/rust-lang/crates.io-index" |
| 1418 | checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" | 1532 | checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" |
| 1419 | 1533 | ||
| 1534 | +[[package]] | ||
| 1535 | +name = "heck" | ||
| 1536 | +version = "0.5.0" | ||
| 1537 | +source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 1538 | +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" | ||
| 1539 | + | ||
| 1420 | [[package]] | 1540 | [[package]] |
| 1421 | name = "hermit-abi" | 1541 | name = "hermit-abi" |
| 1422 | version = "0.3.9" | 1542 | version = "0.3.9" |
| @@ -2122,6 +2242,17 @@ dependencies = [ | |||
| 2122 | "malloc_buf", | 2242 | "malloc_buf", |
| 2123 | ] | 2243 | ] |
| 2124 | 2244 | ||
| 2245 | +[[package]] | ||
| 2246 | +name = "objc-foundation" | ||
| 2247 | +version = "0.1.1" | ||
| 2248 | +source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2249 | +checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" | ||
| 2250 | +dependencies = [ | ||
| 2251 | + "block", | ||
| 2252 | + "objc", | ||
| 2253 | + "objc_id", | ||
| 2254 | +] | ||
| 2255 | + | ||
| 2125 | [[package]] | 2256 | [[package]] |
| 2126 | name = "objc-sys" | 2257 | name = "objc-sys" |
| 2127 | version = "0.2.0-beta.2" | 2258 | version = "0.2.0-beta.2" |
| @@ -2221,6 +2352,15 @@ dependencies = [ | |||
| 2221 | "objc2-core-foundation", | 2352 | "objc2-core-foundation", |
| 2222 | ] | 2353 | ] |
| 2223 | 2354 | ||
| 2355 | +[[package]] | ||
| 2356 | +name = "objc_id" | ||
| 2357 | +version = "0.1.1" | ||
| 2358 | +source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2359 | +checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" | ||
| 2360 | +dependencies = [ | ||
| 2361 | + "objc", | ||
| 2362 | +] | ||
| 2363 | + | ||
| 2224 | [[package]] | 2364 | [[package]] |
| 2225 | name = "once_cell" | 2365 | name = "once_cell" |
| 2226 | version = "1.21.4" | 2366 | version = "1.21.4" |
| @@ -2299,6 +2439,18 @@ dependencies = [ | |||
| 2299 | "ttf-parser", | 2439 | "ttf-parser", |
| 2300 | ] | 2440 | ] |
| 2301 | 2441 | ||
| 2442 | +[[package]] | ||
| 2443 | +name = "pango-sys" | ||
| 2444 | +version = "0.18.0" | ||
| 2445 | +source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2446 | +checksum = "436737e391a843e5933d6d9aa102cb126d501e815b83601365a948a518555dc5" | ||
| 2447 | +dependencies = [ | ||
| 2448 | + "glib-sys", | ||
| 2449 | + "gobject-sys", | ||
| 2450 | + "libc", | ||
| 2451 | + "system-deps", | ||
| 2452 | +] | ||
| 2453 | + | ||
| 2302 | [[package]] | 2454 | [[package]] |
| 2303 | name = "parking" | 2455 | name = "parking" |
| 2304 | version = "2.2.1" | 2456 | version = "2.2.1" |
| @@ -2443,7 +2595,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
| 2443 | checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" | 2595 | checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" |
| 2444 | dependencies = [ | 2596 | dependencies = [ |
| 2445 | "once_cell", | 2597 | "once_cell", |
| 2446 | - "toml_edit", | 2598 | + "toml_edit 0.19.15", |
| 2447 | ] | 2599 | ] |
| 2448 | 2600 | ||
| 2449 | [[package]] | 2601 | [[package]] |
| @@ -2620,6 +2772,29 @@ dependencies = [ | |||
| 2620 | "winreg", | 2772 | "winreg", |
| 2621 | ] | 2773 | ] |
| 2622 | 2774 | ||
| 2775 | +[[package]] | ||
| 2776 | +name = "rfd" | ||
| 2777 | +version = "0.12.1" | ||
| 2778 | +source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 2779 | +checksum = "3c9e7b57df6e8472152674607f6cc68aa14a748a3157a857a94f516e11aeacc2" | ||
| 2780 | +dependencies = [ | ||
| 2781 | + "block", | ||
| 2782 | + "dispatch", | ||
| 2783 | + "glib-sys", | ||
| 2784 | + "gobject-sys", | ||
| 2785 | + "gtk-sys", | ||
| 2786 | + "js-sys", | ||
| 2787 | + "log", | ||
| 2788 | + "objc", | ||
| 2789 | + "objc-foundation", | ||
| 2790 | + "objc_id", | ||
| 2791 | + "raw-window-handle", | ||
| 2792 | + "wasm-bindgen", | ||
| 2793 | + "wasm-bindgen-futures", | ||
| 2794 | + "web-sys", | ||
| 2795 | + "windows-sys 0.48.0", | ||
| 2796 | +] | ||
| 2797 | + | ||
| 2623 | [[package]] | 2798 | [[package]] |
| 2624 | name = "rss" | 2799 | name = "rss" |
| 2625 | version = "2.1.0" | 2800 | version = "2.1.0" |
| @@ -2645,6 +2820,7 @@ dependencies = [ | |||
| 2645 | "md5", | 2820 | "md5", |
| 2646 | "pathdiff", | 2821 | "pathdiff", |
| 2647 | "reqwest", | 2822 | "reqwest", |
| 2823 | + "rfd", | ||
| 2648 | "rss", | 2824 | "rss", |
| 2649 | "serde", | 2825 | "serde", |
| 2650 | "serde_json", | 2826 | "serde_json", |
| @@ -2836,6 +3012,15 @@ dependencies = [ | |||
| 2836 | "syn 2.0.118", | 3012 | "syn 2.0.118", |
| 2837 | ] | 3013 | ] |
| 2838 | 3014 | ||
| 3015 | +[[package]] | ||
| 3016 | +name = "serde_spanned" | ||
| 3017 | +version = "0.6.9" | ||
| 3018 | +source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 3019 | +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" | ||
| 3020 | +dependencies = [ | ||
| 3021 | + "serde", | ||
| 3022 | +] | ||
| 3023 | + | ||
| 2839 | [[package]] | 3024 | [[package]] |
| 2840 | name = "serde_urlencoded" | 3025 | name = "serde_urlencoded" |
| 2841 | version = "0.7.1" | 3026 | version = "0.7.1" |
| @@ -3045,6 +3230,25 @@ dependencies = [ | |||
| 3045 | "libc", | 3230 | "libc", |
| 3046 | ] | 3231 | ] |
| 3047 | 3232 | ||
| 3233 | +[[package]] | ||
| 3234 | +name = "system-deps" | ||
| 3235 | +version = "6.2.2" | ||
| 3236 | +source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 3237 | +checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" | ||
| 3238 | +dependencies = [ | ||
| 3239 | + "cfg-expr", | ||
| 3240 | + "heck", | ||
| 3241 | + "pkg-config", | ||
| 3242 | + "toml", | ||
| 3243 | + "version-compare", | ||
| 3244 | +] | ||
| 3245 | + | ||
| 3246 | +[[package]] | ||
| 3247 | +name = "target-lexicon" | ||
| 3248 | +version = "0.12.16" | ||
| 3249 | +source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 3250 | +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" | ||
| 3251 | + | ||
| 3048 | [[package]] | 3252 | [[package]] |
| 3049 | name = "tempfile" | 3253 | name = "tempfile" |
| 3050 | version = "3.27.0" | 3254 | version = "3.27.0" |
| @@ -3173,11 +3377,26 @@ dependencies = [ | |||
| 3173 | "tokio", | 3377 | "tokio", |
| 3174 | ] | 3378 | ] |
| 3175 | 3379 | ||
| 3380 | +[[package]] | ||
| 3381 | +name = "toml" | ||
| 3382 | +version = "0.8.23" | ||
| 3383 | +source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 3384 | +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" | ||
| 3385 | +dependencies = [ | ||
| 3386 | + "serde", | ||
| 3387 | + "serde_spanned", | ||
| 3388 | + "toml_datetime", | ||
| 3389 | + "toml_edit 0.22.27", | ||
| 3390 | +] | ||
| 3391 | + | ||
| 3176 | [[package]] | 3392 | [[package]] |
| 3177 | name = "toml_datetime" | 3393 | name = "toml_datetime" |
| 3178 | version = "0.6.11" | 3394 | version = "0.6.11" |
| 3179 | source = "registry+https://github.com/rust-lang/crates.io-index" | 3395 | source = "registry+https://github.com/rust-lang/crates.io-index" |
| 3180 | checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" | 3396 | checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" |
| 3397 | +dependencies = [ | ||
| 3398 | + "serde", | ||
| 3399 | +] | ||
| 3181 | 3400 | ||
| 3182 | [[package]] | 3401 | [[package]] |
| 3183 | name = "toml_edit" | 3402 | name = "toml_edit" |
| @@ -3187,7 +3406,20 @@ checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" | |||
| 3187 | dependencies = [ | 3406 | dependencies = [ |
| 3188 | "indexmap", | 3407 | "indexmap", |
| 3189 | "toml_datetime", | 3408 | "toml_datetime", |
| 3190 | - "winnow", | 3409 | + "winnow 0.5.40", |
| 3410 | +] | ||
| 3411 | + | ||
| 3412 | +[[package]] | ||
| 3413 | +name = "toml_edit" | ||
| 3414 | +version = "0.22.27" | ||
| 3415 | +source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 3416 | +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" | ||
| 3417 | +dependencies = [ | ||
| 3418 | + "indexmap", | ||
| 3419 | + "serde", | ||
| 3420 | + "serde_spanned", | ||
| 3421 | + "toml_datetime", | ||
| 3422 | + "winnow 0.7.15", | ||
| 3191 | ] | 3423 | ] |
| 3192 | 3424 | ||
| 3193 | [[package]] | 3425 | [[package]] |
| @@ -3304,6 +3536,12 @@ version = "0.8.2" | |||
| 3304 | source = "registry+https://github.com/rust-lang/crates.io-index" | 3536 | source = "registry+https://github.com/rust-lang/crates.io-index" |
| 3305 | checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" | 3537 | checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" |
| 3306 | 3538 | ||
| 3539 | +[[package]] | ||
| 3540 | +name = "version-compare" | ||
| 3541 | +version = "0.2.1" | ||
| 3542 | +source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 3543 | +checksum = "03c2856837ef78f57382f06b2b8563a2f512f7185d732608fd9176cb3b8edf0e" | ||
| 3544 | + | ||
| 3307 | [[package]] | 3545 | [[package]] |
| 3308 | name = "version_check" | 3546 | name = "version_check" |
| 3309 | version = "0.9.5" | 3547 | version = "0.9.5" |
| @@ -4004,6 +4242,15 @@ dependencies = [ | |||
| 4004 | "memchr", | 4242 | "memchr", |
| 4005 | ] | 4243 | ] |
| 4006 | 4244 | ||
| 4245 | +[[package]] | ||
| 4246 | +name = "winnow" | ||
| 4247 | +version = "0.7.15" | ||
| 4248 | +source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 4249 | +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" | ||
| 4250 | +dependencies = [ | ||
| 4251 | + "memchr", | ||
| 4252 | +] | ||
| 4253 | + | ||
| 4007 | [[package]] | 4254 | [[package]] |
| 4008 | name = "winreg" | 4255 | name = "winreg" |
| 4009 | version = "0.50.0" | 4256 | version = "0.50.0" |
modified
Cargo.toml +3 -0 | @@ -54,6 +54,9 @@ futures-util = "0.3" | ||
| 54 | 54 | # Hashing for filename generation |
| 55 | 55 | md5 = "0.7" |
| 56 | 56 | |
| 57 | +# File dialogs for export/import | |
| 58 | +rfd = "0.12" | |
| 59 | + | |
| 57 | 60 | # Date parsing |
| 58 | 61 | # The rss crate already includes chrono, but we need additional date parsing |
| 59 | 62 | diligent-date-parser = "0.1" |
| @@ -54,6 +54,9 @@ futures-util = "0.3" | |||
| 54 | # Hashing for filename generation | 54 | # Hashing for filename generation |
| 55 | md5 = "0.7" | 55 | md5 = "0.7" |
| 56 | 56 | ||
| 57 | +# File dialogs for export/import | ||
| 58 | +rfd = "0.12" | ||
| 59 | + | ||
| 57 | # Date parsing | 60 | # Date parsing |
| 58 | # The rss crate already includes chrono, but we need additional date parsing | 61 | # The rss crate already includes chrono, but we need additional date parsing |
| 59 | diligent-date-parser = "0.1" | 62 | diligent-date-parser = "0.1" |
modified
spec/init-plan.md +1 -1 | @@ -322,7 +322,7 @@ pub async fn download_episode( | ||
| 322 | 322 | | Phase 5 | 2 jours | J11-J12 | ✅ | |
| 323 | 323 | | Phase 6 | 2 jours | J13-J14 | ✅ | |
| 324 | 324 | | Phase 7 | 1 jour | J15 | ✅ | |
| 325 | -| Phase 8 | 3 jours | J16-J18 | 🟡 75% (6/8 tâches) | | |
| 325 | +| Phase 8 | 3 jours | J16-J18 | ✅ | | |
| 326 | 326 | | **Total** | **18 jours** | | | |
| 327 | 327 | |
| 328 | 328 | --- |
| @@ -322,7 +322,7 @@ pub async fn download_episode( | |||
| 322 | | Phase 5 | 2 jours | J11-J12 | ✅ | | 322 | | Phase 5 | 2 jours | J11-J12 | ✅ | |
| 323 | | Phase 6 | 2 jours | J13-J14 | ✅ | | 323 | | Phase 6 | 2 jours | J13-J14 | ✅ | |
| 324 | | Phase 7 | 1 jour | J15 | ✅ | | 324 | | Phase 7 | 1 jour | J15 | ✅ | |
| 325 | -| Phase 8 | 3 jours | J16-J18 | 🟡 75% (6/8 tâches) | | 325 | +| Phase 8 | 3 jours | J16-J18 | ✅ | |
| 326 | | **Total** | **18 jours** | | | | 326 | | **Total** | **18 jours** | | | |
| 327 | 327 | ||
| 328 | --- | 328 | --- |
modified
spec/init-tasks.md +4 -4 | @@ -186,8 +186,8 @@ | ||
| 186 | 186 | | T8.4 | Implémenter le filtrage par date | M | 2h | `src/ui/filter_panel.rs`, `src/config/app_state.rs`, `src/ui/feed_list.rs`, `src/ui/home.rs`, `src/ui/mod.rs` | T5.2 | ✅ | |
| 187 | 187 | | T8.5 | Implémenter le filtrage par numéro d'épisode | M | 2h | `src/ui/filter_panel.rs`, `src/config/episode.rs`, `src/config/app_state.rs` | T2.3, T8.4 | ✅ | |
| 188 | 188 | | T8.6 | Ajouter un système de tags pour les flux | L | 2h | `src/config/feed.rs`, `src/ui/feed_edit_dialog.rs`, `src/ui/feed_list.rs`, `src/config/app_state.rs` | T2.1 | ✅ | |
| 189 | -| T8.7 | Implémenter l'export des flux (fichier JSON personnalisé) | L | 2h | `src/config/storage.rs`, `src/ui/home.rs` | T2.8 | ⬜ | | |
| 190 | -| T8.8 | Implémenter l'import des flux | L | 2h | `src/config/storage.rs`, `src/ui/home.rs` | T8.7 | ⬜ | | |
| 189 | +| T8.7 | Implémenter l'export des flux (fichier JSON personnalisé) | L | 2h | `Cargo.toml`, `src/config/storage.rs`, `src/ui/export_import.rs`, `src/ui/home.rs`, `src/ui/mod.rs`, `src/config/app_state.rs` | T2.8 | ✅ | | |
| 190 | +| T8.8 | Implémenter l'import des flux | L | 2h | `Cargo.toml`, `src/config/storage.rs`, `src/ui/export_import.rs`, `src/ui/home.rs`, `src/ui/mod.rs`, `src/config/app_state.rs` | T8.7 | ✅ | | |
| 191 | 191 | |
| 192 | 192 | **Total Phase 8** : 20 heures (2.5 jours) |
| 193 | 193 | |
| @@ -204,8 +204,8 @@ | ||
| 204 | 204 | | Phase 5 | 10 tâches | 16h | ✅ Terminé | |
| 205 | 205 | | Phase 6 | 12 tâches | 24h | ✅ Terminé | |
| 206 | 206 | | Phase 7 | 10 tâches | 11h | ✅ Terminé | |
| 207 | -| Phase 8 | 8 tâches | 20h | 🟡 75% complet (6/8) | | |
| 208 | -| **Total** | **88 tâches** | **145 heures** (~18 jours) | 🟡 97.7% complet | | |
| 207 | +| Phase 8 | 8 tâches | 20h | ✅ Terminé | | |
| 208 | +| **Total** | **88 tâches** | **145 heures** (~18 jours) | ✅ 100% complet | | |
| 209 | 209 | |
| 210 | 210 | --- |
| 211 | 211 | |
| @@ -186,8 +186,8 @@ | |||
| 186 | | T8.4 | Implémenter le filtrage par date | M | 2h | `src/ui/filter_panel.rs`, `src/config/app_state.rs`, `src/ui/feed_list.rs`, `src/ui/home.rs`, `src/ui/mod.rs` | T5.2 | ✅ | | 186 | | T8.4 | Implémenter le filtrage par date | M | 2h | `src/ui/filter_panel.rs`, `src/config/app_state.rs`, `src/ui/feed_list.rs`, `src/ui/home.rs`, `src/ui/mod.rs` | T5.2 | ✅ | |
| 187 | | T8.5 | Implémenter le filtrage par numéro d'épisode | M | 2h | `src/ui/filter_panel.rs`, `src/config/episode.rs`, `src/config/app_state.rs` | T2.3, T8.4 | ✅ | | 187 | | T8.5 | Implémenter le filtrage par numéro d'épisode | M | 2h | `src/ui/filter_panel.rs`, `src/config/episode.rs`, `src/config/app_state.rs` | T2.3, T8.4 | ✅ | |
| 188 | | T8.6 | Ajouter un système de tags pour les flux | L | 2h | `src/config/feed.rs`, `src/ui/feed_edit_dialog.rs`, `src/ui/feed_list.rs`, `src/config/app_state.rs` | T2.1 | ✅ | | 188 | | T8.6 | Ajouter un système de tags pour les flux | L | 2h | `src/config/feed.rs`, `src/ui/feed_edit_dialog.rs`, `src/ui/feed_list.rs`, `src/config/app_state.rs` | T2.1 | ✅ | |
| 189 | -| T8.7 | Implémenter l'export des flux (fichier JSON personnalisé) | L | 2h | `src/config/storage.rs`, `src/ui/home.rs` | T2.8 | ⬜ | | 189 | +| T8.7 | Implémenter l'export des flux (fichier JSON personnalisé) | L | 2h | `Cargo.toml`, `src/config/storage.rs`, `src/ui/export_import.rs`, `src/ui/home.rs`, `src/ui/mod.rs`, `src/config/app_state.rs` | T2.8 | ✅ | |
| 190 | -| T8.8 | Implémenter l'import des flux | L | 2h | `src/config/storage.rs`, `src/ui/home.rs` | T8.7 | ⬜ | | 190 | +| T8.8 | Implémenter l'import des flux | L | 2h | `Cargo.toml`, `src/config/storage.rs`, `src/ui/export_import.rs`, `src/ui/home.rs`, `src/ui/mod.rs`, `src/config/app_state.rs` | T8.7 | ✅ | |
| 191 | 191 | ||
| 192 | **Total Phase 8** : 20 heures (2.5 jours) | 192 | **Total Phase 8** : 20 heures (2.5 jours) |
| 193 | 193 | ||
| @@ -204,8 +204,8 @@ | |||
| 204 | | Phase 5 | 10 tâches | 16h | ✅ Terminé | | 204 | | Phase 5 | 10 tâches | 16h | ✅ Terminé | |
| 205 | | Phase 6 | 12 tâches | 24h | ✅ Terminé | | 205 | | Phase 6 | 12 tâches | 24h | ✅ Terminé | |
| 206 | | Phase 7 | 10 tâches | 11h | ✅ Terminé | | 206 | | Phase 7 | 10 tâches | 11h | ✅ Terminé | |
| 207 | -| Phase 8 | 8 tâches | 20h | 🟡 75% complet (6/8) | | 207 | +| Phase 8 | 8 tâches | 20h | ✅ Terminé | |
| 208 | -| **Total** | **88 tâches** | **145 heures** (~18 jours) | 🟡 97.7% complet | | 208 | +| **Total** | **88 tâches** | **145 heures** (~18 jours) | ✅ 100% complet | |
| 209 | 209 | ||
| 210 | --- | 210 | --- |
| 211 | 211 | ||
modified
spec/progress.md +16 -15 | @@ -1,7 +1,7 @@ | ||
| 1 | 1 | # RSS Podcast Downloader - Suivi des Progrès |
| 2 | 2 | |
| 3 | 3 | *Dernière mise à jour: 05/07/2026* |
| 4 | -*Version: 2.2* | |
| 4 | +*Version: 3.0* | |
| 5 | 5 | |
| 6 | 6 | --- |
| 7 | 7 | |
| @@ -255,7 +255,7 @@ | ||
| 255 | 255 | |
| 256 | 256 | --- |
| 257 | 257 | |
| 258 | -## Phase 8 : Fonctionnalités Avancées (6/8 tâches - 75%) | |
| 258 | +## Phase 8 : Fonctionnalités Avancées (8/8 tâches - 100%) | |
| 259 | 259 | |
| 260 | 260 | - [x] T8.1 - Implémenter la détection automatique des nouveaux épisodes |
| 261 | 261 | - *Fichiers: src/rss/sync.rs, src/rss/downloader.rs* |
| @@ -287,13 +287,15 @@ | ||
| 287 | 287 | - *Contenu: Champ tags dans Feed, édition des tags dans le dialogue d'édition, affichage des tags dans la liste* |
| 288 | 288 | - *Date: 05/07/2026* |
| 289 | 289 | |
| 290 | -- [ ] T8.7 - Implémenter l'export des flux (fichier JSON personnalisé) | |
| 291 | - - *Fichiers: src/config/storage.rs, src/ui/home.rs* | |
| 292 | - - *Statut: Non commencé* | |
| 290 | +- [x] T8.7 - Implémenter l'export des flux (fichier JSON personnalisé) | |
| 291 | + - *Fichiers: Cargo.toml, src/config/storage.rs, src/ui/export_import.rs, src/ui/home.rs, src/ui/mod.rs, src/config/app_state.rs* | |
| 292 | + - *Contenu: Ajout de la crate rfd, dialogues natifs de sélection de fichier, export en JSON pretty* | |
| 293 | + - *Date: 05/07/2026* | |
| 293 | 294 | |
| 294 | -- [ ] T8.8 - Implémenter l'import des flux | |
| 295 | - - *Fichiers: src/config/storage.rs, src/ui/home.rs* | |
| 296 | - - *Statut: Non commencé* | |
| 295 | +- [x] T8.8 - Implémenter l'import des flux | |
| 296 | + - *Fichiers: Cargo.toml, src/config/storage.rs, src/ui/export_import.rs, src/ui/home.rs, src/ui/mod.rs, src/config/app_state.rs* | |
| 297 | + - *Contenu: Dialogue d'import, fusion des flux importés avec les flux existants, sauvegarde automatique* | |
| 298 | + - *Date: 05/07/2026* | |
| 297 | 299 | |
| 298 | 300 | --- |
| 299 | 301 | |
| @@ -308,18 +310,17 @@ | ||
| 308 | 310 | | Phase 5 | 10 | 10 | 100% | Terminé | |
| 309 | 311 | | Phase 6 | 12 | 12 | 100% | Terminé | |
| 310 | 312 | | Phase 7 | 10 | 10 | 100% | Terminé | |
| 311 | -| Phase 8 | 8 | 6 | 75% | En cours | | |
| 312 | -| **Total** | **88** | **86** | **97.7%** | En cours | | |
| 313 | +| Phase 8 | 8 | 8 | 100% | Terminé | | |
| 314 | +| **Total** | **88** | **88** | **100%** | Terminé | | |
| 313 | 315 | |
| 314 | -**Projet complété à 97.7%** | |
| 316 | +**Projet complété à 100%!** | |
| 315 | 317 | |
| 316 | 318 | --- |
| 317 | 319 | |
| 318 | 320 | ## Prochaines Étapes |
| 319 | 321 | |
| 320 | -### Phase 8 en cours (6/8 tâches - 75% complet) | |
| 321 | -- Continuer avec T8.7 - Implémenter l'export des flux | |
| 322 | -- Continuer avec T8.8 - Implémenter l'import des flux | |
| 322 | +### Projet Complété à 100% | |
| 323 | +Toutes les phases ont été implémentées avec succès! | |
| 323 | 324 | |
| 324 | 325 | ### Historique des commits |
| 325 | 326 | - Phase 1: Initialisation du projet |
| @@ -397,4 +398,4 @@ Phase 7: Finalisation | ||
| 397 | 398 | --- |
| 398 | 399 | |
| 399 | 400 | *Document généré et mis à jour le 05/07/2026* |
| 400 | -*Projet RSS Podcast Downloader - 97.7% complet (Phase 8 en cours - 6/8 tâches)* | |
| 401 | +*Projet RSS Podcast Downloader - 100% COMPLÉTÉ (Toutes les phases terminées)* | |
| @@ -1,7 +1,7 @@ | |||
| 1 | # RSS Podcast Downloader - Suivi des Progrès | 1 | # RSS Podcast Downloader - Suivi des Progrès |
| 2 | 2 | ||
| 3 | *Dernière mise à jour: 05/07/2026* | 3 | *Dernière mise à jour: 05/07/2026* |
| 4 | -*Version: 2.2* | 4 | +*Version: 3.0* |
| 5 | 5 | ||
| 6 | --- | 6 | --- |
| 7 | 7 | ||
| @@ -255,7 +255,7 @@ | |||
| 255 | 255 | ||
| 256 | --- | 256 | --- |
| 257 | 257 | ||
| 258 | -## Phase 8 : Fonctionnalités Avancées (6/8 tâches - 75%) | 258 | +## Phase 8 : Fonctionnalités Avancées (8/8 tâches - 100%) |
| 259 | 259 | ||
| 260 | - [x] T8.1 - Implémenter la détection automatique des nouveaux épisodes | 260 | - [x] T8.1 - Implémenter la détection automatique des nouveaux épisodes |
| 261 | - *Fichiers: src/rss/sync.rs, src/rss/downloader.rs* | 261 | - *Fichiers: src/rss/sync.rs, src/rss/downloader.rs* |
| @@ -287,13 +287,15 @@ | |||
| 287 | - *Contenu: Champ tags dans Feed, édition des tags dans le dialogue d'édition, affichage des tags dans la liste* | 287 | - *Contenu: Champ tags dans Feed, édition des tags dans le dialogue d'édition, affichage des tags dans la liste* |
| 288 | - *Date: 05/07/2026* | 288 | - *Date: 05/07/2026* |
| 289 | 289 | ||
| 290 | -- [ ] T8.7 - Implémenter l'export des flux (fichier JSON personnalisé) | 290 | +- [x] T8.7 - Implémenter l'export des flux (fichier JSON personnalisé) |
| 291 | - - *Fichiers: src/config/storage.rs, src/ui/home.rs* | 291 | + - *Fichiers: Cargo.toml, src/config/storage.rs, src/ui/export_import.rs, src/ui/home.rs, src/ui/mod.rs, src/config/app_state.rs* |
| 292 | - - *Statut: Non commencé* | 292 | + - *Contenu: Ajout de la crate rfd, dialogues natifs de sélection de fichier, export en JSON pretty* |
| 293 | + - *Date: 05/07/2026* | ||
| 293 | 294 | ||
| 294 | -- [ ] T8.8 - Implémenter l'import des flux | 295 | +- [x] T8.8 - Implémenter l'import des flux |
| 295 | - - *Fichiers: src/config/storage.rs, src/ui/home.rs* | 296 | + - *Fichiers: Cargo.toml, src/config/storage.rs, src/ui/export_import.rs, src/ui/home.rs, src/ui/mod.rs, src/config/app_state.rs* |
| 296 | - - *Statut: Non commencé* | 297 | + - *Contenu: Dialogue d'import, fusion des flux importés avec les flux existants, sauvegarde automatique* |
| 298 | + - *Date: 05/07/2026* | ||
| 297 | 299 | ||
| 298 | --- | 300 | --- |
| 299 | 301 | ||
| @@ -308,18 +310,17 @@ | |||
| 308 | | Phase 5 | 10 | 10 | 100% | Terminé | | 310 | | Phase 5 | 10 | 10 | 100% | Terminé | |
| 309 | | Phase 6 | 12 | 12 | 100% | Terminé | | 311 | | Phase 6 | 12 | 12 | 100% | Terminé | |
| 310 | | Phase 7 | 10 | 10 | 100% | Terminé | | 312 | | Phase 7 | 10 | 10 | 100% | Terminé | |
| 311 | -| Phase 8 | 8 | 6 | 75% | En cours | | 313 | +| Phase 8 | 8 | 8 | 100% | Terminé | |
| 312 | -| **Total** | **88** | **86** | **97.7%** | En cours | | 314 | +| **Total** | **88** | **88** | **100%** | Terminé | |
| 313 | 315 | ||
| 314 | -**Projet complété à 97.7%** | 316 | +**Projet complété à 100%!** |
| 315 | 317 | ||
| 316 | --- | 318 | --- |
| 317 | 319 | ||
| 318 | ## Prochaines Étapes | 320 | ## Prochaines Étapes |
| 319 | 321 | ||
| 320 | -### Phase 8 en cours (6/8 tâches - 75% complet) | 322 | +### Projet Complété à 100% |
| 321 | -- Continuer avec T8.7 - Implémenter l'export des flux | 323 | +Toutes les phases ont été implémentées avec succès! |
| 322 | -- Continuer avec T8.8 - Implémenter l'import des flux | ||
| 323 | 324 | ||
| 324 | ### Historique des commits | 325 | ### Historique des commits |
| 325 | - Phase 1: Initialisation du projet | 326 | - Phase 1: Initialisation du projet |
| @@ -397,4 +398,4 @@ Phase 7: Finalisation | |||
| 397 | --- | 398 | --- |
| 398 | 399 | ||
| 399 | *Document généré et mis à jour le 05/07/2026* | 400 | *Document généré et mis à jour le 05/07/2026* |
| 400 | -*Projet RSS Podcast Downloader - 97.7% complet (Phase 8 en cours - 6/8 tâches)* | 401 | +*Projet RSS Podcast Downloader - 100% COMPLÉTÉ (Toutes les phases terminées)* |
modified
src/config/app_state.rs +26 -0 | @@ -96,6 +96,15 @@ pub struct AppState { | ||
| 96 | 96 | /// Whether to show the date picker for 'to' date |
| 97 | 97 | #[allow(dead_code)] |
| 98 | 98 | pub show_date_picker_to: bool, |
| 99 | + /// Whether the export dialog is visible | |
| 100 | + #[allow(dead_code)] | |
| 101 | + pub show_export_dialog: bool, | |
| 102 | + /// Whether the import dialog is visible | |
| 103 | + #[allow(dead_code)] | |
| 104 | + pub show_import_dialog: bool, | |
| 105 | + /// Last export/import error message | |
| 106 | + #[allow(dead_code)] | |
| 107 | + pub export_import_error: Option<String>, | |
| 99 | 108 | } |
| 100 | 109 | |
| 101 | 110 | impl AppState { |
| @@ -135,6 +144,9 @@ impl AppState { | ||
| 135 | 144 | filter_episode_number: String::new(), |
| 136 | 145 | show_date_picker_from: false, |
| 137 | 146 | show_date_picker_to: false, |
| 147 | + show_export_dialog: false, | |
| 148 | + show_import_dialog: false, | |
| 149 | + export_import_error: None, | |
| 138 | 150 | } |
| 139 | 151 | } |
| 140 | 152 | |
| @@ -421,6 +433,20 @@ impl AppState { | ||
| 421 | 433 | self.filter_episode_number.clear(); |
| 422 | 434 | self.notification_manager.info("Filtres effacés"); |
| 423 | 435 | } |
| 436 | + | |
| 437 | + /// Sets an export/import error message | |
| 438 | + #[allow(dead_code)] | |
| 439 | + pub fn set_export_import_error(&mut self, message: impl Into<String>) { | |
| 440 | + let msg: String = message.into(); | |
| 441 | + self.export_import_error = Some(msg.clone()); | |
| 442 | + self.notification_manager.error(msg); | |
| 443 | + } | |
| 444 | + | |
| 445 | + /// Clears the export/import error message | |
| 446 | + #[allow(dead_code)] | |
| 447 | + pub fn clear_export_import_error(&mut self) { | |
| 448 | + self.export_import_error = None; | |
| 449 | + } | |
| 424 | 450 | } |
| 425 | 451 | |
| 426 | 452 | #[cfg(test)] |
| @@ -96,6 +96,15 @@ pub struct AppState { | |||
| 96 | /// Whether to show the date picker for 'to' date | 96 | /// Whether to show the date picker for 'to' date |
| 97 | #[allow(dead_code)] | 97 | #[allow(dead_code)] |
| 98 | pub show_date_picker_to: bool, | 98 | pub show_date_picker_to: bool, |
| 99 | + /// Whether the export dialog is visible | ||
| 100 | + #[allow(dead_code)] | ||
| 101 | + pub show_export_dialog: bool, | ||
| 102 | + /// Whether the import dialog is visible | ||
| 103 | + #[allow(dead_code)] | ||
| 104 | + pub show_import_dialog: bool, | ||
| 105 | + /// Last export/import error message | ||
| 106 | + #[allow(dead_code)] | ||
| 107 | + pub export_import_error: Option<String>, | ||
| 99 | } | 108 | } |
| 100 | 109 | ||
| 101 | impl AppState { | 110 | impl AppState { |
| @@ -135,6 +144,9 @@ impl AppState { | |||
| 135 | filter_episode_number: String::new(), | 144 | filter_episode_number: String::new(), |
| 136 | show_date_picker_from: false, | 145 | show_date_picker_from: false, |
| 137 | show_date_picker_to: false, | 146 | show_date_picker_to: false, |
| 147 | + show_export_dialog: false, | ||
| 148 | + show_import_dialog: false, | ||
| 149 | + export_import_error: None, | ||
| 138 | } | 150 | } |
| 139 | } | 151 | } |
| 140 | 152 | ||
| @@ -421,6 +433,20 @@ impl AppState { | |||
| 421 | self.filter_episode_number.clear(); | 433 | self.filter_episode_number.clear(); |
| 422 | self.notification_manager.info("Filtres effacés"); | 434 | self.notification_manager.info("Filtres effacés"); |
| 423 | } | 435 | } |
| 436 | + | ||
| 437 | + /// Sets an export/import error message | ||
| 438 | + #[allow(dead_code)] | ||
| 439 | + pub fn set_export_import_error(&mut self, message: impl Into<String>) { | ||
| 440 | + let msg: String = message.into(); | ||
| 441 | + self.export_import_error = Some(msg.clone()); | ||
| 442 | + self.notification_manager.error(msg); | ||
| 443 | + } | ||
| 444 | + | ||
| 445 | + /// Clears the export/import error message | ||
| 446 | + #[allow(dead_code)] | ||
| 447 | + pub fn clear_export_import_error(&mut self) { | ||
| 448 | + self.export_import_error = None; | ||
| 449 | + } | ||
| 424 | } | 450 | } |
| 425 | 451 | ||
| 426 | #[cfg(test)] | 452 | #[cfg(test)] |
modified
src/config/storage.rs +40 -0 | @@ -200,6 +200,46 @@ pub fn load_playlists_default() -> Result<Vec<Playlist>, StorageError> { | ||
| 200 | 200 | load_playlists(&get_playlists_path()) |
| 201 | 201 | } |
| 202 | 202 | |
| 203 | +/// Exports feeds to a custom JSON file (user-selected path) | |
| 204 | +/// This is the same as save_feeds but with export semantics | |
| 205 | +#[allow(dead_code)] | |
| 206 | +pub fn export_feeds(feeds: &[Feed], path: &Path) -> Result<(), StorageError> { | |
| 207 | + save_feeds(feeds, path) | |
| 208 | +} | |
| 209 | + | |
| 210 | +/// Imports feeds from a custom JSON file (user-selected path) | |
| 211 | +/// This is the same as load_feeds but with import semantics | |
| 212 | +#[allow(dead_code)] | |
| 213 | +pub fn import_feeds(path: &Path) -> Result<Vec<Feed>, StorageError> { | |
| 214 | + load_feeds(path) | |
| 215 | +} | |
| 216 | + | |
| 217 | +/// Exports feeds to a custom JSON file with a pretty format suitable for sharing | |
| 218 | +#[allow(dead_code)] | |
| 219 | +pub fn export_feeds_pretty(feeds: &[Feed], path: &Path) -> Result<(), StorageError> { | |
| 220 | + info!("Exporting {} feeds to {}", feeds.len(), path.display()); | |
| 221 | + | |
| 222 | + // Create parent directories if they don't exist | |
| 223 | + if let Some(parent) = path.parent() { | |
| 224 | + if !parent.exists() { | |
| 225 | + info!("Creating directory: {}", parent.display()); | |
| 226 | + fs::create_dir_all(parent) | |
| 227 | + .map_err(|e| StorageError::InvalidDirectory(format!("{}: {}", parent.display(), e)))?; | |
| 228 | + } | |
| 229 | + } | |
| 230 | + | |
| 231 | + // Serialize feeds to pretty JSON with additional metadata | |
| 232 | + let json = serde_json::to_string_pretty(feeds) | |
| 233 | + .map_err(|e| StorageError::SerializeError(e.to_string()))?; | |
| 234 | + | |
| 235 | + // Write to file | |
| 236 | + fs::write(path, json) | |
| 237 | + .map_err(|e| StorageError::WriteError(format!("{}: {}", path.display(), e)))?; | |
| 238 | + | |
| 239 | + info!("Successfully exported {} feeds", feeds.len()); | |
| 240 | + Ok(()) | |
| 241 | +} | |
| 242 | + | |
| 203 | 243 | #[cfg(test)] |
| 204 | 244 | mod tests { |
| 205 | 245 | use super::*; |
| @@ -200,6 +200,46 @@ pub fn load_playlists_default() -> Result<Vec<Playlist>, StorageError> { | |||
| 200 | load_playlists(&get_playlists_path()) | 200 | load_playlists(&get_playlists_path()) |
| 201 | } | 201 | } |
| 202 | 202 | ||
| 203 | +/// Exports feeds to a custom JSON file (user-selected path) | ||
| 204 | +/// This is the same as save_feeds but with export semantics | ||
| 205 | +#[allow(dead_code)] | ||
| 206 | +pub fn export_feeds(feeds: &[Feed], path: &Path) -> Result<(), StorageError> { | ||
| 207 | + save_feeds(feeds, path) | ||
| 208 | +} | ||
| 209 | + | ||
| 210 | +/// Imports feeds from a custom JSON file (user-selected path) | ||
| 211 | +/// This is the same as load_feeds but with import semantics | ||
| 212 | +#[allow(dead_code)] | ||
| 213 | +pub fn import_feeds(path: &Path) -> Result<Vec<Feed>, StorageError> { | ||
| 214 | + load_feeds(path) | ||
| 215 | +} | ||
| 216 | + | ||
| 217 | +/// Exports feeds to a custom JSON file with a pretty format suitable for sharing | ||
| 218 | +#[allow(dead_code)] | ||
| 219 | +pub fn export_feeds_pretty(feeds: &[Feed], path: &Path) -> Result<(), StorageError> { | ||
| 220 | + info!("Exporting {} feeds to {}", feeds.len(), path.display()); | ||
| 221 | + | ||
| 222 | + // Create parent directories if they don't exist | ||
| 223 | + if let Some(parent) = path.parent() { | ||
| 224 | + if !parent.exists() { | ||
| 225 | + info!("Creating directory: {}", parent.display()); | ||
| 226 | + fs::create_dir_all(parent) | ||
| 227 | + .map_err(|e| StorageError::InvalidDirectory(format!("{}: {}", parent.display(), e)))?; | ||
| 228 | + } | ||
| 229 | + } | ||
| 230 | + | ||
| 231 | + // Serialize feeds to pretty JSON with additional metadata | ||
| 232 | + let json = serde_json::to_string_pretty(feeds) | ||
| 233 | + .map_err(|e| StorageError::SerializeError(e.to_string()))?; | ||
| 234 | + | ||
| 235 | + // Write to file | ||
| 236 | + fs::write(path, json) | ||
| 237 | + .map_err(|e| StorageError::WriteError(format!("{}: {}", path.display(), e)))?; | ||
| 238 | + | ||
| 239 | + info!("Successfully exported {} feeds", feeds.len()); | ||
| 240 | + Ok(()) | ||
| 241 | +} | ||
| 242 | + | ||
| 203 | #[cfg(test)] | 243 | #[cfg(test)] |
| 204 | mod tests { | 244 | mod tests { |
| 205 | use super::*; | 245 | use super::*; |
added
src/ui/export_import.rs +137 -0 | new file mode 100644 | ||
| @@ -0,0 +1,137 @@ | ||
| 1 | +//! Export/Import UI component | |
| 2 | +//! | |
| 3 | +//! This module contains the UI for exporting and importing feeds. | |
| 4 | + | |
| 5 | +use crate::config::AppState; | |
| 6 | +use egui::{Color32, Ui}; | |
| 7 | +use std::path::PathBuf; | |
| 8 | + | |
| 9 | +/// Draws the export dialog | |
| 10 | +pub fn draw_export_dialog(state: &mut AppState, ui: &mut Ui) { | |
| 11 | + if !state.show_export_dialog { | |
| 12 | + return; | |
| 13 | + } | |
| 14 | + | |
| 15 | + egui::Window::new("Exporter les flux") | |
| 16 | + .resizable(false) | |
| 17 | + .show(ui.ctx(), |ui| { | |
| 18 | + ui.vertical(|ui| { | |
| 19 | + ui.label("Exporter les flux vers un fichier JSON"); | |
| 20 | + ui.label(format!("Nombre de flux à exporter: {}", state.feeds.len())); | |
| 21 | + ui.separator(); | |
| 22 | + | |
| 23 | + ui.horizontal(|ui| { | |
| 24 | + if ui.button("Choisir un fichier").clicked() { | |
| 25 | + if let Some(path) = rfd::FileDialog::new() | |
| 26 | + .add_filter("JSON Files", &["json"]) | |
| 27 | + .add_filter("All Files", &["*"]) | |
| 28 | + .set_title("Exporter les flux") | |
| 29 | + .save_file() | |
| 30 | + { | |
| 31 | + export_feeds_to_path(state, path); | |
| 32 | + } | |
| 33 | + } | |
| 34 | + | |
| 35 | + if ui.button("Annuler").clicked() { | |
| 36 | + state.show_export_dialog = false; | |
| 37 | + state.clear_export_import_error(); | |
| 38 | + } | |
| 39 | + }); | |
| 40 | + | |
| 41 | + // Show error if any | |
| 42 | + if let Some(ref error) = state.export_import_error { | |
| 43 | + ui.separator(); | |
| 44 | + ui.colored_label(Color32::RED, error); | |
| 45 | + } | |
| 46 | + }); | |
| 47 | + }); | |
| 48 | +} | |
| 49 | + | |
| 50 | +/// Exports feeds to the specified path | |
| 51 | +fn export_feeds_to_path(state: &mut AppState, path: PathBuf) { | |
| 52 | + match crate::config::storage::export_feeds_pretty(&state.feeds, &path) { | |
| 53 | + Ok(_) => { | |
| 54 | + log::info!("Successfully exported feeds to {}", path.display()); | |
| 55 | + state.notification_manager.success(format!("Export réussi: {}", path.display())); | |
| 56 | + state.show_export_dialog = false; | |
| 57 | + state.clear_export_import_error(); | |
| 58 | + } | |
| 59 | + Err(e) => { | |
| 60 | + log::error!("Failed to export feeds: {}", e); | |
| 61 | + state.set_export_import_error(format!("Erreur d'export: {}", e)); | |
| 62 | + } | |
| 63 | + } | |
| 64 | +} | |
| 65 | + | |
| 66 | +/// Draws the import dialog | |
| 67 | +pub fn draw_import_dialog(state: &mut AppState, ui: &mut Ui) { | |
| 68 | + if !state.show_import_dialog { | |
| 69 | + return; | |
| 70 | + } | |
| 71 | + | |
| 72 | + egui::Window::new("Importer les flux") | |
| 73 | + .resizable(false) | |
| 74 | + .show(ui.ctx(), |ui| { | |
| 75 | + ui.vertical(|ui| { | |
| 76 | + ui.label("Importer les flux depuis un fichier JSON"); | |
| 77 | + ui.separator(); | |
| 78 | + | |
| 79 | + ui.horizontal(|ui| { | |
| 80 | + if ui.button("Choisir un fichier").clicked() { | |
| 81 | + if let Some(path) = rfd::FileDialog::new() | |
| 82 | + .add_filter("JSON Files", &["json"]) | |
| 83 | + .add_filter("All Files", &["*"]) | |
| 84 | + .set_title("Importer les flux") | |
| 85 | + .pick_file() | |
| 86 | + { | |
| 87 | + import_feeds_from_path(state, path); | |
| 88 | + } | |
| 89 | + } | |
| 90 | + | |
| 91 | + if ui.button("Annuler").clicked() { | |
| 92 | + state.show_import_dialog = false; | |
| 93 | + state.clear_export_import_error(); | |
| 94 | + } | |
| 95 | + }); | |
| 96 | + | |
| 97 | + // Show error if any | |
| 98 | + if let Some(ref error) = state.export_import_error { | |
| 99 | + ui.separator(); | |
| 100 | + ui.colored_label(Color32::RED, error); | |
| 101 | + } | |
| 102 | + }); | |
| 103 | + }); | |
| 104 | +} | |
| 105 | + | |
| 106 | +/// Imports feeds from the specified path | |
| 107 | +fn import_feeds_from_path(state: &mut AppState, path: PathBuf) { | |
| 108 | + match crate::config::storage::import_feeds(&path) { | |
| 109 | + Ok(mut imported_feeds) => { | |
| 110 | + // Assign new unique IDs to imported feeds to avoid conflicts | |
| 111 | + for feed in &mut imported_feeds { | |
| 112 | + if feed.id.is_empty() { | |
| 113 | + feed.id = uuid::Uuid::new_v4().to_string(); | |
| 114 | + } | |
| 115 | + } | |
| 116 | + | |
| 117 | + // Append imported feeds to existing feeds | |
| 118 | + let count = imported_feeds.len(); | |
| 119 | + state.feeds.extend(imported_feeds); | |
| 120 | + | |
| 121 | + // Save the updated feeds | |
| 122 | + if let Err(e) = crate::config::storage::save_feeds_default(&state.feeds) { | |
| 123 | + log::error!("Failed to save imported feeds: {}", e); | |
| 124 | + state.set_export_import_error(format!("Erreur de sauvegarde: {}", e)); | |
| 125 | + } else { | |
| 126 | + log::info!("Successfully imported {} feeds from {}", count, path.display()); | |
| 127 | + state.notification_manager.success(format!("Import réussi: {} flux ajoutés", count)); | |
| 128 | + state.show_import_dialog = false; | |
| 129 | + state.clear_export_import_error(); | |
| 130 | + } | |
| 131 | + } | |
| 132 | + Err(e) => { | |
| 133 | + log::error!("Failed to import feeds: {}", e); | |
| 134 | + state.set_export_import_error(format!("Erreur d'import: {}", e)); | |
| 135 | + } | |
| 136 | + } | |
| 137 | +} | |
| new file mode 100644 | |||
| @@ -0,0 +1,137 @@ | |||
| 1 | +//! Export/Import UI component | ||
| 2 | +//! | ||
| 3 | +//! This module contains the UI for exporting and importing feeds. | ||
| 4 | + | ||
| 5 | +use crate::config::AppState; | ||
| 6 | +use egui::{Color32, Ui}; | ||
| 7 | +use std::path::PathBuf; | ||
| 8 | + | ||
| 9 | +/// Draws the export dialog | ||
| 10 | +pub fn draw_export_dialog(state: &mut AppState, ui: &mut Ui) { | ||
| 11 | + if !state.show_export_dialog { | ||
| 12 | + return; | ||
| 13 | + } | ||
| 14 | + | ||
| 15 | + egui::Window::new("Exporter les flux") | ||
| 16 | + .resizable(false) | ||
| 17 | + .show(ui.ctx(), |ui| { | ||
| 18 | + ui.vertical(|ui| { | ||
| 19 | + ui.label("Exporter les flux vers un fichier JSON"); | ||
| 20 | + ui.label(format!("Nombre de flux à exporter: {}", state.feeds.len())); | ||
| 21 | + ui.separator(); | ||
| 22 | + | ||
| 23 | + ui.horizontal(|ui| { | ||
| 24 | + if ui.button("Choisir un fichier").clicked() { | ||
| 25 | + if let Some(path) = rfd::FileDialog::new() | ||
| 26 | + .add_filter("JSON Files", &["json"]) | ||
| 27 | + .add_filter("All Files", &["*"]) | ||
| 28 | + .set_title("Exporter les flux") | ||
| 29 | + .save_file() | ||
| 30 | + { | ||
| 31 | + export_feeds_to_path(state, path); | ||
| 32 | + } | ||
| 33 | + } | ||
| 34 | + | ||
| 35 | + if ui.button("Annuler").clicked() { | ||
| 36 | + state.show_export_dialog = false; | ||
| 37 | + state.clear_export_import_error(); | ||
| 38 | + } | ||
| 39 | + }); | ||
| 40 | + | ||
| 41 | + // Show error if any | ||
| 42 | + if let Some(ref error) = state.export_import_error { | ||
| 43 | + ui.separator(); | ||
| 44 | + ui.colored_label(Color32::RED, error); | ||
| 45 | + } | ||
| 46 | + }); | ||
| 47 | + }); | ||
| 48 | +} | ||
| 49 | + | ||
| 50 | +/// Exports feeds to the specified path | ||
| 51 | +fn export_feeds_to_path(state: &mut AppState, path: PathBuf) { | ||
| 52 | + match crate::config::storage::export_feeds_pretty(&state.feeds, &path) { | ||
| 53 | + Ok(_) => { | ||
| 54 | + log::info!("Successfully exported feeds to {}", path.display()); | ||
| 55 | + state.notification_manager.success(format!("Export réussi: {}", path.display())); | ||
| 56 | + state.show_export_dialog = false; | ||
| 57 | + state.clear_export_import_error(); | ||
| 58 | + } | ||
| 59 | + Err(e) => { | ||
| 60 | + log::error!("Failed to export feeds: {}", e); | ||
| 61 | + state.set_export_import_error(format!("Erreur d'export: {}", e)); | ||
| 62 | + } | ||
| 63 | + } | ||
| 64 | +} | ||
| 65 | + | ||
| 66 | +/// Draws the import dialog | ||
| 67 | +pub fn draw_import_dialog(state: &mut AppState, ui: &mut Ui) { | ||
| 68 | + if !state.show_import_dialog { | ||
| 69 | + return; | ||
| 70 | + } | ||
| 71 | + | ||
| 72 | + egui::Window::new("Importer les flux") | ||
| 73 | + .resizable(false) | ||
| 74 | + .show(ui.ctx(), |ui| { | ||
| 75 | + ui.vertical(|ui| { | ||
| 76 | + ui.label("Importer les flux depuis un fichier JSON"); | ||
| 77 | + ui.separator(); | ||
| 78 | + | ||
| 79 | + ui.horizontal(|ui| { | ||
| 80 | + if ui.button("Choisir un fichier").clicked() { | ||
| 81 | + if let Some(path) = rfd::FileDialog::new() | ||
| 82 | + .add_filter("JSON Files", &["json"]) | ||
| 83 | + .add_filter("All Files", &["*"]) | ||
| 84 | + .set_title("Importer les flux") | ||
| 85 | + .pick_file() | ||
| 86 | + { | ||
| 87 | + import_feeds_from_path(state, path); | ||
| 88 | + } | ||
| 89 | + } | ||
| 90 | + | ||
| 91 | + if ui.button("Annuler").clicked() { | ||
| 92 | + state.show_import_dialog = false; | ||
| 93 | + state.clear_export_import_error(); | ||
| 94 | + } | ||
| 95 | + }); | ||
| 96 | + | ||
| 97 | + // Show error if any | ||
| 98 | + if let Some(ref error) = state.export_import_error { | ||
| 99 | + ui.separator(); | ||
| 100 | + ui.colored_label(Color32::RED, error); | ||
| 101 | + } | ||
| 102 | + }); | ||
| 103 | + }); | ||
| 104 | +} | ||
| 105 | + | ||
| 106 | +/// Imports feeds from the specified path | ||
| 107 | +fn import_feeds_from_path(state: &mut AppState, path: PathBuf) { | ||
| 108 | + match crate::config::storage::import_feeds(&path) { | ||
| 109 | + Ok(mut imported_feeds) => { | ||
| 110 | + // Assign new unique IDs to imported feeds to avoid conflicts | ||
| 111 | + for feed in &mut imported_feeds { | ||
| 112 | + if feed.id.is_empty() { | ||
| 113 | + feed.id = uuid::Uuid::new_v4().to_string(); | ||
| 114 | + } | ||
| 115 | + } | ||
| 116 | + | ||
| 117 | + // Append imported feeds to existing feeds | ||
| 118 | + let count = imported_feeds.len(); | ||
| 119 | + state.feeds.extend(imported_feeds); | ||
| 120 | + | ||
| 121 | + // Save the updated feeds | ||
| 122 | + if let Err(e) = crate::config::storage::save_feeds_default(&state.feeds) { | ||
| 123 | + log::error!("Failed to save imported feeds: {}", e); | ||
| 124 | + state.set_export_import_error(format!("Erreur de sauvegarde: {}", e)); | ||
| 125 | + } else { | ||
| 126 | + log::info!("Successfully imported {} feeds from {}", count, path.display()); | ||
| 127 | + state.notification_manager.success(format!("Import réussi: {} flux ajoutés", count)); | ||
| 128 | + state.show_import_dialog = false; | ||
| 129 | + state.clear_export_import_error(); | ||
| 130 | + } | ||
| 131 | + } | ||
| 132 | + Err(e) => { | ||
| 133 | + log::error!("Failed to import feeds: {}", e); | ||
| 134 | + state.set_export_import_error(format!("Erreur d'import: {}", e)); | ||
| 135 | + } | ||
| 136 | + } | ||
| 137 | +} | ||
modified
src/ui/home.rs +18 -0 | @@ -45,6 +45,12 @@ pub fn draw_home(state: &mut AppState, ui: &mut Ui) { | ||
| 45 | 45 | |
| 46 | 46 | // Draw edit playlist dialog |
| 47 | 47 | crate::ui::playlist_list::draw_edit_playlist_dialog(state, ui); |
| 48 | + | |
| 49 | + // Draw export dialog | |
| 50 | + crate::ui::export_import::draw_export_dialog(state, ui); | |
| 51 | + | |
| 52 | + // Draw import dialog | |
| 53 | + crate::ui::export_import::draw_import_dialog(state, ui); | |
| 48 | 54 | } |
| 49 | 55 | |
| 50 | 56 | /// Draws the action buttons |
| @@ -58,6 +64,18 @@ fn draw_action_buttons(state: &mut AppState, ui: &mut Ui) { | ||
| 58 | 64 | if ui.button("🔄 Synchroniser tous").clicked() { |
| 59 | 65 | sync_all_feeds(state); |
| 60 | 66 | } |
| 67 | + | |
| 68 | + ui.add_space(10.0); | |
| 69 | + | |
| 70 | + if ui.button("📤 Exporter").clicked() { | |
| 71 | + state.clear_export_import_error(); | |
| 72 | + state.show_export_dialog = true; | |
| 73 | + } | |
| 74 | + | |
| 75 | + if ui.button("📥 Importer").clicked() { | |
| 76 | + state.clear_export_import_error(); | |
| 77 | + state.show_import_dialog = true; | |
| 78 | + } | |
| 61 | 79 | }); |
| 62 | 80 | } |
| 63 | 81 | |
| @@ -45,6 +45,12 @@ pub fn draw_home(state: &mut AppState, ui: &mut Ui) { | |||
| 45 | 45 | ||
| 46 | // Draw edit playlist dialog | 46 | // Draw edit playlist dialog |
| 47 | crate::ui::playlist_list::draw_edit_playlist_dialog(state, ui); | 47 | crate::ui::playlist_list::draw_edit_playlist_dialog(state, ui); |
| 48 | + | ||
| 49 | + // Draw export dialog | ||
| 50 | + crate::ui::export_import::draw_export_dialog(state, ui); | ||
| 51 | + | ||
| 52 | + // Draw import dialog | ||
| 53 | + crate::ui::export_import::draw_import_dialog(state, ui); | ||
| 48 | } | 54 | } |
| 49 | 55 | ||
| 50 | /// Draws the action buttons | 56 | /// Draws the action buttons |
| @@ -58,6 +64,18 @@ fn draw_action_buttons(state: &mut AppState, ui: &mut Ui) { | |||
| 58 | if ui.button("🔄 Synchroniser tous").clicked() { | 64 | if ui.button("🔄 Synchroniser tous").clicked() { |
| 59 | sync_all_feeds(state); | 65 | sync_all_feeds(state); |
| 60 | } | 66 | } |
| 67 | + | ||
| 68 | + ui.add_space(10.0); | ||
| 69 | + | ||
| 70 | + if ui.button("📤 Exporter").clicked() { | ||
| 71 | + state.clear_export_import_error(); | ||
| 72 | + state.show_export_dialog = true; | ||
| 73 | + } | ||
| 74 | + | ||
| 75 | + if ui.button("📥 Importer").clicked() { | ||
| 76 | + state.clear_export_import_error(); | ||
| 77 | + state.show_import_dialog = true; | ||
| 78 | + } | ||
| 61 | }); | 79 | }); |
| 62 | } | 80 | } |
| 63 | 81 | ||
modified
src/ui/mod.rs +1 -0 | @@ -10,3 +10,4 @@ pub mod status_bar; | ||
| 10 | 10 | pub mod notifications; |
| 11 | 11 | pub mod playlist_list; |
| 12 | 12 | pub mod filter_panel; |
| 13 | +pub mod export_import; | |
| @@ -10,3 +10,4 @@ pub mod status_bar; | |||
| 10 | pub mod notifications; | 10 | pub mod notifications; |
| 11 | pub mod playlist_list; | 11 | pub mod playlist_list; |
| 12 | pub mod filter_panel; | 12 | pub mod filter_panel; |
| 13 | +pub mod export_import; | ||