diff --git a/lib/config/routes.dart b/lib/config/routes.dart index decc16606..55a8ba0f4 100644 --- a/lib/config/routes.dart +++ b/lib/config/routes.dart @@ -22,6 +22,7 @@ import 'package:fluffychat/pages/device_settings/device_settings.dart'; import 'package:fluffychat/pages/login/login.dart'; import 'package:fluffychat/pages/new_group/new_group.dart'; import 'package:fluffychat/pages/new_private_chat/new_private_chat.dart'; +import 'package:fluffychat/pages/onboarding/space_code_onboarding.dart'; import 'package:fluffychat/pages/settings/settings.dart'; import 'package:fluffychat/pages/settings_3pid/settings_3pid.dart'; import 'package:fluffychat/pages/settings_chat/settings_chat.dart'; @@ -50,9 +51,9 @@ import 'package:fluffychat/pangea/course_creation/course_invite_page.dart'; import 'package:fluffychat/pangea/course_creation/selected_course_page.dart'; import 'package:fluffychat/pangea/join_codes/join_with_link_page.dart'; import 'package:fluffychat/pangea/learning_settings/settings_learning.dart'; -import 'package:fluffychat/pangea/login/pages/add_course_page.dart'; import 'package:fluffychat/pangea/login/pages/course_code_page.dart'; import 'package:fluffychat/pangea/login/pages/create_pangea_account_page.dart'; +import 'package:fluffychat/pangea/login/pages/find_course_page.dart'; import 'package:fluffychat/pangea/login/pages/language_selection_page.dart'; import 'package:fluffychat/pangea/login/pages/login_or_signup_view.dart'; import 'package:fluffychat/pangea/login/pages/new_course_page.dart'; @@ -213,93 +214,8 @@ abstract class AppRoutes { pageBuilder: (context, state) => defaultPageBuilder( context, state, - const AddCoursePage(route: 'registration'), + const SpaceCodeOnboarding(), ), - routes: [ - GoRoute( - path: 'private', - pageBuilder: (context, state) { - return defaultPageBuilder( - context, - state, - const CourseCodePage(), - ); - }, - ), - GoRoute( - path: 'public', - pageBuilder: (context, state) { - return defaultPageBuilder( - context, - state, - const PublicCoursesPage( - route: 'registration', - showFilters: false, - ), - ); - }, - routes: [ - GoRoute( - path: ':courseid', - pageBuilder: (context, state) { - return defaultPageBuilder( - context, - state, - SelectedCourse( - state.pathParameters['courseid']!, - SelectedCourseMode.join, - roomChunk: state.extra as PublicRoomsChunk?, - ), - ); - }, - ), - ], - ), - GoRoute( - path: 'own', - pageBuilder: (context, state) { - return defaultPageBuilder( - context, - state, - const NewCoursePage( - route: 'registration', - showFilters: false, - ), - ); - }, - routes: [ - GoRoute( - path: ':courseid', - pageBuilder: (context, state) { - return defaultPageBuilder( - context, - state, - SelectedCourse( - state.pathParameters['courseid']!, - SelectedCourseMode.launch, - ), - ); - }, - routes: [ - GoRoute( - path: 'invite', - pageBuilder: (context, state) { - return defaultPageBuilder( - context, - state, - CourseInvitePage( - state.pathParameters['courseid']!, - courseCreationCompleter: - state.extra as Completer?, - ), - ); - }, - ), - ], - ), - ], - ), - ], ), ], ), @@ -434,7 +350,7 @@ abstract class AppRoutes { pageBuilder: (context, state) => defaultPageBuilder( context, state, - const AddCoursePage(route: 'rooms'), + const FindCoursePage(), ), routes: [ GoRoute( diff --git a/lib/l10n/intl_ar.arb b/lib/l10n/intl_ar.arb index 8e38e6faf..0a5a0fce8 100644 --- a/lib/l10n/intl_ar.arb +++ b/lib/l10n/intl_ar.arb @@ -1,6 +1,6 @@ { "@@locale": "ar", - "@@last_modified": "2026-01-21 13:54:18.388293", + "@@last_modified": "2026-01-22 09:36:57.998979", "about": "حول", "@about": { "type": "String", @@ -11117,5 +11117,19 @@ "@knockDesc": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "هل لديك رمز دعوة أو رابط لدورة عامة؟", + "welcomeUser": "مرحبًا {user}", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/l10n/intl_be.arb b/lib/l10n/intl_be.arb index 5cfc00f97..2dce40286 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-21 13:54:07.402936", + "@@last_modified": "2026-01-22 09:36:46.926563", "@alwaysUse24HourFormat": { "type": "String", "placeholders": {} @@ -11999,5 +11999,19 @@ "@knockDesc": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "Ці маеце вы код запрашэння або спасылку на публічны курс?", + "welcomeUser": "Сардэчна запрашаем, {user}", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/l10n/intl_bn.arb b/lib/l10n/intl_bn.arb index d369b9e4a..8f050fc45 100644 --- a/lib/l10n/intl_bn.arb +++ b/lib/l10n/intl_bn.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2026-01-21 13:54:31.328626", + "@@last_modified": "2026-01-22 09:37:11.081120", "about": "সম্পর্কে", "@about": { "type": "String", @@ -12004,5 +12004,19 @@ "@knockDesc": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "আপনার কি একটি আমন্ত্রণ কোড বা একটি পাবলিক কোর্সের লিঙ্ক আছে?", + "welcomeUser": "স্বাগতম {user}", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/l10n/intl_bo.arb b/lib/l10n/intl_bo.arb index 39ccde987..25f3812e6 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-21 13:54:28.767499", + "@@last_modified": "2026-01-22 09:37:08.423146", "@alwaysUse24HourFormat": { "type": "String", "placeholders": {} @@ -10654,5 +10654,19 @@ "@knockDesc": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "Do you have an invite code or link to a public course?", + "welcomeUser": "Welcome {user}", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/l10n/intl_ca.arb b/lib/l10n/intl_ca.arb index 3c477421a..f156261dc 100644 --- a/lib/l10n/intl_ca.arb +++ b/lib/l10n/intl_ca.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2026-01-21 13:54:08.647836", + "@@last_modified": "2026-01-22 09:36:49.492725", "about": "Quant a", "@about": { "type": "String", @@ -10924,5 +10924,19 @@ "@knockDesc": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "Tens un codi d'invitació o un enllaç a un curs públic?", + "welcomeUser": "Benvingut {user}", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/l10n/intl_cs.arb b/lib/l10n/intl_cs.arb index 8c7cbe62d..02f3599bb 100644 --- a/lib/l10n/intl_cs.arb +++ b/lib/l10n/intl_cs.arb @@ -1,6 +1,6 @@ { "@@locale": "cs", - "@@last_modified": "2026-01-21 13:54:04.800051", + "@@last_modified": "2026-01-22 09:36:43.351703", "about": "O aplikaci", "@about": { "type": "String", @@ -11507,5 +11507,19 @@ "@knockDesc": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "Máte pozvánkový kód nebo odkaz na veřejný kurz?", + "welcomeUser": "Vítejte {user}", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/l10n/intl_da.arb b/lib/l10n/intl_da.arb index 84a867b38..cdc417761 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-21 13:53:34.885532", + "@@last_modified": "2026-01-22 09:36:14.204217", "@aboutHomeserver": { "type": "String", "placeholders": { @@ -11961,5 +11961,19 @@ "@knockDesc": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "Har du en invitationskode eller et link til et offentligt kursus?", + "welcomeUser": "Velkommen {user}", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/l10n/intl_de.arb b/lib/l10n/intl_de.arb index d0cfb6194..485190272 100644 --- a/lib/l10n/intl_de.arb +++ b/lib/l10n/intl_de.arb @@ -1,6 +1,6 @@ { "@@locale": "de", - "@@last_modified": "2026-01-21 13:53:56.595777", + "@@last_modified": "2026-01-22 09:36:34.415651", "alwaysUse24HourFormat": "true", "@alwaysUse24HourFormat": { "description": "Set to true to always display time of day in 24 hour format." @@ -10907,5 +10907,19 @@ "@knockDesc": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "Haben Sie einen Einladungscode oder einen Link zu einem öffentlichen Kurs?", + "welcomeUser": "Willkommen {user}", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/l10n/intl_el.arb b/lib/l10n/intl_el.arb index 333511f61..f7acd58b4 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-21 13:54:37.783088", + "@@last_modified": "2026-01-22 09:37:17.865903", "@alwaysUse24HourFormat": { "type": "String", "placeholders": {} @@ -11958,5 +11958,19 @@ "@knockDesc": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "Έχετε έναν κωδικό πρόσκλησης ή σύνδεσμο για ένα δημόσιο μάθημα;", + "welcomeUser": "Καλώς ήρθατε {user}", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index ae9b71bed..d1997a9e4 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -5058,5 +5058,15 @@ "learn": "Learn", "languageUpdated": "Target language updated!", "voiceDropdownTitle": "Pangea Bot voice", - "knockDesc": "Your request has been sent to course admin! You'll be let in if they approve." + "knockDesc": "Your request has been sent to course admin! You'll be let in if they approve.", + "joinSpaceOnboardingDesc": "Do you have an invite code or link to a public course?", + "welcomeUser": "Welcome {user}", + "@welcomeUser": { + "placeholders": { + "user": { + "type": "String" + } + } + }, + "findCourse": "Find a course" } diff --git a/lib/l10n/intl_eo.arb b/lib/l10n/intl_eo.arb index 4d5067671..11ffe3622 100644 --- a/lib/l10n/intl_eo.arb +++ b/lib/l10n/intl_eo.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2026-01-21 13:54:42.193114", + "@@last_modified": "2026-01-22 09:37:22.593342", "about": "Prio", "@about": { "type": "String", @@ -11989,5 +11989,19 @@ "@knockDesc": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "Ĉu vi havas invitkodon aŭ ligon al publika kurso?", + "welcomeUser": "Bonvenon {user}", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/l10n/intl_es.arb b/lib/l10n/intl_es.arb index a7ccb8c3c..e564ce294 100644 --- a/lib/l10n/intl_es.arb +++ b/lib/l10n/intl_es.arb @@ -1,6 +1,6 @@ { "@@locale": "es", - "@@last_modified": "2026-01-21 13:53:29.857658", + "@@last_modified": "2026-01-22 09:36:09.573972", "about": "Acerca de", "@about": { "type": "String", @@ -8134,5 +8134,19 @@ "@knockDesc": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "¿Tienes un código de invitación o un enlace a un curso público?", + "welcomeUser": "Bienvenido {user}", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/l10n/intl_et.arb b/lib/l10n/intl_et.arb index d50c106b2..7a04b0cb1 100644 --- a/lib/l10n/intl_et.arb +++ b/lib/l10n/intl_et.arb @@ -1,6 +1,6 @@ { "@@locale": "et", - "@@last_modified": "2026-01-21 13:53:55.586614", + "@@last_modified": "2026-01-22 09:36:33.207413", "about": "Rakenduse teave", "@about": { "type": "String", @@ -11171,5 +11171,19 @@ "@knockDesc": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "Kas sul on kutsekood või link avalikule kursusele?", + "welcomeUser": "Tere tulemast {user}", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/l10n/intl_eu.arb b/lib/l10n/intl_eu.arb index b8175726d..f5e4ef341 100644 --- a/lib/l10n/intl_eu.arb +++ b/lib/l10n/intl_eu.arb @@ -1,6 +1,6 @@ { "@@locale": "eu", - "@@last_modified": "2026-01-21 13:53:53.122879", + "@@last_modified": "2026-01-22 09:36:30.783445", "about": "Honi buruz", "@about": { "type": "String", @@ -10900,5 +10900,19 @@ "@knockDesc": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "Baduzu gonbidapen kodea edo lotura publiko baten ikastaroarentzako?", + "welcomeUser": "Ongi etorri {user}", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/l10n/intl_fa.arb b/lib/l10n/intl_fa.arb index eb0feb5bd..968b983de 100644 --- a/lib/l10n/intl_fa.arb +++ b/lib/l10n/intl_fa.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2026-01-21 13:54:33.096668", + "@@last_modified": "2026-01-22 09:37:12.739208", "repeatPassword": "تکرار رمزعبور", "@repeatPassword": {}, "about": "درباره", @@ -11632,5 +11632,19 @@ "@knockDesc": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "آیا کد دعوت یا لینکی به یک دوره عمومی دارید؟", + "welcomeUser": "خوش آمدید {user}", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/l10n/intl_fi.arb b/lib/l10n/intl_fi.arb index 8684fcf0d..15045df42 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-21 13:53:33.564588", + "@@last_modified": "2026-01-22 09:36:12.968075", "@alwaysUse24HourFormat": { "type": "String", "placeholders": {} @@ -11523,5 +11523,19 @@ "@knockDesc": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "Onko sinulla kutsukoodia tai linkkiä julkiseen kurssiin?", + "welcomeUser": "Tervetuloa {user}", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/l10n/intl_fil.arb b/lib/l10n/intl_fil.arb index 2489ec5b6..b23a5a12d 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-21 13:54:14.817261", + "@@last_modified": "2026-01-22 09:36:55.313694", "@setCustomPermissionLevel": { "type": "String", "placeholders": {} @@ -11876,5 +11876,19 @@ "@knockDesc": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "Mayroon ka bang invite code o link sa isang pampublikong kurso?", + "welcomeUser": "Maligayang pagdating {user}", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/l10n/intl_fr.arb b/lib/l10n/intl_fr.arb index 700921c07..aa79d94c5 100644 --- a/lib/l10n/intl_fr.arb +++ b/lib/l10n/intl_fr.arb @@ -1,6 +1,6 @@ { "@@locale": "fr", - "@@last_modified": "2026-01-21 13:54:48.318824", + "@@last_modified": "2026-01-22 09:37:30.149848", "about": "À propos", "@about": { "type": "String", @@ -11224,5 +11224,19 @@ "@knockDesc": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "Avez-vous un code d'invitation ou un lien vers un cours public ?", + "welcomeUser": "Bienvenue {user}", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/l10n/intl_ga.arb b/lib/l10n/intl_ga.arb index 9abadb3a0..9977cc5db 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-21 13:54:46.978792", + "@@last_modified": "2026-01-22 09:37:28.516173", "@customReaction": { "type": "String", "placeholders": {} @@ -10898,5 +10898,19 @@ "@knockDesc": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "An bhfuil cód cuireadh nó nasc agat do chúrsa poiblí?", + "welcomeUser": "Fáilte {user}", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/l10n/intl_gl.arb b/lib/l10n/intl_gl.arb index 23f338731..4ca3a571a 100644 --- a/lib/l10n/intl_gl.arb +++ b/lib/l10n/intl_gl.arb @@ -1,6 +1,6 @@ { "@@locale": "gl", - "@@last_modified": "2026-01-21 13:53:31.619299", + "@@last_modified": "2026-01-22 09:36:11.502910", "about": "Acerca de", "@about": { "type": "String", @@ -10897,5 +10897,19 @@ "@knockDesc": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "Tes un código de invitación ou un enlace a un curso público?", + "welcomeUser": "Benvido {user}", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/l10n/intl_he.arb b/lib/l10n/intl_he.arb index af9e0ad59..34b8e27e6 100644 --- a/lib/l10n/intl_he.arb +++ b/lib/l10n/intl_he.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2026-01-21 13:53:47.592162", + "@@last_modified": "2026-01-22 09:36:25.705220", "about": "אודות", "@about": { "type": "String", @@ -11949,5 +11949,19 @@ "@knockDesc": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "האם יש לך קוד הזמנה או קישור לקורס ציבורי?", + "welcomeUser": "ברוך הבא {user}", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/l10n/intl_hi.arb b/lib/l10n/intl_hi.arb index 064cbe283..f2fcd84f3 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-21 13:54:40.850433", + "@@last_modified": "2026-01-22 09:37:20.935542", "@alwaysUse24HourFormat": { "type": "String", "placeholders": {} @@ -11985,5 +11985,19 @@ "@knockDesc": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "क्या आपके पास एक आमंत्रण कोड या सार्वजनिक पाठ्यक्रम के लिए लिंक है?", + "welcomeUser": "स्वागत है {user}", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/l10n/intl_hr.arb b/lib/l10n/intl_hr.arb index 6b8517e96..c324f5510 100644 --- a/lib/l10n/intl_hr.arb +++ b/lib/l10n/intl_hr.arb @@ -1,6 +1,6 @@ { "@@locale": "hr", - "@@last_modified": "2026-01-21 13:53:46.524141", + "@@last_modified": "2026-01-22 09:36:23.684413", "about": "Informacije", "@about": { "type": "String", @@ -11272,5 +11272,19 @@ "@knockDesc": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "Imate li pozivni kod ili link za javni tečaj?", + "welcomeUser": "Dobrodošli {user}", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/l10n/intl_hu.arb b/lib/l10n/intl_hu.arb index b0767225a..335644fa3 100644 --- a/lib/l10n/intl_hu.arb +++ b/lib/l10n/intl_hu.arb @@ -1,6 +1,6 @@ { "@@locale": "hu", - "@@last_modified": "2026-01-21 13:53:36.742109", + "@@last_modified": "2026-01-22 09:36:15.788819", "about": "Névjegy", "@about": { "type": "String", @@ -10901,5 +10901,19 @@ "@knockDesc": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "Van meghívó kódod vagy linked egy nyilvános kurzushoz?", + "welcomeUser": "Üdvözöljük {user}", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/l10n/intl_ia.arb b/lib/l10n/intl_ia.arb index 506658635..8cf7d88de 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-21 13:53:49.028067", + "@@last_modified": "2026-01-22 09:36:27.975426", "@alwaysUse24HourFormat": { "type": "String", "placeholders": {} @@ -11978,5 +11978,19 @@ "@knockDesc": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "¿Tienes un código de invitación o un enlace a un curso público?", + "welcomeUser": "Bienvenido {user}", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/l10n/intl_id.arb b/lib/l10n/intl_id.arb index 5db3bb912..315eb4ad9 100644 --- a/lib/l10n/intl_id.arb +++ b/lib/l10n/intl_id.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2026-01-21 13:53:37.899898", + "@@last_modified": "2026-01-22 09:36:18.048263", "setAsCanonicalAlias": "Atur sebagai alias utama", "@setAsCanonicalAlias": { "type": "String", @@ -10891,5 +10891,19 @@ "@knockDesc": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "Apakah Anda memiliki kode undangan atau tautan ke kursus publik?", + "welcomeUser": "Selamat datang {user}", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/l10n/intl_ie.arb b/lib/l10n/intl_ie.arb index 3d38e5615..95e9c50e4 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-21 13:53:45.416677", + "@@last_modified": "2026-01-22 09:36:22.149976", "@alwaysUse24HourFormat": { "type": "String", "placeholders": {} @@ -11874,5 +11874,19 @@ "@knockDesc": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "¿Tienes un código de invitación o un enlace a un curso público?", + "welcomeUser": "Bienvenido {user}", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/l10n/intl_it.arb b/lib/l10n/intl_it.arb index 312c08f22..9892fd75d 100644 --- a/lib/l10n/intl_it.arb +++ b/lib/l10n/intl_it.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2026-01-21 13:54:01.568848", + "@@last_modified": "2026-01-22 09:36:40.074415", "about": "Informazioni", "@about": { "type": "String", @@ -10903,5 +10903,19 @@ "@knockDesc": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "Hai un codice di invito o un link per un corso pubblico?", + "welcomeUser": "Benvenuto {user}", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/l10n/intl_ja.arb b/lib/l10n/intl_ja.arb index c511c0107..47408d661 100644 --- a/lib/l10n/intl_ja.arb +++ b/lib/l10n/intl_ja.arb @@ -1,6 +1,6 @@ { "@@locale": "ja", - "@@last_modified": "2026-01-21 13:54:39.359536", + "@@last_modified": "2026-01-22 09:37:19.372006", "about": "このアプリについて", "@about": { "type": "String", @@ -11690,5 +11690,19 @@ "@knockDesc": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "招待コードまたは公開コースへのリンクはありますか?", + "welcomeUser": "ようこそ {user} さん", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/l10n/intl_ka.arb b/lib/l10n/intl_ka.arb index 7c3ce8707..593c8768a 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-21 13:54:44.486907", + "@@last_modified": "2026-01-22 09:37:25.958869", "@alwaysUse24HourFormat": { "type": "String", "placeholders": {} @@ -11930,5 +11930,19 @@ "@knockDesc": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "გაქვთ თუ არა მოწვევის კოდი ან ბმული საჯარო კურსზე?", + "welcomeUser": "კეთილი იყოს თქვენი მობრძანება {user}", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/l10n/intl_ko.arb b/lib/l10n/intl_ko.arb index 655637228..14be02641 100644 --- a/lib/l10n/intl_ko.arb +++ b/lib/l10n/intl_ko.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2026-01-21 13:53:28.417406", + "@@last_modified": "2026-01-22 09:36:07.420159", "about": "소개", "@about": { "type": "String", @@ -11008,5 +11008,19 @@ "@knockDesc": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "공개 과정에 대한 초대 코드나 링크가 있습니까?", + "welcomeUser": "환영합니다 {user}", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/l10n/intl_lt.arb b/lib/l10n/intl_lt.arb index 3473469a9..234781a80 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-21 13:54:22.729769", + "@@last_modified": "2026-01-22 09:37:02.748391", "@alwaysUse24HourFormat": { "type": "String", "placeholders": {} @@ -11705,5 +11705,19 @@ "@knockDesc": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "Ar turite kvietimo kodą arba nuorodą į viešą kursą?", + "welcomeUser": "Sveiki atvykę, {user}", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/l10n/intl_lv.arb b/lib/l10n/intl_lv.arb index feff58b67..c061cdd82 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-21 13:54:16.883169", + "@@last_modified": "2026-01-22 09:36:56.779342", "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", @@ -10886,5 +10886,19 @@ "@knockDesc": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "Vai jums ir uzaicinājuma kods vai saite uz publisku kursu?", + "welcomeUser": "Laipni lūdzam, {user}", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/l10n/intl_nb.arb b/lib/l10n/intl_nb.arb index f87cddbc8..2d8a774c6 100644 --- a/lib/l10n/intl_nb.arb +++ b/lib/l10n/intl_nb.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2026-01-21 13:54:06.232198", + "@@last_modified": "2026-01-22 09:36:44.562587", "about": "Om", "@about": { "type": "String", @@ -11993,5 +11993,19 @@ "@knockDesc": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "Har du en invitasjonskode eller lenke til et offentlig kurs?", + "welcomeUser": "Velkommen {user}", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/l10n/intl_nl.arb b/lib/l10n/intl_nl.arb index ed586d553..9d3e13803 100644 --- a/lib/l10n/intl_nl.arb +++ b/lib/l10n/intl_nl.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2026-01-21 13:54:27.649909", + "@@last_modified": "2026-01-22 09:37:07.354119", "about": "Over ons", "@about": { "type": "String", @@ -10900,5 +10900,19 @@ "@knockDesc": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "Heb je een uitnodigingscode of link naar een openbare cursus?", + "welcomeUser": "Welkom {user}", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/l10n/intl_pl.arb b/lib/l10n/intl_pl.arb index d7d2c73a5..578c63e83 100644 --- a/lib/l10n/intl_pl.arb +++ b/lib/l10n/intl_pl.arb @@ -1,6 +1,6 @@ { "@@locale": "pl", - "@@last_modified": "2026-01-21 13:54:34.451816", + "@@last_modified": "2026-01-22 09:37:14.175391", "about": "O aplikacji", "@about": { "type": "String", @@ -10898,5 +10898,19 @@ "@knockDesc": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "Czy masz kod zaproszenia lub link do publicznego kursu?", + "welcomeUser": "Witaj {user}", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/l10n/intl_pt.arb b/lib/l10n/intl_pt.arb index d9b54e65a..d7aa4ddd5 100644 --- a/lib/l10n/intl_pt.arb +++ b/lib/l10n/intl_pt.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2026-01-21 13:53:54.148542", + "@@last_modified": "2026-01-22 09:36:31.935958", "copiedToClipboard": "Copiada para a área de transferência", "@copiedToClipboard": { "type": "String", @@ -12000,5 +12000,19 @@ "@knockDesc": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "Você tem um código de convite ou link para um curso público?", + "welcomeUser": "Bem-vindo {user}", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/l10n/intl_pt_BR.arb b/lib/l10n/intl_pt_BR.arb index 11797eb83..2bf65492d 100644 --- a/lib/l10n/intl_pt_BR.arb +++ b/lib/l10n/intl_pt_BR.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2026-01-21 13:53:51.587209", + "@@last_modified": "2026-01-22 09:36:29.216087", "about": "Sobre", "@about": { "type": "String", @@ -11258,5 +11258,19 @@ "@knockDesc": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "Você tem um código de convite ou link para um curso público?", + "welcomeUser": "Bem-vindo {user}", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/l10n/intl_pt_PT.arb b/lib/l10n/intl_pt_PT.arb index bc97480dc..989bed4ba 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-21 13:54:11.801274", + "@@last_modified": "2026-01-22 09:36:52.464279", "@alwaysUse24HourFormat": { "type": "String", "placeholders": {} @@ -11929,5 +11929,19 @@ "@knockDesc": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "Você tem um código de convite ou link para um curso público?", + "welcomeUser": "Bem-vindo {user}", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/l10n/intl_ro.arb b/lib/l10n/intl_ro.arb index 3f458ad96..4e6931a1b 100644 --- a/lib/l10n/intl_ro.arb +++ b/lib/l10n/intl_ro.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2026-01-21 13:53:41.456181", + "@@last_modified": "2026-01-22 09:36:19.487915", "about": "Despre", "@about": { "type": "String", @@ -11635,5 +11635,19 @@ "@knockDesc": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "Ai un cod de invitație sau un link pentru un curs public?", + "welcomeUser": "Bine ai venit {user}", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/l10n/intl_ru.arb b/lib/l10n/intl_ru.arb index 3cbd203a9..fbf558e17 100644 --- a/lib/l10n/intl_ru.arb +++ b/lib/l10n/intl_ru.arb @@ -1,6 +1,6 @@ { "@@locale": "ru", - "@@last_modified": "2026-01-21 15:35:33.881278", + "@@last_modified": "2026-01-22 09:37:24.211755", "about": "О проекте", "@about": { "type": "String", @@ -11008,5 +11008,19 @@ "@italicText": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "У вас есть код приглашения или ссылка на публичный курс?", + "welcomeUser": "Добро пожаловать {user}", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/l10n/intl_sk.arb b/lib/l10n/intl_sk.arb index 510156730..41ba5c0ac 100644 --- a/lib/l10n/intl_sk.arb +++ b/lib/l10n/intl_sk.arb @@ -1,6 +1,6 @@ { "@@locale": "sk", - "@@last_modified": "2026-01-21 13:53:43.706457", + "@@last_modified": "2026-01-22 09:36:21.123706", "about": "O aplikácii", "@about": { "type": "String", @@ -11984,5 +11984,19 @@ "@knockDesc": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "Máte pozývací kód alebo odkaz na verejný kurz?", + "welcomeUser": "Vitaj {user}", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/l10n/intl_sl.arb b/lib/l10n/intl_sl.arb index 9736fb5f5..f21e4e190 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-21 13:53:58.241980", + "@@last_modified": "2026-01-22 09:36:36.017757", "@alwaysUse24HourFormat": { "type": "String", "placeholders": {} @@ -11981,5 +11981,19 @@ "@knockDesc": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "Imate kodo za povabilo ali povezavo do javnega tečaja?", + "welcomeUser": "Dobrodošli {user}", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/l10n/intl_sr.arb b/lib/l10n/intl_sr.arb index 0b970dceb..e3a0cad71 100644 --- a/lib/l10n/intl_sr.arb +++ b/lib/l10n/intl_sr.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2026-01-21 13:54:45.561732", + "@@last_modified": "2026-01-22 09:37:27.068492", "about": "О програму", "@about": { "type": "String", @@ -12002,5 +12002,19 @@ "@knockDesc": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "Imate li pozivni kod ili link za javni kurs?", + "welcomeUser": "Dobrodošli {user}", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/l10n/intl_sv.arb b/lib/l10n/intl_sv.arb index 302e97dde..bf3877dd1 100644 --- a/lib/l10n/intl_sv.arb +++ b/lib/l10n/intl_sv.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2026-01-21 13:54:35.931933", + "@@last_modified": "2026-01-22 09:37:16.018226", "about": "Om", "@about": { "type": "String", @@ -11378,5 +11378,19 @@ "@knockDesc": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "Har du en inbjudningskod eller länk till en offentlig kurs?", + "welcomeUser": "Välkommen {user}", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/l10n/intl_ta.arb b/lib/l10n/intl_ta.arb index 82050d0e3..f4d1fadf9 100644 --- a/lib/l10n/intl_ta.arb +++ b/lib/l10n/intl_ta.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2026-01-21 13:54:25.999605", + "@@last_modified": "2026-01-22 09:37:06.101200", "acceptedTheInvitation": "👍 {username} அழைப்பை ஏற்றுக்கொண்டது", "@acceptedTheInvitation": { "type": "String", @@ -11124,5 +11124,19 @@ "@knockDesc": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "உங்களுக்கு ஒரு அழைப்பு குறியீடு அல்லது பொது பாடத்திற்கு இணைப்பு உள்ளதா?", + "welcomeUser": "வரவேற்கிறேன் {user}", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/l10n/intl_te.arb b/lib/l10n/intl_te.arb index e457db572..27d5345db 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-21 13:54:20.897642", + "@@last_modified": "2026-01-22 09:37:01.069487", "@setCustomPermissionLevel": { "type": "String", "placeholders": {} @@ -11989,5 +11989,19 @@ "@knockDesc": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "మీకు పబ్లిక్ కోర్సుకు ఆహ్వాన కోడ్ లేదా లింక్ ఉందా?", + "welcomeUser": "స్వాగతం {user}", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/l10n/intl_th.arb b/lib/l10n/intl_th.arb index 397aaa446..5fbd2a2e6 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-21 13:54:10.758435", + "@@last_modified": "2026-01-22 09:36:51.239616", "@alwaysUse24HourFormat": { "type": "String", "placeholders": {} @@ -11958,5 +11958,19 @@ "@knockDesc": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "คุณมีรหัสเชิญหรือลิงก์ไปยังหลักสูตรสาธารณะหรือไม่?", + "welcomeUser": "ยินดีต้อนรับ {user}", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/l10n/intl_tr.arb b/lib/l10n/intl_tr.arb index f38520405..49bfe664c 100644 --- a/lib/l10n/intl_tr.arb +++ b/lib/l10n/intl_tr.arb @@ -1,6 +1,6 @@ { "@@locale": "tr", - "@@last_modified": "2026-01-21 13:54:19.467039", + "@@last_modified": "2026-01-22 09:36:59.414494", "about": "Hakkında", "@about": { "type": "String", @@ -11122,5 +11122,19 @@ "@knockDesc": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "Bir davet kodunuz veya halka açık bir kursa bağlantınız var mı?", + "welcomeUser": "Hoş geldin {user}", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/l10n/intl_uk.arb b/lib/l10n/intl_uk.arb index 5dbfc2938..71f9cbbb6 100644 --- a/lib/l10n/intl_uk.arb +++ b/lib/l10n/intl_uk.arb @@ -1,6 +1,6 @@ { "@@locale": "uk", - "@@last_modified": "2026-01-21 13:54:03.403456", + "@@last_modified": "2026-01-22 09:36:41.798719", "about": "Про застосунок", "@about": { "type": "String", @@ -10894,5 +10894,19 @@ "@knockDesc": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "У вас є код запрошення або посилання на публічний курс?", + "welcomeUser": "Ласкаво просимо {user}", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/l10n/intl_vi.arb b/lib/l10n/intl_vi.arb index 89760d972..9c66dc600 100644 --- a/lib/l10n/intl_vi.arb +++ b/lib/l10n/intl_vi.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2026-01-21 13:54:24.252269", + "@@last_modified": "2026-01-22 09:37:04.643688", "about": "Giới thiệu", "@about": { "type": "String", @@ -6470,5 +6470,19 @@ "@knockDesc": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "Bạn có mã mời hoặc liên kết đến một khóa học công khai không?", + "welcomeUser": "Chào mừng {user}", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/l10n/intl_yue.arb b/lib/l10n/intl_yue.arb index b280b4a62..95063be1f 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-21 13:53:59.885092", + "@@last_modified": "2026-01-22 09:36:38.546245", "@ignoreUser": { "type": "String", "placeholders": {} @@ -11991,5 +11991,19 @@ "@knockDesc": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "你有邀請碼或公共課程的鏈接嗎?", + "welcomeUser": "歡迎 {user}", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/l10n/intl_zh.arb b/lib/l10n/intl_zh.arb index ffe826b05..e4c85be4a 100644 --- a/lib/l10n/intl_zh.arb +++ b/lib/l10n/intl_zh.arb @@ -1,6 +1,6 @@ { "@@locale": "zh", - "@@last_modified": "2026-01-21 13:54:29.681537", + "@@last_modified": "2026-01-22 09:37:09.563669", "about": "关于", "@about": { "type": "String", @@ -10891,5 +10891,19 @@ "@knockDesc": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "您是否有邀请代码或公共课程的链接?", + "welcomeUser": "欢迎 {user}", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/l10n/intl_zh_Hant.arb b/lib/l10n/intl_zh_Hant.arb index fc92bb5dc..5434d1cc6 100644 --- a/lib/l10n/intl_zh_Hant.arb +++ b/lib/l10n/intl_zh_Hant.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2026-01-21 13:54:13.165623", + "@@last_modified": "2026-01-22 09:36:53.893925", "about": "關於", "@about": { "type": "String", @@ -10898,5 +10898,19 @@ "@knockDesc": { "type": "String", "placeholders": {} + }, + "joinSpaceOnboardingDesc": "您是否有邀請碼或公共課程的鏈接?", + "welcomeUser": "歡迎 {user}", + "@joinSpaceOnboardingDesc": { + "type": "String", + "placeholders": {} + }, + "@welcomeUser": { + "type": "String", + "placeholders": { + "user": { + "type": "String" + } + } } } \ No newline at end of file diff --git a/lib/pages/onboarding/space_code_onboarding.dart b/lib/pages/onboarding/space_code_onboarding.dart new file mode 100644 index 000000000..54c50f557 --- /dev/null +++ b/lib/pages/onboarding/space_code_onboarding.dart @@ -0,0 +1,83 @@ +import 'package:flutter/material.dart'; + +import 'package:go_router/go_router.dart'; +import 'package:matrix/matrix.dart'; + +import 'package:fluffychat/pages/onboarding/space_code_onboarding_view.dart'; +import 'package:fluffychat/pangea/common/utils/error_handler.dart'; +import 'package:fluffychat/pangea/join_codes/space_code_controller.dart'; +import 'package:fluffychat/pangea/spaces/space_constants.dart'; +import 'package:fluffychat/widgets/matrix.dart'; + +class SpaceCodeOnboarding extends StatefulWidget { + const SpaceCodeOnboarding({super.key}); + + @override + State createState() => SpaceCodeOnboardingState(); +} + +class SpaceCodeOnboardingState extends State { + Profile? profile; + Client get client => Matrix.of(context).client; + + final TextEditingController codeController = TextEditingController(); + + @override + void initState() { + _setProfile(); + codeController.addListener(() { + if (mounted) setState(() {}); + }); + super.initState(); + } + + @override + void dispose() { + codeController.dispose(); + super.dispose(); + } + + Future _setProfile() async { + try { + profile = await client.getProfileFromUserId( + client.userID!, + ); + } catch (e, s) { + ErrorHandler.logError( + e: e, + s: s, + data: { + 'userId': client.userID, + }, + ); + } finally { + if (mounted) setState(() {}); + } + } + + Future submitCode() async { + String code = codeController.text.trim(); + if (code.isEmpty) return; + + try { + final link = Uri.parse(Uri.parse(code).fragment); + if (link.queryParameters.containsKey(SpaceConstants.classCode)) { + code = link.queryParameters[SpaceConstants.classCode]!; + } + } catch (e) { + debugPrint("Text input is not a URL: $e"); + } + + final roomId = await SpaceCodeController.joinSpaceWithCode(context, code); + if (roomId != null) { + final room = Matrix.of(context).client.getRoomById(roomId); + room?.isSpace ?? true + ? context.go('/rooms/spaces/$roomId/details') + : context.go('/rooms/$roomId'); + } + } + + @override + Widget build(BuildContext context) => + SpaceCodeOnboardingView(controller: this); +} diff --git a/lib/pages/onboarding/space_code_onboarding_view.dart b/lib/pages/onboarding/space_code_onboarding_view.dart new file mode 100644 index 000000000..37dc648f9 --- /dev/null +++ b/lib/pages/onboarding/space_code_onboarding_view.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +import 'package:go_router/go_router.dart'; +import 'package:matrix/matrix.dart'; + +import 'package:fluffychat/l10n/l10n.dart'; +import 'package:fluffychat/pages/onboarding/space_code_onboarding.dart'; +import 'package:fluffychat/pangea/authentication/p_logout.dart'; +import 'package:fluffychat/pangea/login/pages/pangea_login_scaffold.dart'; + +class SpaceCodeOnboardingView extends StatelessWidget { + final SpaceCodeOnboardingState controller; + const SpaceCodeOnboardingView({ + super.key, + required this.controller, + }); + + @override + Widget build(BuildContext context) { + return PangeaLoginScaffold( + customAppBar: AppBar( + leading: BackButton( + onPressed: () => pLogoutAction( + context, + bypassWarning: true, + ), + ), + ), + showAppName: false, + mainAssetUrl: controller.profile?.avatarUrl, + children: [ + Column( + spacing: 8.0, + children: [ + Text( + L10n.of(context).welcomeUser( + controller.profile?.displayName ?? + controller.client.userID?.localpart ?? + "", + ), + style: Theme.of(context) + .textTheme + .titleLarge + ?.copyWith(fontWeight: FontWeight.bold), + ), + Text( + L10n.of(context).joinSpaceOnboardingDesc, + textAlign: TextAlign.center, + ), + TextField( + decoration: InputDecoration( + hintText: L10n.of(context).enterCodeToJoin, + ), + controller: controller.codeController, + onSubmitted: (_) => controller.submitCode, + ), + ElevatedButton( + onPressed: controller.codeController.text.isNotEmpty + ? controller.submitCode + : null, + style: ElevatedButton.styleFrom( + backgroundColor: Theme.of(context).colorScheme.primaryContainer, + foregroundColor: + Theme.of(context).colorScheme.onPrimaryContainer, + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text(L10n.of(context).join), + ], + ), + ), + TextButton( + child: Text(L10n.of(context).skipForNow), + onPressed: () => context.go("/rooms"), + ), + ], + ), + ], + ); + } +} diff --git a/lib/pangea/login/pages/course_code_page.dart b/lib/pangea/login/pages/course_code_page.dart index 6d3cd55ce..fd2e36cb3 100644 --- a/lib/pangea/login/pages/course_code_page.dart +++ b/lib/pangea/login/pages/course_code_page.dart @@ -6,7 +6,7 @@ import 'package:go_router/go_router.dart'; import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/l10n/l10n.dart'; import 'package:fluffychat/pangea/join_codes/space_code_controller.dart'; -import 'package:fluffychat/pangea/login/pages/add_course_page.dart'; +import 'package:fluffychat/pangea/spaces/space_constants.dart'; import 'package:fluffychat/widgets/matrix.dart'; class CourseCodePage extends StatefulWidget { @@ -72,7 +72,7 @@ class CourseCodePageState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ SvgPicture.network( - "${AppConfig.assetsBaseURL}/${AddCoursePage.mapUnlockFileName}", + "${AppConfig.assetsBaseURL}/${SpaceConstants.mapUnlockFileName}", width: 100.0, height: 100.0, colorFilter: ColorFilter.mode( diff --git a/lib/pangea/login/pages/find_course_page.dart b/lib/pangea/login/pages/find_course_page.dart new file mode 100644 index 000000000..df2e4c00e --- /dev/null +++ b/lib/pangea/login/pages/find_course_page.dart @@ -0,0 +1,523 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; + +import 'package:go_router/go_router.dart'; +import 'package:matrix/matrix.dart'; + +import 'package:fluffychat/config/themes.dart'; +import 'package:fluffychat/l10n/l10n.dart'; +import 'package:fluffychat/pangea/common/utils/error_handler.dart'; +import 'package:fluffychat/pangea/common/widgets/error_indicator.dart'; +import 'package:fluffychat/pangea/common/widgets/url_image_widget.dart'; +import 'package:fluffychat/pangea/course_creation/course_info_chip_widget.dart'; +import 'package:fluffychat/pangea/course_creation/course_language_filter.dart'; +import 'package:fluffychat/pangea/course_plans/courses/course_plan_model.dart'; +import 'package:fluffychat/pangea/course_plans/courses/course_plans_repo.dart'; +import 'package:fluffychat/pangea/course_plans/courses/get_localized_courses_request.dart'; +import 'package:fluffychat/pangea/languages/language_model.dart'; +import 'package:fluffychat/pangea/spaces/public_course_extension.dart'; +import 'package:fluffychat/widgets/avatar.dart'; +import 'package:fluffychat/widgets/hover_builder.dart'; +import 'package:fluffychat/widgets/layouts/max_width_body.dart'; +import 'package:fluffychat/widgets/matrix.dart'; + +class FindCoursePage extends StatefulWidget { + const FindCoursePage({super.key}); + + @override + State createState() => FindCoursePageState(); +} + +class FindCoursePageState extends State { + final TextEditingController searchController = TextEditingController(); + + bool loading = true; + bool _fullyLoaded = false; + Object? error; + Timer? _coolDown; + + LanguageModel? targetLanguageFilter; + + List discoveredCourses = []; + Map coursePlans = {}; + String? nextBatch; + + @override + void initState() { + super.initState(); + + final target = MatrixState.pangeaController.userController.userL2; + if (target != null) { + setTargetLanguageFilter(target); + } + + _loadCourses(); + } + + @override + void dispose() { + searchController.dispose(); + _coolDown?.cancel(); + super.dispose(); + } + + void setTargetLanguageFilter(LanguageModel? language) { + if (targetLanguageFilter?.langCodeShort == language?.langCodeShort) return; + setState(() => targetLanguageFilter = language); + _loadCourses(); + } + + void onSearchEnter(String text, {bool globalSearch = true}) { + if (text.isEmpty) { + _loadCourses(); + return; + } + + _coolDown?.cancel(); + _coolDown = Timer(const Duration(milliseconds: 500), _loadCourses); + } + + List get filteredCourses { + List filtered = discoveredCourses + .where( + (c) => + !Matrix.of(context).client.rooms.any( + (r) => + r.id == c.room.roomId && + r.membership == Membership.join, + ) && + coursePlans.containsKey(c.courseId), + ) + .toList(); + + if (targetLanguageFilter != null) { + filtered = filtered.where( + (chunk) { + final course = coursePlans[chunk.courseId]; + if (course == null) return false; + return course.targetLanguage.split('-').first == + targetLanguageFilter!.langCodeShort; + }, + ).toList(); + } + + final searchText = searchController.text.trim().toLowerCase(); + if (searchText.isNotEmpty) { + filtered = filtered.where( + (chunk) { + final course = coursePlans[chunk.courseId]; + if (course == null) return false; + final name = chunk.room.name?.toLowerCase() ?? ''; + final description = course.description.toLowerCase(); + return name.contains(searchText) || description.contains(searchText); + }, + ).toList(); + } + + // sort by join rule, with knock rooms at the end + filtered.sort((a, b) { + final aKnock = a.room.joinRule == JoinRules.knock.name; + final bKnock = b.room.joinRule == JoinRules.knock.name; + if (aKnock && !bKnock) return 1; + if (!aKnock && bKnock) return -1; + return 0; + }); + + return filtered; + } + + Future _loadPublicSpaces() async { + try { + final resp = await Matrix.of(context).client.requestPublicCourses( + since: nextBatch, + ); + + for (final room in resp.courses) { + if (!discoveredCourses.any((e) => e.room.roomId == room.room.roomId)) { + discoveredCourses.add(room); + } + } + + nextBatch = resp.nextBatch; + } catch (e, s) { + error = e; + ErrorHandler.logError( + e: e, + s: s, + data: { + 'nextBatch': nextBatch, + }, + ); + } + } + + Future _loadCourses() async { + if (_fullyLoaded && nextBatch == null) { + return; + } + + setState(() { + loading = true; + error = null; + }); + + await _loadPublicSpaces(); + + int timesLoaded = 0; + while (error == null && timesLoaded < 5 && nextBatch != null) { + await _loadPublicSpaces(); + timesLoaded++; + } + + if (nextBatch == null) { + _fullyLoaded = true; + } + + try { + final resp = await CoursePlansRepo.search( + GetLocalizedCoursesRequest( + coursePlanIds: + discoveredCourses.map((c) => c.courseId).toSet().toList(), + l1: MatrixState.pangeaController.userController.userL1Code!, + ), + ); + final searchResult = resp.coursePlans; + + coursePlans.clear(); + for (final entry in searchResult.entries) { + coursePlans[entry.key] = entry.value; + } + } catch (e, s) { + ErrorHandler.logError( + e: e, + s: s, + data: { + 'discoveredCourses': + discoveredCourses.map((c) => c.courseId).toList(), + }, + ); + } finally { + if (mounted) { + setState(() => loading = false); + } + } + } + + @override + Widget build(BuildContext context) { + return FindCoursePageView(controller: this); + } +} + +class FindCoursePageView extends StatelessWidget { + final FindCoursePageState controller; + + const FindCoursePageView({ + super.key, + required this.controller, + }); + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + final isColumnMode = FluffyThemes.isColumnMode(context); + + return Scaffold( + appBar: AppBar(title: Text(L10n.of(context).findCourse)), + body: MaxWidthBody( + showBorder: false, + withScrolling: false, + maxWidth: 600.0, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 20.0), + child: Column( + spacing: 16.0, + children: [ + TextField( + controller: controller.searchController, + textInputAction: TextInputAction.search, + onChanged: controller.onSearchEnter, + decoration: InputDecoration( + filled: !isColumnMode, + fillColor: isColumnMode + ? null + : theme.colorScheme.secondaryContainer, + border: OutlineInputBorder( + borderSide: + isColumnMode ? const BorderSide() : BorderSide.none, + borderRadius: BorderRadius.circular(100), + ), + contentPadding: const EdgeInsets.fromLTRB( + 0, + 0, + 20.0, + 0, + ), + hintText: L10n.of(context).findCourse, + hintStyle: TextStyle( + color: theme.colorScheme.onPrimaryContainer, + fontWeight: FontWeight.normal, + fontSize: 16.0, + ), + floatingLabelBehavior: FloatingLabelBehavior.never, + prefixIcon: IconButton( + onPressed: () {}, + icon: Icon( + Icons.search_outlined, + color: theme.colorScheme.onPrimaryContainer, + ), + ), + ), + ), + LayoutBuilder( + builder: (context, constrained) { + return Row( + spacing: 12.0, + children: [ + Expanded( + child: CourseLanguageFilter( + value: controller.targetLanguageFilter, + onChanged: controller.setTargetLanguageFilter, + ), + ), + if (constrained.maxWidth >= 500) ...[ + TextButton( + child: Row( + spacing: 8.0, + children: [ + const Icon(Icons.add), + Text(L10n.of(context).newCourse), + ], + ), + onPressed: () => context.go("/rooms/course/own"), + ), + TextButton( + child: Row( + spacing: 8.0, + children: [ + const Icon(Icons.join_full), + Text(L10n.of(context).joinWithCode), + ], + ), + onPressed: () => context.go("/rooms/course/private"), + ), + ] else + PopupMenuButton( + icon: const Icon(Icons.more_vert), + itemBuilder: (context) => [ + PopupMenuItem( + onTap: () => context.go("/rooms/course/own"), + child: Row( + spacing: 8.0, + children: [ + const Icon(Icons.add), + Text(L10n.of(context).newCourse), + ], + ), + ), + PopupMenuItem( + onTap: () => context.go("/rooms/course/private"), + child: Row( + spacing: 8.0, + children: [ + const Icon(Icons.join_full), + Text(L10n.of(context).joinWithCode), + ], + ), + ), + ], + ), + ], + ); + }, + ), + ValueListenableBuilder( + valueListenable: controller.searchController, + builder: (context, _, __) { + if (controller.error != null) { + return ErrorIndicator( + message: L10n.of(context).oopsSomethingWentWrong, + ); + } + + if (controller.loading) { + return const CircularProgressIndicator.adaptive(); + } + + if (controller.filteredCourses.isEmpty) { + return Text( + L10n.of(context).nothingFound, + ); + } + + return Expanded( + child: ListView.builder( + itemCount: controller.filteredCourses.length, + itemBuilder: (context, index) { + final space = controller.filteredCourses[index]; + return _PublicCourseTile( + chunk: space, + course: controller.coursePlans[space.courseId], + ); + }, + ), + ); + }, + ), + ], + ), + ), + ), + ); + } +} + +class _PublicCourseTile extends StatelessWidget { + final PublicCoursesChunk chunk; + final CoursePlanModel? course; + + const _PublicCourseTile({ + required this.chunk, + this.course, + }); + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + final isColumnMode = FluffyThemes.isColumnMode(context); + final space = chunk.room; + final courseId = chunk.courseId; + final displayname = + space.name ?? space.canonicalAlias ?? L10n.of(context).emptyChat; + + return Padding( + padding: isColumnMode + ? const EdgeInsets.only( + bottom: 32.0, + ) + : const EdgeInsets.only( + bottom: 16.0, + ), + child: Material( + type: MaterialType.transparency, + child: InkWell( + onTap: () => context.go( + '/rooms/course/public/$courseId', + extra: space, + ), + borderRadius: BorderRadius.circular(12.0), + child: Container( + padding: const EdgeInsets.all(12.0), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12.0), + border: Border.all( + color: theme.colorScheme.primary, + ), + ), + child: Column( + spacing: 4.0, + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + spacing: 8.0, + children: [ + ImageByUrl( + imageUrl: space.avatarUrl?.toString(), + width: 58.0, + borderRadius: BorderRadius.circular(10.0), + replacement: Avatar( + name: displayname, + borderRadius: BorderRadius.circular( + 10.0, + ), + size: 58.0, + ), + ), + Flexible( + child: Column( + spacing: 0.0, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + displayname, + style: theme.textTheme.bodyLarge, + maxLines: 2, + overflow: TextOverflow.ellipsis, + ), + Row( + spacing: 4.0, + mainAxisSize: MainAxisSize.min, + children: [ + const Icon( + Icons.group, + size: 16.0, + ), + Text( + L10n.of(context).countParticipants( + space.numJoinedMembers, + ), + style: theme.textTheme.bodyMedium, + ), + ], + ), + ], + ), + ), + ], + ), + if (course != null) ...[ + CourseInfoChips( + courseId, + iconSize: 12.0, + fontSize: 12.0, + ), + Text( + course!.description, + style: theme.textTheme.bodyMedium, + ), + ], + const SizedBox(height: 12.0), + HoverBuilder( + builder: (context, hovered) => ElevatedButton( + onPressed: () => context.go( + '/rooms/course/public/$courseId', + extra: space, + ), + style: ElevatedButton.styleFrom( + backgroundColor: + theme.colorScheme.primaryContainer.withAlpha( + hovered ? 255 : 200, + ), + foregroundColor: theme.colorScheme.onPrimaryContainer, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular( + 12.0, + ), + ), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + space.joinRule == JoinRules.knock.name + ? L10n.of( + context, + ).knock + : L10n.of( + context, + ).join, + ), + ], + ), + ), + ), + ], + ), + ), + ), + ), + ); + } +} diff --git a/lib/pangea/spaces/space_constants.dart b/lib/pangea/spaces/space_constants.dart index f6315356f..a387fbcbf 100644 --- a/lib/pangea/spaces/space_constants.dart +++ b/lib/pangea/spaces/space_constants.dart @@ -5,6 +5,7 @@ class SpaceConstants { static const String classCode = 'classcode'; static const String introductionChatAlias = 'introductionChat'; static const String announcementsChatAlias = 'announcementsChat'; + static String mapUnlockFileName = "unlock_trip.svg"; static List introChatIcons = [ '${AppConfig.assetsBaseURL}/Introduction_1.jpg', diff --git a/lib/widgets/navigation_rail.dart b/lib/widgets/navigation_rail.dart index 04f81476a..cb8b08b6c 100644 --- a/lib/widgets/navigation_rail.dart +++ b/lib/widgets/navigation_rail.dart @@ -202,7 +202,7 @@ class SpacesNavigationRail extends StatelessWidget { child: const Icon(Icons.add), ), ), - toolTip: L10n.of(context).addCourse, + toolTip: L10n.of(context).findCourse, expanded: expanded, // Pangea# );