Merge branch 'main' into 5244-grammar-practice-ui-updates

This commit is contained in:
Ava Shilling 2026-01-22 13:43:03 -05:00
commit fa0489e401
73 changed files with 2185 additions and 311 deletions

View file

@ -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<String>?,
),
);
},
),
],
),
],
),
],
),
],
),
@ -434,7 +350,7 @@ abstract class AppRoutes {
pageBuilder: (context, state) => defaultPageBuilder(
context,
state,
const AddCoursePage(route: 'rooms'),
const FindCoursePage(),
),
routes: [
GoRoute(

View file

@ -1,6 +1,6 @@
{
"@@locale": "ar",
"@@last_modified": "2026-01-21 13:54:18.388293",
"@@last_modified": "2026-01-22 12:01:48.002470",
"about": "حول",
"@about": {
"type": "String",
@ -11117,5 +11117,29 @@
"@knockDesc": {
"type": "String",
"placeholders": {}
},
"joinSpaceOnboardingDesc": "هل لديك رمز دعوة أو رابط لدورة عامة؟",
"welcomeUser": "مرحبًا {user}",
"@joinSpaceOnboardingDesc": {
"type": "String",
"placeholders": {}
},
"@welcomeUser": {
"type": "String",
"placeholders": {
"user": {
"type": "String"
}
}
},
"publicInviteDescChat": "ابحث عن المستخدمين لدعوتهم إلى هذه الدردشة.",
"publicInviteDescSpace": "ابحث عن المستخدمين لدعوتهم إلى هذا الفضاء.",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -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 12:01:33.641094",
"@alwaysUse24HourFormat": {
"type": "String",
"placeholders": {}
@ -11999,5 +11999,29 @@
"@knockDesc": {
"type": "String",
"placeholders": {}
},
"joinSpaceOnboardingDesc": "Ці маеце вы код запрашэння або спасылку на публічны курс?",
"welcomeUser": "Сардэчна запрашаем, {user}",
"@joinSpaceOnboardingDesc": {
"type": "String",
"placeholders": {}
},
"@welcomeUser": {
"type": "String",
"placeholders": {
"user": {
"type": "String"
}
}
},
"publicInviteDescChat": "Шукаць карыстальнікаў, каб запрасіць іх у гэты чат.",
"publicInviteDescSpace": "Шукаць карыстальнікаў, каб запрасіць іх у гэтае прастору.",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -1,5 +1,5 @@
{
"@@last_modified": "2026-01-21 13:54:31.328626",
"@@last_modified": "2026-01-22 12:02:02.719528",
"about": "সম্পর্কে",
"@about": {
"type": "String",
@ -12004,5 +12004,29 @@
"@knockDesc": {
"type": "String",
"placeholders": {}
},
"joinSpaceOnboardingDesc": "আপনার কি একটি আমন্ত্রণ কোড বা একটি পাবলিক কোর্সের লিঙ্ক আছে?",
"welcomeUser": "স্বাগতম {user}",
"@joinSpaceOnboardingDesc": {
"type": "String",
"placeholders": {}
},
"@welcomeUser": {
"type": "String",
"placeholders": {
"user": {
"type": "String"
}
}
},
"publicInviteDescChat": "এই চ্যাটে আমন্ত্রণ জানানোর জন্য ব্যবহারকারীদের খুঁজুন।",
"publicInviteDescSpace": "এই স্পেসে আমন্ত্রণ জানানোর জন্য ব্যবহারকারীদের খুঁজুন।",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -4279,7 +4279,7 @@
"joinPublicTrip": "མི་ཚེས་ལ་ལོག་འབད།",
"startOwnTrip": "ངེད་རང་གི་ལོག་ལ་སྦྱོར་བཅོས།",
"@@locale": "bo",
"@@last_modified": "2026-01-21 13:54:28.767499",
"@@last_modified": "2026-01-22 12:01:59.937396",
"@alwaysUse24HourFormat": {
"type": "String",
"placeholders": {}
@ -10654,5 +10654,29 @@
"@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"
}
}
},
"publicInviteDescChat": "Searc for users to invite them to this chat.",
"publicInviteDescSpace": "Searc for users to invite them to this space.",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -1,5 +1,5 @@
{
"@@last_modified": "2026-01-21 13:54:08.647836",
"@@last_modified": "2026-01-22 12:01:35.625715",
"about": "Quant a",
"@about": {
"type": "String",
@ -10924,5 +10924,29 @@
"@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"
}
}
},
"publicInviteDescChat": "Cerca usuaris per convidar-los a aquest xat.",
"publicInviteDescSpace": "Cerca usuaris per convidar-los a aquest espai.",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -1,6 +1,6 @@
{
"@@locale": "cs",
"@@last_modified": "2026-01-21 13:54:04.800051",
"@@last_modified": "2026-01-22 12:01:30.360444",
"about": "O aplikaci",
"@about": {
"type": "String",
@ -11507,5 +11507,29 @@
"@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"
}
}
},
"publicInviteDescChat": "Hledejte uživatele, které chcete pozvat do tohoto chatu.",
"publicInviteDescSpace": "Hledejte uživatele, které chcete pozvat do tohoto prostoru.",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -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 12:00:57.389253",
"@aboutHomeserver": {
"type": "String",
"placeholders": {
@ -11961,5 +11961,29 @@
"@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"
}
}
},
"publicInviteDescChat": "Søg efter brugere for at invitere dem til denne chat.",
"publicInviteDescSpace": "Søg efter brugere for at invitere dem til dette rum.",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -1,6 +1,6 @@
{
"@@locale": "de",
"@@last_modified": "2026-01-21 13:53:56.595777",
"@@last_modified": "2026-01-22 12:01:22.683777",
"alwaysUse24HourFormat": "true",
"@alwaysUse24HourFormat": {
"description": "Set to true to always display time of day in 24 hour format."
@ -10907,5 +10907,29 @@
"@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"
}
}
},
"publicInviteDescChat": "Suchen Sie nach Benutzern, um sie zu diesem Chat einzuladen.",
"publicInviteDescSpace": "Suchen Sie nach Benutzern, um sie zu diesem Raum einzuladen.",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -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 12:02:10.279313",
"@alwaysUse24HourFormat": {
"type": "String",
"placeholders": {}
@ -11958,5 +11958,29 @@
"@knockDesc": {
"type": "String",
"placeholders": {}
},
"joinSpaceOnboardingDesc": "Έχετε έναν κωδικό πρόσκλησης ή σύνδεσμο για ένα δημόσιο μάθημα;",
"welcomeUser": "Καλώς ήρθατε {user}",
"@joinSpaceOnboardingDesc": {
"type": "String",
"placeholders": {}
},
"@welcomeUser": {
"type": "String",
"placeholders": {
"user": {
"type": "String"
}
}
},
"publicInviteDescChat": "Αναζητήστε χρήστες για να τους προσκαλέσετε σε αυτήν την συνομιλία.",
"publicInviteDescSpace": "Αναζητήστε χρήστες για να τους προσκαλέσετε σε αυτόν τον χώρο.",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -5058,5 +5058,17 @@
"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",
"publicInviteDescChat": "Search for users to invite them to this chat.",
"publicInviteDescSpace": "Search for users to invite them to this space."
}

View file

@ -1,5 +1,5 @@
{
"@@last_modified": "2026-01-21 13:54:42.193114",
"@@last_modified": "2026-01-22 12:02:15.725740",
"about": "Prio",
"@about": {
"type": "String",
@ -11989,5 +11989,29 @@
"@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"
}
}
},
"publicInviteDescChat": "Serĉu uzantojn por inviti ilin al ĉi tiu konversacio.",
"publicInviteDescSpace": "Serĉu uzantojn por inviti ilin al ĉi tiu spaco.",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -1,6 +1,6 @@
{
"@@locale": "es",
"@@last_modified": "2026-01-21 13:53:29.857658",
"@@last_modified": "2026-01-22 12:00:51.625942",
"about": "Acerca de",
"@about": {
"type": "String",
@ -8134,5 +8134,29 @@
"@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"
}
}
},
"publicInviteDescChat": "Busca usuarios para invitarlos a este chat.",
"publicInviteDescSpace": "Busca usuarios para invitarlos a este espacio.",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -1,6 +1,6 @@
{
"@@locale": "et",
"@@last_modified": "2026-01-21 13:53:55.586614",
"@@last_modified": "2026-01-22 12:01:20.400166",
"about": "Rakenduse teave",
"@about": {
"type": "String",
@ -11171,5 +11171,29 @@
"@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"
}
}
},
"publicInviteDescChat": "Otsi kasutajaid, et neid sellesse vestlusse kutsuda.",
"publicInviteDescSpace": "Otsi kasutajaid, et neid sellesse ruumi kutsuda.",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -1,6 +1,6 @@
{
"@@locale": "eu",
"@@last_modified": "2026-01-21 13:53:53.122879",
"@@last_modified": "2026-01-22 12:01:17.457241",
"about": "Honi buruz",
"@about": {
"type": "String",
@ -10900,5 +10900,29 @@
"@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"
}
}
},
"publicInviteDescChat": "Bilatu erabiltzaileak txat honetara gonbidatzeko.",
"publicInviteDescSpace": "Bilatu erabiltzaileak espazio honetara gonbidatzeko.",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -1,5 +1,5 @@
{
"@@last_modified": "2026-01-21 13:54:33.096668",
"@@last_modified": "2026-01-22 12:02:04.083596",
"repeatPassword": "تکرار رمزعبور",
"@repeatPassword": {},
"about": "درباره",
@ -11632,5 +11632,29 @@
"@knockDesc": {
"type": "String",
"placeholders": {}
},
"joinSpaceOnboardingDesc": "آیا کد دعوت یا لینکی به یک دوره عمومی دارید؟",
"welcomeUser": "خوش آمدید {user}",
"@joinSpaceOnboardingDesc": {
"type": "String",
"placeholders": {}
},
"@welcomeUser": {
"type": "String",
"placeholders": {
"user": {
"type": "String"
}
}
},
"publicInviteDescChat": "برای دعوت کاربران به این چت، جستجو کنید.",
"publicInviteDescSpace": "برای دعوت کاربران به این فضا، جستجو کنید.",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -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 12:00:55.098205",
"@alwaysUse24HourFormat": {
"type": "String",
"placeholders": {}
@ -11523,5 +11523,29 @@
"@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"
}
}
},
"publicInviteDescChat": "Etsi käyttäjiä kutsuaksesi heidät tähän keskusteluun.",
"publicInviteDescSpace": "Etsi käyttäjiä kutsuaksesi heidät tähän tilaan.",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -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 12:01:44.028462",
"@setCustomPermissionLevel": {
"type": "String",
"placeholders": {}
@ -11876,5 +11876,29 @@
"@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"
}
}
},
"publicInviteDescChat": "Maghanap ng mga gumagamit upang imbitahan sila sa chat na ito.",
"publicInviteDescSpace": "Maghanap ng mga gumagamit upang imbitahan sila sa espasyong ito.",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -1,6 +1,6 @@
{
"@@locale": "fr",
"@@last_modified": "2026-01-21 13:54:48.318824",
"@@last_modified": "2026-01-22 12:02:23.383738",
"about": "À propos",
"@about": {
"type": "String",
@ -11224,5 +11224,29 @@
"@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"
}
}
},
"publicInviteDescChat": "Recherchez des utilisateurs pour les inviter à ce chat.",
"publicInviteDescSpace": "Recherchez des utilisateurs pour les inviter à cet espace.",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -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 12:02:22.009738",
"@customReaction": {
"type": "String",
"placeholders": {}
@ -10898,5 +10898,29 @@
"@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"
}
}
},
"publicInviteDescChat": "Cuardaigh úsáideoirí le cuireadh a thabhairt dóibh chuig an gcomhrá seo.",
"publicInviteDescSpace": "Cuardaigh úsáideoirí le cuireadh a thabhairt dóibh chuig an spás seo.",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -1,6 +1,6 @@
{
"@@locale": "gl",
"@@last_modified": "2026-01-21 13:53:31.619299",
"@@last_modified": "2026-01-22 12:00:52.883998",
"about": "Acerca de",
"@about": {
"type": "String",
@ -10897,5 +10897,29 @@
"@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"
}
}
},
"publicInviteDescChat": "Busca usuarios para convidalos a este chat.",
"publicInviteDescSpace": "Busca usuarios para convidalos a este espazo.",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -1,5 +1,5 @@
{
"@@last_modified": "2026-01-21 13:53:47.592162",
"@@last_modified": "2026-01-22 12:01:11.911490",
"about": "אודות",
"@about": {
"type": "String",
@ -11949,5 +11949,29 @@
"@knockDesc": {
"type": "String",
"placeholders": {}
},
"joinSpaceOnboardingDesc": "האם יש לך קוד הזמנה או קישור לקורס ציבורי?",
"welcomeUser": "ברוך הבא {user}",
"@joinSpaceOnboardingDesc": {
"type": "String",
"placeholders": {}
},
"@welcomeUser": {
"type": "String",
"placeholders": {
"user": {
"type": "String"
}
}
},
"publicInviteDescChat": "חפש משתמשים כדי להזמין אותם לצ'אט הזה.",
"publicInviteDescSpace": "חפש משתמשים כדי להזמין אותם למקום הזה.",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -4483,7 +4483,7 @@
"playWithAI": "अभी के लिए एआई के साथ खेलें",
"courseStartDesc": "पैंजिया बॉट कभी भी जाने के लिए तैयार है!\n\n...लेकिन दोस्तों के साथ सीखना बेहतर है!",
"@@locale": "hi",
"@@last_modified": "2026-01-21 13:54:40.850433",
"@@last_modified": "2026-01-22 12:02:13.864252",
"@alwaysUse24HourFormat": {
"type": "String",
"placeholders": {}
@ -11985,5 +11985,29 @@
"@knockDesc": {
"type": "String",
"placeholders": {}
},
"joinSpaceOnboardingDesc": "क्या आपके पास एक आमंत्रण कोड या सार्वजनिक पाठ्यक्रम के लिए लिंक है?",
"welcomeUser": "स्वागत है {user}",
"@joinSpaceOnboardingDesc": {
"type": "String",
"placeholders": {}
},
"@welcomeUser": {
"type": "String",
"placeholders": {
"user": {
"type": "String"
}
}
},
"publicInviteDescChat": "इस चैट में आमंत्रित करने के लिए उपयोगकर्ताओं की खोज करें।",
"publicInviteDescSpace": "इस स्थान में आमंत्रित करने के लिए उपयोगकर्ताओं की खोज करें।",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -1,6 +1,6 @@
{
"@@locale": "hr",
"@@last_modified": "2026-01-21 13:53:46.524141",
"@@last_modified": "2026-01-22 12:01:10.402528",
"about": "Informacije",
"@about": {
"type": "String",
@ -11272,5 +11272,29 @@
"@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"
}
}
},
"publicInviteDescChat": "Pretražite korisnike kako biste ih pozvali u ovaj chat.",
"publicInviteDescSpace": "Pretražite korisnike kako biste ih pozvali u ovaj prostor.",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -1,6 +1,6 @@
{
"@@locale": "hu",
"@@last_modified": "2026-01-21 13:53:36.742109",
"@@last_modified": "2026-01-22 12:01:00.971468",
"about": "Névjegy",
"@about": {
"type": "String",
@ -10901,5 +10901,29 @@
"@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"
}
}
},
"publicInviteDescChat": "Keresd meg a felhasználókat, hogy meghívd őket erre a csevegésre.",
"publicInviteDescSpace": "Keresd meg a felhasználókat, hogy meghívd őket erre a térre.",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -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 12:01:13.730279",
"@alwaysUse24HourFormat": {
"type": "String",
"placeholders": {}
@ -11978,5 +11978,29 @@
"@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"
}
}
},
"publicInviteDescChat": "Cerca per utenti per invitarli a questa chat.",
"publicInviteDescSpace": "Cerca per utenti per invitarli a questo spazio.",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -1,5 +1,5 @@
{
"@@last_modified": "2026-01-21 13:53:37.899898",
"@@last_modified": "2026-01-22 12:01:02.729155",
"setAsCanonicalAlias": "Atur sebagai alias utama",
"@setAsCanonicalAlias": {
"type": "String",
@ -10891,5 +10891,29 @@
"@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"
}
}
},
"publicInviteDescChat": "Cari pengguna untuk mengundang mereka ke obrolan ini.",
"publicInviteDescSpace": "Cari pengguna untuk mengundang mereka ke ruang ini.",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -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 12:01:08.955250",
"@alwaysUse24HourFormat": {
"type": "String",
"placeholders": {}
@ -11874,5 +11874,29 @@
"@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"
}
}
},
"publicInviteDescChat": "Cuir fiosrúcháin ar úsáideoirí chun iad a gcuir isteach sa chomhrá seo.",
"publicInviteDescSpace": "Cuir fiosrúcháin ar úsáideoirí chun iad a gcuir isteach sa spás seo.",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -1,5 +1,5 @@
{
"@@last_modified": "2026-01-21 13:54:01.568848",
"@@last_modified": "2026-01-22 12:01:27.366543",
"about": "Informazioni",
"@about": {
"type": "String",
@ -10903,5 +10903,29 @@
"@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"
}
}
},
"publicInviteDescChat": "Cerca utenti per invitarli a questa chat.",
"publicInviteDescSpace": "Cerca utenti per invitarli a questo spazio.",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -1,6 +1,6 @@
{
"@@locale": "ja",
"@@last_modified": "2026-01-21 13:54:39.359536",
"@@last_modified": "2026-01-22 12:02:12.048814",
"about": "このアプリについて",
"@about": {
"type": "String",
@ -11690,5 +11690,29 @@
"@knockDesc": {
"type": "String",
"placeholders": {}
},
"joinSpaceOnboardingDesc": "招待コードまたは公開コースへのリンクはありますか?",
"welcomeUser": "ようこそ {user} さん",
"@joinSpaceOnboardingDesc": {
"type": "String",
"placeholders": {}
},
"@welcomeUser": {
"type": "String",
"placeholders": {
"user": {
"type": "String"
}
}
},
"publicInviteDescChat": "このチャットに招待するユーザーを検索します。",
"publicInviteDescSpace": "このスペースに招待するユーザーを検索します。",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -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 12:02:18.860564",
"@alwaysUse24HourFormat": {
"type": "String",
"placeholders": {}
@ -11930,5 +11930,29 @@
"@knockDesc": {
"type": "String",
"placeholders": {}
},
"joinSpaceOnboardingDesc": "გაქვთ თუ არა მოწვევის კოდი ან ბმული საჯარო კურსზე?",
"welcomeUser": "კეთილი იყოს თქვენი მობრძანება {user}",
"@joinSpaceOnboardingDesc": {
"type": "String",
"placeholders": {}
},
"@welcomeUser": {
"type": "String",
"placeholders": {
"user": {
"type": "String"
}
}
},
"publicInviteDescChat": "მომხმარებლების ძიება, რათა მათ ამ ჩატში მოიწვიოთ.",
"publicInviteDescSpace": "მომხმარებლების ძიება, რათა მათ ამ სივრცეში მოიწვიოთ.",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -1,5 +1,5 @@
{
"@@last_modified": "2026-01-21 13:53:28.417406",
"@@last_modified": "2026-01-22 12:00:49.883642",
"about": "소개",
"@about": {
"type": "String",
@ -11008,5 +11008,29 @@
"@knockDesc": {
"type": "String",
"placeholders": {}
},
"joinSpaceOnboardingDesc": "공개 과정에 대한 초대 코드나 링크가 있습니까?",
"welcomeUser": "환영합니다 {user}",
"@joinSpaceOnboardingDesc": {
"type": "String",
"placeholders": {}
},
"@welcomeUser": {
"type": "String",
"placeholders": {
"user": {
"type": "String"
}
}
},
"publicInviteDescChat": "이 채팅에 초대할 사용자를 검색하세요.",
"publicInviteDescSpace": "이 공간에 초대할 사용자를 검색하세요.",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -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 12:01:53.612206",
"@alwaysUse24HourFormat": {
"type": "String",
"placeholders": {}
@ -11705,5 +11705,29 @@
"@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"
}
}
},
"publicInviteDescChat": "Ieškokite vartotojų, kad juos pakviestumėte į šį pokalbį.",
"publicInviteDescSpace": "Ieškokite vartotojų, kad juos pakviestumėte į šią erdvę.",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -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 12:01:46.451812",
"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,29 @@
"@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"
}
}
},
"publicInviteDescChat": "Meklējiet lietotājus, lai viņus aicinātu uz šo čatu.",
"publicInviteDescSpace": "Meklējiet lietotājus, lai viņus aicinātu uz šo telpu.",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -1,5 +1,5 @@
{
"@@last_modified": "2026-01-21 13:54:06.232198",
"@@last_modified": "2026-01-22 12:01:31.934487",
"about": "Om",
"@about": {
"type": "String",
@ -11993,5 +11993,29 @@
"@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"
}
}
},
"publicInviteDescChat": "Søk etter brukere for å invitere dem til denne chatten.",
"publicInviteDescSpace": "Søk etter brukere for å invitere dem til dette rommet.",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -1,5 +1,5 @@
{
"@@last_modified": "2026-01-21 13:54:27.649909",
"@@last_modified": "2026-01-22 12:01:58.109571",
"about": "Over ons",
"@about": {
"type": "String",
@ -10900,5 +10900,29 @@
"@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"
}
}
},
"publicInviteDescChat": "Zoek naar gebruikers om ze uit te nodigen voor deze chat.",
"publicInviteDescSpace": "Zoek naar gebruikers om ze uit te nodigen voor deze ruimte.",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -1,6 +1,6 @@
{
"@@locale": "pl",
"@@last_modified": "2026-01-21 13:54:34.451816",
"@@last_modified": "2026-01-22 12:02:06.402870",
"about": "O aplikacji",
"@about": {
"type": "String",
@ -10898,5 +10898,29 @@
"@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"
}
}
},
"publicInviteDescChat": "Szukaj użytkowników, aby zaprosić ich do tej rozmowy.",
"publicInviteDescSpace": "Szukaj użytkowników, aby zaprosić ich do tej przestrzeni.",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -1,5 +1,5 @@
{
"@@last_modified": "2026-01-21 13:53:54.148542",
"@@last_modified": "2026-01-22 12:01:18.883594",
"copiedToClipboard": "Copiada para a área de transferência",
"@copiedToClipboard": {
"type": "String",
@ -12000,5 +12000,29 @@
"@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"
}
}
},
"publicInviteDescChat": "Procure usuários para convidá-los para este chat.",
"publicInviteDescSpace": "Procure usuários para convidá-los para este espaço.",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -1,5 +1,5 @@
{
"@@last_modified": "2026-01-21 13:53:51.587209",
"@@last_modified": "2026-01-22 12:01:15.782911",
"about": "Sobre",
"@about": {
"type": "String",
@ -11258,5 +11258,29 @@
"@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"
}
}
},
"publicInviteDescChat": "Procure usuários para convidá-los para este chat.",
"publicInviteDescSpace": "Procure usuários para convidá-los para este espaço.",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -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 12:01:38.348686",
"@alwaysUse24HourFormat": {
"type": "String",
"placeholders": {}
@ -11929,5 +11929,29 @@
"@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"
}
}
},
"publicInviteDescChat": "Procure usuários para convidá-los para este chat.",
"publicInviteDescSpace": "Procure usuários para convidá-los para este espaço.",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -1,5 +1,5 @@
{
"@@last_modified": "2026-01-21 13:53:41.456181",
"@@last_modified": "2026-01-22 12:01:04.721303",
"about": "Despre",
"@about": {
"type": "String",
@ -11635,5 +11635,29 @@
"@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"
}
}
},
"publicInviteDescChat": "Caută utilizatori pentru a-i invita în acest chat.",
"publicInviteDescSpace": "Caută utilizatori pentru a-i invita în acest spațiu.",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -1,6 +1,6 @@
{
"@@locale": "ru",
"@@last_modified": "2026-01-21 13:54:43.229000",
"@@last_modified": "2026-01-22 12:02:17.097388",
"about": "О проекте",
"@about": {
"type": "String",
@ -3132,8 +3132,6 @@
"@invalidUrl": {},
"addLink": "Добавить ссылку",
"@addLink": {},
"italicText": "Italic",
"@italicText": {},
"unableToJoinChat": "Невозможно присоединиться к чату. Возможно, другая сторона уже закончила разговор.",
"@unableToJoinChat": {},
"serverLimitReached": "Ограничения сервера. Ожидайте{seconds} секунд...",
@ -3689,13 +3687,6 @@
"acceptSelection": "Принять исправление",
"why": "Почему?",
"definition": "Определение",
"exampleSentence": "Приклад речення",
"reportToTeacher": "Кому ви хочете повідомити про це повідомлення?",
"reportMessageTitle": "{reportingUserId} повідомив про повідомлення від {reportedUserId} у чаті {roomName}",
"reportMessageBody": "Повідомлення: {reportedMessage}\nПричина: {reason}",
"noTeachersFound": "Вчителі не знайдені для повідомлення",
"trialExpiration": "Ваша безкоштовна пробна версія закінчується {expiration}",
"freeTrialDesc": "Нові користувачі отримують тижневу безкоштовну пробну версію Pangea Chat",
"activateTrial": "Безкоштовна 7-денна пробна версія",
"successfullySubscribed": "Ви успішно підписалися!",
"clickToManageSubscription": "Натисніть тут, щоб керувати підпискою.",
@ -4078,13 +4069,6 @@
"constructUseIncMDesc": "Некорректно в деятельности по грамматике",
"constructUseIgnMDesc": "Игнорируется в деятельности по грамматике",
"constructUseEmojiDesc": "Правильно в деятельности по эмодзи",
"constructUseCollected": "Thu thập trong trò chuyện",
"constructUseNanDesc": "Không áp dụng được",
"xpIntoLevel": "{currentXP} / {maxXP} XP",
"enableTTSToolName": "Bật chuyển đổi văn bản thành giọng nói",
"enableTTSToolDescription": "Cho phép ứng dụng tạo ra đầu ra chuyển đổi văn bản thành giọng nói cho các phần của văn bản bằng ngôn ngữ mục tiêu của bạn.",
"yourUsername": "Tên người dùng của bạn",
"yourEmail": "Email của bạn",
"iWantToLearn": "Я хочу учиться",
"pleaseEnterEmail": "Пожалуйста, введите действительный адрес электронной почты.",
"myBaseLanguage": "Мой основной язык",
@ -11005,5 +10989,48 @@
"@knockDesc": {
"type": "String",
"placeholders": {}
},
"italicText": "Курсивный текст",
"exampleSentence": "Пример предложения",
"reportToTeacher": "Кому вы хотите пожаловаться на это сообщение?",
"reportMessageTitle": "{reportingUserId} пожаловался на сообщение от {reportedUserId} в чате {roomName}",
"reportMessageBody": "Сообщение: {reportedMessage}\nПричина: {reason}",
"noTeachersFound": "Учителя для жалобы не найдены",
"trialExpiration": "Ваш бесплатный пробный период истекает {expiration}",
"freeTrialDesc": "Новые пользователи получают бесплатную пробную неделю в Pangea Chat",
"constructUseCollected": "Собрано в чате",
"constructUseNanDesc": "Не применимо",
"xpIntoLevel": "{currentXP} / {maxXP} XP",
"enableTTSToolName": "Включен преобразователь текста в речь",
"enableTTSToolDescription": "Позволяет приложению генерировать озвучивание текста на вашем целевом языке.",
"yourUsername": "Ваше имя пользователя",
"yourEmail": "Ваш email",
"@italicText": {
"type": "String",
"placeholders": {}
},
"joinSpaceOnboardingDesc": "У вас есть код приглашения или ссылка на публичный курс?",
"welcomeUser": "Добро пожаловать {user}",
"@joinSpaceOnboardingDesc": {
"type": "String",
"placeholders": {}
},
"@welcomeUser": {
"type": "String",
"placeholders": {
"user": {
"type": "String"
}
}
},
"publicInviteDescChat": "Ищите пользователей, чтобы пригласить их в этот чат.",
"publicInviteDescSpace": "Ищите пользователей, чтобы пригласить их в это пространство.",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -1,6 +1,6 @@
{
"@@locale": "sk",
"@@last_modified": "2026-01-21 13:53:43.706457",
"@@last_modified": "2026-01-22 12:01:06.427460",
"about": "O aplikácii",
"@about": {
"type": "String",
@ -11984,5 +11984,29 @@
"@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"
}
}
},
"publicInviteDescChat": "Hľadajte používateľov, aby ste ich pozvali do tohto chatu.",
"publicInviteDescSpace": "Hľadajte používateľov, aby ste ich pozvali do tohto priestoru.",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -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 12:01:24.219945",
"@alwaysUse24HourFormat": {
"type": "String",
"placeholders": {}
@ -11981,5 +11981,29 @@
"@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"
}
}
},
"publicInviteDescChat": "Išči uporabnike, da jih povabiš v ta klepet.",
"publicInviteDescSpace": "Išči uporabnike, da jih povabiš v ta prostor.",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -1,5 +1,5 @@
{
"@@last_modified": "2026-01-21 13:54:45.561732",
"@@last_modified": "2026-01-22 12:02:20.533801",
"about": "О програму",
"@about": {
"type": "String",
@ -12002,5 +12002,29 @@
"@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"
}
}
},
"publicInviteDescChat": "Pretražite korisnike da ih pozovete u ovaj čat.",
"publicInviteDescSpace": "Pretražite korisnike da ih pozovete u ovaj prostor.",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -1,5 +1,5 @@
{
"@@last_modified": "2026-01-21 13:54:35.931933",
"@@last_modified": "2026-01-22 12:02:08.064498",
"about": "Om",
"@about": {
"type": "String",
@ -11378,5 +11378,29 @@
"@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"
}
}
},
"publicInviteDescChat": "Sök efter användare för att bjuda in dem till den här chatten.",
"publicInviteDescSpace": "Sök efter användare för att bjuda in dem till det här utrymmet.",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -1,5 +1,5 @@
{
"@@last_modified": "2026-01-21 13:54:25.999605",
"@@last_modified": "2026-01-22 12:01:56.352823",
"acceptedTheInvitation": "👍 {username} அழைப்பை ஏற்றுக்கொண்டது",
"@acceptedTheInvitation": {
"type": "String",
@ -11124,5 +11124,29 @@
"@knockDesc": {
"type": "String",
"placeholders": {}
},
"joinSpaceOnboardingDesc": "உங்களுக்கு ஒரு அழைப்பு குறியீடு அல்லது பொது பாடத்திற்கு இணைப்பு உள்ளதா?",
"welcomeUser": "வரவேற்கிறேன் {user}",
"@joinSpaceOnboardingDesc": {
"type": "String",
"placeholders": {}
},
"@welcomeUser": {
"type": "String",
"placeholders": {
"user": {
"type": "String"
}
}
},
"publicInviteDescChat": "இந்த உரையாடலுக்கு அழைக்க பயனர்களை தேடுங்கள்.",
"publicInviteDescSpace": "இந்த இடத்திற்கு அழைக்க பயனர்களை தேடுங்கள்.",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -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 12:01:51.350363",
"@setCustomPermissionLevel": {
"type": "String",
"placeholders": {}
@ -11989,5 +11989,29 @@
"@knockDesc": {
"type": "String",
"placeholders": {}
},
"joinSpaceOnboardingDesc": "మీకు పబ్లిక్ కోర్సుకు ఆహ్వాన కోడ్ లేదా లింక్ ఉందా?",
"welcomeUser": "స్వాగతం {user}",
"@joinSpaceOnboardingDesc": {
"type": "String",
"placeholders": {}
},
"@welcomeUser": {
"type": "String",
"placeholders": {
"user": {
"type": "String"
}
}
},
"publicInviteDescChat": "ఈ చాట్లో ఆహ్వానించడానికి వినియోగదారులను శోధించండి.",
"publicInviteDescSpace": "ఈ స్థలంలో ఆహ్వానించడానికి వినియోగదారులను శోధించండి.",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -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 12:01:36.919446",
"@alwaysUse24HourFormat": {
"type": "String",
"placeholders": {}
@ -11958,5 +11958,29 @@
"@knockDesc": {
"type": "String",
"placeholders": {}
},
"joinSpaceOnboardingDesc": "คุณมีรหัสเชิญหรือลิงก์ไปยังหลักสูตรสาธารณะหรือไม่?",
"welcomeUser": "ยินดีต้อนรับ {user}",
"@joinSpaceOnboardingDesc": {
"type": "String",
"placeholders": {}
},
"@welcomeUser": {
"type": "String",
"placeholders": {
"user": {
"type": "String"
}
}
},
"publicInviteDescChat": "ค้นหาผู้ใช้เพื่อนำไปเชิญเข้าร่วมแชทนี้。",
"publicInviteDescSpace": "ค้นหาผู้ใช้เพื่อนำไปเชิญเข้าร่วมพื้นที่นี้。",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -1,6 +1,6 @@
{
"@@locale": "tr",
"@@last_modified": "2026-01-21 13:54:19.467039",
"@@last_modified": "2026-01-22 12:01:49.339268",
"about": "Hakkında",
"@about": {
"type": "String",
@ -11122,5 +11122,29 @@
"@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"
}
}
},
"publicInviteDescChat": "Bu sohbete davet etmek için kullanıcıları arayın.",
"publicInviteDescSpace": "Bu alana davet etmek için kullanıcıları arayın.",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -1,6 +1,6 @@
{
"@@locale": "uk",
"@@last_modified": "2026-01-21 13:54:03.403456",
"@@last_modified": "2026-01-22 12:01:28.947095",
"about": "Про застосунок",
"@about": {
"type": "String",
@ -10894,5 +10894,29 @@
"@knockDesc": {
"type": "String",
"placeholders": {}
},
"joinSpaceOnboardingDesc": "У вас є код запрошення або посилання на публічний курс?",
"welcomeUser": "Ласкаво просимо {user}",
"@joinSpaceOnboardingDesc": {
"type": "String",
"placeholders": {}
},
"@welcomeUser": {
"type": "String",
"placeholders": {
"user": {
"type": "String"
}
}
},
"publicInviteDescChat": "Шукайте користувачів, щоб запросити їх до цього чату.",
"publicInviteDescSpace": "Шукайте користувачів, щоб запросити їх до цього простору.",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -1,5 +1,5 @@
{
"@@last_modified": "2026-01-21 13:54:24.252269",
"@@last_modified": "2026-01-22 12:01:54.904291",
"about": "Giới thiệu",
"@about": {
"type": "String",
@ -6470,5 +6470,29 @@
"@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"
}
}
},
"publicInviteDescChat": "Tìm kiếm người dùng để mời họ tham gia trò chuyện này.",
"publicInviteDescSpace": "Tìm kiếm người dùng để mời họ tham gia không gian này.",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -1856,7 +1856,7 @@
"selectAll": "全選",
"deselectAll": "取消全選",
"@@locale": "yue",
"@@last_modified": "2026-01-21 13:53:59.885092",
"@@last_modified": "2026-01-22 12:01:25.863585",
"@ignoreUser": {
"type": "String",
"placeholders": {}
@ -11991,5 +11991,29 @@
"@knockDesc": {
"type": "String",
"placeholders": {}
},
"joinSpaceOnboardingDesc": "你有邀請碼或公共課程的鏈接嗎?",
"welcomeUser": "歡迎 {user}",
"@joinSpaceOnboardingDesc": {
"type": "String",
"placeholders": {}
},
"@welcomeUser": {
"type": "String",
"placeholders": {
"user": {
"type": "String"
}
}
},
"publicInviteDescChat": "搜尋用戶以邀請他們加入此聊天。",
"publicInviteDescSpace": "搜尋用戶以邀請他們加入此空間。",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -1,6 +1,6 @@
{
"@@locale": "zh",
"@@last_modified": "2026-01-21 13:54:29.681537",
"@@last_modified": "2026-01-22 12:02:00.962577",
"about": "关于",
"@about": {
"type": "String",
@ -10891,5 +10891,29 @@
"@knockDesc": {
"type": "String",
"placeholders": {}
},
"joinSpaceOnboardingDesc": "您是否有邀请代码或公共课程的链接?",
"welcomeUser": "欢迎 {user}",
"@joinSpaceOnboardingDesc": {
"type": "String",
"placeholders": {}
},
"@welcomeUser": {
"type": "String",
"placeholders": {
"user": {
"type": "String"
}
}
},
"publicInviteDescChat": "搜索用户以邀请他们加入此聊天。",
"publicInviteDescSpace": "搜索用户以邀请他们加入此空间。",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -1,5 +1,5 @@
{
"@@last_modified": "2026-01-21 13:54:13.165623",
"@@last_modified": "2026-01-22 12:01:42.417971",
"about": "關於",
"@about": {
"type": "String",
@ -10898,5 +10898,29 @@
"@knockDesc": {
"type": "String",
"placeholders": {}
},
"joinSpaceOnboardingDesc": "您是否有邀請碼或公共課程的鏈接?",
"welcomeUser": "歡迎 {user}",
"@joinSpaceOnboardingDesc": {
"type": "String",
"placeholders": {}
},
"@welcomeUser": {
"type": "String",
"placeholders": {
"user": {
"type": "String"
}
}
},
"publicInviteDescChat": "搜尋用戶以邀請他們加入此聊天。",
"publicInviteDescSpace": "搜尋用戶以邀請他們加入此空間。",
"@publicInviteDescChat": {
"type": "String",
"placeholders": {}
},
"@publicInviteDescSpace": {
"type": "String",
"placeholders": {}
}
}

View file

@ -952,6 +952,9 @@ class ChatController extends State<ChatPageWithRoom>
}
final previousEdit = editEvent;
if (showEmojiPicker) {
hideEmojiPicker();
}
room
.pangeaSendTextEvent(

View file

@ -49,8 +49,19 @@ class ChatEmojiPicker extends StatelessWidget {
backgroundColor:
theme.colorScheme.onInverseSurface,
),
bottomActionBarConfig: const BottomActionBarConfig(
enabled: false,
bottomActionBarConfig: BottomActionBarConfig(
// #Pangea
// enabled: false,
showBackspaceButton: false,
backgroundColor: Theme.of(context)
.colorScheme
.surfaceContainer,
buttonColor: Theme.of(context)
.colorScheme
.surfaceContainer,
buttonIconColor:
Theme.of(context).colorScheme.onSurface,
// Pangea#
),
categoryViewConfig: CategoryViewConfig(
backspaceColor: theme.colorScheme.primary,
@ -68,6 +79,17 @@ class ChatEmojiPicker extends StatelessWidget {
)!,
indicatorColor: theme.colorScheme.onSurface,
),
// #Pangea
viewOrderConfig: const ViewOrderConfig(
middle: EmojiPickerItem.searchBar,
top: EmojiPickerItem.categoryBar,
bottom: EmojiPickerItem.emojiView,
),
searchViewConfig: SearchViewConfig(
backgroundColor: theme.colorScheme.surface,
buttonIconColor: theme.colorScheme.onSurface,
),
// Pangea#
),
),
// #Pangea

View file

@ -111,9 +111,12 @@ class ChatListController extends State<ChatList>
// StreamSubscription? _intentUriStreamSubscription;
// Pangea#
ActiveFilter activeFilter = AppConfig.separateChatTypes
? ActiveFilter.messages
: ActiveFilter.allChats;
// #Pangea
// ActiveFilter activeFilter = AppConfig.separateChatTypes
// ? ActiveFilter.messages
// : ActiveFilter.allChats;
ActiveFilter activeFilter = ActiveFilter.allChats;
// Pangea#
// #Pangea
String? get activeSpaceId => widget.activeSpaceId;

View file

@ -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<SpaceCodeOnboarding> createState() => SpaceCodeOnboardingState();
}
class SpaceCodeOnboardingState extends State<SpaceCodeOnboarding> {
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<void> _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<void> 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);
}

View file

@ -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"),
),
],
),
],
);
}
}

