diff --git a/Cargo.lock b/Cargo.lock index 47770847..595841e5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -29,7 +29,7 @@ dependencies = [ "serde", "serde_json", "tauri", - "tauri-build 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tauri-build", "tauri-plugin-cli", "tauri-plugin-deep-link", "tauri-plugin-dialog", @@ -56,9 +56,9 @@ dependencies = [ [[package]] name = "addr2line" -version = "0.24.2" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" dependencies = [ "gimli", ] @@ -310,7 +310,7 @@ dependencies = [ "polling", "rustix", "slab", - "windows-sys 0.61.0", + "windows-sys 0.61.1", ] [[package]] @@ -368,7 +368,7 @@ dependencies = [ "rustix", "signal-hook-registry", "slab", - "windows-sys 0.61.0", + "windows-sys 0.61.1", ] [[package]] @@ -425,9 +425,9 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "backtrace" -version = "0.3.75" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" +checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" dependencies = [ "addr2line", "cfg-if", @@ -435,7 +435,7 @@ dependencies = [ "miniz_oxide", "object", "rustc-demangle", - "windows-targets 0.52.6", + "windows-link 0.2.0", ] [[package]] @@ -1217,7 +1217,7 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.61.0", + "windows-sys 0.61.1", ] [[package]] @@ -1455,7 +1455,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.0", + "windows-sys 0.61.1", ] [[package]] @@ -1916,9 +1916,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.31.1" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" [[package]] name = "gio" @@ -2283,7 +2283,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core 0.62.0", + "windows-core 0.62.1", ] [[package]] @@ -2818,9 +2818,9 @@ checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" [[package]] name = "memchr" -version = "2.7.5" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "memoffset" @@ -3309,9 +3309,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.7" +version = "0.37.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" dependencies = [ "memchr", ] @@ -3791,7 +3791,7 @@ dependencies = [ "hermit-abi", "pin-project-lite", "rustix", - "windows-sys 0.61.0", + "windows-sys 0.61.1", ] [[package]] @@ -4269,9 +4269,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.11.2" +version = "1.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912" +checksum = "8b5288124840bee7b386bc413c487869b360b2b4ec421ea56425128692f2a82c" dependencies = [ "aho-corasick", "memchr", @@ -4281,9 +4281,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6" +checksum = "833eb9ce86d40ef33cb1306d8accf7bc8ec2bfea4355cbdebb3df68b40925cad" dependencies = [ "aho-corasick", "memchr", @@ -4479,7 +4479,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.61.0", + "windows-sys 0.61.1", ] [[package]] @@ -4565,7 +4565,7 @@ version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" dependencies = [ - "windows-sys 0.61.0", + "windows-sys 0.61.1", ] [[package]] @@ -4696,9 +4696,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.226" +version = "1.0.227" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dca6411025b24b60bfa7ec1fe1f8e710ac09782dca409ee8237ba74b51295fd" +checksum = "80ece43fc6fbed4eb5392ab50c07334d3e577cbf40997ee896fe7af40bba4245" dependencies = [ "serde_core", "serde_derive", @@ -4718,18 +4718,18 @@ dependencies = [ [[package]] name = "serde_core" -version = "1.0.226" +version = "1.0.227" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba2ba63999edb9dac981fb34b3e5c0d111a69b0924e253ed29d83f7c99e966a4" +checksum = "7a576275b607a2c86ea29e410193df32bc680303c82f31e275bbfcafe8b33be5" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.226" +version = "1.0.227" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8db53ae22f34573731bafa1db20f04027b2d25e02d8205921b569171699cdb33" +checksum = "51e694923b8824cf0e9b382adf0f60d4e05f348f357b38833a3fa5ed7c2ede04" dependencies = [ "proc-macro2", "quote", @@ -5327,11 +5327,11 @@ dependencies = [ "specta", "swift-rs", "tauri", - "tauri-build 2.4.1", + "tauri-build", "tauri-macros", "tauri-runtime", "tauri-runtime-wry", - "tauri-utils 2.7.0", + "tauri-utils", "thiserror 2.0.16", "tokio", "tracing", @@ -5361,29 +5361,7 @@ dependencies = [ "serde", "serde_json", "tauri-codegen", - "tauri-utils 2.7.0", - "tauri-winres", - "toml 0.9.7", - "walkdir", -] - -[[package]] -name = "tauri-build" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c432ccc9ff661803dab74c6cd78de11026a578a9307610bbc39d3c55be7943f" -dependencies = [ - "anyhow", - "cargo_toml", - "dirs", - "glob", - "heck 0.5.0", - "json-patch", - "schemars 0.8.22", - "semver", - "serde", - "serde_json", - "tauri-utils 2.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tauri-utils", "tauri-winres", "toml 0.9.7", "walkdir", @@ -5406,7 +5384,7 @@ dependencies = [ "serde_json", "sha2", "syn 2.0.106", - "tauri-utils 2.7.0", + "tauri-utils", "thiserror 2.0.16", "time", "url", @@ -5423,7 +5401,7 @@ dependencies = [ "quote", "syn 2.0.106", "tauri-codegen", - "tauri-utils 2.7.0", + "tauri-utils", ] [[package]] @@ -5438,7 +5416,7 @@ dependencies = [ "schemars 0.8.22", "serde", "serde_json", - "tauri-utils 2.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tauri-utils", "toml 0.9.7", "walkdir", ] @@ -5471,7 +5449,7 @@ dependencies = [ "serde_json", "tauri", "tauri-plugin", - "tauri-utils 2.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tauri-utils", "thiserror 2.0.16", "tracing", "url", @@ -5513,7 +5491,7 @@ dependencies = [ "serde_repr", "tauri", "tauri-plugin", - "tauri-utils 2.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tauri-utils", "thiserror 2.0.16", "toml 0.9.7", "url", @@ -5793,7 +5771,7 @@ dependencies = [ "raw-window-handle", "serde", "serde_json", - "tauri-utils 2.7.0", + "tauri-utils", "thiserror 2.0.16", "url", "webkit2gtk", @@ -5818,7 +5796,7 @@ dependencies = [ "softbuffer", "tao", "tauri-runtime", - "tauri-utils 2.7.0", + "tauri-utils", "tracing", "url", "webkit2gtk", @@ -5868,43 +5846,6 @@ dependencies = [ "walkdir", ] -[[package]] -name = "tauri-utils" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41a3852fdf9a4f8fbeaa63dc3e9a85284dd6ef7200751f0bd66ceee30c93f212" -dependencies = [ - "anyhow", - "cargo_metadata", - "ctor", - "dunce", - "glob", - "html5ever", - "http", - "infer", - "json-patch", - "kuchikiki", - "log", - "memchr", - "phf 0.11.3", - "proc-macro2", - "quote", - "regex", - "schemars 0.8.22", - "semver", - "serde", - "serde-untagged", - "serde_json", - "serde_with", - "swift-rs", - "thiserror 2.0.16", - "toml 0.9.7", - "url", - "urlpattern", - "uuid", - "walkdir", -] - [[package]] name = "tauri-winres" version = "0.3.3" @@ -5925,7 +5866,7 @@ dependencies = [ "getrandom 0.3.3", "once_cell", "rustix", - "windows-sys 0.61.0", + "windows-sys 0.61.1", ] [[package]] @@ -6853,7 +6794,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.61.0", + "windows-sys 0.61.1", ] [[package]] @@ -6914,9 +6855,9 @@ dependencies = [ [[package]] name = "windows-core" -version = "0.62.0" +version = "0.62.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57fe7168f7de578d2d8a05b07fd61870d2e73b4020e9f49aa00da8471723497c" +checksum = "6844ee5416b285084d3d3fffd743b925a6c9385455f64f6d4fa3031c4c2749a9" dependencies = [ "windows-implement", "windows-interface", @@ -6938,9 +6879,9 @@ dependencies = [ [[package]] name = "windows-implement" -version = "0.60.0" +version = "0.60.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +checksum = "edb307e42a74fb6de9bf3a02d9712678b22399c87e6fa869d6dfcd8c1b7754e0" dependencies = [ "proc-macro2", "quote", @@ -6949,9 +6890,9 @@ dependencies = [ [[package]] name = "windows-interface" -version = "0.59.1" +version = "0.59.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +checksum = "c0abd1ddbc6964ac14db11c7213d6532ef34bd9aa042c2e5935f59d7908b46a5" dependencies = [ "proc-macro2", "quote", @@ -7060,14 +7001,14 @@ version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets 0.53.3", + "windows-targets 0.53.4", ] [[package]] name = "windows-sys" -version = "0.61.0" +version = "0.61.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e201184e40b2ede64bc2ea34968b28e33622acdbbf37104f0e4a33f7abe657aa" +checksum = "6f109e41dd4a3c848907eb83d5a42ea98b3769495597450cf6d153507b166f0f" dependencies = [ "windows-link 0.2.0", ] @@ -7105,11 +7046,11 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.53.3" +version = "0.53.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" +checksum = "2d42b7b7f66d2a06854650af09cfdf8713e427a439c97ad65a6375318033ac4b" dependencies = [ - "windows-link 0.1.3", + "windows-link 0.2.0", "windows_aarch64_gnullvm 0.53.0", "windows_aarch64_msvc 0.53.0", "windows_i686_gnu 0.53.0", @@ -7131,9 +7072,9 @@ dependencies = [ [[package]] name = "windows-version" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69e061eb0a22b4a1d778ad70f7575ec7845490abb35b08fa320df7895882cacb" +checksum = "700dad7c058606087f6fdc1f88da5841e06da40334413c6cd4367b25ef26d24e" dependencies = [ "windows-link 0.2.0", ] diff --git a/Cargo.toml b/Cargo.toml index d2931d8d..f0a64efc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,8 @@ members = [ "apps/readest-app/src-tauri", "packages/tauri/crates/tauri", + "packages/tauri/crates/tauri-utils", + "packages/tauri/crates/tauri-build", ] resolver = "2" @@ -31,3 +33,5 @@ rust-version = "1.77.2" [patch.crates-io] tauri = { path = "packages/tauri/crates/tauri" } +tauri-utils = { path = "packages/tauri/crates/tauri-utils" } +tauri-build = { path = "packages/tauri/crates/tauri-build" } diff --git a/apps/readest-app/public/locales/ar/translation.json b/apps/readest-app/public/locales/ar/translation.json index a7ea66f2..50704a3a 100644 --- a/apps/readest-app/public/locales/ar/translation.json +++ b/apps/readest-app/public/locales/ar/translation.json @@ -590,5 +590,27 @@ "Single Page": "صفحة واحدة", "Auto Spread": "انتشار تلقائي", "Fit Page": "تناسب الصفحة", - "Fit Width": "تناسب العرض" + "Fit Width": "تناسب العرض", + "Failed to select directory": "فشل في اختيار الدليل", + "The new data directory must be different from the current one.": "يجب أن يكون دليل البيانات الجديد مختلفًا عن الدليل الحالي.", + "Migration failed: {{error}}": "فشل في الترحيل: {{error}}", + "Change Data Location": "تغيير موقع البيانات", + "Current Data Location": "موقع البيانات الحالي", + "Total size: {{size}}": "الحجم الكلي: {{size}}", + "Calculating file info...": "جارٍ حساب معلومات الملف...", + "New Data Location": "موقع البيانات الجديد", + "Choose Different Folder": "اختر مجلدًا مختلفًا", + "Choose New Folder": "اختر مجلدًا جديدًا", + "Migrating data...": "جارٍ ترحيل البيانات...", + "Copying: {{file}}": "جارٍ نسخ: {{file}}", + "{{current}} of {{total}} files": "{{current}} من {{total}} ملف", + "Migration completed successfully!": "اكتمل الترحيل بنجاح!", + "Your data has been moved to the new location. Please restart the application to complete the process.": "تم نقل بياناتك إلى الموقع الجديد. يرجى إعادة تشغيل التطبيق لإكمال العملية.", + "Migration failed": "فشل في الترحيل", + "Important Notice": "إشعار مهم", + "This will move all your app data to the new location. Make sure the destination has enough free space.": "سيؤدي ذلك إلى نقل جميع بيانات التطبيق الخاصة بك إلى الموقع الجديد. تأكد من أن الوجهة تحتوي على مساحة خالية كافية.", + "Restart App": "إعادة تشغيل التطبيق", + "Start Migration": "بدء الترحيل", + "Advanced Settings": "إعدادات متقدمة", + "File count: {{size}}": "عدد الملفات: {{size}}" } diff --git a/apps/readest-app/public/locales/bn/translation.json b/apps/readest-app/public/locales/bn/translation.json index 3123ab3f..502c60bc 100644 --- a/apps/readest-app/public/locales/bn/translation.json +++ b/apps/readest-app/public/locales/bn/translation.json @@ -574,5 +574,27 @@ "Single Page": "একক পৃষ্ঠা", "Auto Spread": "অটো স্প্রেড", "Fit Page": "ফিট পৃষ্ঠা", - "Fit Width": "ফিট প্রস্থ" + "Fit Width": "ফিট প্রস্থ", + "Failed to select directory": "ডিরেক্টরি নির্বাচন করতে ব্যর্থ", + "The new data directory must be different from the current one.": "নতুন ডেটা ডিরেক্টরি বর্তমানটির থেকে আলাদা হতে হবে।", + "Migration failed: {{error}}": "মাইগ্রেশন ব্যর্থ হয়েছে: {{error}}", + "Change Data Location": "ডেটা অবস্থান পরিবর্তন করুন", + "Current Data Location": "বর্তমান ডেটা অবস্থান", + "Total size: {{size}}": "মোট আকার: {{size}}", + "Calculating file info...": "ফাইলের তথ্য গণনা করা হচ্ছে...", + "New Data Location": "নতুন ডেটা অবস্থান", + "Choose Different Folder": "ভিন্ন ফোল্ডার নির্বাচন করুন", + "Choose New Folder": "নতুন ফোল্ডার নির্বাচন করুন", + "Migrating data...": "ডেটা স্থানান্তরিত হচ্ছে...", + "Copying: {{file}}": "কপি করা হচ্ছে: {{file}}", + "{{current}} of {{total}} files": "{{current}} এর {{total}} ফাইল", + "Migration completed successfully!": "মাইগ্রেশন সফলভাবে সম্পন্ন হয়েছে!", + "Your data has been moved to the new location. Please restart the application to complete the process.": "আপনার ডেটা নতুন অবস্থানে স্থানান্তরিত হয়েছে। প্রক্রিয়া সম্পন্ন করতে দয়া করে অ্যাপ্লিকেশনটি পুনরায় চালু করুন।", + "Migration failed": "মাইগ্রেশন ব্যর্থ হয়েছে", + "Important Notice": "গুরুতর বিজ্ঞপ্তি", + "This will move all your app data to the new location. Make sure the destination has enough free space.": "এটি আপনার সমস্ত অ্যাপ ডেটা নতুন অবস্থানে স্থানান্তরিত করবে। নিশ্চিত করুন যে গন্তব্যে পর্যাপ্ত ফ্রি স্পেস রয়েছে।", + "Restart App": "অ্যাপ পুনরায় চালু করুন", + "Start Migration": "মাইগ্রেশন শুরু করুন", + "Advanced Settings": "উন্নত সেটিংস", + "File count: {{size}}": "ফাইলের সংখ্যা: {{size}}" } diff --git a/apps/readest-app/public/locales/bo/translation.json b/apps/readest-app/public/locales/bo/translation.json index fcff8500..499d6830 100644 --- a/apps/readest-app/public/locales/bo/translation.json +++ b/apps/readest-app/public/locales/bo/translation.json @@ -570,5 +570,27 @@ "Single Page": "དེབ་གཅིག", "Auto Spread": "རང་འགུལ་སྤྲོད།", "Fit Page": "དེབ་འདེམས་པ།", - "Fit Width": "ཁྱབ་སྒྲིག་འདེམས་པ།" + "Fit Width": "ཁྱབ་སྒྲིག་འདེམས་པ།", + "Failed to select directory": "གནས་ས་འདེམས་པ་བྱས་མ་ཐུབ།", + "The new data directory must be different from the current one.": "གསར་བཅས་སྐོར་འདེམས་པ་གནས་ས་དང་མཉམ་འབྱུང་བར་བྱས་མ་ཐུབ།", + "Migration failed: {{error}}": "མཉམ་དུ་ཀློག་འཛུལ་བྱས་མ་ཐུབ།", + "Change Data Location": "གསར་བཅས་སྐོར་འདེམས་པ།", + "Current Data Location": "ད་ལྟ་བཅས་སྐོར་འདེམས་པ།", + "Total size: {{size}}": "དངོས་གནས་བཅས་: {{size}}", + "Calculating file info...": "དེབ་གནས་བཅས་པའི་གདམ་ཁ་བཟོ་བྱས་མ་ཐུབ།", + "New Data Location": "གསར་བཅས་སྐོར་འདེམས་པ།", + "Choose Different Folder": "གཞན་དེབ་སྣོད་བཀར་བ།", + "Choose New Folder": "གསར་བཅས་སྣོད་བཀར་བ།", + "Migrating data...": "དེབ་གནས་བཅས་པའི་སྤྱོད་བྱས་མ་ཐུབ།", + "Copying: {{file}}": "དེབ་གནས་བཅས་པའི་སྤྱོད་བྱས་མ་ཐུབ།", + "{{current}} of {{total}} files": "{{current}} དང་ {{total}} དེབ་གནས་བཅས་པའི་སྤྱོད་བྱས་མ་ཐུབ།", + "Migration completed successfully!": "མཉམ་དུ་ཀློག་འཛུལ་བྱས་མ་ཐུབ།", + "Your data has been moved to the new location. Please restart the application to complete the process.": "ཁྱོད་ཀྱི་དེབ་གནས་བཅས་པའི་སྤྱོད་བྱས་མ་ཐུབ།", + "Migration failed": "མཉམ་དུ་ཀློག་འཛུལ་བྱས་མ་ཐུབ།", + "Important Notice": "དོན་གཞི་བརྗེ་བ།", + "This will move all your app data to the new location. Make sure the destination has enough free space.": "འདི་ནས་ཁྱོད་ཀྱི་ཨང་གཏོད་དེབ་གནས་བཅས་པའི་སྤྱོད་བྱས་མ་ཐུབ།", + "Restart App": "དེབ་ཀྱི་སྤྱོད་བྱས་མ་ཐུབ།", + "Start Migration": "མཉམ་དུ་ཀློག་འཛུལ་བྱས་མ་ཐུབ།", + "Advanced Settings": "དབང་བསྐྱོད་སྒྲིག་སྟངས།", + "File count: {{size}}": "དེབ་གནས་བཅས་པའི་ཨང་། {{size}}" } diff --git a/apps/readest-app/public/locales/de/translation.json b/apps/readest-app/public/locales/de/translation.json index 92aeaf70..122afd4a 100644 --- a/apps/readest-app/public/locales/de/translation.json +++ b/apps/readest-app/public/locales/de/translation.json @@ -574,5 +574,27 @@ "Single Page": "Einzelne Seite", "Auto Spread": "Automatische Verbreitung", "Fit Page": "Seite anpassen", - "Fit Width": "Breite anpassen" + "Fit Width": "Breite anpassen", + "Failed to select directory": "Fehler beim Auswählen des Verzeichnisses", + "The new data directory must be different from the current one.": "Das neue Datenverzeichnis muss sich vom aktuellen unterscheiden.", + "Migration failed: {{error}}": "Migration fehlgeschlagen: {{error}}", + "Change Data Location": "Datenstandort ändern", + "Current Data Location": "Aktueller Datenstandort", + "Total size: {{size}}": "Gesamtgröße: {{size}}", + "Calculating file info...": "Dateiinformationen werden berechnet...", + "New Data Location": "Neuer Datenstandort", + "Choose Different Folder": "Anderen Ordner wählen", + "Choose New Folder": "Neuen Ordner wählen", + "Migrating data...": "Daten werden migriert...", + "Copying: {{file}}": "Kopiere: {{file}}", + "{{current}} of {{total}} files": "{{current}} von {{total}} Dateien", + "Migration completed successfully!": "Migration erfolgreich abgeschlossen!", + "Your data has been moved to the new location. Please restart the application to complete the process.": "Ihre Daten wurden an den neuen Speicherort verschoben. Bitte starten Sie die Anwendung neu, um den Vorgang abzuschließen.", + "Migration failed": "Migration fehlgeschlagen", + "Important Notice": "Wichtiger Hinweis", + "This will move all your app data to the new location. Make sure the destination has enough free space.": "Dies wird alle Ihre App-Daten an den neuen Speicherort verschieben. Stellen Sie sicher, dass das Ziel über ausreichend freien Speicherplatz verfügt.", + "Restart App": "App neu starten", + "Start Migration": "Migration starten", + "Advanced Settings": "Erweiterte Einstellungen", + "File count: {{size}}": "Dateianzahl: {{size}}" } diff --git a/apps/readest-app/public/locales/el/translation.json b/apps/readest-app/public/locales/el/translation.json index 5810db54..d0e69990 100644 --- a/apps/readest-app/public/locales/el/translation.json +++ b/apps/readest-app/public/locales/el/translation.json @@ -574,5 +574,27 @@ "Single Page": "Μοναδική σελίδα", "Auto Spread": "Αυτόματη εξάπλωση", "Fit Page": "Προσαρμογή σελίδας", - "Fit Width": "Προσαρμογή πλάτους" + "Fit Width": "Προσαρμογή πλάτους", + "Failed to select directory": "Αποτυχία επιλογής καταλόγου", + "The new data directory must be different from the current one.": "Ο νέος κατάλογος δεδομένων πρέπει να είναι διαφορετικός από τον τρέχοντα.", + "Migration failed: {{error}}": "Η μετανάστευση απέτυχε: {{error}}", + "Change Data Location": "Αλλαγή τοποθεσίας δεδομένων", + "Current Data Location": "Τρέχουσα τοποθεσία δεδομένων", + "Total size: {{size}}": "Συνολικό μέγεθος: {{size}}", + "Calculating file info...": "Υπολογισμός πληροφοριών αρχείου...", + "New Data Location": "Νέα τοποθεσία δεδομένων", + "Choose Different Folder": "Επιλέξτε διαφορετικό φάκελο", + "Choose New Folder": "Επιλέξτε νέο φάκελο", + "Migrating data...": "Μεταφορά δεδομένων...", + "Copying: {{file}}": "Αντιγραφή: {{file}}", + "{{current}} of {{total}} files": "{{current}} από {{total}} αρχεία", + "Migration completed successfully!": "Η μετανάστευση ολοκληρώθηκε με επιτυχία!", + "Your data has been moved to the new location. Please restart the application to complete the process.": "Τα δεδομένα σας έχουν μεταφερθεί στη νέα τοποθεσία. Παρακαλώ επανεκκινήστε την εφαρμογή για να ολοκληρώσετε τη διαδικασία.", + "Migration failed": "Η μετανάστευση απέτυχε", + "Important Notice": "Σημαντική ειδοποίηση", + "This will move all your app data to the new location. Make sure the destination has enough free space.": "Αυτό θα μεταφέρει όλα τα δεδομένα της εφαρμογής σας στη νέα τοποθεσία. Βεβαιωθείτε ότι ο προορισμός έχει αρκετό ελεύθερο χώρο.", + "Restart App": "Επανεκκίνηση εφαρμογής", + "Start Migration": "Έναρξη μετανάστευσης", + "Advanced Settings": "Προηγμένες ρυθμίσεις", + "File count: {{size}}": "Αριθμός αρχείων: {{size}}" } diff --git a/apps/readest-app/public/locales/es/translation.json b/apps/readest-app/public/locales/es/translation.json index 9578b0f0..7fe4ecc8 100644 --- a/apps/readest-app/public/locales/es/translation.json +++ b/apps/readest-app/public/locales/es/translation.json @@ -578,5 +578,27 @@ "Single Page": "Página Única", "Auto Spread": "Distribución Automática", "Fit Page": "Ajustar Página", - "Fit Width": "Ajustar Ancho" + "Fit Width": "Ajustar Ancho", + "Failed to select directory": "Error al seleccionar el directorio", + "The new data directory must be different from the current one.": "El nuevo directorio de datos debe ser diferente del actual.", + "Migration failed: {{error}}": "La migración falló: {{error}}", + "Change Data Location": "Cambiar Ubicación de Datos", + "Current Data Location": "Ubicación Actual de Datos", + "Total size: {{size}}": "Tamaño total: {{size}}", + "Calculating file info...": "Calculando información del archivo...", + "New Data Location": "Nueva Ubicación de Datos", + "Choose Different Folder": "Elegir Carpeta Diferente", + "Choose New Folder": "Elegir Nueva Carpeta", + "Migrating data...": "Migrando datos...", + "Copying: {{file}}": "Copiando: {{file}}", + "{{current}} of {{total}} files": "{{current}} de {{total}} archivos", + "Migration completed successfully!": "¡Migración completada con éxito!", + "Your data has been moved to the new location. Please restart the application to complete the process.": "Tus datos han sido movidos a la nueva ubicación. Por favor, reinicia la aplicación para completar el proceso.", + "Migration failed": "La migración falló", + "Important Notice": "Aviso Importante", + "This will move all your app data to the new location. Make sure the destination has enough free space.": "Esto moverá todos los datos de tu aplicación a la nueva ubicación. Asegúrate de que el destino tenga suficiente espacio libre.", + "Restart App": "Reiniciar Aplicación", + "Start Migration": "Iniciar Migración", + "Advanced Settings": "Configuraciones Avanzadas", + "File count: {{size}}": "Número de archivos: {{size}}" } diff --git a/apps/readest-app/public/locales/fr/translation.json b/apps/readest-app/public/locales/fr/translation.json index 0e8f4c18..162d6b8b 100644 --- a/apps/readest-app/public/locales/fr/translation.json +++ b/apps/readest-app/public/locales/fr/translation.json @@ -578,5 +578,27 @@ "Single Page": "Page Unique", "Auto Spread": "Répartition Automatique", "Fit Page": "Ajuster la Page", - "Fit Width": "Ajuster la Largeur" + "Fit Width": "Ajuster la Largeur", + "Failed to select directory": "Échec de la sélection du répertoire", + "The new data directory must be different from the current one.": "Le nouveau répertoire de données doit être différent de l'actuel.", + "Migration failed: {{error}}": "La migration a échoué : {{error}}", + "Change Data Location": "Changer l'Emplacement des Données", + "Current Data Location": "Emplacement Actuel des Données", + "Total size: {{size}}": "Taille totale : {{size}}", + "Calculating file info...": "Calcul des informations sur le fichier...", + "New Data Location": "Nouvel Emplacement des Données", + "Choose Different Folder": "Choisir un Dossier Différent", + "Choose New Folder": "Choisir un Nouveau Dossier", + "Migrating data...": "Migration des données...", + "Copying: {{file}}": "Copie : {{file}}", + "{{current}} of {{total}} files": "{{current}} sur {{total}} fichiers", + "Migration completed successfully!": "Migration terminée avec succès !", + "Your data has been moved to the new location. Please restart the application to complete the process.": "Vos données ont été déplacées vers le nouvel emplacement. Veuillez redémarrer l'application pour terminer le processus.", + "Migration failed": "La migration a échoué", + "Important Notice": "Avis Important", + "This will move all your app data to the new location. Make sure the destination has enough free space.": "Cela déplacera toutes vos données d'application vers le nouvel emplacement. Assurez-vous que la destination dispose de suffisamment d'espace libre.", + "Restart App": "Redémarrer l'Application", + "Start Migration": "Démarrer la Migration", + "Advanced Settings": "Paramètres Avancés", + "File count: {{size}}": "Nombre de fichiers : {{size}}" } diff --git a/apps/readest-app/public/locales/hi/translation.json b/apps/readest-app/public/locales/hi/translation.json index ddb8ee37..b72958f1 100644 --- a/apps/readest-app/public/locales/hi/translation.json +++ b/apps/readest-app/public/locales/hi/translation.json @@ -574,5 +574,27 @@ "Single Page": "एकल पृष्ठ", "Auto Spread": "स्वचालित फैलाव", "Fit Page": "पृष्ठ में फिट करें", - "Fit Width": "चौड़ाई में फिट करें" + "Fit Width": "चौड़ाई में फिट करें", + "Failed to select directory": "निर्देशिका का चयन करने में विफल", + "The new data directory must be different from the current one.": "नया डेटा निर्देशिका वर्तमान से भिन्न होना चाहिए।", + "Migration failed: {{error}}": "माइग्रेशन विफल: {{error}}", + "Change Data Location": "डेटा स्थान बदलें", + "Current Data Location": "वर्तमान डेटा स्थान", + "Total size: {{size}}": "कुल आकार: {{size}}", + "Calculating file info...": "फ़ाइल जानकारी की गणना कर रहे हैं...", + "New Data Location": "नया डेटा स्थान", + "Choose Different Folder": "विभिन्न फ़ोल्डर चुनें", + "Choose New Folder": "नया फ़ोल्डर चुनें", + "Migrating data...": "डेटा माइग्रेट कर रहे हैं...", + "Copying: {{file}}": "कॉपी कर रहे हैं: {{file}}", + "{{current}} of {{total}} files": "{{current}} में से {{total}} फ़ाइलें", + "Migration completed successfully!": "माइग्रेशन सफलतापूर्वक पूरा हुआ!", + "Your data has been moved to the new location. Please restart the application to complete the process.": "आपका डेटा नए स्थान पर स्थानांतरित कर दिया गया है। कृपया प्रक्रिया को पूरा करने के लिए एप्लिकेशन को पुनरारंभ करें।", + "Migration failed": "माइग्रेशन विफल", + "Important Notice": "महत्वपूर्ण सूचना", + "This will move all your app data to the new location. Make sure the destination has enough free space.": "यह आपके सभी ऐप डेटा को नए स्थान पर स्थानांतरित कर देगा। सुनिश्चित करें कि गंतव्य में पर्याप्त खाली स्थान है।", + "Restart App": "एप्लिकेशन पुनरारंभ करें", + "Start Migration": "माइग्रेशन प्रारंभ करें", + "Advanced Settings": "उन्नत सेटिंग्स", + "File count: {{size}}": "फ़ाइलों की संख्या: {{size}}" } diff --git a/apps/readest-app/public/locales/id/translation.json b/apps/readest-app/public/locales/id/translation.json index 2dcec693..cac02f03 100644 --- a/apps/readest-app/public/locales/id/translation.json +++ b/apps/readest-app/public/locales/id/translation.json @@ -570,5 +570,27 @@ "Single Page": "Halaman Tunggal", "Auto Spread": "Penyebaran Otomatis", "Fit Page": "Sesuaikan Halaman", - "Fit Width": "Sesuaikan Lebar" + "Fit Width": "Sesuaikan Lebar", + "Failed to select directory": "Gagal memilih direktori", + "The new data directory must be different from the current one.": "Direktori data baru harus berbeda dari yang saat ini.", + "Migration failed: {{error}}": "Migrasi gagal: {{error}}", + "Change Data Location": "Ubah Lokasi Data", + "Current Data Location": "Lokasi Data Saat Ini", + "Total size: {{size}}": "Ukuran total: {{size}}", + "Calculating file info...": "Menghitung informasi file...", + "New Data Location": "Lokasi Data Baru", + "Choose Different Folder": "Pilih Folder Berbeda", + "Choose New Folder": "Pilih Folder Baru", + "Migrating data...": "Migrasi data...", + "Copying: {{file}}": "Menyalin: {{file}}", + "{{current}} of {{total}} files": "{{current}} dari {{total}} file", + "Migration completed successfully!": "Migrasi selesai dengan sukses!", + "Your data has been moved to the new location. Please restart the application to complete the process.": "Data Anda telah dipindahkan ke lokasi baru. Silakan restart aplikasi untuk menyelesaikan proses.", + "Migration failed": "Migrasi gagal", + "Important Notice": "Pemberitahuan Penting", + "This will move all your app data to the new location. Make sure the destination has enough free space.": "Ini akan memindahkan semua data aplikasi Anda ke lokasi baru. Pastikan tujuan memiliki cukup ruang kosong.", + "Restart App": "Restart Aplikasi", + "Start Migration": "Mulai Migrasi", + "Advanced Settings": "Pengaturan Lanjutan", + "File count: {{size}}": "Jumlah file: {{size}}" } diff --git a/apps/readest-app/public/locales/it/translation.json b/apps/readest-app/public/locales/it/translation.json index e00a6524..d02ce1ce 100644 --- a/apps/readest-app/public/locales/it/translation.json +++ b/apps/readest-app/public/locales/it/translation.json @@ -578,5 +578,27 @@ "Single Page": "Pagina singola", "Auto Spread": "Distribuzione automatica", "Fit Page": "Adatta pagina", - "Fit Width": "Adatta larghezza" + "Fit Width": "Adatta larghezza", + "Failed to select directory": "Impossibile selezionare la directory", + "The new data directory must be different from the current one.": "La nuova directory dei dati deve essere diversa da quella attuale.", + "Migration failed: {{error}}": "Migrzione fallita: {{error}}", + "Change Data Location": "Cambia posizione dei dati", + "Current Data Location": "Posizione attuale dei dati", + "Total size: {{size}}": "Dimensione totale: {{size}}", + "Calculating file info...": "Calcolo informazioni file...", + "New Data Location": "Nuova posizione dei dati", + "Choose Different Folder": "Scegli una cartella diversa", + "Choose New Folder": "Scegli una nuova cartella", + "Migrating data...": "Migrando dati...", + "Copying: {{file}}": "Copia in corso: {{file}}", + "{{current}} of {{total}} files": "{{current}} di {{total}} file", + "Migration completed successfully!": "Migrzione completata con successo!", + "Your data has been moved to the new location. Please restart the application to complete the process.": "I tuoi dati sono stati spostati nella nuova posizione. Riavvia l'applicazione per completare il processo.", + "Migration failed": "Migrzione fallita", + "Important Notice": "Avviso Importante", + "This will move all your app data to the new location. Make sure the destination has enough free space.": "Questo sposterà tutti i dati dell'app nella nuova posizione. Assicurati che la destinazione abbia spazio libero sufficiente.", + "Restart App": "Riavvia App", + "Start Migration": "Inizia Migrazione", + "Advanced Settings": "Impostazioni Avanzate", + "File count: {{size}}": "Conteggio file: {{size}}" } diff --git a/apps/readest-app/public/locales/ja/translation.json b/apps/readest-app/public/locales/ja/translation.json index f30e35f7..d1eab325 100644 --- a/apps/readest-app/public/locales/ja/translation.json +++ b/apps/readest-app/public/locales/ja/translation.json @@ -570,5 +570,27 @@ "Single Page": "シングルページ", "Auto Spread": "自動スプレッド", "Fit Page": "ページに合わせる", - "Fit Width": "幅に合わせる" + "Fit Width": "幅に合わせる", + "Failed to select directory": "ディレクトリの選択に失敗しました", + "The new data directory must be different from the current one.": "新しいデータディレクトリは現在のものと異なる必要があります。", + "Migration failed: {{error}}": "移行に失敗しました: {{error}}", + "Change Data Location": "データの場所を変更", + "Current Data Location": "現在のデータの場所", + "Total size: {{size}}": "合計サイズ: {{size}}", + "Calculating file info...": "ファイル情報を計算中...", + "New Data Location": "新しいデータの場所", + "Choose Different Folder": "別のフォルダーを選択", + "Choose New Folder": "新しいフォルダーを選択", + "Migrating data...": "データを移行中...", + "Copying: {{file}}": "コピー中: {{file}}", + "{{current}} of {{total}} files": "{{current}} / {{total}} ファイル", + "Migration completed successfully!": "移行が成功しました!", + "Your data has been moved to the new location. Please restart the application to complete the process.": "データは新しい場所に移動されました。プロセスを完了するにはアプリケーションを再起動してください。", + "Migration failed": "移行に失敗しました", + "Important Notice": "重要なお知らせ", + "This will move all your app data to the new location. Make sure the destination has enough free space.": "これにより、すべてのアプリデータが新しい場所に移動されます。宛先に十分な空き容量があることを確認してください。", + "Restart App": "アプリを再起動", + "Start Migration": "移行を開始", + "Advanced Settings": "詳細設定", + "File count: {{size}}": "ファイル数: {{size}}" } diff --git a/apps/readest-app/public/locales/ko/translation.json b/apps/readest-app/public/locales/ko/translation.json index 7f002490..c1a3bef7 100644 --- a/apps/readest-app/public/locales/ko/translation.json +++ b/apps/readest-app/public/locales/ko/translation.json @@ -570,5 +570,27 @@ "Single Page": "단일 페이지", "Auto Spread": "자동 스프레드", "Fit Page": "페이지에 맞춤", - "Fit Width": "너비에 맞춤" + "Fit Width": "너비에 맞춤", + "Failed to select directory": "디렉토리 선택 실패", + "The new data directory must be different from the current one.": "새 데이터 디렉토리는 현재 디렉토리와 달라야 합니다.", + "Migration failed: {{error}}": "마이그레이션 실패: {{error}}", + "Change Data Location": "데이터 위치 변경", + "Current Data Location": "현재 데이터 위치", + "Total size: {{size}}": "총 크기: {{size}}", + "Calculating file info...": "파일 정보 계산 중...", + "New Data Location": "새 데이터 위치", + "Choose Different Folder": "다른 폴더 선택", + "Choose New Folder": "새 폴더 선택", + "Migrating data...": "데이터 마이그레이션 중...", + "Copying: {{file}}": "복사 중: {{file}}", + "{{current}} of {{total}} files": "{{current}} / {{total}} 파일", + "Migration completed successfully!": "마이그레이션이 성공적으로 완료되었습니다!", + "Your data has been moved to the new location. Please restart the application to complete the process.": "데이터가 새 위치로 이동되었습니다. 프로세스를 완료하려면 애플리케이션을 재시작하십시오.", + "Migration failed": "마이그레이션 실패", + "Important Notice": "중요한 공지", + "This will move all your app data to the new location. Make sure the destination has enough free space.": "이 작업은 모든 앱 데이터를 새 위치로 이동합니다. 대상에 충분한 여유 공간이 있는지 확인하십시오.", + "Restart App": "앱 재시작", + "Start Migration": "마이그레이션 시작", + "Advanced Settings": "고급 설정", + "File count: {{size}}": "파일 수: {{size}}" } diff --git a/apps/readest-app/public/locales/nl/translation.json b/apps/readest-app/public/locales/nl/translation.json index 00b025f5..b183e99e 100644 --- a/apps/readest-app/public/locales/nl/translation.json +++ b/apps/readest-app/public/locales/nl/translation.json @@ -574,5 +574,27 @@ "Single Page": "Enkele Pagina", "Auto Spread": "Automatische Verspreiding", "Fit Page": "Pagina Aanpassen", - "Fit Width": "Breedte Aanpassen" + "Fit Width": "Breedte Aanpassen", + "Failed to select directory": "Selecteren van map is mislukt", + "The new data directory must be different from the current one.": "De nieuwe gegevensmap moet anders zijn dan de huidige.", + "Migration failed: {{error}}": "Migratie mislukt: {{error}}", + "Change Data Location": "Gegevenslocatie Wijzigen", + "Current Data Location": "Huidige Gegevenslocatie", + "Total size: {{size}}": "Totale grootte: {{size}}", + "Calculating file info...": "Bestandinformatie wordt berekend...", + "New Data Location": "Nieuwe Gegevenslocatie", + "Choose Different Folder": "Kies Een Andere Map", + "Choose New Folder": "Kies Nieuwe Map", + "Migrating data...": "Gegevens worden gemigreerd...", + "Copying: {{file}}": "Kopiëren: {{file}}", + "{{current}} of {{total}} files": "{{current}} van {{total}} bestanden", + "Migration completed successfully!": "Migratie succesvol voltooid!", + "Your data has been moved to the new location. Please restart the application to complete the process.": "Uw gegevens zijn naar de nieuwe locatie verplaatst. Start de applicatie opnieuw op om het proces te voltooien.", + "Migration failed": "Migratie mislukt", + "Important Notice": "Belangrijke Kennisgeving", + "This will move all your app data to the new location. Make sure the destination has enough free space.": "Dit zal al uw app-gegevens naar de nieuwe locatie verplaatsen. Zorg ervoor dat de bestemming voldoende vrije ruimte heeft.", + "Restart App": "Herstart App", + "Start Migration": "Start Migratie", + "Advanced Settings": "Geavanceerde Instellingen", + "File count: {{size}}": "Bestandsaantal: {{size}}" } diff --git a/apps/readest-app/public/locales/pl/translation.json b/apps/readest-app/public/locales/pl/translation.json index f66f85ca..de5d0a9d 100644 --- a/apps/readest-app/public/locales/pl/translation.json +++ b/apps/readest-app/public/locales/pl/translation.json @@ -582,5 +582,27 @@ "Single Page": "Pojedyncza Strona", "Auto Spread": "Automatyczne Rozprzestrzenianie", "Fit Page": "Dopasuj Stronę", - "Fit Width": "Dopasuj Szerokość" + "Fit Width": "Dopasuj Szerokość", + "Failed to select directory": "Nie udało się wybrać katalogu", + "The new data directory must be different from the current one.": "Nowy katalog danych musi różnić się od obecnego.", + "Migration failed: {{error}}": "Migracja nie powiodła się: {{error}}", + "Change Data Location": "Zmień lokalizację danych", + "Current Data Location": "Bieżąca lokalizacja danych", + "Total size: {{size}}": "Całkowity rozmiar: {{size}}", + "Calculating file info...": "Obliczanie informacji o pliku...", + "New Data Location": "Nowa lokalizacja danych", + "Choose Different Folder": "Wybierz inny folder", + "Choose New Folder": "Wybierz nowy folder", + "Migrating data...": "Migracja danych...", + "Copying: {{file}}": "Kopiowanie: {{file}}", + "{{current}} of {{total}} files": "{{current}} z {{total}} plików", + "Migration completed successfully!": "Migracja zakończona pomyślnie!", + "Your data has been moved to the new location. Please restart the application to complete the process.": "Twoje dane zostały przeniesione do nowej lokalizacji. Proszę zrestartować aplikację, aby zakończyć proces.", + "Migration failed": "Migracja nie powiodła się", + "Important Notice": "Ważne powiadomienie", + "This will move all your app data to the new location. Make sure the destination has enough free space.": "To przeniesie wszystkie dane aplikacji do nowej lokalizacji. Upewnij się, że docelowy folder ma wystarczająco dużo wolnego miejsca.", + "Restart App": "Zrestartuj aplikację", + "Start Migration": "Rozpocznij migrację", + "Advanced Settings": "Ustawienia zaawansowane", + "File count: {{size}}": "Liczba plików: {{size}}" } diff --git a/apps/readest-app/public/locales/pt/translation.json b/apps/readest-app/public/locales/pt/translation.json index 97c3d04c..955cfef6 100644 --- a/apps/readest-app/public/locales/pt/translation.json +++ b/apps/readest-app/public/locales/pt/translation.json @@ -578,5 +578,27 @@ "Single Page": "Página Única", "Auto Spread": "Espalhamento Automático", "Fit Page": "Ajustar Página", - "Fit Width": "Ajustar Largura" + "Fit Width": "Ajustar Largura", + "Failed to select directory": "Falha ao selecionar diretório", + "The new data directory must be different from the current one.": "O novo diretório de dados deve ser diferente do atual.", + "Migration failed: {{error}}": "A migração falhou: {{error}}", + "Change Data Location": "Alterar Localização dos Dados", + "Current Data Location": "Localização Atual dos Dados", + "Total size: {{size}}": "Tamanho total: {{size}}", + "Calculating file info...": "Calculando informações do arquivo...", + "New Data Location": "Nova Localização dos Dados", + "Choose Different Folder": "Escolher Pasta Diferente", + "Choose New Folder": "Escolher Nova Pasta", + "Migrating data...": "Migrando dados...", + "Copying: {{file}}": "Copiando: {{file}}", + "{{current}} of {{total}} files": "{{current}} de {{total}} arquivos", + "Migration completed successfully!": "Migração concluída com sucesso!", + "Your data has been moved to the new location. Please restart the application to complete the process.": "Seus dados foram movidos para a nova localização. Reinicie o aplicativo para concluir o processo.", + "Migration failed": "Migração falhou", + "Important Notice": "Aviso Importante", + "This will move all your app data to the new location. Make sure the destination has enough free space.": "Isso moverá todos os dados do seu aplicativo para a nova localização. Certifique-se de que o destino tenha espaço livre suficiente.", + "Restart App": "Reiniciar Aplicativo", + "Start Migration": "Iniciar Migração", + "Advanced Settings": "Configurações Avançadas", + "File count: {{size}}": "Contagem de arquivos: {{size}}" } diff --git a/apps/readest-app/public/locales/ru/translation.json b/apps/readest-app/public/locales/ru/translation.json index 4563409c..31d20817 100644 --- a/apps/readest-app/public/locales/ru/translation.json +++ b/apps/readest-app/public/locales/ru/translation.json @@ -582,5 +582,27 @@ "Single Page": "Одна страница", "Auto Spread": "Автоматическое растяжение", "Fit Page": "Подогнать страницу", - "Fit Width": "Подогнать ширину" + "Fit Width": "Подогнать ширину", + "Failed to select directory": "Не удалось выбрать каталог", + "The new data directory must be different from the current one.": "Новая директория данных должна отличаться от текущей.", + "Migration failed: {{error}}": "Ошибка миграции: {{error}}", + "Change Data Location": "Изменить расположение данных", + "Current Data Location": "Текущее расположение данных", + "Total size: {{size}}": "Общий размер: {{size}}", + "Calculating file info...": "Вычисление информации о файле...", + "New Data Location": "Новое расположение данных", + "Choose Different Folder": "Выбрать другую папку", + "Choose New Folder": "Выбрать новую папку", + "Migrating data...": "Миграция данных...", + "Copying: {{file}}": "Копирование: {{file}}", + "{{current}} of {{total}} files": "{{current}} из {{total}} файлов", + "Migration completed successfully!": "Миграция завершена успешно!", + "Your data has been moved to the new location. Please restart the application to complete the process.": "Ваши данные были перемещены в новое расположение. Пожалуйста, перезапустите приложение, чтобы завершить процесс.", + "Migration failed": "Ошибка миграции", + "Important Notice": "Важное уведомление", + "This will move all your app data to the new location. Make sure the destination has enough free space.": "Это переместит все ваши данные приложения в новое расположение. Убедитесь, что в целевом месте достаточно свободного места.", + "Restart App": "Перезапустить приложение", + "Start Migration": "Начать миграцию", + "Advanced Settings": "Расширенные настройки", + "File count: {{size}}": "Количество файлов: {{size}}" } diff --git a/apps/readest-app/public/locales/si/translation.json b/apps/readest-app/public/locales/si/translation.json index 4c36accc..20495d2f 100644 --- a/apps/readest-app/public/locales/si/translation.json +++ b/apps/readest-app/public/locales/si/translation.json @@ -574,5 +574,27 @@ "Single Page": "එක් පිටුව", "Auto Spread": "ස්වයංක්‍රීය ව්‍යාප්තිය", "Fit Page": "පිටුවට ගැලපෙන ලෙස", - "Fit Width": "පැතිකඩට ගැලපෙන ලෙස" + "Fit Width": "පැතිකඩට ගැලපෙන ලෙස", + "Failed to select directory": "ෆෝල්ඩරය තෝරා ගැනීමට අසමත්", + "The new data directory must be different from the current one.": "නව දත්ත ෆෝල්ඩරය වර්තමාන ෆෝල්ඩරයෙන් වෙනස් විය යුතුය.", + "Migration failed: {{error}}": "මැතිවරණය අසමත් විය: {{error}}", + "Change Data Location": "දත්ත ස්ථානය වෙනස් කරන්න", + "Current Data Location": "වර්තමාන දත්ත ස්ථානය", + "Total size: {{size}}": "මුළු ප්‍රමාණය: {{size}}", + "Calculating file info...": "ගොනු තොරතුරු ගණනය කරමින්...", + "New Data Location": "නව දත්ත ස්ථානය", + "Choose Different Folder": "වෙනත් ෆෝල්ඩරයක් තෝරන්න", + "Choose New Folder": "නව ෆෝල්ඩරයක් තෝරන්න", + "Migrating data...": "දත්ත මැතිවරණය කරමින්...", + "Copying: {{file}}": "පිටපත් කරමින්: {{file}}", + "{{current}} of {{total}} files": "{{current}}/{{total}} ගොනු", + "Migration completed successfully!": "මැතිවරණය සාර්ථකව නිමවිය!", + "Your data has been moved to the new location. Please restart the application to complete the process.": "ඔබගේ දත්ත නව ස්ථානයට මාරු කර ඇත. ක්‍රියාවලිය සම්පූර්ණ කිරීමට කරුණාකර යෙදුම නැවත ආරම්භ කරන්න.", + "Migration failed": "මැතිවරණය අසමත් විය", + "Important Notice": "මහත් අවධානයක්", + "This will move all your app data to the new location. Make sure the destination has enough free space.": "මෙය ඔබගේ යෙදුම් දත්ත සියල්ල නව ස්ථානයට මාරු කරනු ඇත. ගමන් මාර්ගය ප්‍රමාණවත් නිදහස් ස්ථානයක් ඇති බවට සහතික වන්න.", + "Restart App": "යෙදුම නැවත ආරම්භ කරන්න", + "Start Migration": "මැතිවරණය ආරම්භ කරන්න", + "Advanced Settings": "උසස් සැකසුම්", + "File count: {{size}}": "ගොනු ගණන: {{size}}" } diff --git a/apps/readest-app/public/locales/ta/translation.json b/apps/readest-app/public/locales/ta/translation.json index c672ea88..6f5cd943 100644 --- a/apps/readest-app/public/locales/ta/translation.json +++ b/apps/readest-app/public/locales/ta/translation.json @@ -574,5 +574,27 @@ "Single Page": "ஒரு பக்கம்", "Auto Spread": "தானாக பரவல்", "Fit Page": "பக்கத்திற்கு பொருந்தும்", - "Fit Width": "அகலத்திற்கு பொருந்தும்" + "Fit Width": "அகலத்திற்கு பொருந்தும்", + "Failed to select directory": "கோப்புறையைத் தேர்வுசெய்ய முடியவில்லை", + "The new data directory must be different from the current one.": "புதிய தரவுக் கோப்புறை தற்போதையதைப் போலவே இருக்கக்கூடாது.", + "Migration failed: {{error}}": "மொத்தமாக்கல் தோல்வியுற்றது: {{error}}", + "Change Data Location": "தரவுப் இடத்தை மாற்றவும்", + "Current Data Location": "தற்போதைய தரவுப் இடம்", + "Total size: {{size}}": "மொத்த அளவு: {{size}}", + "Calculating file info...": "கோப்பு தகவலை கணக்கிடுகிறது...", + "New Data Location": "புதிய தரவுப் இடம்", + "Choose Different Folder": "வேறுபட்ட கோப்புறையைத் தேர்ந்தெடுக்கவும்", + "Choose New Folder": "புதிய கோப்புறையைத் தேர்ந்தெடுக்கவும்", + "Migrating data...": "தரவை மாறுகிறது...", + "Copying: {{file}}": "பகுப்பாய்வு: {{file}}", + "{{current}} of {{total}} files": "{{current}}/{{total}} கோப்புகள்", + "Migration completed successfully!": "மொத்தமாக்கல் வெற்றிகரமாக முடிந்தது!", + "Your data has been moved to the new location. Please restart the application to complete the process.": "உங்கள் தரவுகள் புதிய இடத்திற்கு மாறியுள்ளன. செயலியை மீண்டும் தொடங்கவும்.", + "Migration failed": "மொத்தமாக்கல் தோல்வியுற்றது", + "Important Notice": "முக்கிய அறிவிப்பு", + "This will move all your app data to the new location. Make sure the destination has enough free space.": "இது உங்கள் செயலியின் அனைத்து தரவுகளையும் புதிய இடத்திற்கு நகர்த்தும். இலக்கு இடத்தில் போதுமான இலவச இடம் உள்ளதா என்பதை உறுதிப்படுத்தவும்.", + "Restart App": "செயலியை மீண்டும் தொடங்கவும்", + "Start Migration": "மொத்தமாக்கலை தொடங்கவும்", + "Advanced Settings": "மேம்பட்ட அமைப்புகள்", + "File count: {{size}}": "கோப்பு எண்ணிக்கை: {{size}}" } diff --git a/apps/readest-app/public/locales/th/translation.json b/apps/readest-app/public/locales/th/translation.json index aa91b9c9..8062aaa7 100644 --- a/apps/readest-app/public/locales/th/translation.json +++ b/apps/readest-app/public/locales/th/translation.json @@ -570,5 +570,27 @@ "Single Page": "หน้าเดียว", "Auto Spread": "การกระจายอัตโนมัติ", "Fit Page": "พอดีกับหน้า", - "Fit Width": "พอดีกับความกว้าง" + "Fit Width": "พอดีกับความกว้าง", + "Failed to select directory": "ไม่สามารถเลือกไดเรกทอรีได้", + "The new data directory must be different from the current one.": "ไดเรกทอรีข้อมูลใหม่จะต้องแตกต่างจากไดเรกทอรีปัจจุบัน", + "Migration failed: {{error}}": "การย้ายข้อมูลล้มเหลว: {{error}}", + "Change Data Location": "เปลี่ยนตำแหน่งข้อมูล", + "Current Data Location": "ตำแหน่งข้อมูลปัจจุบัน", + "Total size: {{size}}": "ขนาดรวม: {{size}}", + "Calculating file info...": "กำลังคำนวณข้อมูลไฟล์...", + "New Data Location": "ตำแหน่งข้อมูลใหม่", + "Choose Different Folder": "เลือกโฟลเดอร์ที่แตกต่าง", + "Choose New Folder": "เลือกโฟลเดอร์ใหม่", + "Migrating data...": "กำลังย้ายข้อมูล...", + "Copying: {{file}}": "กำลังคัดลอก: {{file}}", + "{{current}} of {{total}} files": "{{current}} จาก {{total}} ไฟล์", + "Migration completed successfully!": "การย้ายข้อมูลเสร็จสมบูรณ์!", + "Your data has been moved to the new location. Please restart the application to complete the process.": "ข้อมูลของคุณได้ถูกย้ายไปยังตำแหน่งใหม่แล้ว กรุณารีสตาร์ทแอปพลิเคชันเพื่อทำให้กระบวนการเสร็จสมบูรณ์", + "Migration failed": "การย้ายข้อมูลล้มเหลว", + "Important Notice": "ประกาศสำคัญ", + "This will move all your app data to the new location. Make sure the destination has enough free space.": "สิ่งนี้จะย้ายข้อมูลแอปทั้งหมดของคุณไปยังตำแหน่งใหม่ ตรวจสอบให้แน่ใจว่าตำแหน่งปลายทางมีพื้นที่ว่างเพียงพอ", + "Restart App": "รีสตาร์ทแอป", + "Start Migration": "เริ่มการย้ายข้อมูล", + "Advanced Settings": "การตั้งค่าขั้นสูง", + "File count: {{size}}": "จำนวนไฟล์: {{size}}" } diff --git a/apps/readest-app/public/locales/tr/translation.json b/apps/readest-app/public/locales/tr/translation.json index 1f7970b6..4523fcb0 100644 --- a/apps/readest-app/public/locales/tr/translation.json +++ b/apps/readest-app/public/locales/tr/translation.json @@ -574,5 +574,27 @@ "Single Page": "Tek Sayfa", "Auto Spread": "Otomatik Yayılma", "Fit Page": "Sayfaya Sığdır", - "Fit Width": "Genişliğe Sığdır" + "Fit Width": "Genişliğe Sığdır", + "Failed to select directory": "Dizini seçme başarısız oldu", + "The new data directory must be different from the current one.": "Yeni veri dizini mevcut olanla farklı olmalıdır.", + "Migration failed: {{error}}": "Taşıma işlemi başarısız oldu: {{error}}", + "Change Data Location": "Veri Konumunu Değiştir", + "Current Data Location": "Mevcut Veri Konumu", + "Total size: {{size}}": "Toplam boyut: {{size}}", + "Calculating file info...": "Dosya bilgileri hesaplanıyor...", + "New Data Location": "Yeni Veri Konumu", + "Choose Different Folder": "Farklı Klasör Seç", + "Choose New Folder": "Yeni Klasör Seç", + "Migrating data...": "Veri taşınıyor...", + "Copying: {{file}}": "Kopyalanıyor: {{file}}", + "{{current}} of {{total}} files": "{{current}} / {{total}} dosya", + "Migration completed successfully!": "Taşıma işlemi başarıyla tamamlandı!", + "Your data has been moved to the new location. Please restart the application to complete the process.": "Verileriniz yeni konuma taşındı. Lütfen işlemi tamamlamak için uygulamayı yeniden başlatın.", + "Migration failed": "Taşıma işlemi başarısız oldu", + "Important Notice": "Önemli Duyuru", + "This will move all your app data to the new location. Make sure the destination has enough free space.": "Bu, tüm uygulama verilerinizi yeni konuma taşıyacaktır. Hedefin yeterli boş alana sahip olduğundan emin olun.", + "Restart App": "Uygulamayı Yeniden Başlat", + "Start Migration": "Taşımayı Başlat", + "Advanced Settings": "Gelişmiş Ayarlar", + "File count: {{size}}": "Dosya sayısı: {{size}}" } diff --git a/apps/readest-app/public/locales/uk/translation.json b/apps/readest-app/public/locales/uk/translation.json index 856120f1..c504f341 100644 --- a/apps/readest-app/public/locales/uk/translation.json +++ b/apps/readest-app/public/locales/uk/translation.json @@ -582,5 +582,27 @@ "Single Page": "Одна сторінка", "Auto Spread": "Автоматичне розповсюдження", "Fit Page": "Підганяти під сторінку", - "Fit Width": "Підганяти під ширину" + "Fit Width": "Підганяти під ширину", + "Failed to select directory": "Не вдалося вибрати каталог", + "The new data directory must be different from the current one.": "Новий каталог даних повинен відрізнятися від поточного.", + "Migration failed: {{error}}": "Переміщення не вдалося: {{error}}", + "Change Data Location": "Змінити розташування даних", + "Current Data Location": "Поточне розташування даних", + "Total size: {{size}}": "Загальний розмір: {{size}}", + "Calculating file info...": "Обчислення інформації про файл...", + "New Data Location": "Нове розташування даних", + "Choose Different Folder": "Вибрати іншу папку", + "Choose New Folder": "Вибрати нову папку", + "Migrating data...": "Переміщення даних...", + "Copying: {{file}}": "Копіювання: {{file}}", + "{{current}} of {{total}} files": "{{current}} з {{total}} файлів", + "Migration completed successfully!": "Переміщення завершено успішно!", + "Your data has been moved to the new location. Please restart the application to complete the process.": "Ваші дані були переміщені до нового розташування. Будь ласка, перезапустіть програму, щоб завершити процес.", + "Migration failed": "Переміщення не вдалося", + "Important Notice": "Важливе повідомлення", + "This will move all your app data to the new location. Make sure the destination has enough free space.": "Це перемістить всі ваші дані програми до нового розташування. Переконайтеся, що в призначенні достатньо вільного місця.", + "Restart App": "Перезапустити програму", + "Start Migration": "Почати переміщення", + "Advanced Settings": "Розширені налаштування", + "File count: {{size}}": "Кількість файлів: {{size}}" } diff --git a/apps/readest-app/public/locales/vi/translation.json b/apps/readest-app/public/locales/vi/translation.json index fed926e8..56ab4fd9 100644 --- a/apps/readest-app/public/locales/vi/translation.json +++ b/apps/readest-app/public/locales/vi/translation.json @@ -570,5 +570,27 @@ "Single Page": "Một trang", "Auto Spread": "Tự động trải rộng", "Fit Page": "Vừa trang", - "Fit Width": "Vừa chiều rộng" + "Fit Width": "Vừa chiều rộng", + "Failed to select directory": "Không thể chọn thư mục", + "The new data directory must be different from the current one.": "Thư mục dữ liệu mới phải khác với thư mục hiện tại.", + "Migration failed: {{error}}": "Di chuyển không thành công: {{error}}", + "Change Data Location": "Thay đổi vị trí dữ liệu", + "Current Data Location": "Vị trí dữ liệu hiện tại", + "Total size: {{size}}": "Tổng kích thước: {{size}}", + "Calculating file info...": "Đang tính toán thông tin tệp...", + "New Data Location": "Vị trí dữ liệu mới", + "Choose Different Folder": "Chọn thư mục khác", + "Choose New Folder": "Chọn thư mục mới", + "Migrating data...": "Đang di chuyển dữ liệu...", + "Copying: {{file}}": "Đang sao chép: {{file}}", + "{{current}} of {{total}} files": "{{current}} của {{total}} tệp", + "Migration completed successfully!": "Di chuyển hoàn tất thành công!", + "Your data has been moved to the new location. Please restart the application to complete the process.": "Dữ liệu của bạn đã được chuyển đến vị trí mới. Vui lòng khởi động lại ứng dụng để hoàn tất quá trình.", + "Migration failed": "Di chuyển không thành công", + "Important Notice": "Thông báo quan trọng", + "This will move all your app data to the new location. Make sure the destination has enough free space.": "Điều này sẽ di chuyển tất cả dữ liệu ứng dụng của bạn đến vị trí mới. Hãy chắc chắn rằng đích đến có đủ không gian trống.", + "Restart App": "Khởi động lại ứng dụng", + "Start Migration": "Bắt đầu di chuyển", + "Advanced Settings": "Cài đặt nâng cao", + "File count: {{size}}": "Số lượng tệp: {{size}}" } diff --git a/apps/readest-app/public/locales/zh-CN/translation.json b/apps/readest-app/public/locales/zh-CN/translation.json index dfef332f..78055472 100644 --- a/apps/readest-app/public/locales/zh-CN/translation.json +++ b/apps/readest-app/public/locales/zh-CN/translation.json @@ -570,5 +570,27 @@ "Single Page": "单页", "Auto Spread": "自动展开", "Fit Page": "适应页面", - "Fit Width": "适应宽度" + "Fit Width": "适应宽度", + "Failed to select directory": "选择目录失败", + "The new data directory must be different from the current one.": "新的数据目录必须与当前目录不同。", + "Migration failed: {{error}}": "迁移失败: {{error}}", + "Change Data Location": "更改数据位置", + "Current Data Location": "当前数据位置", + "Total size: {{size}}": "总大小: {{size}}", + "Calculating file info...": "正在计算文件信息...", + "New Data Location": "新数据位置", + "Choose Different Folder": "选择不同的文件夹", + "Choose New Folder": "选择新文件夹", + "Migrating data...": "正在迁移数据...", + "Copying: {{file}}": "正在复制: {{file}}", + "{{current}} of {{total}} files": "{{current}} / {{total}} 个文件", + "Migration completed successfully!": "迁移成功完成!", + "Your data has been moved to the new location. Please restart the application to complete the process.": "您的数据已移动到新位置。请重新启动应用程序以完成此过程。", + "Migration failed": "迁移失败", + "Important Notice": "重要通知", + "This will move all your app data to the new location. Make sure the destination has enough free space.": "这将把您所有的应用数据移动到新位置。请确保目标位置有足够的可用空间。", + "Restart App": "重启应用", + "Start Migration": "开始迁移", + "Advanced Settings": "高级设置", + "File count: {{size}}": "文件数量: {{size}}" } diff --git a/apps/readest-app/public/locales/zh-TW/translation.json b/apps/readest-app/public/locales/zh-TW/translation.json index 7eadd2ef..6565715f 100644 --- a/apps/readest-app/public/locales/zh-TW/translation.json +++ b/apps/readest-app/public/locales/zh-TW/translation.json @@ -570,5 +570,27 @@ "Single Page": "單頁", "Auto Spread": "自動展開", "Fit Page": "適應頁面", - "Fit Width": "適應寬度" + "Fit Width": "適應寬度", + "Failed to select directory": "選擇目錄失敗", + "The new data directory must be different from the current one.": "新的數據目錄必須與當前目錄不同。", + "Migration failed: {{error}}": "遷移失敗: {{error}}", + "Change Data Location": "更改數據位置", + "Current Data Location": "當前數據位置", + "Total size: {{size}}": "總大小: {{size}}", + "Calculating file info...": "正在計算文件信息...", + "New Data Location": "新的數據位置", + "Choose Different Folder": "選擇不同的文件夾", + "Choose New Folder": "選擇新文件夾", + "Migrating data...": "正在遷移數據...", + "Copying: {{file}}": "正在複製: {{file}}", + "{{current}} of {{total}} files": "{{current}} / {{total}} 個文件", + "Migration completed successfully!": "遷移成功完成!", + "Your data has been moved to the new location. Please restart the application to complete the process.": "您的數據已移動到新位置。請重新啟動應用程序以完成此過程。", + "Migration failed": "遷移失敗", + "Important Notice": "重要通知", + "This will move all your app data to the new location. Make sure the destination has enough free space.": "這將把您所有的應用數據移動到新位置。請確保目標位置有足夠的可用空間。", + "Restart App": "重新啟動應用", + "Start Migration": "開始遷移", + "Advanced Settings": "高級設置", + "File count: {{size}}": "文件數量: {{size}}" } diff --git a/apps/readest-app/src-tauri/capabilities/default.json b/apps/readest-app/src-tauri/capabilities/default.json index aad2a58f..c5884ad0 100644 --- a/apps/readest-app/src-tauri/capabilities/default.json +++ b/apps/readest-app/src-tauri/capabilities/default.json @@ -61,6 +61,17 @@ } ] }, + { + "identifier": "fs:scope", + "allow": [ + { + "path": "**/Readest" + }, + { + "path": "**/Readest/**/*" + } + ] + }, { "identifier": "http:default", "allow": [ diff --git a/apps/readest-app/src-tauri/tauri.conf.json b/apps/readest-app/src-tauri/tauri.conf.json index 8ff15c37..214ad4db 100644 --- a/apps/readest-app/src-tauri/tauri.conf.json +++ b/apps/readest-app/src-tauri/tauri.conf.json @@ -30,6 +30,7 @@ "$APPDATA/**/*", "$APPCACHE/**/*", "$TEMP/**/*", + "**/Readest/**/*", "/private/var/mobile/Containers/Data/Application/**/*" ], "deny": [] diff --git a/apps/readest-app/src/app/library/components/BookshelfItem.tsx b/apps/readest-app/src/app/library/components/BookshelfItem.tsx index ebcafb6a..27fd22a4 100644 --- a/apps/readest-app/src/app/library/components/BookshelfItem.tsx +++ b/apps/readest-app/src/app/library/components/BookshelfItem.tsx @@ -290,7 +290,7 @@ const BookshelfItem: React.FC = ({ groupContextMenuHandler(item as BooksGroup); } }, 100), - [itemSelected], + [itemSelected, settings.localBooksDir], ); const { pressing, handlers } = useLongPress( diff --git a/apps/readest-app/src/app/library/components/MigrateDataWindow.tsx b/apps/readest-app/src/app/library/components/MigrateDataWindow.tsx new file mode 100644 index 00000000..fea95150 --- /dev/null +++ b/apps/readest-app/src/app/library/components/MigrateDataWindow.tsx @@ -0,0 +1,399 @@ +import React, { useEffect, useState } from 'react'; +import { + RiFolderOpenLine, + RiCheckboxCircleFill, + RiErrorWarningFill, + RiLoader2Line, +} from 'react-icons/ri'; +import { join } from '@tauri-apps/api/path'; +import { relaunch } from '@tauri-apps/plugin-process'; +import { useEnv } from '@/context/EnvContext'; +import { useTranslation } from '@/hooks/useTranslation'; +import { useSettingsStore } from '@/store/settingsStore'; +import { revealItemInDir } from '@tauri-apps/plugin-opener'; +import { DATA_SUBDIR } from '@/services/constants'; +import { FileItem } from '@/types/system'; +import { getDirPath } from '@/utils/path'; +import { getOSPlatform } from '@/utils/misc'; +import { FILE_REVEAL_LABELS, FILE_REVEAL_PLATFORMS } from '@/utils/os'; +import Dialog from '@/components/Dialog'; +import { formatBytes } from '@/utils/book'; + +export const setMigrateDataDirDialogVisible = (visible: boolean) => { + const dialog = document.getElementById('migrate_data_dir_window'); + if (dialog) { + const event = new CustomEvent('setDialogVisibility', { + detail: { visible }, + }); + dialog.dispatchEvent(event); + } +}; + +type MigrationStatus = 'idle' | 'selecting' | 'migrating' | 'completed' | 'error'; + +interface MigrationProgress { + current: number; + total: number; + currentFile?: string; +} + +export const MigrateDataWindow = () => { + const _ = useTranslation(); + const { appService, envConfig } = useEnv(); + const { settings, setSettings, saveSettings } = useSettingsStore(); + const [isOpen, setIsOpen] = useState(false); + const [currentDataDir, setCurrentDataDir] = useState(''); + const [newDataDir, setNewDataDir] = useState(''); + const [migrationStatus, setMigrationStatus] = useState('idle'); + const [migrationProgress, setMigrationProgress] = useState({ + current: 0, + total: 0, + }); + const [errorMessage, setErrorMessage] = useState(''); + const [filesToMigrate, setFilesToMigrate] = useState([]); + const [currentDirFileCount, setCurrentDirFileCount] = useState(''); + const [currentDirFileSize, setCurrentDirFileSize] = useState(0); + + useEffect(() => { + const handleCustomEvent = (event: CustomEvent) => { + setIsOpen(event.detail.visible); + if (event.detail.visible) { + loadCurrentDataDir(); + } + }; + + const el = document.getElementById('migrate_data_dir_window'); + if (el) { + el.addEventListener('setDialogVisibility', handleCustomEvent as EventListener); + } + + return () => { + if (el) { + el.removeEventListener('setDialogVisibility', handleCustomEvent as EventListener); + } + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + const loadCurrentDataDir = async () => { + try { + if (!appService) return; + + const dataDir = await appService.resolveFilePath('', 'Data'); + setCurrentDataDir(dataDir); + const files = await appService.readDirectory(dataDir, 'None'); + setFilesToMigrate(files); + setCurrentDirFileCount(files.length.toLocaleString()); + setCurrentDirFileSize(files.reduce((acc, file) => acc + file.size, 0)); + } catch (error) { + console.error('Error loading current data directory:', error); + } + }; + + const handleSelectNewDir = async () => { + setMigrationStatus('selecting'); + setErrorMessage(''); + + try { + const selectedDir = await appService?.selectDirectory?.('write'); + if (selectedDir) { + const newDataDir = await join(selectedDir, DATA_SUBDIR); + await appService?.createDir(newDataDir, 'None', true); + setNewDataDir(newDataDir); + setMigrationStatus('idle'); + } else { + setMigrationStatus('idle'); + } + } catch (error) { + console.error('Error selecting directory:', error); + setErrorMessage(_('Failed to select directory')); + setMigrationStatus('error'); + } + }; + + const handleStartMigration = async () => { + if (!appService || !currentDataDir || !newDataDir || !filesToMigrate.length) return; + + setMigrationStatus('migrating'); + setErrorMessage(''); + setMigrationProgress({ current: 0, total: 0 }); + + try { + if (newDataDir === currentDataDir) { + throw new Error(_('The new data directory must be different from the current one.')); + } + + // Copy all files to new location + for (let i = 0; i < filesToMigrate.length; i++) { + const file = filesToMigrate[i]!; + setMigrationProgress({ + current: i + 1, + total: filesToMigrate.length, + currentFile: file.path, + }); + + const srcPath = await join(currentDataDir, file.path); + const destPath = await join(newDataDir, file.path); + await appService.copyFile(srcPath, destPath, 'None'); + } + + // Verify all files copied + const filesMigrated = await appService.readDirectory(newDataDir, 'None'); + for (const file of filesToMigrate) { + if (!filesMigrated.find((f) => f.path === file.path && f.size === file.size)) { + throw new Error(`File ${file.path} failed to copy.`); + } + } + + // Delete old data directory + await appService.deleteDir(currentDataDir, 'None', true); + + // Update settings for new data directory + const customRootDir = getDirPath(newDataDir); + await appService.setCustomRootDir(customRootDir); + settings.customRootDir = customRootDir; + settings.localBooksDir = await appService.resolveFilePath('', 'Books'); + setSettings({ ...settings }); + await saveSettings(envConfig, settings); + + // Finalize migration + setMigrationStatus('completed'); + setCurrentDataDir(newDataDir); + setFilesToMigrate([]); + setCurrentDirFileCount(''); + setCurrentDirFileSize(0); + loadCurrentDataDir(); + } catch (error) { + console.error('Error migrating data:', error); + setErrorMessage(_('Migration failed: {{error}}', { error: error || 'Unknown error' })); + setMigrationStatus('error'); + } + }; + + const handleClose = () => { + if (migrationStatus === 'migrating') { + return; + } + setIsOpen(false); + setNewDataDir(''); + setMigrationStatus('idle'); + setErrorMessage(''); + setMigrationProgress({ current: 0, total: 0 }); + }; + + const handleRestartApp = () => { + relaunch(); + }; + + const handleRevealDir = (dataDir: string) => { + if (dataDir) { + revealItemInDir(dataDir); + } + }; + + const progressPercentage = + migrationProgress.total > 0 + ? Math.round((migrationProgress.current / migrationProgress.total) * 100) + : 0; + + const canStartMigration = + newDataDir && newDataDir !== currentDataDir && migrationStatus === 'idle'; + + const osPlatform = getOSPlatform(); + const fileRevealLabel = + FILE_REVEAL_LABELS[osPlatform as FILE_REVEAL_PLATFORMS] || FILE_REVEAL_LABELS.default; + + return ( + + {isOpen && ( +
+ {/* Current Data Directory */} +
+

+ {_('Current Data Location')} +

+ + {currentDirFileCount ? ( +
+

+ {_('File count: {{size}}', { size: currentDirFileCount })} +

+

+ {_('Total size: {{size}}', { size: formatBytes(currentDirFileSize) })} +

+
+ ) : ( +

{_('Calculating file info...')}

+ )} +
+ + {/* New Data Directory Selection */} +
+

{_('New Data Location')}

+ + {newDataDir && ( + + )} + + +
+ + {/* Migration Progress */} + {migrationStatus === 'migrating' && ( +
+
+ + + {_('Migrating data...')} + + {progressPercentage}% +
+ +
+
+
+ + {migrationProgress.currentFile && ( +

+ {_('Copying: {{file}}', { file: migrationProgress.currentFile })} +

+ )} + +

+ {_('{{current}} of {{total}} files', { + current: migrationProgress.current.toLocaleString(), + total: migrationProgress.total.toLocaleString(), + })} +

+
+ )} + + {/* Success State */} + {migrationStatus === 'completed' && ( +
+
+ + {_('Migration completed successfully!')} +
+
+

+ {_( + 'Your data has been moved to the new location. Please restart the application to complete the process.', + )} +

+
+
+ )} + + {/* Error State */} + {migrationStatus === 'error' && errorMessage && ( +
+
+ + {_('Migration failed')} +
+
+

{errorMessage}

+
+
+ )} + + {/* Warning */} + {canStartMigration && ( +
+
+ +
+

{_('Important Notice')}

+

+ {_( + 'This will move all your app data to the new location. Make sure the destination has enough free space.', + )} +

+
+
+
+ )} + + {/* Action Buttons */} +
+ {migrationStatus === 'completed' ? ( + <> + + + + ) : ( + <> + + + + )} +
+
+ )} +
+ ); +}; diff --git a/apps/readest-app/src/app/library/components/SettingsMenu.tsx b/apps/readest-app/src/app/library/components/SettingsMenu.tsx index 00860e26..4863a2d8 100644 --- a/apps/readest-app/src/app/library/components/SettingsMenu.tsx +++ b/apps/readest-app/src/app/library/components/SettingsMenu.tsx @@ -6,7 +6,6 @@ import { PiUserCircleCheck } from 'react-icons/pi'; import { TbSunMoon } from 'react-icons/tb'; import { BiMoon, BiSun } from 'react-icons/bi'; -import { setAboutDialogVisible } from '@/components/AboutWindow'; import { isTauriAppPlatform, isWebAppPlatform } from '@/services/environment'; import { DOWNLOAD_READEST_URL } from '@/services/constants'; import { useAuth } from '@/context/AuthContext'; @@ -19,6 +18,8 @@ import { useResponsiveSize } from '@/hooks/useResponsiveSize'; import { navigateToLogin, navigateToProfile } from '@/utils/nav'; import { tauriHandleSetAlwaysOnTop, tauriHandleToggleFullScreen } from '@/utils/window'; import { optInTelemetry, optOutTelemetry } from '@/utils/telemetry'; +import { setAboutDialogVisible } from '@/components/AboutWindow'; +import { setMigrateDataDirDialogVisible } from '@/app/library/components/MigrateDataWindow'; import UserAvatar from '@/components/UserAvatar'; import MenuItem from '@/components/MenuItem'; import Quota from '@/components/Quota'; @@ -162,6 +163,11 @@ const SettingsMenu: React.FC = ({ setIsDropdownOpen }) => { setIsDropdownOpen?.(false); }; + const handleSetRootDir = () => { + setMigrateDataDirDialogVisible(true); + setIsDropdownOpen?.(false); + }; + const avatarUrl = user?.user_metadata?.['picture'] || user?.user_metadata?.['avatar_url']; const userFullName = user?.user_metadata?.['full_name']; const userDisplayName = userFullName ? userFullName.split(' ')[0] : null; @@ -262,6 +268,16 @@ const SettingsMenu: React.FC = ({ setIsDropdownOpen }) => { Icon={themeMode === 'dark' ? BiMoon : themeMode === 'light' ? BiSun : TbSunMoon} onClick={cycleThemeMode} /> + {appService?.isDesktopApp && !appService?.isPortableApp && ( + <> + + +
    + +
+
+ + )} {user && userPlan === 'free' && !appService?.isIOSApp && ( diff --git a/apps/readest-app/src/app/library/page.tsx b/apps/readest-app/src/app/library/page.tsx index eac8e871..79b377c8 100644 --- a/apps/readest-app/src/app/library/page.tsx +++ b/apps/readest-app/src/app/library/page.tsx @@ -43,10 +43,11 @@ import { tauriQuitApp, } from '@/utils/window'; -import { AboutWindow } from '@/components/AboutWindow'; -import { UpdaterWindow } from '@/components/UpdaterWindow'; import { BookMetadata } from '@/libs/document'; +import { AboutWindow } from '@/components/AboutWindow'; import { BookDetailModal } from '@/components/metadata'; +import { UpdaterWindow } from '@/components/UpdaterWindow'; +import { MigrateDataWindow } from './components/MigrateDataWindow'; import { Toast } from '@/components/Toast'; import Spinner from '@/components/Spinner'; import LibraryHeader from './components/LibraryHeader'; @@ -729,6 +730,7 @@ const LibraryPageContent = ({ searchParams }: { searchParams: ReadonlyURLSearchP )} + ); diff --git a/apps/readest-app/src/components/metadata/BookDetailView.tsx b/apps/readest-app/src/components/metadata/BookDetailView.tsx index 4dc3aabd..fc7b729a 100644 --- a/apps/readest-app/src/components/metadata/BookDetailView.tsx +++ b/apps/readest-app/src/components/metadata/BookDetailView.tsx @@ -13,7 +13,7 @@ import { useTranslation } from '@/hooks/useTranslation'; import { formatAuthors, formatDate, - formatFileSize, + formatBytes, formatLanguage, formatPublisher, formatTitle, @@ -158,9 +158,7 @@ const BookDetailView: React.FC = ({
{_('File Size')} -

- {formatFileSize(fileSize) || _('Unknown')} -

+

{formatBytes(fileSize) || _('Unknown')}

diff --git a/apps/readest-app/src/services/appService.ts b/apps/readest-app/src/services/appService.ts index 48eee5a3..0c880214 100644 --- a/apps/readest-app/src/services/appService.ts +++ b/apps/readest-app/src/services/appService.ts @@ -1,6 +1,13 @@ import { v4 as uuidv4 } from 'uuid'; import { SystemSettings } from '@/types/settings'; -import { AppPlatform, AppService, OsPlatform, ResolvedPath } from '@/types/system'; +import { + AppPlatform, + AppService, + FileItem, + OsPlatform, + ResolvedPath, + SelectDirectoryMode, +} from '@/types/system'; import { FileSystem, BaseDir, DeleteAction } from '@/types/system'; import { Book, @@ -68,6 +75,7 @@ export abstract class BaseAppService implements AppService { isIOSApp = false; isMobileApp = false; isPortableApp = false; + isDesktopApp = false; hasTrafficLight = false; hasWindow = false; hasWindowBar = false; @@ -83,10 +91,12 @@ export abstract class BaseAppService implements AppService { protected abstract fs: FileSystem; protected abstract resolvePath(fp: string, base: BaseDir): ResolvedPath; - abstract selectDirectory(): Promise; + abstract init(): Promise; + abstract setCustomRootDir(customRootDir: string): Promise; + abstract selectDirectory(mode: SelectDirectoryMode): Promise; abstract selectFiles(name: string, extensions: string[]): Promise; - async init() { + async prepareBooksDir() { this.localBooksDir = await this.fs.getPrefix('Books'); } @@ -94,9 +104,29 @@ export abstract class BaseAppService implements AppService { return await this.fs.openFile(path, base); } + async copyFile(srcPath: string, dstPath: string, base: BaseDir): Promise { + return await this.fs.copyFile(srcPath, dstPath, base); + } + + async createDir(path: string, base: BaseDir, recursive: boolean = true): Promise { + return await this.fs.createDir(path, base, recursive); + } + + async deleteFile(path: string, base: BaseDir): Promise { + return await this.fs.removeFile(path, base); + } + + async deleteDir(path: string, base: BaseDir, recursive: boolean = true): Promise { + return await this.fs.removeDir(path, base, recursive); + } + async resolveFilePath(path: string, base: BaseDir): Promise { const prefix = await this.fs.getPrefix(base); - return `${prefix}/${path}`; + return path ? `${prefix}/${path}` : prefix; + } + + async readDirectory(path: string, base: BaseDir): Promise { + return await this.fs.readDir(path, base); } getCoverImageUrl = (book: Book): string => { diff --git a/apps/readest-app/src/services/constants.ts b/apps/readest-app/src/services/constants.ts index 1c059a1d..67c22f62 100644 --- a/apps/readest-app/src/services/constants.ts +++ b/apps/readest-app/src/services/constants.ts @@ -15,10 +15,10 @@ import { UserStorageQuota, UserDailyTranslationQuota } from '@/types/user'; import { getDefaultMaxBlockSize, getDefaultMaxInlineSize } from '@/utils/config'; import { stubTranslation as _ } from '@/utils/misc'; -export const LOCAL_BOOKS_SUBDIR = 'Readest/Books'; -export const CLOUD_BOOKS_SUBDIR = 'Readest/Books'; -export const LOCAL_FONTS_SUBDIR = 'Readest/Fonts'; -export const LOCAL_DATA_SUBDIR = 'Readest/Data'; +export const DATA_SUBDIR = 'Readest'; +export const LOCAL_BOOKS_SUBDIR = `${DATA_SUBDIR}/Books`; +export const CLOUD_BOOKS_SUBDIR = `${DATA_SUBDIR}/Books`; +export const LOCAL_FONTS_SUBDIR = `${DATA_SUBDIR}/Fonts`; export const SETTINGS_FILENAME = 'settings.json'; diff --git a/apps/readest-app/src/services/nativeAppService.ts b/apps/readest-app/src/services/nativeAppService.ts index 56171d52..5f89b921 100644 --- a/apps/readest-app/src/services/nativeAppService.ts +++ b/apps/readest-app/src/services/nativeAppService.ts @@ -8,8 +8,10 @@ import { readDir, remove, copyFile, + stat, BaseDirectory, WriteFileOptions, + DirEntry, } from '@tauri-apps/plugin-fs'; import { invoke, convertFileSrc } from '@tauri-apps/api/core'; import { open as openDialog } from '@tauri-apps/plugin-dialog'; @@ -24,7 +26,7 @@ import { } from '@tauri-apps/api/path'; import { type as osType } from '@tauri-apps/plugin-os'; -import { FileSystem, BaseDir, AppPlatform, ResolvedPath } from '@/types/system'; +import { FileSystem, BaseDir, AppPlatform, ResolvedPath, FileItem } from '@/types/system'; import { getOSPlatform, isContentURI, isValidURL } from '@/utils/misc'; import { getDirPath, getFilename } from '@/utils/path'; import { NativeFile, RemoteFile } from '@/utils/file'; @@ -32,8 +34,8 @@ import { copyURIToPath } from '@/utils/bridge'; import { BaseAppService } from './appService'; import { + DATA_SUBDIR, LOCAL_BOOKS_SUBDIR, - LOCAL_DATA_SUBDIR, LOCAL_FONTS_SUBDIR, SETTINGS_FILENAME, } from './constants'; @@ -67,8 +69,10 @@ const getPathResolver = ({ const isCustomBaseDir = Boolean(customRootDir); const getCustomBasePrefixSync = isCustomBaseDir ? (baseDir: BaseDir) => { - return () => - `${customRootDir}/${['Settings', 'Data', 'Books', 'Fonts'].includes(baseDir) ? '' : baseDir}`; + return () => { + const leafDir = ['Settings', 'Data', 'Books', 'Fonts'].includes(baseDir) ? '' : baseDir; + return leafDir ? `${customRootDir}/${leafDir}` : customRootDir!; + }; } : undefined; @@ -84,7 +88,7 @@ const getPathResolver = ({ return { baseDir: isPortable ? 0 : BaseDirectory.AppConfig, basePrefix: isPortable && execDir ? async () => execDir : appConfigDir, - fp: isPortable && execDir ? `${execDir}/${path}` : path, + fp: isPortable && execDir ? `${execDir}${path ? `/${path}` : ''}` : path, base, }; case 'Cache': @@ -98,7 +102,7 @@ const getPathResolver = ({ return { baseDir: isCustomBaseDir ? 0 : BaseDirectory.AppLog, basePrefix: customBasePrefix ?? appLogDir, - fp: customBasePrefixSync ? `${customBasePrefixSync()}/${path}` : path, + fp: customBasePrefixSync ? `${customBasePrefixSync()}${path ? `/${path}` : ''}` : path, base, }; case 'Data': @@ -106,8 +110,8 @@ const getPathResolver = ({ baseDir: customBaseDir ?? BaseDirectory.AppData, basePrefix: customBasePrefix ?? appDataDir, fp: customBasePrefixSync - ? `${customBasePrefixSync()}/${LOCAL_DATA_SUBDIR}/${path}` - : `${LOCAL_DATA_SUBDIR}/${path}`, + ? `${customBasePrefixSync()}/${DATA_SUBDIR}${path ? `/${path}` : ''}` + : `${DATA_SUBDIR}${path ? `/${path}` : ''}`, base, }; case 'Books': @@ -115,8 +119,8 @@ const getPathResolver = ({ baseDir: customBaseDir ?? BaseDirectory.AppData, basePrefix: customBasePrefix || appDataDir, fp: customBasePrefixSync - ? `${customBasePrefixSync()}/${LOCAL_BOOKS_SUBDIR}/${path}` - : `${LOCAL_BOOKS_SUBDIR}/${path}`, + ? `${customBasePrefixSync()}/${LOCAL_BOOKS_SUBDIR}${path ? `/${path}` : ''}` + : `${LOCAL_BOOKS_SUBDIR}${path ? `/${path}` : ''}`, base, }; case 'Fonts': @@ -124,8 +128,8 @@ const getPathResolver = ({ baseDir: customBaseDir ?? BaseDirectory.AppData, basePrefix: customBasePrefix || appDataDir, fp: customBasePrefixSync - ? `${customBasePrefixSync()}/${LOCAL_FONTS_SUBDIR}/${path}` - : `${LOCAL_FONTS_SUBDIR}/${path}`, + ? `${customBasePrefixSync()}/${LOCAL_FONTS_SUBDIR}${path ? `/${path}` : ''}` + : `${LOCAL_FONTS_SUBDIR}${path ? `/${path}` : ''}`, base, }; case 'None': @@ -152,7 +156,8 @@ export const nativeFileSystem: FileSystem = { async getPrefix(base: BaseDir) { const { basePrefix, fp, baseDir } = this.resolvePath('', base); - const basePath = await basePrefix(); + let basePath = await basePrefix(); + basePath = basePath.replace(/\/+$/, ''); return fp ? (baseDir === 0 ? fp : await join(basePath, fp)) : basePath; }, getURL(path: string) { @@ -200,6 +205,9 @@ export const nativeFileSystem: FileSystem = { } }, async copyFile(srcPath: string, dstPath: string, base: BaseDir) { + if (!(await this.exists(getDirPath(dstPath), base))) { + await this.createDir(getDirPath(dstPath), base, true); + } if (isContentURI(srcPath)) { const prefix = await this.getPrefix(base); if (!prefix) { @@ -264,13 +272,37 @@ export const nativeFileSystem: FileSystem = { async readDir(path: string, base: BaseDir) { const { fp, baseDir } = this.resolvePath(path, base); - const list = await readDir(fp, baseDir ? { baseDir } : undefined); - return list.map((entity) => { - return { - path: entity.name, - isDir: entity.isDirectory, - }; - }); + const entries = await readDir(fp, baseDir ? { baseDir } : undefined); + const fileList: FileItem[] = []; + const readDirRecursively = async ( + parent: string, + relative: string, + entries: DirEntry[], + fileList: FileItem[], + ) => { + for (const entry of entries) { + if (entry.isDirectory) { + const dir = await join(parent, entry.name); + const relativeDir = relative ? await join(relative, entry.name) : entry.name; + await readDirRecursively( + dir, + relativeDir, + await readDir(dir, baseDir ? { baseDir } : undefined), + fileList, + ); + } else { + const filePath = await join(parent, entry.name); + const relativePath = relative ? await join(relative, entry.name) : entry.name; + const fileInfo = await stat(filePath, baseDir ? { baseDir } : undefined); + fileList.push({ + path: relativePath, + size: fileInfo.size, + }); + } + } + }; + await readDirRecursively(path, '', entries, fileList); + return fileList; }, async exists(path: string, base: BaseDir) { const { fp, baseDir } = this.resolvePath(path, base); @@ -294,6 +326,7 @@ export class NativeAppService extends BaseAppService { override isMacOSApp = OS_TYPE === 'macos'; override isLinuxApp = OS_TYPE === 'linux'; override isMobileApp = ['android', 'ios'].includes(OS_TYPE); + override isDesktopApp = ['macos', 'windows', 'linux'].includes(OS_TYPE); override hasTrafficLight = OS_TYPE === 'macos'; override hasWindow = !(OS_TYPE === 'ios' || OS_TYPE === 'android'); override hasWindowBar = !(OS_TYPE === 'ios' || OS_TYPE === 'android'); @@ -310,9 +343,11 @@ export class NativeAppService extends BaseAppService { (OS_TYPE === 'ios' && getOSPlatform() === 'ios') || OS_TYPE === 'android'; override canCustomRootDir = OS_TYPE !== 'ios'; override distChannel = process.env['NEXT_PUBLIC_DIST_CHANNEL'] || 'readest'; + private execDir?: string = undefined; override async init() { const execDir = await invoke('get_executable_dir'); + this.execDir = execDir; if ( process.env['NEXT_PUBLIC_PORTABLE_APP'] || (await this.fs.exists(`${execDir}/${SETTINGS_FILENAME}`, 'None')) @@ -332,13 +367,22 @@ export class NativeAppService extends BaseAppService { execDir, }); } - await super.init(); + await this.prepareBooksDir(); } override resolvePath(fp: string, base: BaseDir): ResolvedPath { return this.fs.resolvePath(fp, base); } + async setCustomRootDir(customRootDir: string) { + this.fs.resolvePath = getPathResolver({ + customRootDir, + isPortable: this.isPortableApp, + execDir: this.execDir, + }); + await this.prepareBooksDir(); + } + async selectDirectory(): Promise { const selected = await openDialog({ directory: true, diff --git a/apps/readest-app/src/services/webAppService.ts b/apps/readest-app/src/services/webAppService.ts index 72e5b210..4bd704c6 100644 --- a/apps/readest-app/src/services/webAppService.ts +++ b/apps/readest-app/src/services/webAppService.ts @@ -1,16 +1,16 @@ -import { FileSystem, BaseDir, AppPlatform, ResolvedPath } from '@/types/system'; +import { FileSystem, BaseDir, AppPlatform, ResolvedPath, FileItem } from '@/types/system'; import { getOSPlatform, isValidURL } from '@/utils/misc'; import { RemoteFile } from '@/utils/file'; import { isPWA } from './environment'; import { BaseAppService } from './appService'; -import { LOCAL_BOOKS_SUBDIR, LOCAL_DATA_SUBDIR, LOCAL_FONTS_SUBDIR } from './constants'; +import { DATA_SUBDIR, LOCAL_BOOKS_SUBDIR, LOCAL_FONTS_SUBDIR } from './constants'; const basePrefix = async () => ''; const resolvePath = (path: string, base: BaseDir): ResolvedPath => { switch (base) { case 'Data': - return { baseDir: 0, basePrefix, fp: `${LOCAL_DATA_SUBDIR}/${path}`, base }; + return { baseDir: 0, basePrefix, fp: `${DATA_SUBDIR}/${path}`, base }; case 'Books': return { baseDir: 0, basePrefix, fp: `${LOCAL_BOOKS_SUBDIR}/${path}`, base }; case 'Fonts': @@ -168,17 +168,27 @@ const indexedDBFileSystem: FileSystem = { const { fp } = this.resolvePath(path, base); const db = await openIndexedDB(); - return new Promise<{ path: string; isDir: boolean }[]>((resolve, reject) => { + return new Promise((resolve, reject) => { const transaction = db.transaction('files', 'readonly'); const store = transaction.objectStore('files'); const request = store.getAll(); request.onsuccess = () => { - const files = request.result as { path: string }[]; + const files = request.result as { path: string; content: string | ArrayBuffer | Blob }[]; resolve( files .filter((file) => file.path.startsWith(fp)) - .map((file) => ({ path: file.path.slice(fp.length + 1), isDir: false })), + .map((file) => ({ + path: file.path.slice(fp.length + 1), + size: + file.content instanceof Blob + ? file.content.size + : typeof file.content === 'string' + ? file.content.length + : file.content instanceof ArrayBuffer + ? file.content.byteLength + : 0, + })), ); }; @@ -208,13 +218,17 @@ export class WebAppService extends BaseAppService { override async init() { await this.loadSettings(); - await super.init(); + await this.prepareBooksDir(); } override resolvePath(fp: string, base: BaseDir): ResolvedPath { return this.fs.resolvePath(fp, base); } + async setCustomRootDir() { + // No-op in web environment + } + async selectDirectory(): Promise { throw new Error('selectDirectory is not supported in browser'); } diff --git a/apps/readest-app/src/types/system.ts b/apps/readest-app/src/types/system.ts index 43f40629..6e5a5cc4 100644 --- a/apps/readest-app/src/types/system.ts +++ b/apps/readest-app/src/types/system.ts @@ -8,6 +8,7 @@ export type AppPlatform = 'web' | 'tauri'; export type OsPlatform = 'android' | 'ios' | 'macos' | 'windows' | 'linux' | 'unknown'; export type BaseDir = 'Books' | 'Settings' | 'Data' | 'Fonts' | 'Log' | 'Cache' | 'Temp' | 'None'; export type DeleteAction = 'cloud' | 'local' | 'both'; +export type SelectDirectoryMode = 'read' | 'write'; export type ResolvedPath = { baseDir: number; @@ -16,6 +17,11 @@ export type ResolvedPath = { base: BaseDir; }; +export type FileItem = { + path: string; + size: number; +}; + export interface FileSystem { resolvePath(path: string, base: BaseDir): ResolvedPath; getURL(path: string): string; @@ -25,7 +31,7 @@ export interface FileSystem { readFile(path: string, base: BaseDir, mode: 'text' | 'binary'): Promise; writeFile(path: string, base: BaseDir, content: string | ArrayBuffer | File): Promise; removeFile(path: string, base: BaseDir): Promise; - readDir(path: string, base: BaseDir): Promise<{ path: string; isDir: boolean }[]>; + readDir(path: string, base: BaseDir): Promise; createDir(path: string, base: BaseDir, recursive?: boolean): Promise; removeDir(path: string, base: BaseDir, recursive?: boolean): Promise; exists(path: string, base: BaseDir): Promise; @@ -52,14 +58,22 @@ export interface AppService { isMacOSApp: boolean; isLinuxApp: boolean; isPortableApp: boolean; + isDesktopApp: boolean; distChannel: string; init(): Promise; openFile(path: string, base: BaseDir): Promise; + copyFile(srcPath: string, dstPath: string, base: BaseDir): Promise; + createDir(path: string, base: BaseDir, recursive?: boolean): Promise; + deleteFile(path: string, base: BaseDir): Promise; + deleteDir(path: string, base: BaseDir, recursive?: boolean): Promise; + + setCustomRootDir(customRootDir: string): Promise; resolveFilePath(path: string, base: BaseDir): Promise; getCachedImageUrl(pathOrUrl: string): Promise; - selectDirectory(): Promise; + selectDirectory(mode: SelectDirectoryMode): Promise; selectFiles(name: string, extensions: string[]): Promise; + readDirectory(path: string, base: BaseDir): Promise; getDefaultViewSettings(): ViewSettings; loadSettings(): Promise; diff --git a/apps/readest-app/src/utils/book.ts b/apps/readest-app/src/utils/book.ts index 525e6562..9a8c70bf 100644 --- a/apps/readest-app/src/utils/book.ts +++ b/apps/readest-app/src/utils/book.ts @@ -172,16 +172,18 @@ export const formatDate = (date: string | number | Date | null | undefined, isUT } }; -export const formatFileSize = (size: number | null) => { - if (size === null) return ''; - const formatter = new Intl.NumberFormat('en', { +export const formatBytes = (bytes?: number | null, locale = 'en-US') => { + if (!bytes) return ''; + const units = ['byte', 'kilobyte', 'megabyte', 'gigabyte', 'terabyte']; + const i = Math.floor(Math.log(bytes) / Math.log(1024)); + const value = bytes / Math.pow(1024, i); + const formatter = new Intl.NumberFormat(locale, { style: 'unit', - unit: 'byte', - unitDisplay: 'narrow', - notation: 'compact', - compactDisplay: 'short', + unit: units[i], + unitDisplay: 'short', + maximumFractionDigits: 2, }); - return formatter.format(size); + return formatter.format(value); }; export const getCurrentPage = (book: Book, progress: BookProgress) => {