diff --git a/lib/l10n/intl_ar.arb b/lib/l10n/intl_ar.arb index 70fa0fc97..3642fb278 100644 --- a/lib/l10n/intl_ar.arb +++ b/lib/l10n/intl_ar.arb @@ -1,6 +1,6 @@ { "@@locale": "ar", - "@@last_modified": "2026-01-20 12:31:24.671375", + "@@last_modified": "2026-01-21 10:42:52.513008", "about": "حول", "@about": { "type": "String", @@ -11107,5 +11107,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "صوت بوت بانجيا", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/l10n/intl_be.arb b/lib/l10n/intl_be.arb index d1ff0babf..f7593b805 100644 --- a/lib/l10n/intl_be.arb +++ b/lib/l10n/intl_be.arb @@ -1911,7 +1911,7 @@ "playWithAI": "Пакуль гуляйце з ШІ", "courseStartDesc": "Pangea Bot гатовы да працы ў любы час!\n\n...але навучанне лепш з сябрамі!", "@@locale": "be", - "@@last_modified": "2026-01-20 12:31:06.570011", + "@@last_modified": "2026-01-21 10:42:45.087111", "@alwaysUse24HourFormat": { "type": "String", "placeholders": {} @@ -11989,5 +11989,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "Голас Pangea Bot", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/l10n/intl_bn.arb b/lib/l10n/intl_bn.arb index 28c180422..451b639ab 100644 --- a/lib/l10n/intl_bn.arb +++ b/lib/l10n/intl_bn.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2026-01-20 12:31:49.464406", + "@@last_modified": "2026-01-21 10:43:01.204800", "about": "সম্পর্কে", "@about": { "type": "String", @@ -11994,5 +11994,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "প্যাঙ্গিয়া বটের কণ্ঠ", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/l10n/intl_bo.arb b/lib/l10n/intl_bo.arb index 800c24594..a87317500 100644 --- a/lib/l10n/intl_bo.arb +++ b/lib/l10n/intl_bo.arb @@ -4279,7 +4279,7 @@ "joinPublicTrip": "མི་ཚེས་ལ་ལོག་འབད།", "startOwnTrip": "ངེད་རང་གི་ལོག་ལ་སྦྱོར་བཅོས།", "@@locale": "bo", - "@@last_modified": "2026-01-20 12:31:44.969872", + "@@last_modified": "2026-01-21 10:42:59.058441", "@alwaysUse24HourFormat": { "type": "String", "placeholders": {} @@ -10644,5 +10644,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "Pangea Bot voz", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/l10n/intl_ca.arb b/lib/l10n/intl_ca.arb index 5eb437241..7c6d2d7fa 100644 --- a/lib/l10n/intl_ca.arb +++ b/lib/l10n/intl_ca.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2026-01-20 12:31:09.126351", + "@@last_modified": "2026-01-21 10:42:46.152113", "about": "Quant a", "@about": { "type": "String", @@ -10914,5 +10914,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "Veu del bot Pangea", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/l10n/intl_cs.arb b/lib/l10n/intl_cs.arb index 321734d12..fef398790 100644 --- a/lib/l10n/intl_cs.arb +++ b/lib/l10n/intl_cs.arb @@ -1,6 +1,6 @@ { "@@locale": "cs", - "@@last_modified": "2026-01-20 12:31:00.323945", + "@@last_modified": "2026-01-21 10:42:42.984636", "about": "O aplikaci", "@about": { "type": "String", @@ -11497,5 +11497,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "Hlas Pangea Bota", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/l10n/intl_da.arb b/lib/l10n/intl_da.arb index 372a6e7c8..46dbe3d2c 100644 --- a/lib/l10n/intl_da.arb +++ b/lib/l10n/intl_da.arb @@ -1930,7 +1930,7 @@ "playWithAI": "Leg med AI for nu", "courseStartDesc": "Pangea Bot er klar til at starte når som helst!\n\n...men læring er bedre med venner!", "@@locale": "da", - "@@last_modified": "2026-01-20 12:30:10.761209", + "@@last_modified": "2026-01-21 10:42:22.819549", "@aboutHomeserver": { "type": "String", "placeholders": { @@ -11951,5 +11951,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "Pangea Bot stemme", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/l10n/intl_de.arb b/lib/l10n/intl_de.arb index 634b76211..2f9214e0b 100644 --- a/lib/l10n/intl_de.arb +++ b/lib/l10n/intl_de.arb @@ -1,6 +1,6 @@ { "@@locale": "de", - "@@last_modified": "2026-01-20 12:30:47.434524", + "@@last_modified": "2026-01-21 10:42:37.466783", "alwaysUse24HourFormat": "true", "@alwaysUse24HourFormat": { "description": "Set to true to always display time of day in 24 hour format." @@ -10897,5 +10897,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "Pangea Bot Stimme", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/l10n/intl_el.arb b/lib/l10n/intl_el.arb index 176fb6f07..b90f11cdb 100644 --- a/lib/l10n/intl_el.arb +++ b/lib/l10n/intl_el.arb @@ -4456,7 +4456,7 @@ "playWithAI": "Παίξτε με την Τεχνητή Νοημοσύνη προς το παρόν", "courseStartDesc": "Ο Pangea Bot είναι έτοιμος να ξεκινήσει οποιαδήποτε στιγμή!\n\n...αλλά η μάθηση είναι καλύτερη με φίλους!", "@@locale": "el", - "@@last_modified": "2026-01-20 12:31:59.503296", + "@@last_modified": "2026-01-21 10:43:05.204211", "@alwaysUse24HourFormat": { "type": "String", "placeholders": {} @@ -11948,5 +11948,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "Φωνή Pangea Bot", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index abc4a3d63..e90dfca6b 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -5056,5 +5056,6 @@ "constructUseIncGEDesc": "Incorrect grammar error practice", "fillInBlank": "Fill in the blank with the correct choice", "learn": "Learn", - "languageUpdated": "Target language updated!" + "languageUpdated": "Target language updated!", + "voiceDropdownTitle": "Pangea Bot voice" } diff --git a/lib/l10n/intl_eo.arb b/lib/l10n/intl_eo.arb index 5914ed46b..942654f9f 100644 --- a/lib/l10n/intl_eo.arb +++ b/lib/l10n/intl_eo.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2026-01-20 12:32:07.490560", + "@@last_modified": "2026-01-21 10:43:08.060333", "about": "Prio", "@about": { "type": "String", @@ -11979,5 +11979,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "Voĉo de Pangea Bot", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/l10n/intl_es.arb b/lib/l10n/intl_es.arb index 144e71870..4e77d447b 100644 --- a/lib/l10n/intl_es.arb +++ b/lib/l10n/intl_es.arb @@ -1,6 +1,6 @@ { "@@locale": "es", - "@@last_modified": "2026-01-20 12:29:59.898184", + "@@last_modified": "2026-01-21 10:42:19.343875", "about": "Acerca de", "@about": { "type": "String", @@ -8124,5 +8124,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "Voz del bot Pangea", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/l10n/intl_et.arb b/lib/l10n/intl_et.arb index 5d4e3f6c2..30c19ef49 100644 --- a/lib/l10n/intl_et.arb +++ b/lib/l10n/intl_et.arb @@ -1,6 +1,6 @@ { "@@locale": "et", - "@@last_modified": "2026-01-20 12:30:45.162738", + "@@last_modified": "2026-01-21 10:42:36.742735", "about": "Rakenduse teave", "@about": { "type": "String", @@ -11161,5 +11161,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "Pangea Boti hääl", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/l10n/intl_eu.arb b/lib/l10n/intl_eu.arb index 225d963e7..d913d4db3 100644 --- a/lib/l10n/intl_eu.arb +++ b/lib/l10n/intl_eu.arb @@ -1,6 +1,6 @@ { "@@locale": "eu", - "@@last_modified": "2026-01-20 12:30:40.144354", + "@@last_modified": "2026-01-21 10:42:34.277635", "about": "Honi buruz", "@about": { "type": "String", @@ -10890,5 +10890,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "Pangea Bot ahotsa", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/l10n/intl_fa.arb b/lib/l10n/intl_fa.arb index 977dd42b8..6e395bb02 100644 --- a/lib/l10n/intl_fa.arb +++ b/lib/l10n/intl_fa.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2026-01-20 12:31:52.231221", + "@@last_modified": "2026-01-21 10:43:02.232868", "repeatPassword": "تکرار رمزعبور", "@repeatPassword": {}, "about": "درباره", @@ -11622,5 +11622,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "صدای ربات پانژیا", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/l10n/intl_fi.arb b/lib/l10n/intl_fi.arb index 6184adfec..707872200 100644 --- a/lib/l10n/intl_fi.arb +++ b/lib/l10n/intl_fi.arb @@ -4009,7 +4009,7 @@ "playWithAI": "Leiki tekoälyn kanssa nyt", "courseStartDesc": "Pangea Bot on valmis milloin tahansa!\n\n...mutta oppiminen on parempaa ystävien kanssa!", "@@locale": "fi", - "@@last_modified": "2026-01-20 12:30:08.099637", + "@@last_modified": "2026-01-21 10:42:21.857816", "@alwaysUse24HourFormat": { "type": "String", "placeholders": {} @@ -11513,5 +11513,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "Pangea Botin ääni", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/l10n/intl_fil.arb b/lib/l10n/intl_fil.arb index 986aa4015..a51993f5e 100644 --- a/lib/l10n/intl_fil.arb +++ b/lib/l10n/intl_fil.arb @@ -2787,7 +2787,7 @@ "selectAll": "Piliin lahat", "deselectAll": "Huwag piliin lahat", "@@locale": "fil", - "@@last_modified": "2026-01-20 12:31:19.884620", + "@@last_modified": "2026-01-21 10:42:50.349708", "@setCustomPermissionLevel": { "type": "String", "placeholders": {} @@ -11866,5 +11866,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "Boses ng Pangea Bot", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/l10n/intl_fr.arb b/lib/l10n/intl_fr.arb index c279297f0..58d082c74 100644 --- a/lib/l10n/intl_fr.arb +++ b/lib/l10n/intl_fr.arb @@ -1,6 +1,6 @@ { "@@locale": "fr", - "@@last_modified": "2026-01-20 12:32:20.398562", + "@@last_modified": "2026-01-21 10:43:12.775361", "about": "À propos", "@about": { "type": "String", @@ -11214,5 +11214,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "Voix du bot Pangea", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/l10n/intl_ga.arb b/lib/l10n/intl_ga.arb index c923a3bbd..b6e3263eb 100644 --- a/lib/l10n/intl_ga.arb +++ b/lib/l10n/intl_ga.arb @@ -4517,7 +4517,7 @@ "playWithAI": "Imir le AI faoi láthair", "courseStartDesc": "Tá Bot Pangea réidh chun dul am ar bith!\n\n...ach is fearr foghlaim le cairde!", "@@locale": "ga", - "@@last_modified": "2026-01-20 12:32:18.033824", + "@@last_modified": "2026-01-21 10:43:11.760663", "@customReaction": { "type": "String", "placeholders": {} @@ -10888,5 +10888,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "guth Pangea Bot", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/l10n/intl_gl.arb b/lib/l10n/intl_gl.arb index 3ebc2943d..28655e165 100644 --- a/lib/l10n/intl_gl.arb +++ b/lib/l10n/intl_gl.arb @@ -1,6 +1,6 @@ { "@@locale": "gl", - "@@last_modified": "2026-01-20 12:30:05.234280", + "@@last_modified": "2026-01-21 10:42:20.142432", "about": "Acerca de", "@about": { "type": "String", @@ -10887,5 +10887,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "Voz do bot Pangea", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/l10n/intl_he.arb b/lib/l10n/intl_he.arb index 7ad96af48..f36caa914 100644 --- a/lib/l10n/intl_he.arb +++ b/lib/l10n/intl_he.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2026-01-20 12:30:31.884050", + "@@last_modified": "2026-01-21 10:42:30.598205", "about": "אודות", "@about": { "type": "String", @@ -11939,5 +11939,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "קול של פנגיאה בוט", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/l10n/intl_hi.arb b/lib/l10n/intl_hi.arb index a465a07b2..611db19dd 100644 --- a/lib/l10n/intl_hi.arb +++ b/lib/l10n/intl_hi.arb @@ -4483,7 +4483,7 @@ "playWithAI": "अभी के लिए एआई के साथ खेलें", "courseStartDesc": "पैंजिया बॉट कभी भी जाने के लिए तैयार है!\n\n...लेकिन दोस्तों के साथ सीखना बेहतर है!", "@@locale": "hi", - "@@last_modified": "2026-01-20 12:32:05.240015", + "@@last_modified": "2026-01-21 10:43:07.054066", "@alwaysUse24HourFormat": { "type": "String", "placeholders": {} @@ -11975,5 +11975,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "पैंगिया बॉट की आवाज़", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/l10n/intl_hr.arb b/lib/l10n/intl_hr.arb index 64f6cccf8..17ea4d22e 100644 --- a/lib/l10n/intl_hr.arb +++ b/lib/l10n/intl_hr.arb @@ -1,6 +1,6 @@ { "@@locale": "hr", - "@@last_modified": "2026-01-20 12:30:29.823787", + "@@last_modified": "2026-01-21 10:42:29.581714", "about": "Informacije", "@about": { "type": "String", @@ -11262,5 +11262,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "Pangea Bot glas", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/l10n/intl_hu.arb b/lib/l10n/intl_hu.arb index 8d543fa7e..490d3b22f 100644 --- a/lib/l10n/intl_hu.arb +++ b/lib/l10n/intl_hu.arb @@ -1,6 +1,6 @@ { "@@locale": "hu", - "@@last_modified": "2026-01-20 12:30:13.762355", + "@@last_modified": "2026-01-21 10:42:24.298395", "about": "Névjegy", "@about": { "type": "String", @@ -10891,5 +10891,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "Pangea Bot hang", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/l10n/intl_ia.arb b/lib/l10n/intl_ia.arb index 4fda86d9e..54974eb51 100644 --- a/lib/l10n/intl_ia.arb +++ b/lib/l10n/intl_ia.arb @@ -1958,7 +1958,7 @@ "playWithAI": "Joca con le IA pro ora", "courseStartDesc": "Pangea Bot es preste a comenzar a qualunque momento!\n\n...ma apprender es melior con amicos!", "@@locale": "ia", - "@@last_modified": "2026-01-20 12:30:35.012898", + "@@last_modified": "2026-01-21 10:42:31.403920", "@alwaysUse24HourFormat": { "type": "String", "placeholders": {} @@ -11968,5 +11968,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "Voix du bot Pangea", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/l10n/intl_id.arb b/lib/l10n/intl_id.arb index 50917db2e..2d02858ce 100644 --- a/lib/l10n/intl_id.arb +++ b/lib/l10n/intl_id.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2026-01-20 12:30:15.788809", + "@@last_modified": "2026-01-21 10:42:25.871973", "setAsCanonicalAlias": "Atur sebagai alias utama", "@setAsCanonicalAlias": { "type": "String", @@ -10881,5 +10881,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "Suara Pangea Bot", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/l10n/intl_ie.arb b/lib/l10n/intl_ie.arb index 17b5245cf..caf59b6b4 100644 --- a/lib/l10n/intl_ie.arb +++ b/lib/l10n/intl_ie.arb @@ -4372,7 +4372,7 @@ "playWithAI": "Joca con AI pro ora", "courseStartDesc": "Pangea Bot es preste a partir a qualunque momento!\n\n...ma apprender es melior con amicos!", "@@locale": "ie", - "@@last_modified": "2026-01-20 12:30:26.700297", + "@@last_modified": "2026-01-21 10:42:28.431424", "@alwaysUse24HourFormat": { "type": "String", "placeholders": {} @@ -11864,5 +11864,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "Pangea Bot guth", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/l10n/intl_it.arb b/lib/l10n/intl_it.arb index 5c8d17791..9284e09b3 100644 --- a/lib/l10n/intl_it.arb +++ b/lib/l10n/intl_it.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2026-01-20 12:30:55.791406", + "@@last_modified": "2026-01-21 10:42:40.690823", "about": "Informazioni", "@about": { "type": "String", @@ -10893,5 +10893,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "Voce del bot Pangea", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/l10n/intl_ja.arb b/lib/l10n/intl_ja.arb index 30d520729..c83be27b4 100644 --- a/lib/l10n/intl_ja.arb +++ b/lib/l10n/intl_ja.arb @@ -1,6 +1,6 @@ { "@@locale": "ja", - "@@last_modified": "2026-01-20 12:32:02.883097", + "@@last_modified": "2026-01-21 10:43:06.128364", "about": "このアプリについて", "@about": { "type": "String", @@ -11680,5 +11680,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "パンゲアボットの声", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/l10n/intl_ka.arb b/lib/l10n/intl_ka.arb index 8026eff56..d8e600706 100644 --- a/lib/l10n/intl_ka.arb +++ b/lib/l10n/intl_ka.arb @@ -2594,7 +2594,7 @@ "playWithAI": "ამ დროისთვის ითამაშეთ AI-თან", "courseStartDesc": "Pangea Bot მზადაა ნებისმიერ დროს გასასვლელად!\n\n...მაგრამ სწავლა უკეთესია მეგობრებთან ერთად!", "@@locale": "ka", - "@@last_modified": "2026-01-20 12:32:12.611848", + "@@last_modified": "2026-01-21 10:43:09.701292", "@alwaysUse24HourFormat": { "type": "String", "placeholders": {} @@ -11920,5 +11920,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "პანჯეა ბოტის ხმა", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/l10n/intl_ko.arb b/lib/l10n/intl_ko.arb index f711d1304..ed5289391 100644 --- a/lib/l10n/intl_ko.arb +++ b/lib/l10n/intl_ko.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2026-01-20 12:29:56.840054", + "@@last_modified": "2026-01-21 10:42:17.603097", "about": "소개", "@about": { "type": "String", @@ -10998,5 +10998,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "판게아 봇 음성", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/l10n/intl_lt.arb b/lib/l10n/intl_lt.arb index 888944382..35ca44e54 100644 --- a/lib/l10n/intl_lt.arb +++ b/lib/l10n/intl_lt.arb @@ -3861,7 +3861,7 @@ "playWithAI": "Žaiskite su dirbtiniu intelektu dabar", "courseStartDesc": "Pangea botas pasiruošęs bet kada pradėti!\n\n...bet mokymasis yra geresnis su draugais!", "@@locale": "lt", - "@@last_modified": "2026-01-20 12:31:36.164653", + "@@last_modified": "2026-01-21 10:42:55.447627", "@alwaysUse24HourFormat": { "type": "String", "placeholders": {} @@ -11695,5 +11695,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "Pangea Bot balsas", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/l10n/intl_lv.arb b/lib/l10n/intl_lv.arb index 79a2fd834..64bbaf040 100644 --- a/lib/l10n/intl_lv.arb +++ b/lib/l10n/intl_lv.arb @@ -4482,7 +4482,7 @@ "playWithAI": "Tagad spēlējiet ar AI", "courseStartDesc": "Pangea bots ir gatavs jebkurā laikā!\n\n...bet mācīties ir labāk ar draugiem!", "@@locale": "lv", - "@@last_modified": "2026-01-20 12:31:22.453166", + "@@last_modified": "2026-01-21 10:42:51.147364", "analyticsInactiveTitle": "Pieprasījumi neaktīviem lietotājiem nevar tikt nosūtīti", "analyticsInactiveDesc": "Neaktīvi lietotāji, kuri nav pieteikušies kopš šīs funkcijas ieviešanas, neredzēs jūsu pieprasījumu.\n\nPieprasījuma poga parādīsies, kad viņi atgriezīsies. Jūs varat atkārtoti nosūtīt pieprasījumu vēlāk, noklikšķinot uz pieprasījuma pogas viņu vārdā, kad tā būs pieejama.", "accessRequestedTitle": "Pieprasījums piekļūt analītikai", @@ -10876,5 +10876,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "Pangea Bot balss", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/l10n/intl_nb.arb b/lib/l10n/intl_nb.arb index 8d8592bdb..5615f0550 100644 --- a/lib/l10n/intl_nb.arb +++ b/lib/l10n/intl_nb.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2026-01-20 12:31:02.821968", + "@@last_modified": "2026-01-21 10:42:43.891386", "about": "Om", "@about": { "type": "String", @@ -11983,5 +11983,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "Pangea Bot-stemme", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/l10n/intl_nl.arb b/lib/l10n/intl_nl.arb index 755841dc9..b021f9ad1 100644 --- a/lib/l10n/intl_nl.arb +++ b/lib/l10n/intl_nl.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2026-01-20 12:31:42.507524", + "@@last_modified": "2026-01-21 10:42:58.326124", "about": "Over ons", "@about": { "type": "String", @@ -10890,5 +10890,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "Pangea Bot stem", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/l10n/intl_pl.arb b/lib/l10n/intl_pl.arb index 48ebf5396..9e3d32b91 100644 --- a/lib/l10n/intl_pl.arb +++ b/lib/l10n/intl_pl.arb @@ -1,6 +1,6 @@ { "@@locale": "pl", - "@@last_modified": "2026-01-20 12:31:54.796841", + "@@last_modified": "2026-01-21 10:43:03.257336", "about": "O aplikacji", "@about": { "type": "String", @@ -10888,5 +10888,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "Głos bota Pangea", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/l10n/intl_pt.arb b/lib/l10n/intl_pt.arb index 1ac41d131..f80792528 100644 --- a/lib/l10n/intl_pt.arb +++ b/lib/l10n/intl_pt.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2026-01-20 12:30:42.601068", + "@@last_modified": "2026-01-21 10:42:35.392050", "copiedToClipboard": "Copiada para a área de transferência", "@copiedToClipboard": { "type": "String", @@ -11990,5 +11990,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "Voz do Bot Pangea", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/l10n/intl_pt_BR.arb b/lib/l10n/intl_pt_BR.arb index da1140756..933c9f8f3 100644 --- a/lib/l10n/intl_pt_BR.arb +++ b/lib/l10n/intl_pt_BR.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2026-01-20 12:30:37.380939", + "@@last_modified": "2026-01-21 10:42:32.545549", "about": "Sobre", "@about": { "type": "String", @@ -11248,5 +11248,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "Voz do Bot Pangea", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/l10n/intl_pt_PT.arb b/lib/l10n/intl_pt_PT.arb index c0a85355c..643c67fee 100644 --- a/lib/l10n/intl_pt_PT.arb +++ b/lib/l10n/intl_pt_PT.arb @@ -3331,7 +3331,7 @@ "selectAll": "Selecionar tudo", "deselectAll": "Desmarcar tudo", "@@locale": "pt_PT", - "@@last_modified": "2026-01-20 12:31:13.609297", + "@@last_modified": "2026-01-21 10:42:48.198355", "@alwaysUse24HourFormat": { "type": "String", "placeholders": {} @@ -11919,5 +11919,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "Voz do Bot Pangea", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/l10n/intl_ro.arb b/lib/l10n/intl_ro.arb index 5154c946d..7e868c193 100644 --- a/lib/l10n/intl_ro.arb +++ b/lib/l10n/intl_ro.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2026-01-20 12:30:21.408747", + "@@last_modified": "2026-01-21 10:42:26.609980", "about": "Despre", "@about": { "type": "String", @@ -11625,5 +11625,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "Vocea Pangea Bot", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/l10n/intl_ru.arb b/lib/l10n/intl_ru.arb index ca196e82b..e08d12d6e 100644 --- a/lib/l10n/intl_ru.arb +++ b/lib/l10n/intl_ru.arb @@ -1,6 +1,6 @@ { "@@locale": "ru", - "@@last_modified": "2026-01-20 12:32:09.850624", + "@@last_modified": "2026-01-21 10:43:08.936913", "about": "О проекте", "@about": { "type": "String", @@ -10995,5 +10995,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "Голос бота Pangea", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/l10n/intl_sk.arb b/lib/l10n/intl_sk.arb index ceb204959..26dd291f9 100644 --- a/lib/l10n/intl_sk.arb +++ b/lib/l10n/intl_sk.arb @@ -1,6 +1,6 @@ { "@@locale": "sk", - "@@last_modified": "2026-01-20 12:30:24.498564", + "@@last_modified": "2026-01-21 10:42:27.675920", "about": "O aplikácii", "@about": { "type": "String", @@ -11974,5 +11974,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "Hlas Pangea Bota", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/l10n/intl_sl.arb b/lib/l10n/intl_sl.arb index 9e4a1ff56..a9889e3a1 100644 --- a/lib/l10n/intl_sl.arb +++ b/lib/l10n/intl_sl.arb @@ -2464,7 +2464,7 @@ "playWithAI": "Za zdaj igrajte z AI-jem", "courseStartDesc": "Pangea Bot je pripravljen kadarkoli!\n\n...ampak je bolje učiti se s prijatelji!", "@@locale": "sl", - "@@last_modified": "2026-01-20 12:30:51.399294", + "@@last_modified": "2026-01-21 10:42:38.801732", "@alwaysUse24HourFormat": { "type": "String", "placeholders": {} @@ -11971,5 +11971,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "Glas Pangea Bota", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/l10n/intl_sr.arb b/lib/l10n/intl_sr.arb index fe98f2112..c32c01635 100644 --- a/lib/l10n/intl_sr.arb +++ b/lib/l10n/intl_sr.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2026-01-20 12:32:14.799697", + "@@last_modified": "2026-01-21 10:43:10.733270", "about": "О програму", "@about": { "type": "String", @@ -11992,5 +11992,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "Glas Pangea Bota", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/l10n/intl_sv.arb b/lib/l10n/intl_sv.arb index 1d9224f70..9bffc0e88 100644 --- a/lib/l10n/intl_sv.arb +++ b/lib/l10n/intl_sv.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2026-01-20 12:31:57.066428", + "@@last_modified": "2026-01-21 10:43:04.367889", "about": "Om", "@about": { "type": "String", @@ -11368,5 +11368,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "Pangea Bot röst", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/l10n/intl_ta.arb b/lib/l10n/intl_ta.arb index 42b73b4d5..5592467b6 100644 --- a/lib/l10n/intl_ta.arb +++ b/lib/l10n/intl_ta.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2026-01-20 12:31:40.562260", + "@@last_modified": "2026-01-21 10:42:57.399546", "acceptedTheInvitation": "👍 {username} அழைப்பை ஏற்றுக்கொண்டது", "@acceptedTheInvitation": { "type": "String", @@ -11114,5 +11114,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "பாஙேஆ பாட்டின் குரல்", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/l10n/intl_te.arb b/lib/l10n/intl_te.arb index 3043221dc..9e1e5fe94 100644 --- a/lib/l10n/intl_te.arb +++ b/lib/l10n/intl_te.arb @@ -1920,7 +1920,7 @@ "playWithAI": "ఇప్పుడే AI తో ఆడండి", "courseStartDesc": "పాంజియా బాట్ ఎప్పుడైనా సిద్ధంగా ఉంటుంది!\n\n...కానీ స్నేహితులతో నేర్చుకోవడం మెరుగైనది!", "@@locale": "te", - "@@last_modified": "2026-01-20 12:31:32.903548", + "@@last_modified": "2026-01-21 10:42:54.652537", "@setCustomPermissionLevel": { "type": "String", "placeholders": {} @@ -11979,5 +11979,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "పాంజియా బాట్ శబ్దం", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/l10n/intl_th.arb b/lib/l10n/intl_th.arb index ceb9ff50a..b07d69284 100644 --- a/lib/l10n/intl_th.arb +++ b/lib/l10n/intl_th.arb @@ -4456,7 +4456,7 @@ "playWithAI": "เล่นกับ AI ชั่วคราว", "courseStartDesc": "Pangea Bot พร้อมที่จะเริ่มต้นได้ทุกเมื่อ!\n\n...แต่การเรียนรู้ดีกว่ากับเพื่อน!", "@@locale": "th", - "@@last_modified": "2026-01-20 12:31:11.891533", + "@@last_modified": "2026-01-21 10:42:47.175182", "@alwaysUse24HourFormat": { "type": "String", "placeholders": {} @@ -11948,5 +11948,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "เสียงของ Pangea Bot", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/l10n/intl_tr.arb b/lib/l10n/intl_tr.arb index 8d86e681c..fe247f360 100644 --- a/lib/l10n/intl_tr.arb +++ b/lib/l10n/intl_tr.arb @@ -1,6 +1,6 @@ { "@@locale": "tr", - "@@last_modified": "2026-01-20 12:31:28.469826", + "@@last_modified": "2026-01-21 10:42:53.424381", "about": "Hakkında", "@about": { "type": "String", @@ -11112,5 +11112,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "Pangea Bot sesi", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/l10n/intl_uk.arb b/lib/l10n/intl_uk.arb index b8330d92c..7734ef4fe 100644 --- a/lib/l10n/intl_uk.arb +++ b/lib/l10n/intl_uk.arb @@ -1,6 +1,6 @@ { "@@locale": "uk", - "@@last_modified": "2026-01-20 12:30:57.869011", + "@@last_modified": "2026-01-21 10:42:41.558170", "about": "Про застосунок", "@about": { "type": "String", @@ -10884,5 +10884,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "Голос Pangea Bot", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/l10n/intl_vi.arb b/lib/l10n/intl_vi.arb index 69d334c03..0d9c741ab 100644 --- a/lib/l10n/intl_vi.arb +++ b/lib/l10n/intl_vi.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2026-01-20 12:31:38.101874", + "@@last_modified": "2026-01-21 10:42:56.498587", "about": "Giới thiệu", "@about": { "type": "String", @@ -6460,5 +6460,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "Giọng nói của Pangea Bot", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/l10n/intl_yue.arb b/lib/l10n/intl_yue.arb index 69867a6fc..15558c19a 100644 --- a/lib/l10n/intl_yue.arb +++ b/lib/l10n/intl_yue.arb @@ -1856,7 +1856,7 @@ "selectAll": "全選", "deselectAll": "取消全選", "@@locale": "yue", - "@@last_modified": "2026-01-20 12:30:53.854617", + "@@last_modified": "2026-01-21 10:42:39.595731", "@ignoreUser": { "type": "String", "placeholders": {} @@ -11981,5 +11981,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "Pangea Bot 聲音", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/l10n/intl_zh.arb b/lib/l10n/intl_zh.arb index 0953fb23e..e3b4d480b 100644 --- a/lib/l10n/intl_zh.arb +++ b/lib/l10n/intl_zh.arb @@ -1,6 +1,6 @@ { "@@locale": "zh", - "@@last_modified": "2026-01-20 12:31:47.017242", + "@@last_modified": "2026-01-21 10:43:00.180549", "about": "关于", "@about": { "type": "String", @@ -10881,5 +10881,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "潘吉亚机器人声音", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/l10n/intl_zh_Hant.arb b/lib/l10n/intl_zh_Hant.arb index 26f055262..3491a8f78 100644 --- a/lib/l10n/intl_zh_Hant.arb +++ b/lib/l10n/intl_zh_Hant.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2026-01-20 12:31:16.140892", + "@@last_modified": "2026-01-21 10:42:49.437032", "about": "關於", "@about": { "type": "String", @@ -10888,5 +10888,10 @@ "@languageUpdated": { "type": "String", "placeholders": {} + }, + "voiceDropdownTitle": "Pangea Bot 語音", + "@voiceDropdownTitle": { + "type": "String", + "placeholders": {} } } \ No newline at end of file diff --git a/lib/pages/chat/events/message.dart b/lib/pages/chat/events/message.dart index fe4f9bf1f..fc2ea9d32 100644 --- a/lib/pages/chat/events/message.dart +++ b/lib/pages/chat/events/message.dart @@ -13,8 +13,6 @@ import 'package:fluffychat/pages/chat/events/room_creation_state_event.dart'; import 'package:fluffychat/pangea/activity_sessions/activity_room_extension.dart'; import 'package:fluffychat/pangea/activity_sessions/activity_session_chat/activity_roles_event_widget.dart'; import 'package:fluffychat/pangea/activity_sessions/activity_summary_widget.dart'; -import 'package:fluffychat/pangea/bot/utils/bot_name.dart'; -import 'package:fluffychat/pangea/bot/widgets/bot_settings_language_icon.dart'; import 'package:fluffychat/pangea/chat/extensions/custom_room_display_extension.dart'; import 'package:fluffychat/pangea/common/widgets/pressable_button.dart'; import 'package:fluffychat/pangea/common/widgets/shimmer_background.dart'; @@ -477,18 +475,6 @@ class Message extends StatelessWidget { presenceBackgroundColor: wallpaperMode ? Colors.transparent : null, - // #Pangea - miniIcon: - user.id == BotName.byEnvironment - ? BotSettingsLanguageIcon( - user: user, - ) - : null, - presenceOffset: - user.id == BotName.byEnvironment - ? const Offset(0, 0) - : null, - // Pangea# ); }, ), diff --git a/lib/pangea/activity_sessions/activity_participant_indicator.dart b/lib/pangea/activity_sessions/activity_participant_indicator.dart index 58fd0403f..61370cec7 100644 --- a/lib/pangea/activity_sessions/activity_participant_indicator.dart +++ b/lib/pangea/activity_sessions/activity_participant_indicator.dart @@ -6,8 +6,6 @@ import 'package:shimmer/shimmer.dart'; import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/l10n/l10n.dart'; -import 'package:fluffychat/pangea/bot/utils/bot_name.dart'; -import 'package:fluffychat/pangea/bot/widgets/bot_settings_language_icon.dart'; import 'package:fluffychat/utils/string_color.dart'; import 'package:fluffychat/widgets/avatar.dart'; import 'package:fluffychat/widgets/hover_builder.dart'; @@ -70,14 +68,6 @@ class ActivityParticipantIndicator extends StatelessWidget { name: userId!.localpart, size: 60.0, userId: userId, - miniIcon: - room != null && userId == BotName.byEnvironment - ? BotSettingsLanguageIcon(user: user!) - : null, - presenceOffset: - room != null && userId == BotName.byEnvironment - ? const Offset(0, 0) - : null, ) : ClipRRect( borderRadius: BorderRadius.circular(30), diff --git a/lib/pangea/bot/widgets/bot_chat_settings_dialog.dart b/lib/pangea/bot/widgets/bot_chat_settings_dialog.dart deleted file mode 100644 index a748fdccc..000000000 --- a/lib/pangea/bot/widgets/bot_chat_settings_dialog.dart +++ /dev/null @@ -1,194 +0,0 @@ -import 'package:flutter/material.dart'; - -import 'package:dropdown_button2/dropdown_button2.dart'; -import 'package:matrix/matrix.dart'; - -import 'package:fluffychat/l10n/l10n.dart'; -import 'package:fluffychat/pangea/activity_sessions/activity_room_extension.dart'; -import 'package:fluffychat/pangea/bot/utils/bot_room_extension.dart'; -import 'package:fluffychat/pangea/chat_settings/models/bot_options_model.dart'; -import 'package:fluffychat/pangea/chat_settings/widgets/language_level_dropdown.dart'; -import 'package:fluffychat/pangea/common/utils/error_handler.dart'; -import 'package:fluffychat/pangea/common/widgets/dropdown_text_button.dart'; -import 'package:fluffychat/pangea/languages/language_model.dart'; -import 'package:fluffychat/pangea/languages/p_language_store.dart'; -import 'package:fluffychat/pangea/learning_settings/language_level_type_enum.dart'; -import 'package:fluffychat/pangea/learning_settings/p_language_dropdown.dart'; -import 'package:fluffychat/widgets/matrix.dart'; - -class BotChatSettingsDialog extends StatefulWidget { - final Room room; - - const BotChatSettingsDialog({ - required this.room, - super.key, - }); - - @override - BotChatSettingsDialogState createState() => BotChatSettingsDialogState(); -} - -class BotChatSettingsDialogState extends State { - LanguageModel? _selectedLang; - LanguageLevelTypeEnum? _selectedLevel; - String? _selectedVoice; - - @override - void initState() { - final botSettings = widget.room.botOptions; - final activityPlan = _isActivity ? widget.room.activityPlan : null; - - _selectedLevel = activityPlan?.req.cefrLevel ?? botSettings?.languageLevel; - _selectedVoice = botSettings?.targetVoice; - final lang = - activityPlan?.req.targetLanguage ?? botSettings?.targetLanguage; - if (lang != null) { - _selectedLang = PLanguageStore.byLangCode(lang); - } - super.initState(); - } - - bool get _isActivity => widget.room.isActivitySession; - - Future _setLanguage(LanguageModel? lang) async { - setState(() { - _selectedLang = lang; - _selectedVoice = null; - }); - - final model = widget.room.botOptions ?? BotOptionsModel(); - model.targetLanguage = lang?.langCode; - model.targetVoice = null; - - try { - await widget.room.setBotOptions(model); - } catch (e, s) { - ErrorHandler.logError( - e: e, - s: s, - data: { - 'roomId': widget.room.id, - 'langCode': lang?.langCode, - }, - ); - } - } - - Future _setLevel(LanguageLevelTypeEnum? level) async { - if (level == null) return; - - setState(() => _selectedLevel = level); - final model = widget.room.botOptions ?? BotOptionsModel(); - model.languageLevel = level; - try { - await widget.room.setBotOptions(model); - } catch (e, s) { - ErrorHandler.logError( - e: e, - s: s, - data: { - 'roomId': widget.room.id, - 'level': level.name, - }, - ); - } - } - - Future _setVoice(String? voice) async { - setState(() => _selectedVoice = voice); - final model = widget.room.botOptions ?? BotOptionsModel(); - model.targetVoice = voice; - try { - await widget.room.setBotOptions(model); - } catch (e, s) { - ErrorHandler.logError( - e: e, - s: s, - data: { - 'roomId': widget.room.id, - 'voice': voice, - }, - ); - } - } - - @override - Widget build(BuildContext context) { - return Material( - type: MaterialType.transparency, - child: Column( - spacing: 12.0, - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - if (widget.room.isActivitySession) - ListTile( - contentPadding: const EdgeInsets.all(0.0), - minLeadingWidth: 12.0, - leading: Icon( - Icons.info_outline, - size: 12.0, - color: Theme.of(context).disabledColor, - ), - title: Text( - L10n.of(context).activitySettingsOverrideWarning, - style: TextStyle( - color: Theme.of(context).disabledColor, - fontSize: 12.0, - ), - ), - ) - else - const SizedBox(), - PLanguageDropdown( - onChange: _setLanguage, - initialLanguage: _selectedLang, - languages: - MatrixState.pangeaController.pLanguageStore.targetOptions, - isL2List: true, - decorationText: L10n.of(context).targetLanguage, - enabled: !widget.room.isActivitySession, - ), - LanguageLevelDropdown( - initialLevel: _selectedLevel, - onChanged: _setLevel, - enabled: !widget.room.isActivitySession, - width: 300, - maxHeight: 300, - ), - DropdownButtonFormField2( - customButton: _selectedVoice != null - ? CustomDropdownTextButton(text: _selectedVoice!) - : null, - menuItemStyleData: const MenuItemStyleData( - padding: EdgeInsets.symmetric( - vertical: 8.0, - horizontal: 16.0, - ), - ), - decoration: InputDecoration( - labelText: L10n.of(context).voice, - ), - isExpanded: true, - dropdownStyleData: DropdownStyleData( - maxHeight: 250, - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.surfaceContainerHigh, - borderRadius: BorderRadius.circular(14.0), - ), - ), - items: (_selectedLang?.voices ?? []).map((voice) { - return DropdownMenuItem( - value: voice, - child: Text(voice), - ); - }).toList(), - onChanged: _setVoice, - value: _selectedVoice, - ), - const SizedBox(), - ], - ), - ); - } -} diff --git a/lib/pangea/bot/widgets/bot_settings_language_icon.dart b/lib/pangea/bot/widgets/bot_settings_language_icon.dart deleted file mode 100644 index 837bba59f..000000000 --- a/lib/pangea/bot/widgets/bot_settings_language_icon.dart +++ /dev/null @@ -1,57 +0,0 @@ -import 'package:flutter/material.dart'; - -import 'package:matrix/matrix.dart'; - -import 'package:fluffychat/pangea/activity_sessions/activity_room_extension.dart'; -import 'package:fluffychat/pangea/bot/utils/bot_room_extension.dart'; -import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart'; -import 'package:fluffychat/widgets/member_actions_popup_menu_button.dart'; - -class BotSettingsLanguageIcon extends StatelessWidget { - final User user; - - const BotSettingsLanguageIcon({ - super.key, - required this.user, - }); - - @override - Widget build(BuildContext context) { - final room = user.room; - String? langCode = room.botOptions?.targetLanguage; - if (room.isActivitySession && room.activityPlan != null) { - langCode = room.activityPlan!.req.targetLanguage; - } - if (langCode == null) { - return const SizedBox(); - } - - langCode = langCode.split('-').first; - return InkWell( - borderRadius: BorderRadius.circular(32.0), - onTap: room.isRoomAdmin - ? () => showMemberActionsPopupMenu( - context: context, - user: user, - room: room, - ) - : null, - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(16.0), - color: Theme.of(context).colorScheme.primaryContainer, - ), - padding: const EdgeInsets.symmetric(horizontal: 4.0), - child: Text( - langCode, - style: TextStyle( - fontSize: 10.0, - color: Theme.of(context).colorScheme.onPrimaryContainer, - fontWeight: FontWeight.bold, - ), - textAlign: TextAlign.center, - ), - ), - ); - } -} diff --git a/lib/pangea/chat_settings/models/bot_options_model.dart b/lib/pangea/chat_settings/models/bot_options_model.dart index 4108890d4..e21f141b9 100644 --- a/lib/pangea/chat_settings/models/bot_options_model.dart +++ b/lib/pangea/chat_settings/models/bot_options_model.dart @@ -8,23 +8,23 @@ import 'package:fluffychat/pangea/common/utils/error_handler.dart'; import 'package:fluffychat/pangea/learning_settings/language_level_type_enum.dart'; class BotOptionsModel { - LanguageLevelTypeEnum languageLevel; - String topic; - List keywords; - bool safetyModeration; - String mode; - String? discussionTopic; - String? discussionKeywords; - bool? discussionTriggerReactionEnabled; - String? discussionTriggerReactionKey; - String? customSystemPrompt; - bool? customTriggerReactionEnabled; - String? customTriggerReactionKey; - String? textAdventureGameMasterInstructions; - String? targetLanguage; - String? targetVoice; + final LanguageLevelTypeEnum languageLevel; + final String topic; + final List keywords; + final bool safetyModeration; + final String mode; + final String? discussionTopic; + final String? discussionKeywords; + final bool? discussionTriggerReactionEnabled; + final String? discussionTriggerReactionKey; + final String? customSystemPrompt; + final bool? customTriggerReactionEnabled; + final String? customTriggerReactionKey; + final String? textAdventureGameMasterInstructions; + final String? targetLanguage; + final String? targetVoice; - BotOptionsModel({ + const BotOptionsModel({ //////////////////////////////////////////////////////////////////////////// // General Bot Options //////////////////////////////////////////////////////////////////////////// @@ -133,50 +133,45 @@ class BotOptionsModel { } } - //TODO: define enum with all possible values - updateBotOption(String key, dynamic value) { - switch (key) { - case ModelKey.languageLevel: - languageLevel = value; - break; - case ModelKey.safetyModeration: - safetyModeration = value; - break; - case ModelKey.mode: - mode = value; - break; - case ModelKey.discussionTopic: - discussionTopic = value; - break; - case ModelKey.discussionKeywords: - discussionKeywords = value; - break; - case ModelKey.discussionTriggerReactionEnabled: - discussionTriggerReactionEnabled = value; - break; - case ModelKey.discussionTriggerReactionKey: - discussionTriggerReactionKey = value; - break; - case ModelKey.customSystemPrompt: - customSystemPrompt = value; - break; - case ModelKey.customTriggerReactionEnabled: - customTriggerReactionEnabled = value; - break; - case ModelKey.customTriggerReactionKey: - customTriggerReactionKey = value; - break; - case ModelKey.textAdventureGameMasterInstructions: - textAdventureGameMasterInstructions = value; - break; - case ModelKey.targetLanguage: - targetLanguage = value; - break; - case ModelKey.targetVoice: - targetVoice = value; - break; - default: - throw Exception('Invalid key for bot options - $key'); - } + BotOptionsModel copyWith({ + LanguageLevelTypeEnum? languageLevel, + String? topic, + List? keywords, + bool? safetyModeration, + String? mode, + String? discussionTopic, + String? discussionKeywords, + bool? discussionTriggerReactionEnabled, + String? discussionTriggerReactionKey, + String? customSystemPrompt, + bool? customTriggerReactionEnabled, + String? customTriggerReactionKey, + String? textAdventureGameMasterInstructions, + String? targetLanguage, + String? targetVoice, + }) { + return BotOptionsModel( + languageLevel: languageLevel ?? this.languageLevel, + topic: topic ?? this.topic, + keywords: keywords ?? this.keywords, + safetyModeration: safetyModeration ?? this.safetyModeration, + mode: mode ?? this.mode, + discussionTopic: discussionTopic ?? this.discussionTopic, + discussionKeywords: discussionKeywords ?? this.discussionKeywords, + discussionTriggerReactionEnabled: discussionTriggerReactionEnabled ?? + this.discussionTriggerReactionEnabled, + discussionTriggerReactionKey: + discussionTriggerReactionKey ?? this.discussionTriggerReactionKey, + customSystemPrompt: customSystemPrompt ?? this.customSystemPrompt, + customTriggerReactionEnabled: + customTriggerReactionEnabled ?? this.customTriggerReactionEnabled, + customTriggerReactionKey: + customTriggerReactionKey ?? this.customTriggerReactionKey, + textAdventureGameMasterInstructions: + textAdventureGameMasterInstructions ?? + this.textAdventureGameMasterInstructions, + targetLanguage: targetLanguage ?? this.targetLanguage, + targetVoice: targetVoice ?? this.targetVoice, + ); } } diff --git a/lib/pangea/chat_settings/utils/bot_client_extension.dart b/lib/pangea/chat_settings/utils/bot_client_extension.dart index 6fbb1c636..5021d19ed 100644 --- a/lib/pangea/chat_settings/utils/bot_client_extension.dart +++ b/lib/pangea/chat_settings/utils/bot_client_extension.dart @@ -7,23 +7,19 @@ import 'package:fluffychat/pangea/chat/constants/default_power_level.dart'; import 'package:fluffychat/pangea/chat_settings/constants/bot_mode.dart'; import 'package:fluffychat/pangea/chat_settings/models/bot_options_model.dart'; import 'package:fluffychat/pangea/events/constants/pangea_event_types.dart'; +import 'package:fluffychat/pangea/user/user_model.dart'; import 'package:fluffychat/widgets/matrix.dart'; extension BotClientExtension on Client { bool get hasBotDM => rooms.any((r) => r.isBotDM); + Room? get botDM => rooms.firstWhereOrNull((r) => r.isBotDM); - Room? get botDM => rooms.firstWhereOrNull( - (room) { - if (room.isDirectChat && - room.directChatMatrixID == BotName.byEnvironment) { - return true; - } - if (room.botOptions?.mode == BotMode.directChat) { - return true; - } - return false; - }, - ); + // All 2-member rooms with the bot + List get targetBotChats => rooms.where((r) { + if (r.isBotDM) return true; + if (r.summary.mJoinedMemberCount != 2) return false; + return r.getParticipants().any((u) => u.id == BotName.byEnvironment); + }).toList(); Future startChatWithBot() => startDirectChat( BotName.byEnvironment, @@ -45,27 +41,31 @@ extension BotClientExtension on Client { ], ); - Future updateBotOptions() async { - if (!isLogged() || botDM == null) return; + Future updateBotOptions(UserSettings userSettings) async { + final rooms = targetBotChats; + if (rooms.isEmpty) return; - final targetLanguage = - MatrixState.pangeaController.userController.userL2?.langCode; - final cefrLevel = MatrixState - .pangeaController.userController.profile.userSettings.cefrLevel; - final updateBotOptions = botDM!.botOptions ?? BotOptionsModel(); + final futures = []; + for (final room in rooms) { + final botOptions = room.botOptions ?? const BotOptionsModel(); + final targetLanguage = userSettings.targetLanguage; + final languageLevel = userSettings.cefrLevel; + final voice = userSettings.voice; - if (updateBotOptions.targetLanguage == targetLanguage && - updateBotOptions.languageLevel == cefrLevel) { - return; + if (botOptions.targetLanguage == targetLanguage && + botOptions.languageLevel == languageLevel && + botOptions.targetVoice == voice) { + continue; + } + + final updated = botOptions.copyWith( + targetLanguage: targetLanguage, + languageLevel: languageLevel, + targetVoice: voice, + ); + futures.add(room.setBotOptions(updated)); } - if (targetLanguage != null && - updateBotOptions.targetLanguage != targetLanguage) { - updateBotOptions.targetVoice = null; - } - - updateBotOptions.targetLanguage = targetLanguage; - updateBotOptions.languageLevel = cefrLevel; - await botDM!.setBotOptions(updateBotOptions); + await Future.wait(futures); } } diff --git a/lib/pangea/common/controllers/pangea_controller.dart b/lib/pangea/common/controllers/pangea_controller.dart index 5257753d3..e90d6d9a9 100644 --- a/lib/pangea/common/controllers/pangea_controller.dart +++ b/lib/pangea/common/controllers/pangea_controller.dart @@ -117,8 +117,9 @@ class PangeaController { userController.languageStream.stream.listen(_onLanguageUpdate); _settingsSubscription?.cancel(); - _settingsSubscription = userController.settingsUpdateStream.stream - .listen((_) => matrixState.client.updateBotOptions()); + _settingsSubscription = userController.settingsUpdateStream.stream.listen( + (update) => matrixState.client.updateBotOptions(update.userSettings), + ); _joinSpaceSubscription?.cancel(); _joinSpaceSubscription ??= matrixState.client.onSync.stream @@ -176,7 +177,7 @@ class PangeaController { } _clearCache(exclude: exclude); - matrixState.client.updateBotOptions(); + matrixState.client.updateBotOptions(userController.profile.userSettings); } static final List _storageKeys = [ diff --git a/lib/pangea/learning_settings/p_settings_switch_list_tile.dart b/lib/pangea/learning_settings/p_settings_switch_list_tile.dart index 188debae1..a0e928def 100644 --- a/lib/pangea/learning_settings/p_settings_switch_list_tile.dart +++ b/lib/pangea/learning_settings/p_settings_switch_list_tile.dart @@ -44,7 +44,6 @@ class PSettingsSwitchListTileState @override Widget build(BuildContext context) { return SwitchListTile.adaptive( - contentPadding: EdgeInsets.zero, value: currentValue, title: Text(widget.title), activeThumbColor: AppConfig.activeToggleColor, diff --git a/lib/pangea/learning_settings/settings_learning.dart b/lib/pangea/learning_settings/settings_learning.dart index f3e5f8765..d9bdcfa69 100644 --- a/lib/pangea/learning_settings/settings_learning.dart +++ b/lib/pangea/learning_settings/settings_learning.dart @@ -41,7 +41,6 @@ class SettingsLearningController extends State { PangeaController pangeaController = MatrixState.pangeaController; late Profile _profile; - final GlobalKey formKey = GlobalKey(); String? languageMatchError; final ScrollController scrollController = ScrollController(); @@ -110,18 +109,16 @@ class SettingsLearningController extends State { updateToolSetting(ToolSetting.enableTTS, false); } - if (formKey.currentState!.validate()) { - await showFutureLoadingDialog( - context: context, - future: () async => pangeaController.userController - .updateProfile( - (_) => _profile, - waitForDataInSync: true, - ) - .timeout(const Duration(seconds: 15)), - ); - Navigator.of(context).pop(); - } + await showFutureLoadingDialog( + context: context, + future: () async => pangeaController.userController + .updateProfile( + (_) => _profile, + waitForDataInSync: true, + ) + .timeout(const Duration(seconds: 15)), + ); + Navigator.of(context).pop(); } Future resetInstructionTooltips() async { @@ -153,11 +150,12 @@ class SettingsLearningController extends State { LanguageModel? sourceLanguage, LanguageModel? targetLanguage, }) async { - if (sourceLanguage != null) { + if (sourceLanguage != null && sourceLanguage != selectedSourceLanguage) { _profile.userSettings.sourceLanguage = sourceLanguage.langCode; } - if (targetLanguage != null) { + if (targetLanguage != null && targetLanguage != selectedTargetLanguage) { _profile.userSettings.targetLanguage = targetLanguage.langCode; + _profile.userSettings.voice = null; if (!_profile.toolSettings.enableTTS && isTTSSupported) { updateToolSetting(ToolSetting.enableTTS, true); } @@ -181,6 +179,11 @@ class SettingsLearningController extends State { if (mounted) setState(() {}); } + void setVoice(String? voice) { + _profile.userSettings.voice = voice; + if (mounted) setState(() {}); + } + void changeCountry(Country? country) { _profile.userSettings.country = country?.name; if (mounted) setState(() {}); @@ -343,6 +346,8 @@ class SettingsLearningController extends State { LanguageLevelTypeEnum get cefrLevel => _profile.userSettings.cefrLevel; + String? get selectedVoice => _profile.userSettings.voice; + Country? get country => CountryService().findByName(_profile.userSettings.country); diff --git a/lib/pangea/learning_settings/settings_learning_view.dart b/lib/pangea/learning_settings/settings_learning_view.dart index d6037fc87..1f11f2872 100644 --- a/lib/pangea/learning_settings/settings_learning_view.dart +++ b/lib/pangea/learning_settings/settings_learning_view.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; import 'package:fluffychat/config/app_config.dart'; -import 'package:fluffychat/config/themes.dart'; import 'package:fluffychat/l10n/l10n.dart'; import 'package:fluffychat/pangea/chat_settings/widgets/language_level_dropdown.dart'; import 'package:fluffychat/pangea/common/constants/model_keys.dart'; @@ -14,6 +13,7 @@ import 'package:fluffychat/pangea/learning_settings/p_language_dropdown.dart'; import 'package:fluffychat/pangea/learning_settings/p_settings_switch_list_tile.dart'; import 'package:fluffychat/pangea/learning_settings/settings_learning.dart'; import 'package:fluffychat/pangea/learning_settings/tool_settings_enum.dart'; +import 'package:fluffychat/pangea/learning_settings/voice_dropdown.dart'; import 'package:fluffychat/widgets/layouts/max_width_body.dart'; import 'package:fluffychat/widgets/matrix.dart'; @@ -45,21 +45,23 @@ class SettingsLearningView extends StatelessWidget { ) : null, ), - body: Form( - key: controller.formKey, - child: ListTileTheme( - iconColor: Theme.of(context).textTheme.bodyLarge!.color, - child: MaxWidthBody( - withScrolling: false, - child: Column( - children: [ - Expanded( - child: SingleChildScrollView( - controller: controller.scrollController, + body: ListTileTheme( + iconColor: Theme.of(context).textTheme.bodyLarge!.color, + child: MaxWidthBody( + withScrolling: false, + child: Column( + children: [ + Expanded( + child: SingleChildScrollView( + controller: controller.scrollController, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 32.0), child: Column( + spacing: 16.0, children: [ Padding( - padding: const EdgeInsets.all(16.0), + padding: + const EdgeInsets.symmetric(horizontal: 16.0), child: Column( spacing: 16.0, children: [ @@ -99,171 +101,112 @@ class SettingsLearningView extends StatelessWidget { .colorScheme .surfaceContainerHigh, ), - AnimatedSize( - duration: FluffyThemes.animationDuration, - curve: FluffyThemes.animationCurve, - child: controller.userL1?.langCodeShort == - controller.userL2?.langCodeShort - ? Padding( - padding: const EdgeInsets.symmetric( - horizontal: 16.0, + if (controller.userL1?.langCodeShort == + controller.userL2?.langCodeShort) + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 16.0, + ), + child: Row( + spacing: 8.0, + children: [ + Icon( + Icons.info_outlined, + color: Theme.of(context) + .colorScheme + .error, + ), + Flexible( + child: Text( + L10n.of(context) + .noIdenticalLanguages, + style: TextStyle( + color: Theme.of(context) + .colorScheme + .error, + ), ), - child: Row( - spacing: 8.0, - children: [ - Icon( - Icons.info_outlined, - color: Theme.of(context) - .colorScheme - .error, - ), - Flexible( - child: Text( - L10n.of(context) - .noIdenticalLanguages, - style: TextStyle( - color: Theme.of(context) - .colorScheme - .error, - ), - ), - ), - ], - ), - ) - : const SizedBox.shrink(), - ), - CountryPickerDropdown(controller), + ), + ], + ), + ), LanguageLevelDropdown( initialLevel: controller.cefrLevel, onChanged: controller.setCefrLevel, ), + VoiceDropdown( + value: controller.selectedVoice, + language: controller.selectedTargetLanguage, + onChanged: controller.setVoice, + ), + CountryPickerDropdown(controller), GenderDropdown( initialGender: controller.gender, onChanged: controller.setGender, ), - Container( - decoration: BoxDecoration( - border: Border.all( - color: Colors.white54, - ), - borderRadius: BorderRadius.circular(8.0), - ), - padding: const EdgeInsets.all(8.0), - child: Column( - children: [ - ProfileSettingsSwitchListTile.adaptive( - defaultValue: - controller.getToolSetting( - ToolSetting.autoIGC, - ), - title: ToolSetting.autoIGC - .toolName(context), - subtitle: ToolSetting.autoIGC - .toolDescription(context), - onChange: (bool value) => - controller.updateToolSetting( - ToolSetting.autoIGC, - value, - ), - enabled: true, - ), - ProfileSettingsSwitchListTile.adaptive( - defaultValue: - controller.getToolSetting( - ToolSetting.enableAutocorrect, - ), - title: ToolSetting.enableAutocorrect - .toolName(context), - subtitle: ToolSetting - .enableAutocorrect - .toolDescription(context), - onChange: (bool value) { - controller.updateToolSetting( - ToolSetting.enableAutocorrect, - value, - ); - if (value) { - controller - .showKeyboardSettingsDialog(); - } - }, - enabled: true, - ), - ], - ), - ), - for (final toolSetting - in ToolSetting.values.where( - (tool) => - tool.isAvailableSetting && - tool != ToolSetting.autoIGC && - tool != ToolSetting.enableAutocorrect, - )) - Column( - children: [ - ProfileSettingsSwitchListTile.adaptive( - defaultValue: controller - .getToolSetting(toolSetting), - title: toolSetting.toolName(context), - subtitle: toolSetting == - ToolSetting.enableTTS && - !controller.isTTSSupported - ? null - : toolSetting - .toolDescription(context), - onChange: (bool value) => - controller.updateToolSetting( - toolSetting, - value, - ), - ), - ], - ), - SwitchListTile.adaptive( - value: controller.publicProfile, - onChanged: controller.setPublicProfile, - title: Text( - L10n.of(context).publicProfileTitle, - ), - subtitle: Text( - L10n.of(context).publicProfileDesc, - ), - activeThumbColor: - AppConfig.activeToggleColor, - contentPadding: EdgeInsets.zero, - ), - ResetInstructionsListTile( - controller: controller, - ), ], ), ), + ...ToolSetting.values + .where( + (tool) => tool.isAvailableSetting, + ) + .map( + (toolSetting) => _ProfileSwitchTile( + value: + controller.getToolSetting(toolSetting), + setting: toolSetting, + onChanged: (v) { + controller.updateToolSetting( + toolSetting, + v, + ); + if (v && + toolSetting == + ToolSetting.enableTTS) { + controller.showKeyboardSettingsDialog(); + } + }, + ), + ), + SwitchListTile.adaptive( + value: controller.publicProfile, + onChanged: controller.setPublicProfile, + title: Text( + L10n.of(context).publicProfileTitle, + ), + subtitle: Text( + L10n.of(context).publicProfileDesc, + ), + activeThumbColor: AppConfig.activeToggleColor, + ), + ResetInstructionsListTile( + controller: controller, + ), ], ), ), ), - Padding( - padding: const EdgeInsets.all(16.0), - child: SizedBox( - width: double.infinity, - child: ElevatedButton( - onPressed: controller.haveSettingsBeenChanged - ? controller.submit - : null, - child: Text(L10n.of(context).saveChanges), - ), + ), + Padding( + padding: const EdgeInsets.all(16.0), + child: SizedBox( + width: double.infinity, + child: ElevatedButton( + onPressed: controller.haveSettingsBeenChanged + ? controller.submit + : null, + child: Text(L10n.of(context).saveChanges), ), ), - ], - ), + ), + ], ), ), ), ); if (!controller.widget.isDialog) return dialogContent; - return FullWidthDialog( dialogContent: dialogContent, maxWidth: 600, @@ -273,3 +216,25 @@ class SettingsLearningView extends StatelessWidget { ); } } + +class _ProfileSwitchTile extends StatelessWidget { + final bool value; + final ToolSetting setting; + final Function(bool) onChanged; + + const _ProfileSwitchTile({ + required this.value, + required this.setting, + required this.onChanged, + }); + + @override + Widget build(BuildContext context) { + return ProfileSettingsSwitchListTile.adaptive( + defaultValue: value, + title: setting.toolName(context), + subtitle: setting.toolDescription(context), + onChange: onChanged, + ); + } +} diff --git a/lib/pangea/learning_settings/voice_dropdown.dart b/lib/pangea/learning_settings/voice_dropdown.dart new file mode 100644 index 000000000..4c6b77133 --- /dev/null +++ b/lib/pangea/learning_settings/voice_dropdown.dart @@ -0,0 +1,53 @@ +import 'package:flutter/material.dart'; + +import 'package:dropdown_button2/dropdown_button2.dart'; + +import 'package:fluffychat/l10n/l10n.dart'; +import 'package:fluffychat/pangea/common/widgets/dropdown_text_button.dart'; +import 'package:fluffychat/pangea/languages/language_model.dart'; + +class VoiceDropdown extends StatelessWidget { + final String? value; + final LanguageModel? language; + final Function(String?) onChanged; + + const VoiceDropdown({ + super.key, + this.value, + this.language, + required this.onChanged, + }); + + @override + Widget build(BuildContext context) { + return DropdownButtonFormField2( + customButton: + value != null ? CustomDropdownTextButton(text: value!) : null, + menuItemStyleData: const MenuItemStyleData( + padding: EdgeInsets.symmetric( + vertical: 8.0, + horizontal: 16.0, + ), + ), + decoration: InputDecoration( + labelText: L10n.of(context).voiceDropdownTitle, + ), + isExpanded: true, + dropdownStyleData: DropdownStyleData( + maxHeight: 250, + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.surfaceContainerHigh, + borderRadius: BorderRadius.circular(14.0), + ), + ), + items: (language?.voices ?? []).map((voice) { + return DropdownMenuItem( + value: voice, + child: Text(voice), + ); + }).toList(), + onChanged: onChanged, + value: value, + ); + } +} diff --git a/lib/pangea/toolbar/message_practice/message_audio_card.dart b/lib/pangea/toolbar/message_practice/message_audio_card.dart index bf57035aa..6a3661b61 100644 --- a/lib/pangea/toolbar/message_practice/message_audio_card.dart +++ b/lib/pangea/toolbar/message_practice/message_audio_card.dart @@ -8,10 +8,10 @@ import 'package:matrix/matrix.dart'; import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/pages/chat/events/audio_player.dart'; import 'package:fluffychat/pangea/analytics_misc/text_loading_shimmer.dart'; -import 'package:fluffychat/pangea/bot/utils/bot_room_extension.dart'; import 'package:fluffychat/pangea/common/utils/error_handler.dart'; import 'package:fluffychat/pangea/events/event_wrappers/pangea_message_event.dart'; import 'package:fluffychat/pangea/text_to_speech/text_to_speech_response_model.dart'; +import 'package:fluffychat/widgets/matrix.dart'; class MessageAudioCard extends StatefulWidget { final PangeaMessageEvent messageEvent; @@ -44,7 +44,7 @@ class MessageAudioCardState extends State { try { audioFile = await widget.messageEvent.requestTextToSpeech( widget.messageEvent.messageDisplayLangCode, - widget.messageEvent.room.botOptions?.targetVoice, + MatrixState.pangeaController.userController.voice, ); debugPrint("audio file is now: $audioFile. setting starts and ends..."); if (mounted) setState(() => _isLoading = false); diff --git a/lib/pangea/toolbar/reading_assistance/select_mode_controller.dart b/lib/pangea/toolbar/reading_assistance/select_mode_controller.dart index a5f243674..f7abe6588 100644 --- a/lib/pangea/toolbar/reading_assistance/select_mode_controller.dart +++ b/lib/pangea/toolbar/reading_assistance/select_mode_controller.dart @@ -7,7 +7,6 @@ import 'package:matrix/matrix.dart'; import 'package:path_provider/path_provider.dart'; import 'package:fluffychat/pangea/analytics_misc/lemma_emoji_setter_mixin.dart'; -import 'package:fluffychat/pangea/bot/utils/bot_room_extension.dart'; import 'package:fluffychat/pangea/common/utils/async_state.dart'; import 'package:fluffychat/pangea/events/event_wrappers/pangea_message_event.dart'; import 'package:fluffychat/pangea/events/models/pangea_token_text_model.dart'; @@ -58,7 +57,7 @@ class _AudioLoader extends AsyncLoader<(PangeaAudioFile, File?)> { Future<(PangeaAudioFile, File?)> fetch() async { final audioBytes = await messageEvent.requestTextToSpeech( messageEvent.messageDisplayLangCode, - messageEvent.room.botOptions?.targetVoice, + MatrixState.pangeaController.userController.voice, ); File? audioFile; diff --git a/lib/pangea/user/user_controller.dart b/lib/pangea/user/user_controller.dart index 43b9736ea..2e3be4226 100644 --- a/lib/pangea/user/user_controller.dart +++ b/lib/pangea/user/user_controller.dart @@ -431,6 +431,8 @@ class UserController { : langModel; } + String? get voice => profile.userSettings.voice; + bool get languagesSet => userL1Code != null && userL2Code != null && diff --git a/lib/pangea/user/user_model.dart b/lib/pangea/user/user_model.dart index 60ce1873a..ff0184627 100644 --- a/lib/pangea/user/user_model.dart +++ b/lib/pangea/user/user_model.dart @@ -19,6 +19,7 @@ class UserSettings { GenderEnum gender; String? country; LanguageLevelTypeEnum cefrLevel; + String? voice; UserSettings({ this.dateOfBirth, @@ -29,6 +30,7 @@ class UserSettings { this.gender = GenderEnum.unselected, this.country, this.cefrLevel = LanguageLevelTypeEnum.a1, + this.voice, }); factory UserSettings.fromJson(Map json) => UserSettings( @@ -52,6 +54,7 @@ class UserSettings { json[ModelKey.cefrLevel], ) : LanguageLevelTypeEnum.a1, + voice: json[ModelKey.voice], ); Map toJson() { @@ -64,6 +67,7 @@ class UserSettings { data[ModelKey.userGender] = gender.string; data[ModelKey.userCountry] = country; data[ModelKey.cefrLevel] = cefrLevel.string; + data[ModelKey.voice] = voice; return data; } @@ -123,6 +127,7 @@ class UserSettings { gender: gender, country: country, cefrLevel: cefrLevel, + voice: voice, ); } @@ -138,7 +143,8 @@ class UserSettings { other.sourceLanguage == sourceLanguage && other.gender == gender && other.country == country && - other.cefrLevel == cefrLevel; + other.cefrLevel == cefrLevel && + other.voice == voice; } @override @@ -151,6 +157,7 @@ class UserSettings { gender.hashCode, country.hashCode, cefrLevel.hashCode, + voice.hashCode, ]); } diff --git a/lib/widgets/avatar.dart b/lib/widgets/avatar.dart index bfba786b1..ae0e10471 100644 --- a/lib/widgets/avatar.dart +++ b/lib/widgets/avatar.dart @@ -28,7 +28,6 @@ class Avatar extends StatelessWidget { final double? presenceSize; final Offset? presenceOffset; - final Widget? miniIcon; // Pangea# const Avatar({ @@ -48,7 +47,6 @@ class Avatar extends StatelessWidget { this.userId, this.presenceSize, this.presenceOffset, - this.miniIcon, // Pangea# super.key, }); @@ -140,13 +138,7 @@ class Avatar extends StatelessWidget { ), // #Pangea // if (presenceUserId != null) - if (miniIcon != null) - Positioned( - bottom: presenceOffset?.dy ?? -3, - right: presenceOffset?.dx ?? -3, - child: miniIcon!, - ) - else if (presenceUserId != null && size >= 32.0 && showPresence) + if (presenceUserId != null && size >= 32.0 && showPresence) // Pangea# PresenceBuilder( client: client, diff --git a/lib/widgets/member_actions_popup_menu_button.dart b/lib/widgets/member_actions_popup_menu_button.dart index 75376e351..c80524b5a 100644 --- a/lib/widgets/member_actions_popup_menu_button.dart +++ b/lib/widgets/member_actions_popup_menu_button.dart @@ -6,8 +6,6 @@ import 'package:matrix/matrix.dart'; import 'package:fluffychat/l10n/l10n.dart'; import 'package:fluffychat/pangea/analytics_misc/level_display_name.dart'; import 'package:fluffychat/pangea/bot/utils/bot_name.dart'; -import 'package:fluffychat/pangea/bot/widgets/bot_chat_settings_dialog.dart'; -import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart'; import 'package:fluffychat/widgets/avatar.dart'; import 'package:fluffychat/widgets/permission_slider_dialog.dart'; import 'adaptive_dialogs/show_ok_cancel_alert_dialog.dart'; @@ -108,15 +106,15 @@ void showMemberActionsPopupMenu({ ], ), ), - if (user.id == BotName.byEnvironment && room != null && room.isRoomAdmin) - PopupMenuItem( - enabled: false, - padding: const EdgeInsets.only( - left: 12.0, - right: 12.0, - ), - child: BotChatSettingsDialog(room: room), - ), + // if (user.id == BotName.byEnvironment && room != null && room.isRoomAdmin) + // PopupMenuItem( + // enabled: false, + // padding: const EdgeInsets.only( + // left: 12.0, + // right: 12.0, + // ), + // child: BotChatSettingsDialog(room: room), + // ), const PopupMenuDivider(), // #Pangea if (user.room.client.userID != user.id)