View file

@ -147,9 +147,7 @@ class SettingsView extends StatelessWidget {
displayname,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
fontSize: 18,
),
style: const TextStyle(fontSize: 18),
),
),
TextButton.icon(
@ -171,25 +169,6 @@ class SettingsView extends StatelessWidget {
// style: const TextStyle(fontSize: 12),
),
),
// #Pangea
TextButton.icon(
onPressed: controller.setStatus,
icon: const Icon(
Icons.add,
size: 14,
),
style: TextButton.styleFrom(
foregroundColor:
theme.colorScheme.secondary,
iconColor: theme.colorScheme.secondary,
),
label: Text(
L10n.of(context).setStatus,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
// Pangea#
],
),
),

View file

@ -353,14 +353,14 @@ class SettingsStyleView extends StatelessWidget {
storeKey: SettingKeys.showPresences,
defaultValue: AppConfig.showPresences,
),
SettingsSwitchListTile.adaptive(
title: L10n.of(context).separateChatTypes,
onChanged: (b) => AppConfig.separateChatTypes = b,
storeKey: SettingKeys.separateChatTypes,
defaultValue: AppConfig.separateChatTypes,
),
// #Pangea
// SettingsSwitchListTile.adaptive(
// title: L10n.of(context).separateChatTypes,
// onChanged: (b) => AppConfig.separateChatTypes = b,
// storeKey: SettingKeys.separateChatTypes,
// defaultValue: AppConfig.separateChatTypes,
// ),
// SettingsSwitchListTile.adaptive(
// title: L10n.of(context).displayNavigationRail,
// onChanged: (b) => AppConfig.displayNavigationRail = b,
// storeKey: SettingKeys.displayNavigationRail,

View file

@ -44,15 +44,9 @@ extension ActivityMenuLogic on ChatController {
return false;
}
final l1 =
MatrixState.pangeaController.userController.userL1?.langCodeShort;
final l2 =
MatrixState.pangeaController.userController.userL2?.langCodeShort;
final activityLang = room.activityPlan?.req.targetLanguage.split('-').first;
return activityLang != null &&
l2 != null &&
l2 != activityLang &&
l1 != activityLang;
return activityLang != null && l2 != activityLang;
}
}

View file

@ -8,7 +8,6 @@ import 'package:matrix/matrix.dart';
import 'package:fluffychat/l10n/l10n.dart';
import 'package:fluffychat/pangea/extensions/pangea_rooms_chunk_extension.dart';
import 'package:fluffychat/pangea/join_codes/space_code_controller.dart';
import 'package:fluffychat/pangea/navigation/navigation_util.dart';
import 'package:fluffychat/utils/adaptive_bottom_sheet.dart';
import 'package:fluffychat/widgets/avatar.dart';
import 'package:fluffychat/widgets/future_loading_dialog.dart';
@ -30,7 +29,7 @@ class PublicRoomBottomSheet extends StatefulWidget {
assert(roomAlias != null || chunk != null);
}
static Future<bool?> show({
static Future<String?> show({
required BuildContext context,
String? roomAlias,
PublicRoomsChunk? chunk,
@ -91,26 +90,13 @@ class PublicRoomBottomSheetState extends State<PublicRoomBottomSheet> {
notFoundError: L10n.of(context).notTheCodeError,
);
if (resp != null) {
Navigator.of(context).pop(true);
}
}
void _goToRoom(String roomID) {
if (chunk?.roomType != 'm.space' && !client.getRoomById(roomID)!.isSpace) {
NavigationUtil.goToSpaceRoute(
roomID,
[],
context,
);
} else {
context.go('/rooms/spaces/$roomID/details');
Navigator.of(context).pop(resp);
}
}
Future<void> _joinRoom() async {
if (_isRoomMember) {
_goToRoom(room!.id);
Navigator.of(context).pop();
Navigator.of(context).pop(room!.id);
return;
}
@ -131,15 +117,13 @@ class PublicRoomBottomSheetState extends State<PublicRoomBottomSheet> {
);
if (result.result != null) {
_goToRoom(result.result!);
Navigator.of(context).pop(true);
Navigator.of(context).pop(result.result!);
}
}
Future<void> _knockRoom() async {
if (_isRoomMember) {
_goToRoom(room!.id);
Navigator.of(context).pop();
Navigator.of(context).pop(room!.id);
return;
}

View file

@ -148,6 +148,20 @@ class PangeaInvitationSelectionController
return parents.first;
}
bool get showInviteAllInSpaceButton {
final roomParticipants = participants;
if (roomParticipants == null ||
filter != InvitationFilter.space ||
spaceParent == null) {
return false;
}
final spaceParticipants = spaceParent!.getParticipants();
return spaceParticipants.any(
(participant) => !roomParticipants.any((p) => p.id == participant.id),
);
}
List<InvitationFilter> get availableFilters => InvitationFilter.values
.where(
(f) => switch (f) {

View file

@ -157,27 +157,34 @@ class PangeaInvitationSelectionView extends StatelessWidget {
final participants =
room.getParticipants().map((user) => user.id).toSet();
return controller.filter == InvitationFilter.public
? ListView.builder(
itemCount: controller.foundProfiles.length,
itemBuilder: (BuildContext context, int i) =>
_InviteContactListTile(
profile: controller.foundProfiles[i],
isMember: participants.contains(
controller.foundProfiles[i].userId,
),
onTap: () => controller.inviteAction(
controller.foundProfiles[i].userId,
),
controller: controller,
),
)
? controller.foundProfiles.isEmpty
? Padding(
padding: const EdgeInsets.all(24.0),
child: Text(
room.isSpace
? L10n.of(context).publicInviteDescSpace
: L10n.of(context).publicInviteDescChat,
),
)
: ListView.builder(
itemCount: controller.foundProfiles.length,
itemBuilder: (BuildContext context, int i) =>
_InviteContactListTile(
profile: controller.foundProfiles[i],
isMember: participants.contains(
controller.foundProfiles[i].userId,
),
onTap: () => controller.inviteAction(
controller.foundProfiles[i].userId,
),
controller: controller,
),
)
: ListView.builder(
itemCount: contacts.length + 2,
itemBuilder: (BuildContext context, int i) {
if (i == 0) {
return controller.filter ==
InvitationFilter.space &&
controller.spaceParent != null
return controller.showInviteAllInSpaceButton
? ListTile(
leading: ClipPath(
clipper: MapClipper(),

View file

@ -1,94 +1,68 @@
import 'package:flutter/foundation.dart';
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/learning_settings/language_level_type_enum.dart';
class LanguageLevelDropdown extends StatelessWidget {
final LanguageLevelTypeEnum? initialLevel;
final Function(LanguageLevelTypeEnum)? onChanged;
final FormFieldValidator<Object>? validator;
final bool enabled;
final Color? backgroundColor;
final double? width;
final double? maxHeight;
const LanguageLevelDropdown({
super.key,
this.initialLevel = LanguageLevelTypeEnum.a1,
this.onChanged,
this.validator,
this.enabled = true,
this.backgroundColor,
this.width,
this.maxHeight,
});
@override
Widget build(BuildContext context) {
final l10n = L10n.of(context);
return DropdownButtonFormField2<LanguageLevelTypeEnum>(
customButton: initialLevel != null &&
LanguageLevelTypeEnum.values.contains(initialLevel)
? CustomDropdownTextButton(text: initialLevel!.title(context))
: null,
menuItemStyleData: const MenuItemStyleData(
padding: EdgeInsets.symmetric(
vertical: 8.0,
horizontal: 16.0,
return ButtonTheme(
alignedDropdown: true,
child: DropdownButtonFormField<LanguageLevelTypeEnum>(
itemHeight: null,
decoration: InputDecoration(
labelText: l10n.cefrLevelLabel,
),
height: 100.0,
),
decoration: InputDecoration(
labelText: l10n.cefrLevelLabel,
),
isExpanded: true,
dropdownStyleData: DropdownStyleData(
maxHeight: maxHeight ?? (kIsWeb ? 500 : null),
decoration: BoxDecoration(
color: backgroundColor ??
Theme.of(context).colorScheme.surfaceContainerHigh,
borderRadius: BorderRadius.circular(14.0),
),
width: width,
),
items:
LanguageLevelTypeEnum.values.map((LanguageLevelTypeEnum levelOption) {
return DropdownMenuItem(
value: levelOption,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.min,
children: [
Text(levelOption.title(context)),
Flexible(
child: Text(
levelOption.description(context),
style: TextStyle(
color: Theme.of(context).colorScheme.onSurfaceVariant,
fontSize: 14,
selectedItemBuilder: (context) => LanguageLevelTypeEnum.values
.map((levelOption) => Text(levelOption.title(context)))
.toList(),
isExpanded: true,
dropdownColor: Theme.of(context).colorScheme.surfaceContainerHigh,
borderRadius: BorderRadius.circular(14.0),
onChanged: (value) {
if (value != null) onChanged?.call(value);
},
initialValue: initialLevel,
items: LanguageLevelTypeEnum.values
.map((LanguageLevelTypeEnum levelOption) {
return DropdownMenuItem(
value: levelOption,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.min,
children: [
Text(levelOption.title(context)),
Flexible(
child: Text(
levelOption.description(context),
style: TextStyle(
color: Theme.of(context).colorScheme.onSurfaceVariant,
fontSize: 14,
),
maxLines: 5,
overflow: TextOverflow.ellipsis,
),
),
maxLines: 5,
overflow: TextOverflow.ellipsis,
),
],
),
],
),
);
}).toList(),
onChanged: enabled
? (value) {
if (value != null) onChanged?.call(value);
}
: null,
value: initialLevel,
validator: validator,
enableFeedback: enabled,
),
);
}).toList(),
),
);
}
}

View file

@ -438,7 +438,7 @@ class CourseChatsController extends State<CourseChats>
void joinChildRoom(SpaceRoomsChunk item) async {
final space = widget.client.getRoomById(widget.roomId);
final joined = await PublicRoomBottomSheet.show(
final roomId = await PublicRoomBottomSheet.show(
context: context,
chunk: item,
via: space?.spaceChildren
@ -447,10 +447,12 @@ class CourseChatsController extends State<CourseChats>
)
?.via,
);
if (mounted && joined == true) {
if (mounted && roomId != null) {
setState(() {
discoveredChildren?.remove(item);
});
NavigationUtil.goToSpaceRoute(roomId, [], context);
}
}

View file

@ -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<CourseCodePage> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SvgPicture.network(
"${AppConfig.assetsBaseURL}/${AddCoursePage.mapUnlockFileName}",
"${AppConfig.assetsBaseURL}/${SpaceConstants.mapUnlockFileName}",
width: 100.0,
height: 100.0,
colorFilter: ColorFilter.mode(

View file

@ -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<FindCoursePage> createState() => FindCoursePageState();
}
class FindCoursePageState extends State<FindCoursePage> {
final TextEditingController searchController = TextEditingController();
bool loading = true;
bool _fullyLoaded = false;
Object? error;
Timer? _coolDown;
LanguageModel? targetLanguageFilter;
List<PublicCoursesChunk> discoveredCourses = [];
Map<String, CoursePlanModel> 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<PublicCoursesChunk> get filteredCourses {
List<PublicCoursesChunk> 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<void> _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<void> _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,
),
],
),
),
),
],
),
),
),
),
);
}
}

View file

@ -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<String> introChatIcons = [
'${AppConfig.assetsBaseURL}/Introduction_1.jpg',

View file

@ -39,7 +39,7 @@ class UnderlineText extends StatelessWidget {
),
),
Positioned(
bottom: 2, // fixed distance from baseline
bottom: 0,
left: 0,
right: 0,
child: Container(

View file

@ -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#
);