diff --git a/lib/config/app_config.dart b/lib/config/app_config.dart index 5dda2ae41..55e038192 100644 --- a/lib/config/app_config.dart +++ b/lib/config/app_config.dart @@ -120,12 +120,10 @@ abstract class AppConfig { static const double readingAssistanceInputBarHeight = 175.0; static String errorSubscriptionId = "pangea_subscription_error"; - static TextStyle messageTextStyle( - Event? event, - Color textColor, - ) { + static TextStyle messageTextStyle(Event? event, Color textColor) { final fontSize = messageFontSize * AppSettings.fontSizeFactor.value; - final bigEmotes = event != null && + final bigEmotes = + event != null && event.onlyEmotes && event.numberEmotes > 0 && event.numberEmotes <= 3; @@ -133,10 +131,12 @@ abstract class AppConfig { return TextStyle( color: textColor, fontSize: bigEmotes ? fontSize * 5 : fontSize, - decoration: - (event?.redacted ?? false) ? TextDecoration.lineThrough : null, + decoration: (event?.redacted ?? false) + ? TextDecoration.lineThrough + : null, height: 1.3, ); } + // Pangea# } diff --git a/lib/config/routes.dart b/lib/config/routes.dart index 8a8463ae0..ddc628d92 100644 --- a/lib/config/routes.dart +++ b/lib/config/routes.dart @@ -75,26 +75,22 @@ abstract class AppRoutes { static FutureOr loggedInRedirect( BuildContext context, GoRouterState state, - ) { // #Pangea - // Matrix.of(context).widget.clients.any((client) => client.isLogged()) - // ? '/rooms' - // : null; - return PAuthGaurd.homeRedirect(context, state); - // Pangea# - } + // ) => Matrix.of(context).widget.clients.any((client) => client.isLogged()) + // ? '/rooms' + // : null; + ) => PAuthGaurd.homeRedirect(context, state); + // Pangea# static FutureOr loggedOutRedirect( BuildContext context, GoRouterState state, - ) { // #Pangea - // Matrix.of(context).widget.clients.any((client) => client.isLogged()) + // ) => Matrix.of(context).widget.clients.any((client) => client.isLogged()) // ? null // : '/home'; - return PAuthGaurd.roomsRedirect(context, state); - // Pangea# - } + ) => PAuthGaurd.roomsRedirect(context, state); + // Pangea# AppRoutes(); @@ -103,8 +99,8 @@ abstract class AppRoutes { path: '/', redirect: (context, state) => Matrix.of(context).widget.clients.any((client) => client.isLogged()) - ? '/rooms' - : '/home', + ? '/rooms' + : '/home', ), GoRoute( path: '/home', @@ -145,28 +141,20 @@ abstract class AppRoutes { // #Pangea GoRoute( path: 'language', - pageBuilder: (context, state) => defaultPageBuilder( - context, - state, - const LanguageSelectionPage(), - ), + pageBuilder: (context, state) => + defaultPageBuilder(context, state, const LanguageSelectionPage()), routes: [ GoRoute( path: 'signup', - pageBuilder: (context, state) => defaultPageBuilder( - context, - state, - const SignupPage(), - ), + pageBuilder: (context, state) => + defaultPageBuilder(context, state, const SignupPage()), routes: [ GoRoute( path: 'email', pageBuilder: (context, state) => defaultPageBuilder( context, state, - const SignupPage( - withEmail: true, - ), + const SignupPage(withEmail: true), ), ), ], @@ -178,28 +166,19 @@ abstract class AppRoutes { ), GoRoute( path: '/logs', - pageBuilder: (context, state) => defaultPageBuilder( - context, - state, - const LogViewer(), - ), + pageBuilder: (context, state) => + defaultPageBuilder(context, state, const LogViewer()), ), GoRoute( path: '/configs', - pageBuilder: (context, state) => defaultPageBuilder( - context, - state, - const ConfigViewer(), - ), + pageBuilder: (context, state) => + defaultPageBuilder(context, state, const ConfigViewer()), ), // #Pangea GoRoute( path: '/registration', - pageBuilder: (context, state) => defaultPageBuilder( - context, - state, - const LanguageSelectionPage(), - ), + pageBuilder: (context, state) => + defaultPageBuilder(context, state, const LanguageSelectionPage()), redirect: PAuthGaurd.onboardingRedirect, routes: [ GoRoute( @@ -212,14 +191,13 @@ abstract class AppRoutes { ), GoRoute( path: 'notifications', - pageBuilder: (context, state) => defaultPageBuilder( - context, - state, - const EnableNotifications(), - ), + pageBuilder: (context, state) => + defaultPageBuilder(context, state, const EnableNotifications()), redirect: (context, state) async { - final redirect = - await PAuthGaurd.onboardingRedirect(context, state); + final redirect = await PAuthGaurd.onboardingRedirect( + context, + state, + ); if (redirect != null) return redirect; final enabled = await Matrix.of(context).notificationsEnabled; if (enabled) return "/registration/course"; @@ -228,11 +206,8 @@ abstract class AppRoutes { ), GoRoute( path: 'course', - pageBuilder: (context, state) => defaultPageBuilder( - context, - state, - const SpaceCodeOnboarding(), - ), + pageBuilder: (context, state) => + defaultPageBuilder(context, state, const SpaceCodeOnboarding()), ), ], ), @@ -253,9 +228,7 @@ abstract class AppRoutes { pageBuilder: (context, state) => defaultPageBuilder( context, state, - BootstrapDialog( - wipe: state.uri.queryParameters['wipe'] == 'true', - ), + BootstrapDialog(wipe: state.uri.queryParameters['wipe'] == 'true'), ), ), ShellRoute( @@ -278,10 +251,7 @@ abstract class AppRoutes { // sideView: child, // ) // : child, - TwoColumnLayout( - state: state, - sideView: child, - ), + TwoColumnLayout(state: state, sideView: child), // Pangea# ), routes: [ @@ -310,11 +280,8 @@ abstract class AppRoutes { routes: [ GoRoute( path: 'archive', - pageBuilder: (context, state) => defaultPageBuilder( - context, - state, - const Archive(), - ), + pageBuilder: (context, state) => + defaultPageBuilder(context, state, const Archive()), routes: [ GoRoute( path: ':roomid', @@ -333,23 +300,14 @@ abstract class AppRoutes { ), GoRoute( path: 'newprivatechat', - pageBuilder: (context, state) => defaultPageBuilder( - context, - state, - const NewPrivateChat(), - ), + pageBuilder: (context, state) => + defaultPageBuilder(context, state, const NewPrivateChat()), redirect: loggedOutRedirect, ), GoRoute( path: 'newgroup', - pageBuilder: (context, state) => defaultPageBuilder( - context, - state, - // #Pangea - // const NewGroup(), - NewGroup(spaceId: state.uri.queryParameters['space']), - // Pangea# - ), + pageBuilder: (context, state) => + defaultPageBuilder(context, state, const NewGroup()), redirect: loggedOutRedirect, ), GoRoute( @@ -364,11 +322,8 @@ abstract class AppRoutes { // #Pangea GoRoute( path: 'course', - pageBuilder: (context, state) => defaultPageBuilder( - context, - state, - const FindCoursePage(), - ), + pageBuilder: (context, state) => + defaultPageBuilder(context, state, const FindCoursePage()), routes: [ GoRoute( path: 'private', @@ -638,11 +593,8 @@ abstract class AppRoutes { ), GoRoute( path: 'style', - pageBuilder: (context, state) => defaultPageBuilder( - context, - state, - const SettingsStyle(), - ), + pageBuilder: (context, state) => + defaultPageBuilder(context, state, const SettingsStyle()), redirect: loggedOutRedirect, ), GoRoute( @@ -656,20 +608,15 @@ abstract class AppRoutes { ), GoRoute( path: 'chat', - pageBuilder: (context, state) => defaultPageBuilder( - context, - state, - const SettingsChat(), - ), + pageBuilder: (context, state) => + defaultPageBuilder(context, state, const SettingsChat()), routes: [ GoRoute( path: 'emotes', pageBuilder: (context, state) => defaultPageBuilder( context, state, - EmotesSettings( - roomId: state.pathParameters['roomid'], - ), + EmotesSettings(roomId: state.pathParameters['roomid']), ), ), ], @@ -758,9 +705,7 @@ abstract class AppRoutes { pageBuilder: (context, state) => defaultPageBuilder( context, state, - const SettingsLearning( - isDialog: false, - ), + const SettingsLearning(isDialog: false), ), redirect: loggedOutRedirect, ), @@ -780,11 +725,8 @@ abstract class AppRoutes { // #Pangea GoRoute( path: 'spaces', - pageBuilder: (context, state) => defaultPageBuilder( - context, - state, - const EmptyPage(), - ), + pageBuilder: (context, state) => + defaultPageBuilder(context, state, const EmptyPage()), redirect: (context, state) { if (state.pathParameters['spaceid'] == null) { return "/rooms"; @@ -806,15 +748,12 @@ abstract class AppRoutes { routes: [ GoRoute( path: 'details', - pageBuilder: (context, state) => defaultPageBuilder( - context, - state, - const EmptyPage(), - ), + pageBuilder: (context, state) => + defaultPageBuilder(context, state, const EmptyPage()), redirect: (context, state) { String subroute = state.fullPath?.split(":spaceid/details").last ?? - ""; + ""; if (state.uri.queryParameters.isNotEmpty) { final queryString = state.uri.queryParameters.entries @@ -911,10 +850,10 @@ abstract class AppRoutes { roomId: state.pathParameters['roomid']!, initialFilter: state.uri.queryParameters['filter'] != null - ? InvitationFilter.fromString( - state.uri.queryParameters['filter']!, - ) - : null, + ? InvitationFilter.fromString( + state.uri.queryParameters['filter']!, + ) + : null, ), ), redirect: loggedOutRedirect, @@ -966,9 +905,7 @@ abstract class AppRoutes { pageBuilder: (context, state) => defaultPageBuilder( context, state, - ChatSearchPage( - roomId: state.pathParameters['roomid']!, - ), + ChatSearchPage(roomId: state.pathParameters['roomid']!), ), redirect: loggedOutRedirect, ), @@ -1009,9 +946,7 @@ abstract class AppRoutes { pageBuilder: (context, state) => defaultPageBuilder( context, state, - ChatDetails( - roomId: state.pathParameters['roomid']!, - ), + ChatDetails(roomId: state.pathParameters['roomid']!), ), // #Pangea routes: roomDetailsRoutes('roomid'), @@ -1063,9 +998,7 @@ abstract class AppRoutes { // pageBuilder: (context, state) => defaultPageBuilder( // context, // state, - // EmotesSettings( - // roomId: state.pathParameters['roomid'], - // ), + // EmotesSettings(roomId: state.pathParameters['roomid']), // ), // redirect: loggedOutRedirect, // ), @@ -1085,142 +1018,126 @@ abstract class AppRoutes { BuildContext context, GoRouterState state, Widget child, - ) => - NoTransitionPage( - key: state.pageKey, - restorationId: state.pageKey.value, - child: child, - ); + ) => NoTransitionPage( + key: state.pageKey, + restorationId: state.pageKey.value, + child: child, + ); static Page defaultPageBuilder( BuildContext context, GoRouterState state, Widget child, - ) => - // #Pangea - noTransitionPageBuilder(context, state, child); - // FluffyThemes.isColumnMode(context) - // ? noTransitionPageBuilder(context, state, child) - // : MaterialPage( - // key: state.pageKey, - // restorationId: state.pageKey.value, - // child: child, - // ); + // #Pangea + // ) => FluffyThemes.isColumnMode(context) + // ? noTransitionPageBuilder(context, state, child) + // : MaterialPage( + // key: state.pageKey, + // restorationId: state.pageKey.value, + // child: child, + // ); + ) => noTransitionPageBuilder(context, state, child); // Pangea# // #Pangea static List get newRoomRoutes => [ - GoRoute( - path: 'newgroup', - pageBuilder: (context, state) => defaultPageBuilder( - context, - state, - const NewGroup(), - ), - redirect: loggedOutRedirect, - ), - GoRoute( - path: 'newspace', - pageBuilder: (context, state) => defaultPageBuilder( - context, - state, - const NewGroup(createGroupType: CreateGroupType.space), - ), - redirect: loggedOutRedirect, - ), - ]; + GoRoute( + path: 'newgroup', + pageBuilder: (context, state) => + defaultPageBuilder(context, state, const NewGroup()), + redirect: loggedOutRedirect, + ), + GoRoute( + path: 'newspace', + pageBuilder: (context, state) => defaultPageBuilder( + context, + state, + const NewGroup(createGroupType: CreateGroupType.space), + ), + redirect: loggedOutRedirect, + ), + ]; static List roomDetailsRoutes(String roomKey) => [ - GoRoute( - path: '/edit', - redirect: loggedOutRedirect, - pageBuilder: (context, state) => defaultPageBuilder( - context, - state, - EditCourse(roomId: state.pathParameters[roomKey]!), - ), + GoRoute( + path: '/edit', + redirect: loggedOutRedirect, + pageBuilder: (context, state) => defaultPageBuilder( + context, + state, + EditCourse(roomId: state.pathParameters[roomKey]!), + ), + ), + GoRoute( + path: '/analytics', + redirect: loggedOutRedirect, + pageBuilder: (context, state) => defaultPageBuilder( + context, + state, + SpaceAnalytics(roomId: state.pathParameters[roomKey]!), + ), + ), + GoRoute( + path: 'access', + pageBuilder: (context, state) => defaultPageBuilder( + context, + state, + ChatAccessSettings(roomId: state.pathParameters[roomKey]!), + ), + redirect: loggedOutRedirect, + ), + GoRoute( + path: 'members', + pageBuilder: (context, state) => defaultPageBuilder( + context, + state, + ChatMembersPage( + roomId: state.pathParameters[roomKey]!, + filter: state.uri.queryParameters['filter'], ), - GoRoute( - path: '/analytics', - redirect: loggedOutRedirect, - pageBuilder: (context, state) => defaultPageBuilder( - context, - state, - SpaceAnalytics( - roomId: state.pathParameters[roomKey]!, - ), - ), + ), + redirect: loggedOutRedirect, + ), + GoRoute( + path: 'permissions', + pageBuilder: (context, state) => + defaultPageBuilder(context, state, const ChatPermissionsSettings()), + redirect: loggedOutRedirect, + ), + GoRoute( + path: 'invite', + pageBuilder: (context, state) => defaultPageBuilder( + context, + state, + PangeaInvitationSelection( + roomId: state.pathParameters[roomKey]!, + initialFilter: state.uri.queryParameters['filter'] != null + ? InvitationFilter.fromString( + state.uri.queryParameters['filter']!, + ) + : null, ), - GoRoute( - path: 'access', - pageBuilder: (context, state) => defaultPageBuilder( - context, - state, - ChatAccessSettings( - roomId: state.pathParameters[roomKey]!, - ), - ), - redirect: loggedOutRedirect, - ), - GoRoute( - path: 'members', - pageBuilder: (context, state) => defaultPageBuilder( - context, - state, - ChatMembersPage( - roomId: state.pathParameters[roomKey]!, - filter: state.uri.queryParameters['filter'], - ), - ), - redirect: loggedOutRedirect, - ), - GoRoute( - path: 'permissions', - pageBuilder: (context, state) => defaultPageBuilder( - context, - state, - const ChatPermissionsSettings(), - ), - redirect: loggedOutRedirect, - ), - GoRoute( - path: 'invite', - pageBuilder: (context, state) => defaultPageBuilder( - context, - state, - PangeaInvitationSelection( - roomId: state.pathParameters[roomKey]!, - initialFilter: state.uri.queryParameters['filter'] != null - ? InvitationFilter.fromString( - state.uri.queryParameters['filter']!, - ) - : null, - ), - ), - redirect: loggedOutRedirect, - ), - GoRoute( - path: 'emotes', - pageBuilder: (context, state) => defaultPageBuilder( - context, - state, - EmotesSettings( - roomId: state.pathParameters[roomKey]!, - ), - ), - redirect: loggedOutRedirect, - ), - GoRoute( - path: 'emotes/:state_key', - pageBuilder: (context, state) => defaultPageBuilder( - context, - state, - EmotesSettings( - roomId: state.pathParameters[roomKey]!, - ), - ), - redirect: loggedOutRedirect, - ), - ]; + ), + redirect: loggedOutRedirect, + ), + GoRoute( + path: 'emotes', + pageBuilder: (context, state) => defaultPageBuilder( + context, + state, + EmotesSettings(roomId: state.pathParameters[roomKey]!), + ), + redirect: loggedOutRedirect, + ), + GoRoute( + path: 'emotes/:state_key', + pageBuilder: (context, state) => defaultPageBuilder( + context, + state, + EmotesSettings(roomId: state.pathParameters[roomKey]!), + ), + redirect: loggedOutRedirect, + ), + ]; // Pangea# } diff --git a/lib/config/setting_keys.dart b/lib/config/setting_keys.dart index 0a604f9ab..04a5f854a 100644 --- a/lib/config/setting_keys.dart +++ b/lib/config/setting_keys.dart @@ -54,10 +54,7 @@ enum AppSettings { 'chat.fluffy.no_encryption_warning_shown', false, ), - displayChatDetailsColumn( - 'chat.fluffy.display_chat_details_column', - false, - ), + displayChatDetailsColumn('chat.fluffy.display_chat_details_column', false), // AppConfig-mirrored settings // #Pangea // applicationName('chat.fluffy.application_name', 'FluffyChat'), @@ -65,14 +62,9 @@ enum AppSettings { applicationName('chat.fluffy.application_name', 'Pangea Chat'), // Pangea# // colorSchemeSeed stored as ARGB int - colorSchemeSeedInt( - 'chat.fluffy.color_scheme_seed', - // #Pangea - // 0xFF5625BA, - 0xFF8560E0, - // Pangea# - ), // #Pangea + // colorSchemeSeedInt('chat.fluffy.color_scheme_seed', 0xFF5625BA), + colorSchemeSeedInt('chat.fluffy.color_scheme_seed', 0xFF8560E0), volume('pangea.volume', 1.0), // Pangea# emojiSuggestionLocale('emoji_suggestion_locale', ''), @@ -92,10 +84,9 @@ enum AppSettings { final store = AppSettings._store = await SharedPreferences.getInstance(); // Migrate wrong datatype for fontSizeFactor - final fontSizeFactorString = - Result(() => store.getString(AppSettings.fontSizeFactor.key)) - .asValue - ?.value; + final fontSizeFactorString = Result( + () => store.getString(AppSettings.fontSizeFactor.key), + ).asValue?.value; if (fontSizeFactorString != null) { Logs().i('Migrate wrong datatype for fontSizeFactor!'); await store.remove(AppSettings.fontSizeFactor.key); @@ -110,8 +101,9 @@ enum AppSettings { } if (kIsWeb && loadWebConfigFile) { try { - final configJsonString = - utf8.decode((await http.get(Uri.parse('config.json'))).bodyBytes); + final configJsonString = utf8.decode( + (await http.get(Uri.parse('config.json'))).bodyBytes, + ); final configJson = json.decode(configJsonString) as Map; for (final setting in AppSettings.values) { diff --git a/lib/config/themes.dart b/lib/config/themes.dart index 71247db2b..eadce08c4 100644 --- a/lib/config/themes.dart +++ b/lib/config/themes.dart @@ -24,10 +24,7 @@ abstract class FluffyThemes { static bool isThreeColumnMode(BuildContext context) => MediaQuery.sizeOf(context).width > FluffyThemes.columnWidth * 3.5; - static LinearGradient backgroundGradient( - BuildContext context, - int alpha, - ) { + static LinearGradient backgroundGradient(BuildContext context, int alpha) { final colorScheme = Theme.of(context).colorScheme; return LinearGradient( begin: Alignment.topCenter, @@ -95,16 +92,18 @@ abstract class FluffyThemes { ), appBarTheme: AppBarTheme( toolbarHeight: isColumnMode ? 72 : 56, - shadowColor: - isColumnMode ? colorScheme.surfaceContainer.withAlpha(128) : null, + shadowColor: isColumnMode + ? colorScheme.surfaceContainer.withAlpha(128) + : null, // #Pangea // surfaceTintColor: isColumnMode ? colorScheme.surface : null, // backgroundColor: isColumnMode ? colorScheme.surface : null, surfaceTintColor: colorScheme.surface, backgroundColor: colorScheme.surface, // Pangea# - actionsPadding: - isColumnMode ? const EdgeInsets.symmetric(horizontal: 16.0) : null, + actionsPadding: isColumnMode + ? const EdgeInsets.symmetric(horizontal: 16.0) + : null, systemOverlayStyle: SystemUiOverlayStyle( statusBarColor: Colors.transparent, statusBarIconBrightness: brightness.reversed, @@ -115,10 +114,7 @@ abstract class FluffyThemes { ), outlinedButtonTheme: OutlinedButtonThemeData( style: OutlinedButton.styleFrom( - side: BorderSide( - width: 1, - color: colorScheme.primary, - ), + side: BorderSide(width: 1, color: colorScheme.primary), shape: RoundedRectangleBorder( side: BorderSide(color: colorScheme.primary), borderRadius: BorderRadius.circular(AppConfig.borderRadius / 2), @@ -201,8 +197,8 @@ extension BubbleColorTheme on ThemeData { : colorScheme.onPrimaryContainer; Color get secondaryBubbleColor => HSLColor.fromColor( - brightness == Brightness.light - ? colorScheme.tertiary - : colorScheme.tertiaryContainer, - ).withSaturation(0.5).toColor(); + brightness == Brightness.light + ? colorScheme.tertiary + : colorScheme.tertiaryContainer, + ).withSaturation(0.5).toColor(); } diff --git a/lib/main.dart b/lib/main.dart index ca021cafb..ce48ce4f0 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -114,8 +114,9 @@ Future startGui(List clients, SharedPreferences store) async { String? pin; if (PlatformInfos.isMobile) { try { - pin = - await const FlutterSecureStorage().read(key: 'chat.fluffy.app_lock'); + pin = await const FlutterSecureStorage().read( + key: 'chat.fluffy.app_lock', + ); } catch (e, s) { Logs().d('Unable to read PIN from Secure storage', e, s); } diff --git a/lib/pages/archive/archive_view.dart b/lib/pages/archive/archive_view.dart index f9446c26f..5ef4176f2 100644 --- a/lib/pages/archive/archive_view.dart +++ b/lib/pages/archive/archive_view.dart @@ -60,8 +60,9 @@ class ArchiveView extends StatelessWidget { itemBuilder: (BuildContext context, int i) => ChatListItem( controller.archive[i], onForget: () => controller.forgetRoomAction(i), - onTap: () => context - .go('/rooms/archive/${controller.archive[i].id}'), + onTap: () => context.go( + '/rooms/archive/${controller.archive[i].id}', + ), ), ); } diff --git a/lib/pages/bootstrap/bootstrap_dialog.dart b/lib/pages/bootstrap/bootstrap_dialog.dart index 7d91593c0..f518fb5d5 100644 --- a/lib/pages/bootstrap/bootstrap_dialog.dart +++ b/lib/pages/bootstrap/bootstrap_dialog.dart @@ -23,10 +23,7 @@ import '../key_verification/key_verification_dialog.dart'; class BootstrapDialog extends StatefulWidget { final bool wipe; - const BootstrapDialog({ - super.key, - this.wipe = false, - }); + const BootstrapDialog({super.key, this.wipe = false}); @override BootstrapDialogState createState() => BootstrapDialogState(); @@ -148,7 +145,7 @@ class BootstrapDialogState extends State { builder: (context, snapshot) { final status = snapshot.data; return Column( - mainAxisAlignment: MainAxisAlignment.center, + mainAxisAlignment: .center, children: [ CircularProgressIndicator.adaptive(value: status?.progress), if (status != null) Text(status.calcLocalizedString(context)), @@ -177,8 +174,9 @@ class BootstrapDialogState extends State { ), body: Center( child: ConstrainedBox( - constraints: - const BoxConstraints(maxWidth: FluffyThemes.columnWidth * 1.5), + constraints: const BoxConstraints( + maxWidth: FluffyThemes.columnWidth * 1.5, + ), child: ListView( padding: const EdgeInsets.all(16.0), children: [ @@ -193,10 +191,7 @@ class BootstrapDialogState extends State { ), subtitle: Text(L10n.of(context).chatBackupDescription), ), - const Divider( - height: 32, - thickness: 1, - ), + const Divider(height: 32, thickness: 1), TextField( minLines: 2, maxLines: 4, @@ -220,8 +215,9 @@ class BootstrapDialogState extends State { }); }, title: Text(_getSecureStorageLocalizedName()), - subtitle: - Text(L10n.of(context).storeInSecureStorageDescription), + subtitle: Text( + L10n.of(context).storeInSecureStorageDescription, + ), ), const SizedBox(height: 16), CheckboxListTile.adaptive( @@ -241,16 +237,16 @@ class BootstrapDialogState extends State { label: Text(L10n.of(context).next), onPressed: (_recoveryKeyCopied || _storeInSecureStorage == true) - ? () { - if (_storeInSecureStorage == true) { - const FlutterSecureStorage().write( - key: _secureStorageKey, - value: key, - ); - } - setState(() => _recoveryKeyStored = true); - } - : null, + ? () { + if (_storeInSecureStorage == true) { + const FlutterSecureStorage().write( + key: _secureStorageKey, + value: key, + ); + } + setState(() => _recoveryKeyStored = true); + } + : null, ), ], ), @@ -303,8 +299,9 @@ class BootstrapDialogState extends State { padding: const EdgeInsets.all(16.0), children: [ ListTile( - contentPadding: - const EdgeInsets.symmetric(horizontal: 8.0), + contentPadding: const EdgeInsets.symmetric( + horizontal: 8.0, + ), trailing: Icon( Icons.info_outlined, color: theme.colorScheme.primary, @@ -370,7 +367,9 @@ class BootstrapDialogState extends State { ); try { await bootstrap - .client.encryption!.crossSigning + .client + .encryption! + .crossSigning .selfSign(recoveryKey: key); Logs().d('Successful selfsigned'); } catch (e, s) { @@ -383,13 +382,14 @@ class BootstrapDialogState extends State { } } on InvalidPassphraseException catch (e) { setState( - () => _recoveryKeyInputError = - e.toLocalizedString(context), + () => _recoveryKeyInputError = e + .toLocalizedString(context), ); } on FormatException catch (_) { setState( - () => _recoveryKeyInputError = - L10n.of(context).wrongRecoveryKey, + () => _recoveryKeyInputError = L10n.of( + context, + ).wrongRecoveryKey, ); } catch (e, s) { ErrorReporter( @@ -397,8 +397,8 @@ class BootstrapDialogState extends State { 'Unable to open SSSS with recovery key', ).onErrorCallback(e, s); setState( - () => _recoveryKeyInputError = - e.toLocalizedString(context), + () => _recoveryKeyInputError = e + .toLocalizedString(context), ); } finally { setState( @@ -428,8 +428,9 @@ class BootstrapDialogState extends State { final consent = await showOkCancelAlertDialog( context: context, title: L10n.of(context).verifyOtherDevice, - message: L10n.of(context) - .verifyOtherDeviceDescription, + message: L10n.of( + context, + ).verifyOtherDeviceDescription, okLabel: L10n.of(context).ok, cancelLabel: L10n.of(context).cancel, ); @@ -452,17 +453,18 @@ class BootstrapDialogState extends State { final waitForSecret = Completer(); final secretsSub = client - .encryption!.ssss.onSecretStored.stream - .listen(( - event, - ) async { - if (await client.encryption!.keyManager - .isCached() && - await client.encryption!.crossSigning - .isCached()) { - waitForSecret.complete(); - } - }); + .encryption! + .ssss + .onSecretStored + .stream + .listen((event) async { + if (await client.encryption!.keyManager + .isCached() && + await client.encryption!.crossSigning + .isCached()) { + waitForSecret.complete(); + } + }); final result = await showFutureLoadingDialog( context: context, @@ -542,7 +544,7 @@ class BootstrapDialogState extends State { case BootstrapState.done: titleText = L10n.of(context).everythingReady; body = Column( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ const Icon( Icons.check_circle_rounded, @@ -576,13 +578,9 @@ class BootstrapDialogState extends State { child: Padding( padding: const EdgeInsets.all(20.0), child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - body, - const SizedBox(height: 8), - ...buttons, - ], + mainAxisSize: .min, + crossAxisAlignment: .stretch, + children: [body, const SizedBox(height: 8), ...buttons], ), ), ), diff --git a/lib/pages/chat/add_widget_tile_view.dart b/lib/pages/chat/add_widget_tile_view.dart index 9877ac576..c69968d6a 100644 --- a/lib/pages/chat/add_widget_tile_view.dart +++ b/lib/pages/chat/add_widget_tile_view.dart @@ -19,20 +19,21 @@ class AddWidgetTileView extends StatelessWidget { CupertinoSegmentedControl( groupValue: controller.widgetType, padding: const EdgeInsets.all(8), - children: { - 'm.etherpad': Text(L10n.of(context).widgetEtherpad), - 'm.jitsi': Text(L10n.of(context).widgetJitsi), - 'm.video': Text(L10n.of(context).widgetVideo), - 'm.custom': Text(L10n.of(context).widgetCustom), - }.map( - (key, value) => MapEntry( - key, - Padding( - padding: const EdgeInsets.symmetric(horizontal: 4.0), - child: value, + children: + { + 'm.etherpad': Text(L10n.of(context).widgetEtherpad), + 'm.jitsi': Text(L10n.of(context).widgetJitsi), + 'm.video': Text(L10n.of(context).widgetVideo), + 'm.custom': Text(L10n.of(context).widgetCustom), + }.map( + (key, value) => MapEntry( + key, + Padding( + padding: const EdgeInsets.symmetric(horizontal: 4.0), + child: value, + ), + ), ), - ), - ), onValueChanged: controller.setWidgetType, ), Padding( diff --git a/lib/pages/chat/chat.dart b/lib/pages/chat/chat.dart index 06af7d6e7..7369b6ccd 100644 --- a/lib/pages/chat/chat.dart +++ b/lib/pages/chat/chat.dart @@ -289,14 +289,14 @@ class ChatController extends State } void enterThread(String eventId) => setState(() { - activeThreadId = eventId; - selectedEvents.clear(); - }); + activeThreadId = eventId; + selectedEvents.clear(); + }); void closeThread() => setState(() { - activeThreadId = null; - selectedEvents.clear(); - }); + activeThreadId = null; + selectedEvents.clear(); + }); void recreateChat() async { final room = this.room; @@ -386,9 +386,7 @@ class ChatController extends State closeIconColor: theme.colorScheme.onErrorContainer, content: Text( L10n.of(context).otherPartyNotLoggedIn, - style: TextStyle( - color: theme.colorScheme.onErrorContainer, - ), + style: TextStyle(color: theme.colorScheme.onErrorContainer), ), showCloseIcon: true, ), @@ -429,11 +427,9 @@ class ChatController extends State } return KeyEventResult.handled; } else if (evt.logicalKey.keyLabel == 'Enter' && evt is KeyDownEvent) { - final currentLineNum = sendController.text - .substring( - 0, - sendController.selection.baseOffset, - ) + final currentLineNum = + sendController.text + .substring(0, sendController.selection.baseOffset) .split('\n') .length - 1; @@ -482,10 +478,11 @@ class ChatController extends State sendingClient = Matrix.of(context).client; final lastEventThreadId = room.lastEvent?.relationshipType == RelationshipTypes.thread - ? room.lastEvent?.relationshipEventId - : null; - readMarkerEventId = - room.hasNewMessages ? lastEventThreadId ?? room.fullyRead : ''; + ? room.lastEvent?.relationshipEventId + : null; + readMarkerEventId = room.hasNewMessages + ? lastEventThreadId ?? room.fullyRead + : ''; WidgetsBinding.instance.addObserver(this); _tryLoadTimeline(); if (kIsWeb) { @@ -499,11 +496,7 @@ class ChatController extends State // #Pangea void _onLevelUp(LevelUpdate update) { - LevelUpUtil.showLevelUpDialog( - update.newLevel, - update.prevLevel, - context, - ); + LevelUpUtil.showLevelUpDialog(update.newLevel, update.prevLevel, context); } void _onUnlockConstructs(Set constructs) { @@ -551,10 +544,7 @@ class ChatController extends State matrix.audioPlayer!.setFilePath(file.path); } else { matrix.audioPlayer!.setAudioSource( - BytesAudioSource( - audioFile.bytes, - audioFile.mimeType, - ), + BytesAudioSource(audioFile.bytes, audioFile.mimeType), ); } @@ -568,11 +558,13 @@ class ChatController extends State _levelSubscription = updater.levelUpdateStream.stream.listen(_onLevelUp); - _constructsSubscription = - updater.unlockedConstructsStream.stream.listen(_onUnlockConstructs); + _constructsSubscription = updater.unlockedConstructsStream.stream.listen( + _onUnlockConstructs, + ); - _tokensSubscription = - updater.newConstructsStream.stream.listen(_onTokenUpdate); + _tokensSubscription = updater.newConstructsStream.stream.listen( + _onTokenUpdate, + ); _botAudioSubscription = room.client.onSync.stream.listen(_botAudioListener); @@ -585,7 +577,8 @@ class ChatController extends State if (!mounted) return; LanguageService.showDialogOnEmptyLanguage( context, - () => () => setState(() {}), + () => + () => setState(() {}), ); }); } @@ -625,11 +618,11 @@ class ChatController extends State var readMarkerEventIndex = readMarkerEventId.isEmpty ? -1 : timeline!.events - .filterByVisibleInGui( - exceptionEventId: readMarkerEventId, - threadId: activeThreadId, - ) - .indexWhere((e) => e.eventId == readMarkerEventId); + .filterByVisibleInGui( + exceptionEventId: readMarkerEventId, + threadId: activeThreadId, + ) + .indexWhere((e) => e.eventId == readMarkerEventId); // Read marker is existing but not found in first events. Try a single // requestHistory call before opening timeline on event context: @@ -664,12 +657,12 @@ class ChatController extends State String? scrollUpBannerEventId; void discardScrollUpBannerEventId() => setState(() { - scrollUpBannerEventId = null; - }); + scrollUpBannerEventId = null; + }); void _showScrollUpMaterialBanner(String eventId) => setState(() { - scrollUpBannerEventId = eventId; - }); + scrollUpBannerEventId = eventId; + }); void updateView() { if (!mounted) return; @@ -691,17 +684,10 @@ class ChatController extends State // #Pangea List get visibleEvents => - timeline?.events - .where( - (x) => x.isVisibleInGui, - ) - .toList() ?? - []; + timeline?.events.where((x) => x.isVisibleInGui).toList() ?? []; // Pangea# - Future _getTimeline({ - String? eventContextId, - }) async { + Future _getTimeline({String? eventContextId}) async { await Matrix.of(context).client.roomsLoading; await Matrix.of(context).client.accountDataLoading; if (eventContextId != null && @@ -814,30 +800,30 @@ class ChatController extends State // ignore: unawaited_futures _setReadMarkerFuture = timeline .setReadMarker( - eventId: eventId, - public: AppSettings.sendPublicReadReceipts.value, - ) - .then((_) { - _setReadMarkerFuture = null; - }) + eventId: eventId, + public: AppSettings.sendPublicReadReceipts.value, + ) // #Pangea + // .then((_) { + // _setReadMarkerFuture = null; + // }); + .then((_) { + _setReadMarkerFuture = null; + }) .catchError((e, s) { - ErrorHandler.logError( - e: PangeaWarningError("Failed to set read marker: $e"), - s: s, - data: { - 'eventId': eventId, - 'roomId': roomId, - }, - ); - Sentry.captureException( - e, - stackTrace: s, - withScope: (scope) { - scope.setTag('where', 'setReadMarker'); - }, - ); - }); + ErrorHandler.logError( + e: PangeaWarningError("Failed to set read marker: $e"), + s: s, + data: {'eventId': eventId, 'roomId': roomId}, + ); + Sentry.captureException( + e, + stackTrace: s, + withScope: (scope) { + scope.setTag('where', 'setReadMarker'); + }, + ); + }); // Pangea# if (eventId == null || eventId == timeline.room.lastEvent?.eventId) { Matrix.of(context).backgroundPush?.cancelNotification(roomId); @@ -908,34 +894,34 @@ class ChatController extends State void setSendingClient(Client c) { // #Pangea - // // first cancel typing with the old sending client - // if (currentlyTyping) { - // // no need to have the setting typing to false be blocking - // typingCoolDown?.cancel(); - // typingCoolDown = null; - // room.setTyping(false); - // currentlyTyping = false; - // } - // // then cancel the old timeline - // // fixes bug with read reciepts and quick switching - // loadTimelineFuture = _getTimeline(eventContextId: room.fullyRead).onError( - // ErrorReporter( - // context, - // 'Unable to load timeline after changing sending Client', - // ).onErrorCallback, - // ); - - // // then set the new sending client - // setState(() => sendingClient = c); + // // first cancel typing with the old sending client + // if (currentlyTyping) { + // // no need to have the setting typing to false be blocking + // typingCoolDown?.cancel(); + // typingCoolDown = null; + // room.setTyping(false); + // currentlyTyping = false; // } + // // then cancel the old timeline + // // fixes bug with read reciepts and quick switching + // loadTimelineFuture = _getTimeline(eventContextId: room.fullyRead).onError( + // ErrorReporter( + // context, + // 'Unable to load timeline after changing sending Client', + // ).onErrorCallback, + // ); - // void setActiveClient(Client c) { - // setState(() { - // Matrix.of(context).setActiveClient(c); - // }); + // // then set the new sending client + // setState(() => sendingClient = c); // Pangea# } + // #Pangea + // void setActiveClient(Client c) => setState(() { + // Matrix.of(context).setActiveClient(c); + // }); + // Pangea# + // #Pangea Event? pangeaEditingEvent; void clearEditingEvent() { @@ -958,9 +944,7 @@ class ChatController extends State } // Future send() async { - // Original send function gets the tx id within the matrix lib, - // but for choero, the tx id is generated before the message send. - // Also, adding PangeaMessageData + // if (sendController.text.trim().isEmpty) return; Future send() async { final message = sendController.text; final edit = editEvent.value; @@ -978,7 +962,6 @@ class ChatController extends State choreographer.clear(); if (message.trim().isEmpty) return; - // if (sendController.text.trim().isEmpty) return; // Pangea# _storeInputTimeoutTimer?.cancel(); final prefs = Matrix.of(context).store; @@ -1014,10 +997,6 @@ class ChatController extends State // parseCommands: parseCommands, // threadRootEventId: activeThreadId, // ); - // sendController.value = TextEditingValue( - // text: pendingText, - // selection: const TextSelection.collapsed(offset: 0), - // ); // If the message and the sendController text don't match, it's possible // that there was a delay in tokenization before send, and the user started // typing a new message. We don't want to erase that, so only reset the input @@ -1033,52 +1012,70 @@ class ChatController extends State room .pangeaSendTextEvent( - message, - inReplyTo: reply, - editEventId: edit?.eventId, - parseCommands: parseCommands, - originalWritten: content.originalWritten, - tokensSent: content.tokensSent, - tokensWritten: content.tokensWritten, - choreo: content.choreo, - txid: tempEventId, - threadRootEventId: activeThreadId, - ) - .then( - (String? msgEventId) async { - // #Pangea - // There's a listen in my_analytics_controller that decides when to auto-update - // analytics based on when / how many messages the logged in user send. This - // stream sends the data for newly sent messages. - _sendMessageAnalytics( - msgEventId, - originalSent: PangeaRepresentation( - langCode: content.tokensSent?.detections?.firstOrNull?.langCode ?? - LanguageKeys.unknownLanguage, - text: message, - originalSent: true, - originalWritten: false, - ), + message, + inReplyTo: reply, + editEventId: edit?.eventId, + parseCommands: parseCommands, + originalWritten: content.originalWritten, tokensSent: content.tokensSent, + tokensWritten: content.tokensWritten, choreo: content.choreo, - ); - - if (previousEdit != null) { - pangeaEditingEvent = previousEdit; - } - - final spaceCode = room.classCode; - if (spaceCode != null) { - GoogleAnalytics.sendMessage( - room.id, - spaceCode, + txid: tempEventId, + threadRootEventId: activeThreadId, + ) + .then((String? msgEventId) async { + // #Pangea + // There's a listen in my_analytics_controller that decides when to auto-update + // analytics based on when / how many messages the logged in user send. This + // stream sends the data for newly sent messages. + _sendMessageAnalytics( + msgEventId, + originalSent: PangeaRepresentation( + langCode: + content.tokensSent?.detections?.firstOrNull?.langCode ?? + LanguageKeys.unknownLanguage, + text: message, + originalSent: true, + originalWritten: false, + ), + tokensSent: content.tokensSent, + choreo: content.choreo, ); - } - if (msgEventId == null) { + if (previousEdit != null) { + pangeaEditingEvent = previousEdit; + } + + final spaceCode = room.classCode; + if (spaceCode != null) { + GoogleAnalytics.sendMessage(room.id, spaceCode); + } + + if (msgEventId == null) { + ErrorHandler.logError( + e: Exception('msgEventId is null'), + s: StackTrace.current, + data: { + 'roomId': roomId, + 'text': message, + 'inReplyTo': reply?.eventId, + 'editEventId': edit?.eventId, + }, + ); + return; + } + }) + .catchError((err, s) { + if (err is EventTooLarge) { + showAdaptiveDialog( + context: context, + builder: (context) => const EventTooLargeDialog(), + ); + return; + } ErrorHandler.logError( - e: Exception('msgEventId is null'), - s: StackTrace.current, + e: err, + s: s, data: { 'roomId': roomId, 'text': message, @@ -1086,29 +1083,7 @@ class ChatController extends State 'editEventId': edit?.eventId, }, ); - return; - } - }, - ).catchError((err, s) { - if (err is EventTooLarge) { - showAdaptiveDialog( - context: context, - builder: (context) => const EventTooLargeDialog(), - ); - return; - } - ErrorHandler.logError( - e: err, - s: s, - data: { - 'roomId': roomId, - 'text': message, - 'inReplyTo': reply?.eventId, - 'editEventId': edit?.eventId, - }, - ); - }); - // #Pangea + }); // sendController.value = TextEditingValue( // text: pendingText, // selection: const TextSelection.collapsed(offset: 0), @@ -1125,11 +1100,7 @@ class ChatController extends State } void sendFileAction({FileSelectorType type = FileSelectorType.any}) async { - final files = await selectFiles( - context, - allowMultiple: true, - type: type, - ); + final files = await selectFiles(context, allowMultiple: true, type: type); if (files.isEmpty) return; await showAdaptiveDialog( context: context, @@ -1236,21 +1207,20 @@ class ChatController extends State // setState(() { // replyEvent = null; // }); + final reply = replyEvent.value; replyEvent.value = null; // Pangea# + room .sendFileEvent( file, // #Pangea // inReplyTo: replyEvent, - inReplyTo: replyEvent.value, + inReplyTo: reply, // Pangea# threadRootEventId: activeThreadId, extraContent: { - 'info': { - ...file.info, - 'duration': duration, - }, + 'info': {...file.info, 'duration': duration}, 'org.matrix.msc3245.voice': {}, 'org.matrix.msc1767.audio': { 'duration': duration, @@ -1268,32 +1238,21 @@ class ChatController extends State ErrorHandler.logError( e: e, s: s, - data: { - 'roomId': roomId, - 'file': file.name, - }, + data: {'roomId': roomId, 'file': file.name}, ); scaffoldMessenger.showSnackBar( - SnackBar( - content: Text( - (e as Object).toLocalizedString(context), - ), - ), + SnackBar(content: Text((e as Object).toLocalizedString(context))), ); return null; }); - // ).catchError((e) { + // .catchError((e) { // scaffoldMessenger.showSnackBar( - // SnackBar( - // content: Text( - // (e as Object).toLocalizedString(context), - // ), - // ), + // SnackBar(content: Text((e as Object).toLocalizedString(context))), // ); // return null; // }); - // return; // Pangea# + return; } void hideEmojiPicker() { @@ -1333,7 +1292,9 @@ class ChatController extends State } for (final event in selectedEvents) { if (copyString.isNotEmpty) copyString += '\n\n'; - copyString += event.getDisplayEvent(timeline!).calcLocalizedBodyFallback( + copyString += event + .getDisplayEvent(timeline!) + .calcLocalizedBodyFallback( MatrixLocals(L10n.of(context)), withSenderNamePrefix: true, ); @@ -1364,14 +1325,8 @@ class ChatController extends State value: -100, label: L10n.of(context).extremeOffensive, ), - AdaptiveModalAction( - value: -50, - label: L10n.of(context).offensive, - ), - AdaptiveModalAction( - value: 0, - label: L10n.of(context).inoffensive, - ), + AdaptiveModalAction(value: -50, label: L10n.of(context).offensive), + AdaptiveModalAction(value: 0, label: L10n.of(context).inoffensive), ], ); if (score == null) return; @@ -1386,11 +1341,11 @@ class ChatController extends State final result = await showFutureLoadingDialog( context: context, future: () => Matrix.of(context).client.reportEvent( - event.roomId!, - event.eventId, - reason: reason, - score: score, - ), + event.roomId!, + event.eventId, + reason: reason, + score: score, + ), ); if (result.error != null) return; // #Pangea @@ -1461,16 +1416,6 @@ class ChatController extends State onProgress(i / count); if (event.status.isSent) { if (event.canRedact) { - // #Pangea - // https://github.com/pangeachat/client/issues/3353 - if (room.pinnedEventIds.contains(event.eventId) && - room.canChangeStateEvent(EventTypes.RoomPinnedEvents)) { - final pinnedEvents = room.pinnedEventIds - .where((e) => e != event.eventId) - .toList(); - await room.setPinnedEvents(pinnedEvents); - } - // Pangea# await event.redactEvent(reason: reason); } else { final client = currentRoomBundle.firstWhere( @@ -1481,9 +1426,10 @@ class ChatController extends State return; } final room = client.getRoomById(roomId)!; - await Event.fromJson(event.toJson(), room).redactEvent( - reason: reason, - ); + await Event.fromJson( + event.toJson(), + room, + ).redactEvent(reason: reason); } } else { await event.cancelSend(); @@ -1536,8 +1482,9 @@ class ChatController extends State !selectedEvents.first.status.isSent) { return false; } - return currentRoomBundle - .any((cl) => selectedEvents.first.senderId == cl!.userID); + return currentRoomBundle.any( + (cl) => selectedEvents.first.senderId == cl!.userID, + ); } void forwardEventsAction() async { @@ -1545,9 +1492,9 @@ class ChatController extends State final timeline = this.timeline; if (timeline == null) return; - final forwardEvents = List.from(selectedEvents) - .map((event) => event.getDisplayEvent(timeline)) - .toList(); + final forwardEvents = List.from( + selectedEvents, + ).map((event) => event.getDisplayEvent(timeline)).toList(); await showScaffoldDialog( context: context, @@ -1557,10 +1504,11 @@ class ChatController extends State // .map((event) => ContentShareItem(event.content)) // .toList(), .map((event) { - final content = Map.from(event.content); - content.remove("m.relates_to"); - return ContentShareItem(content); - }).toList(), + final content = Map.from(event.content); + content.remove("m.relates_to"); + return ContentShareItem(content); + }) + .toList(), // Pangea# ), ); @@ -1613,29 +1561,29 @@ class ChatController extends State inputFocus.requestFocus(); } - void scrollToEventId( - String eventId, { - bool highlightEvent = true, - }) async { - final foundEvent = - timeline!.events.firstWhereOrNull((event) => event.eventId == eventId); + void scrollToEventId(String eventId, {bool highlightEvent = true}) async { + final foundEvent = timeline!.events.firstWhereOrNull( + (event) => event.eventId == eventId, + ); final eventIndex = foundEvent == null ? -1 : timeline!.events - .filterByVisibleInGui( - exceptionEventId: eventId, - threadId: activeThreadId, - ) - .indexOf(foundEvent); + .filterByVisibleInGui( + exceptionEventId: eventId, + threadId: activeThreadId, + ) + .indexOf(foundEvent); if (eventIndex == -1) { setState(() { timeline = null; _scrolledUp = false; loadTimelineFuture = _getTimeline(eventContextId: eventId).onError( - ErrorReporter(context, 'Unable to load timeline after scroll to ID') - .onErrorCallback, + ErrorReporter( + context, + 'Unable to load timeline after scroll to ID', + ).onErrorCallback, ); }); await loadTimelineFuture; @@ -1663,8 +1611,10 @@ class ChatController extends State timeline = null; _scrolledUp = false; loadTimelineFuture = _getTimeline().onError( - ErrorReporter(context, 'Unable to load timeline after scroll down') - .onErrorCallback, + ErrorReporter( + context, + 'Unable to load timeline after scroll down', + ).onErrorCallback, ); }); await loadTimelineFuture; @@ -1712,9 +1662,15 @@ class ChatController extends State // #Pangea // void clearSelectedEvents() => setState(() { - // selectedEvents.clear(); - // showEmojiPicker = false; - // }); + // selectedEvents.clear(); + // showEmojiPicker = false; + // }); + + // void clearSingleSelectedEvent() { + // if (selectedEvents.length <= 1) { + // clearSelectedEvents(); + // } + // } void clearSelectedEvents() { if (!mounted) return; if (!_isToolbarOpen && selectedEvents.isEmpty) return; @@ -1733,13 +1689,6 @@ class ChatController extends State selectedEvents.add(event); }); } - - // #Pangea - // void clearSingleSelectedEvent() { - // if (selectedEvents.length <= 1) { - // clearSelectedEvents(); - // } - // } // Pangea# void editSelectedEventAction() { @@ -1755,22 +1704,24 @@ class ChatController extends State // setState(() { // pendingText = sendController.text; // editEvent = selectedEvents.first; - // sendController.text = - // editEvent!.getDisplayEvent(timeline!).calcLocalizedBodyFallback( - // MatrixLocals(L10n.of(context)), - // withSenderNamePrefix: false, - // hideReply: true, - // ); + // sendController.text = editEvent + // .getDisplayEvent(timeline!) + // .calcLocalizedBodyFallback( + // MatrixLocals(L10n.of(context)), + // withSenderNamePrefix: false, + // hideReply: true, + // ); // selectedEvents.clear(); // }); pendingText = sendController.text; editEvent.value = selectedEvents.first; - sendController.text = - editEvent.value!.getDisplayEvent(timeline!).calcLocalizedBodyFallback( - MatrixLocals(L10n.of(context)), - withSenderNamePrefix: false, - hideReply: true, - ); + sendController.text = editEvent.value! + .getDisplayEvent(timeline!) + .calcLocalizedBodyFallback( + MatrixLocals(L10n.of(context)), + withSenderNamePrefix: false, + hideReply: true, + ); clearSelectedEvents(); // Pangea# inputFocus.requestFocus(); @@ -1795,23 +1746,16 @@ class ChatController extends State if (!mounted) return; context.go('/rooms/${result.result!}'); - await showFutureLoadingDialog( - context: context, - future: room.leave, - ); + await showFutureLoadingDialog(context: context, future: room.leave); } // #Pangea // void onSelectMessage(Event event) { // if (!event.redacted) { // if (selectedEvents.contains(event)) { - // setState( - // () => selectedEvents.remove(event), - // ); + // setState(() => selectedEvents.remove(event)); // } else { - // setState( - // () => selectedEvents.add(event), - // ); + // setState(() => selectedEvents.add(event)); // } // selectedEvents.sort( // (a, b) => a.originServerTs.compareTo(b.originServerTs), @@ -1842,14 +1786,15 @@ class ChatController extends State // void onInputBarSubmitted(String _) { // send(); // FocusScope.of(context).requestFocus(inputFocus); + // } Future onInputBarSubmitted() async { if (MatrixState.pangeaController.subscriptionController.shouldShowPaywall) { PaywallCard.show(context, ChoreoConstants.inputTransformTargetKey); return; } await onRequestWritingAssistance(manual: false, autosend: true); - // Pangea# } + // Pangea# void onAddPopupMenuButtonSelected(AddPopupMenuActions choice) { room.client.getConfig(); @@ -1914,7 +1859,8 @@ class ChatController extends State // Pangea# final pinnedEventIds = room.pinnedEventIds; final selectedEventIds = selectedEvents.map((e) => e.eventId).toSet(); - final unpin = selectedEventIds.length == 1 && + final unpin = + selectedEventIds.length == 1 && pinnedEventIds.contains(selectedEventIds.single); if (unpin) { // #Pangea @@ -1947,11 +1893,7 @@ class ChatController extends State // _inputTextIsEmpty = text.isEmpty; // }); // } - // if (_inputTextIsEmpty.value != text.isEmpty) { - // _inputTextIsEmpty.value = text.isEmpty; - // } // Pangea# - _storeInputTimeoutTimer?.cancel(); _storeInputTimeoutTimer = Timer(_storeInputTimeout, () async { final prefs = Matrix.of(context).store; @@ -2049,25 +1991,25 @@ class ChatController extends State try { await voipPlugin!.voip.inviteToCall(room, callType); } catch (e) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text(e.toLocalizedString(context))), - ); + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text(e.toLocalizedString(context)))); } } void cancelReplyEventAction() => setState(() { - // #Pangea - // sendController.text = pendingText; - sendController.setSystemText(pendingText, EditTypeEnum.other); - // Pangea# - pendingText = ''; - // #Pangea - // replyEvent = null; - // editEvent = null; - replyEvent.value = null; - editEvent.value = null; - // Pangea# - }); + // #Pangea + // sendController.text = pendingText; + sendController.setSystemText(pendingText, EditTypeEnum.other); + // Pangea# + pendingText = ''; + // #Pangea + // replyEvent = null; + // editEvent = null; + replyEvent.value = null; + editEvent.value = null; + // Pangea# + }); // #Pangea ValueNotifier depressMessageButton = ValueNotifier(false); @@ -2088,10 +2030,7 @@ class ChatController extends State event.senderId == BotName.byEnvironment && !event.redacted, ); - if (candidate?.hasAggregatedEvents( - timeline!, - RelationshipTypes.edit, - ) == + if (candidate?.hasAggregatedEvents(timeline!, RelationshipTypes.edit) == true) { return null; } @@ -2150,8 +2089,8 @@ class ChatController extends State final delay = keyboardOpen ? const Duration(milliseconds: 500) : isButton - ? const Duration(milliseconds: 200) - : null; + ? const Duration(milliseconds: 200) + : null; if (isButton) { depressMessageButton.value = true; @@ -2251,9 +2190,7 @@ class ChatController extends State ErrorHandler.logError( e: Exception('eventID null in voiceMessageAction'), s: StackTrace.current, - data: { - 'roomId': roomId, - }, + data: {'roomId': roomId}, ); return; } @@ -2263,9 +2200,7 @@ class ChatController extends State ErrorHandler.logError( e: Exception('Event not found after sending voice message'), s: StackTrace.current, - data: { - 'roomId': roomId, - }, + data: {'roomId': roomId}, ); return; } @@ -2288,18 +2223,14 @@ class ChatController extends State if (constructs.isEmpty) return; _showAnalyticsFeedback(constructs, eventId); - Matrix.of(context).analyticsDataService.updateService.addAnalytics( - eventId, - constructs, - ); + Matrix.of( + context, + ).analyticsDataService.updateService.addAnalytics(eventId, constructs); } catch (e, s) { ErrorHandler.logError( e: e, s: s, - data: { - 'roomId': roomId, - 'eventId': eventId, - }, + data: {'roomId': roomId, 'eventId': eventId}, ); } } @@ -2365,13 +2296,12 @@ class ChatController extends State context: context, future: () async { clearSelectedEvents(); - await MatrixState.pangeaController.userController.updateProfile( - (profile) { - profile.userSettings.targetLanguage = target; - return profile; - }, - waitForDataInSync: true, - ); + await MatrixState.pangeaController.userController.updateProfile(( + profile, + ) { + profile.userSettings.targetLanguage = target; + return profile; + }, waitForDataInSync: true); }, ); if (resp.isError) return; @@ -2435,8 +2365,9 @@ class ChatController extends State child: MessageAnalyticsFeedback( newGrammarConstructs: newGrammarConstructs, newVocabConstructs: newVocabConstructs, - close: () => MatrixState.pAnyState - .closeOverlay("msg_analytics_feedback_$eventId"), + close: () => MatrixState.pAnyState.closeOverlay( + "msg_analytics_feedback_$eventId", + ), ), transformTargetId: eventId, ignorePointer: true, @@ -2485,10 +2416,9 @@ class ChatController extends State if (result.isError) return; final r = Matrix.of(context).client.getRoomById(widget.room.id); if (r != null && r.membership != Membership.leave) { - await Matrix.of(context).client.waitForRoomInSync( - widget.room.id, - leave: true, - ); + await Matrix.of( + context, + ).client.waitForRoomInSync(widget.room.id, leave: true); } NavigationUtil.goToSpaceRoute(null, [], context); @@ -2508,18 +2438,13 @@ class ChatController extends State clearSelectedEvents(); await showFutureLoadingDialog( context: context, - future: () => room.sendEvent( - { - "m.relates_to": { - "rel_type": PangeaEventTypes.regenerationRequest, - "event_id": eventId, - }, - PangeaEventTypes.regenerationRequest: { - "reason": reason, - }, + future: () => room.sendEvent({ + "m.relates_to": { + "rel_type": PangeaEventTypes.regenerationRequest, + "event_id": eventId, }, - type: PangeaEventTypes.regenerationRequest, - ), + PangeaEventTypes.regenerationRequest: {"reason": reason}, + }, type: PangeaEventTypes.regenerationRequest), ); } // Pangea# @@ -2540,46 +2465,36 @@ class ChatController extends State room: room, builder: (context, participants) { if (!room.participantListComplete && participants.loading) { - return const Center( - child: CircularProgressIndicator.adaptive(), - ); + return const Center(child: CircularProgressIndicator.adaptive()); } // Pangea# final theme = Theme.of(context); return Row( children: [ - Expanded( - child: ChatView(this), - ), + Expanded(child: ChatView(this)), ValueListenableBuilder( valueListenable: _displayChatDetailsColumn, builder: (context, displayChatDetailsColumn, _) => !FluffyThemes.isThreeColumnMode(context) || - room.membership != Membership.join || - !displayChatDetailsColumn - ? const SizedBox( - height: double.infinity, - width: 0, - ) - : Container( - width: FluffyThemes.columnWidth, - clipBehavior: Clip.hardEdge, - decoration: BoxDecoration( - border: Border( - left: BorderSide( - width: 1, - color: theme.dividerColor, - ), - ), - ), - child: ChatDetails( - roomId: roomId, - embeddedCloseButton: IconButton( - icon: const Icon(Icons.close), - onPressed: toggleDisplayChatDetailsColumn, - ), - ), + room.membership != Membership.join || + !displayChatDetailsColumn + ? const SizedBox(height: double.infinity, width: 0) + : Container( + width: FluffyThemes.columnWidth, + clipBehavior: Clip.hardEdge, + decoration: BoxDecoration( + border: Border( + left: BorderSide(width: 1, color: theme.dividerColor), ), + ), + child: ChatDetails( + roomId: roomId, + embeddedCloseButton: IconButton( + icon: const Icon(Icons.close), + onPressed: toggleDisplayChatDetailsColumn, + ), + ), + ), ), ], ); diff --git a/lib/pages/chat/chat_app_bar_list_tile.dart b/lib/pages/chat/chat_app_bar_list_tile.dart index a1fc21b43..0f038a89e 100644 --- a/lib/pages/chat/chat_app_bar_list_tile.dart +++ b/lib/pages/chat/chat_app_bar_list_tile.dart @@ -31,7 +31,7 @@ class ChatAppBarListTile extends StatelessWidget { onTap: onTap, child: Row( children: [ - if (leading != null) leading, + ?leading, Expanded( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 4.0), @@ -56,7 +56,7 @@ class ChatAppBarListTile extends StatelessWidget { ), ), ), - if (trailing != null) trailing, + ?trailing, ], ), ), diff --git a/lib/pages/chat/chat_app_bar_title.dart b/lib/pages/chat/chat_app_bar_title.dart index a0cbf4648..e8fbdeaea 100644 --- a/lib/pages/chat/chat_app_bar_title.dart +++ b/lib/pages/chat/chat_app_bar_title.dart @@ -36,14 +36,10 @@ class ChatAppBarTitle extends StatelessWidget { onTap: controller.isArchived ? null : () => FluffyThemes.isThreeColumnMode(context) - ? controller.toggleDisplayChatDetailsColumn() - // #Pangea - // : context.go('/rooms/${room.id}/details'), - : NavigationUtil.goToSpaceRoute( - room.id, - ['details'], - context, - ), + ? controller.toggleDisplayChatDetailsColumn() + // #Pangea + // : context.go('/rooms/${room.id}/details'), + : NavigationUtil.goToSpaceRoute(room.id, ['details'], context), // Pangea# child: Row( children: [ @@ -63,22 +59,22 @@ class ChatAppBarTitle extends StatelessWidget { const SizedBox(width: 12), Expanded( child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + crossAxisAlignment: .start, children: [ Text( room.getLocalizedDisplayname(MatrixLocals(L10n.of(context))), maxLines: 1, overflow: TextOverflow.ellipsis, - style: const TextStyle( - fontSize: 16, - ), + style: const TextStyle(fontSize: 16), ), StreamBuilder( stream: room.client.onSyncStatus.stream, builder: (context, snapshot) { - final status = room.client.onSyncStatus.value ?? + final status = + room.client.onSyncStatus.value ?? const SyncStatusUpdate(SyncStatus.waitingForResponse); - final hide = FluffyThemes.isColumnMode(context) || + final hide = + FluffyThemes.isColumnMode(context) || (room.client.onSync.value != null && status.status != SyncStatus.error && room.client.prevBatch != null); @@ -103,8 +99,9 @@ class ChatAppBarTitle extends StatelessWidget { if (lastActiveTimestamp != null) { return Text( L10n.of(context).lastActiveAgo( - lastActiveTimestamp - .localizedTimeShort(context), + lastActiveTimestamp.localizedTimeShort( + context, + ), ), style: style, ); diff --git a/lib/pages/chat/chat_emoji_picker.dart b/lib/pages/chat/chat_emoji_picker.dart index 04e93e5f1..4a7076f5a 100644 --- a/lib/pages/chat/chat_emoji_picker.dart +++ b/lib/pages/chat/chat_emoji_picker.dart @@ -54,20 +54,22 @@ class ChatEmojiPicker extends StatelessWidget { // #Pangea // enabled: false, showBackspaceButton: false, - backgroundColor: Theme.of(context) - .colorScheme - .surfaceContainer, - buttonColor: Theme.of(context) - .colorScheme - .surfaceContainer, - buttonIconColor: - Theme.of(context).colorScheme.onSurface, + 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, - iconColor: - theme.colorScheme.primary.withAlpha(128), + iconColor: theme.colorScheme.primary.withAlpha( + 128, + ), iconColorSelected: theme.colorScheme.primary, indicatorColor: theme.colorScheme.primary, backgroundColor: theme.colorScheme.surface, diff --git a/lib/pages/chat/chat_event_list.dart b/lib/pages/chat/chat_event_list.dart index 090e11f9f..497624e10 100644 --- a/lib/pages/chat/chat_event_list.dart +++ b/lib/pages/chat/chat_event_list.dart @@ -17,10 +17,7 @@ import 'package:fluffychat/utils/platform_infos.dart'; class ChatEventList extends StatelessWidget { final ChatController controller; - const ChatEventList({ - super.key, - required this.controller, - }); + const ChatEventList({super.key, required this.controller}); @override Widget build(BuildContext context) { @@ -31,10 +28,7 @@ class ChatEventList extends StatelessWidget { } final theme = Theme.of(context); - final colors = [ - theme.secondaryBubbleColor, - theme.bubbleColor, - ]; + final colors = [theme.secondaryBubbleColor, theme.bubbleColor]; final horizontalPadding = FluffyThemes.isColumnMode(context) ? 8.0 : 0.0; @@ -96,7 +90,7 @@ class ChatEventList extends StatelessWidget { ); } return Column( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ SeenByRow(controller), TypingIndicators(controller), @@ -118,8 +112,9 @@ class ChatEventList extends StatelessWidget { ); if (visibleIndex > timeline.events.length - 50) { // #Pangea - // WidgetsBinding.instance - // .addPostFrameCallback(controller.requestHistory); + // WidgetsBinding.instance.addPostFrameCallback( + // controller.requestHistory, + // ); WidgetsBinding.instance.addPostFrameCallback( (_) => controller.requestHistory(), ); @@ -156,7 +151,8 @@ class ChatEventList extends StatelessWidget { // The message at this index: final event = events[i]; - final animateIn = animateInEventIndex != null && + final animateIn = + animateInEventIndex != null && timeline.events.length > animateInEventIndex && event == timeline.events[animateInEventIndex]; @@ -164,10 +160,12 @@ class ChatEventList extends StatelessWidget { final previousEvent = i > 0 ? events[i - 1] : null; // Collapsed state event - final canExpand = event.isCollapsedState && + final canExpand = + event.isCollapsedState && nextEvent?.isCollapsedState == true && previousEvent?.isCollapsedState != true; - final isCollapsed = event.isCollapsedState && + final isCollapsed = + event.isCollapsedState && previousEvent?.isCollapsedState == true && !controller.expandedEventIds.contains(event.eventId); @@ -202,11 +200,12 @@ class ChatEventList extends StatelessWidget { isButton: event.eventId == controller.buttonEventID, canRefresh: event.eventId == controller.refreshEventID, // Pangea# - selected: controller.selectedEvents - .any((e) => e.eventId == event.eventId), + selected: controller.selectedEvents.any( + (e) => e.eventId == event.eventId, + ), singleSelected: controller.selectedEvents.singleOrNull?.eventId == - event.eventId, + event.eventId, onEdit: () => controller.editSelectedEventAction(), timeline: timeline, displayReadMarker: @@ -222,10 +221,9 @@ class ChatEventList extends StatelessWidget { : null, onExpand: canExpand ? () => controller.expandEventsFrom( - event, - !controller.expandedEventIds - .contains(event.eventId), - ) + event, + !controller.expandedEventIds.contains(event.eventId), + ) : null, ), ); diff --git a/lib/pages/chat/chat_input_row.dart b/lib/pages/chat/chat_input_row.dart index 9c48a397c..68258f251 100644 --- a/lib/pages/chat/chat_input_row.dart +++ b/lib/pages/chat/chat_input_row.dart @@ -1,5 +1,9 @@ +// import 'package:flutter/material.dart'; + // import 'package:animations/animations.dart'; // import 'package:emoji_picker_flutter/locales/default_emoji_set_locale.dart'; +// import 'package:matrix/matrix.dart'; + // import 'package:fluffychat/config/setting_keys.dart'; // import 'package:fluffychat/l10n/l10n.dart'; // import 'package:fluffychat/pages/chat/recording_input_row.dart'; @@ -8,9 +12,6 @@ // import 'package:fluffychat/utils/platform_infos.dart'; // import 'package:fluffychat/widgets/avatar.dart'; // import 'package:fluffychat/widgets/matrix.dart'; -// import 'package:flutter/material.dart'; -// import 'package:matrix/matrix.dart'; - // import '../../config/themes.dart'; // import 'chat.dart'; // import 'input_bar.dart'; @@ -52,12 +53,13 @@ // ); // } // return Row( -// crossAxisAlignment: CrossAxisAlignment.end, -// mainAxisAlignment: MainAxisAlignment.spaceBetween, +// crossAxisAlignment: .end, +// mainAxisAlignment: .spaceBetween, // children: controller.selectMode // ? [ -// if (controller.selectedEvents -// .every((event) => event.status == EventStatus.error)) +// if (controller.selectedEvents.every( +// (event) => event.status == EventStatus.error, +// )) // SizedBox( // height: height, // child: TextButton( @@ -89,36 +91,36 @@ // ), // controller.selectedEvents.length == 1 // ? controller.selectedEvents.first -// .getDisplayEvent(controller.timeline!) -// .status -// .isSent -// ? SizedBox( -// height: height, -// child: TextButton( -// style: selectedTextButtonStyle, -// onPressed: controller.replyAction, -// child: Row( -// children: [ -// Text(L10n.of(context).reply), -// const Icon(Icons.keyboard_arrow_right), -// ], +// .getDisplayEvent(controller.timeline!) +// .status +// .isSent +// ? SizedBox( +// height: height, +// child: TextButton( +// style: selectedTextButtonStyle, +// onPressed: controller.replyAction, +// child: Row( +// children: [ +// Text(L10n.of(context).reply), +// const Icon(Icons.keyboard_arrow_right), +// ], +// ), // ), -// ), -// ) -// : SizedBox( -// height: height, -// child: TextButton( -// style: selectedTextButtonStyle, -// onPressed: controller.sendAgainAction, -// child: Row( -// children: [ -// Text(L10n.of(context).tryToSendAgain), -// const SizedBox(width: 4), -// const Icon(Icons.send_outlined, size: 16), -// ], +// ) +// : SizedBox( +// height: height, +// child: TextButton( +// style: selectedTextButtonStyle, +// onPressed: controller.sendAgainAction, +// child: Row( +// children: [ +// Text(L10n.of(context).tryToSendAgain), +// const SizedBox(width: 4), +// const Icon(Icons.send_outlined, size: 16), +// ], +// ), // ), -// ), -// ) +// ) // : const SizedBox.shrink(), // ] // : [ @@ -126,8 +128,9 @@ // AnimatedContainer( // duration: FluffyThemes.animationDuration, // curve: FluffyThemes.animationCurve, -// width: -// controller.sendController.text.isNotEmpty ? 0 : height, +// width: controller.sendController.text.isNotEmpty +// ? 0 +// : height, // height: height, // alignment: Alignment.center, // decoration: const BoxDecoration(), @@ -189,8 +192,9 @@ // theme.colorScheme.onPrimaryContainer, // foregroundColor: // theme.colorScheme.primaryContainer, -// child: -// const Icon(Icons.video_camera_back_outlined), +// child: const Icon( +// Icons.video_camera_back_outlined, +// ), // ), // title: Text(L10n.of(context).sendVideo), // contentPadding: const EdgeInsets.all(0), @@ -269,19 +273,20 @@ // tooltip: L10n.of(context).emojis, // color: theme.colorScheme.onPrimaryContainer, // icon: PageTransitionSwitcher( -// transitionBuilder: ( -// Widget child, -// Animation primaryAnimation, -// Animation secondaryAnimation, -// ) { -// return SharedAxisTransition( -// animation: primaryAnimation, -// secondaryAnimation: secondaryAnimation, -// transitionType: SharedAxisTransitionType.scaled, -// fillColor: Colors.transparent, -// child: child, -// ); -// }, +// transitionBuilder: +// ( +// Widget child, +// Animation primaryAnimation, +// Animation secondaryAnimation, +// ) { +// return SharedAxisTransition( +// animation: primaryAnimation, +// secondaryAnimation: secondaryAnimation, +// transitionType: SharedAxisTransitionType.scaled, +// fillColor: Colors.transparent, +// child: child, +// ); +// }, // child: Icon( // controller.showEmojiPicker // ? Icons.keyboard @@ -312,9 +317,9 @@ // keyboardType: TextInputType.multiline, // textInputAction: // AppSettings.sendOnEnter.value == true && -// PlatformInfos.isMobile -// ? TextInputAction.send -// : null, +// PlatformInfos.isMobile +// ? TextInputAction.send +// : null, // onSubmitted: controller.onInputBarSubmitted, // onSubmitImage: controller.sendImageFromClipBoard, // focusNode: controller.inputFocus, @@ -334,14 +339,18 @@ // filled: false, // ), // onChanged: controller.onInputBarChanged, -// suggestionEmojis: getDefaultEmojiLocale( -// AppSettings.emojiSuggestionLocale.value.isNotEmpty -// ? Locale(AppSettings.emojiSuggestionLocale.value) -// : Localizations.localeOf(context), -// ).fold( -// [], -// (emojis, category) => emojis..addAll(category.emoji), -// ), +// suggestionEmojis: +// getDefaultEmojiLocale( +// AppSettings.emojiSuggestionLocale.value.isNotEmpty +// ? Locale( +// AppSettings.emojiSuggestionLocale.value, +// ) +// : Localizations.localeOf(context), +// ).fold( +// [], +// (emojis, category) => +// emojis..addAll(category.emoji), +// ), // ), // ), // ), @@ -349,19 +358,21 @@ // height: height, // width: height, // alignment: Alignment.center, -// child: PlatformInfos.platformCanRecord && +// child: +// PlatformInfos.platformCanRecord && // controller.sendController.text.isEmpty // ? IconButton( // tooltip: L10n.of(context).voiceMessage, // onPressed: () => // ScaffoldMessenger.of(context).showSnackBar( -// SnackBar( -// content: Text( -// L10n.of(context) -// .longPressToRecordVoiceMessage, +// SnackBar( +// content: Text( +// L10n.of( +// context, +// ).longPressToRecordVoiceMessage, +// ), +// ), // ), -// ), -// ), // onLongPress: () => recordingViewModel // .startRecording(controller.room), // style: IconButton.styleFrom( @@ -393,9 +404,9 @@ // const _ChatAccountPicker(this.controller); // void _popupMenuButtonSelected(String mxid, BuildContext context) { -// final client = Matrix.of(context) -// .currentBundle! -// .firstWhere((cl) => cl!.userID == mxid, orElse: () => null); +// final client = Matrix.of( +// context, +// ).currentBundle!.firstWhere((cl) => cl!.userID == mxid, orElse: () => null); // if (client == null) { // Logs().w('Attempted to switch to a non-existing client $mxid'); // return; @@ -422,7 +433,8 @@ // builder: (context, snapshot) => ListTile( // leading: Avatar( // mxContent: snapshot.data?.avatarUrl, -// name: snapshot.data?.displayName ?? +// name: +// snapshot.data?.displayName ?? // client.userID!.localpart, // size: 20, // ), @@ -435,7 +447,8 @@ // .toList(), // child: Avatar( // mxContent: snapshot.data?.avatarUrl, -// name: snapshot.data?.displayName ?? +// name: +// snapshot.data?.displayName ?? // Matrix.of(context).client.userID!.localpart, // size: 20, // ), diff --git a/lib/pages/chat/chat_view.dart b/lib/pages/chat/chat_view.dart index 81f696e54..123bafd46 100644 --- a/lib/pages/chat/chat_view.dart +++ b/lib/pages/chat/chat_view.dart @@ -60,8 +60,9 @@ class ChatView extends StatelessWidget { // IconButton( // icon: const Icon(Icons.message_outlined), // tooltip: L10n.of(context).replyInThread, - // onPressed: () => controller - // .enterThread(controller.selectedEvents.single.eventId), + // onPressed: () => controller.enterThread( + // controller.selectedEvents.single.eventId, + // ), // ), // IconButton( // icon: const Icon(Icons.copy_outlined), @@ -94,7 +95,7 @@ class ChatView extends StatelessWidget { // onTap: controller.pinEvent, // value: null, // child: Row( - // mainAxisSize: MainAxisSize.min, + // mainAxisSize: .min, // children: [ // const Icon(Icons.push_pin_outlined), // const SizedBox(width: 12), @@ -107,7 +108,7 @@ class ChatView extends StatelessWidget { // onTap: () => controller.saveSelectedEvent(context), // value: null, // child: Row( - // mainAxisSize: MainAxisSize.min, + // mainAxisSize: .min, // children: [ // const Icon(Icons.download_outlined), // const SizedBox(width: 12), @@ -118,7 +119,7 @@ class ChatView extends StatelessWidget { // PopupMenuItem( // value: _EventContextAction.info, // child: Row( - // mainAxisSize: MainAxisSize.min, + // mainAxisSize: .min, // children: [ // const Icon(Icons.info_outlined), // const SizedBox(width: 12), @@ -130,12 +131,9 @@ class ChatView extends StatelessWidget { // PopupMenuItem( // value: _EventContextAction.report, // child: Row( - // mainAxisSize: MainAxisSize.min, + // mainAxisSize: .min, // children: [ - // const Icon( - // Icons.shield_outlined, - // color: Colors.red, - // ), + // const Icon(Icons.shield_outlined, color: Colors.red), // const SizedBox(width: 12), // Text(L10n.of(context).reportMessage), // ], @@ -166,10 +164,7 @@ class ChatView extends StatelessWidget { if (controller.room.showActivityChatUI) { return [ ActivityMenuButton(controller: controller), - ActivitySessionPopupMenu( - controller.room, - onLeave: controller.onLeave, - ), + ActivitySessionPopupMenu(controller.room, onLeave: controller.onLeave), ]; } @@ -178,11 +173,9 @@ class ChatView extends StatelessWidget { icon: const Icon(Icons.search_outlined), tooltip: L10n.of(context).search, onPressed: () { - NavigationUtil.goToSpaceRoute( - controller.room.id, - ['search'], - context, - ); + NavigationUtil.goToSpaceRoute(controller.room.id, [ + 'search', + ], context); }, ), IconButton( @@ -190,17 +183,11 @@ class ChatView extends StatelessWidget { tooltip: L10n.of(context).chatDetails, onPressed: () { if (GoRouterState.of(context).uri.path.endsWith('/details')) { - NavigationUtil.goToSpaceRoute( - controller.room.id, - [], - context, - ); + NavigationUtil.goToSpaceRoute(controller.room.id, [], context); } else { - NavigationUtil.goToSpaceRoute( - controller.room.id, - ['details'], - context, - ); + NavigationUtil.goToSpaceRoute(controller.room.id, [ + 'details', + ], context); } }, ), @@ -224,7 +211,8 @@ class ChatView extends StatelessWidget { final accountConfig = Matrix.of(context).client.applicationAccountConfig; return PopScope( - canPop: controller.selectedEvents.isEmpty && + canPop: + controller.selectedEvents.isEmpty && !controller.showEmojiPicker && controller.activeThreadId == null, onPopInvokedWithResult: (pop, _) async { @@ -276,8 +264,8 @@ class ChatView extends StatelessWidget { // ), // backgroundColor: controller.selectedEvents.isEmpty // ? controller.activeThreadId != null - // ? theme.colorScheme.secondaryContainer - // : null + // ? theme.colorScheme.secondaryContainer + // : null // : theme.colorScheme.tertiaryContainer, // Pangea# automaticallyImplyLeading: false, @@ -289,55 +277,50 @@ class ChatView extends StatelessWidget { color: theme.colorScheme.onTertiaryContainer, ) : activeThreadId != null - ? IconButton( - icon: const Icon(Icons.close), - onPressed: controller.closeThread, - tooltip: L10n.of(context).backToMainChat, - color: theme.colorScheme.onSecondaryContainer, - ) + ? IconButton( + icon: const Icon(Icons.close), + onPressed: controller.closeThread, + tooltip: L10n.of(context).backToMainChat, + color: theme.colorScheme.onSecondaryContainer, + ) + // #Pangea + : controller.widget.backButton != null + ? controller.widget.backButton! + // : FluffyThemes.isColumnMode(context) + // ? null + // Pangea# + : StreamBuilder( + stream: Matrix.of(context).client.onSync.stream.where( + (syncUpdate) => syncUpdate.hasRoomUpdate, + ), // #Pangea - : controller.widget.backButton != null - ? controller.widget.backButton! - // : FluffyThemes.isColumnMode(context) - // ? null - // Pangea# - : StreamBuilder( - stream: Matrix.of(context) - .client - .onSync - .stream - .where( - (syncUpdate) => syncUpdate.hasRoomUpdate, - ), - // #Pangea - // builder: (context, _) => UnreadRoomsBadge( - // filter: (r) => r.id != controller.roomId, - // badgePosition: - // BadgePosition.topEnd(end: 8, top: 4), - // child: const Center(child: BackButton()), - // ), - builder: (context, _) => Center( - child: SizedBox( - height: kToolbarHeight, - child: UnreadRoomsBadge( - filter: (r) => r.id != controller.roomId, - badgePosition: BadgePosition.topEnd( - end: 8, - top: 9, - ), - child: const Center(child: BackButton()), - ), - ), - ), - // Pangea# + // builder: (context, _) => UnreadRoomsBadge( + // filter: (r) => r.id != controller.roomId, + // badgePosition: BadgePosition.topEnd(end: 8, top: 4), + // child: const Center(child: BackButton()), + // ), + builder: (context, _) => Center( + child: SizedBox( + height: kToolbarHeight, + child: UnreadRoomsBadge( + filter: (r) => r.id != controller.roomId, + badgePosition: BadgePosition.topEnd( + end: 8, + top: 9, ), + child: const Center(child: BackButton()), + ), + ), + ), + // Pangea# + ), titleSpacing: FluffyThemes.isColumnMode(context) ? 24 : 0, title: ChatAppBarTitle(controller), actions: _appBarActions(context), bottom: PreferredSize( preferredSize: Size.fromHeight(appbarBottomHeight), child: Column( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ PinnedEvents(controller), if (activeThreadId != null) @@ -374,9 +357,7 @@ class ChatView extends StatelessWidget { title: L10n.of(context).jumpToLastReadMessage, trailing: TextButton( onPressed: () { - controller.scrollToEventId( - scrollUpBannerEventId, - ); + controller.scrollToEventId(scrollUpBannerEventId); controller.discardScrollUpBannerEventId(); }, child: Text(L10n.of(context).jump), @@ -389,7 +370,8 @@ class ChatView extends StatelessWidget { // #Pangea // floatingActionButtonLocation: // FloatingActionButtonLocation.miniCenterFloat, - // floatingActionButton: controller.showScrollDownButton && + // floatingActionButton: + // controller.showScrollDownButton && // controller.selectedEvents.isEmpty // ? Padding( // padding: const EdgeInsets.only(bottom: 56.0), @@ -429,7 +411,8 @@ class ChatView extends StatelessWidget { sigmaX: accountConfig.wallpaperBlur ?? 0.0, sigmaY: accountConfig.wallpaperBlur ?? 0.0, ), - child: controller.room.activityPlan!.imageURL! + child: + controller.room.activityPlan!.imageURL! .toString() .startsWith('mxc') ? MxcImage( @@ -438,7 +421,9 @@ class ChatView extends StatelessWidget { height: MediaQuery.sizeOf(context).height, width: MediaQuery.sizeOf(context).width, cacheKey: controller - .room.activityPlan!.imageURL + .room + .activityPlan! + .imageURL .toString(), isThumbnail: false, ) @@ -448,8 +433,8 @@ class ChatView extends StatelessWidget { fit: BoxFit.cover, height: MediaQuery.sizeOf(context).height, width: MediaQuery.sizeOf(context).width, - headers: controller - .room.activityPlan!.imageURL + headers: + controller.room.activityPlan!.imageURL .toString() .contains(Environment.cmsApi) ? { @@ -512,10 +497,7 @@ class ChatView extends StatelessWidget { ), // #Pangea // if (controller.showScrollDownButton) - // Divider( - // height: 1, - // color: theme.dividerColor, - // ), + // Divider(height: 1, color: theme.dividerColor), ListenableBuilder( listenable: controller.scrollController, builder: (context, _) { @@ -561,14 +543,11 @@ class ChatView extends StatelessWidget { // ), // child: controller.room.isAbandonedDMRoom == true // ? Row( - // mainAxisAlignment: - // MainAxisAlignment.spaceEvenly, + // mainAxisAlignment: .spaceEvenly, // children: [ // TextButton.icon( // style: TextButton.styleFrom( - // padding: const EdgeInsets.all( - // 16, - // ), + // padding: const EdgeInsets.all(16), // foregroundColor: // theme.colorScheme.error, // ), @@ -576,15 +555,11 @@ class ChatView extends StatelessWidget { // Icons.archive_outlined, // ), // onPressed: controller.leaveChat, - // label: Text( - // L10n.of(context).leave, - // ), + // label: Text(L10n.of(context).leave), // ), // TextButton.icon( // style: TextButton.styleFrom( - // padding: const EdgeInsets.all( - // 16, - // ), + // padding: const EdgeInsets.all(16), // ), // icon: const Icon( // Icons.forum_outlined, @@ -597,7 +572,7 @@ class ChatView extends StatelessWidget { // ], // ) // : Column( - // mainAxisSize: MainAxisSize.min, + // mainAxisSize: .min, // children: [ // ReplyDisplay(controller), // ChatInputRow(controller), @@ -622,9 +597,7 @@ class ChatView extends StatelessWidget { controller: controller, ), if (controller.room.isActivityFinished) - LoadActivitySummaryWidget( - room: controller.room, - ), + LoadActivitySummaryWidget(room: controller.room), // Pangea# ], ), @@ -635,7 +608,7 @@ class ChatView extends StatelessWidget { ValueListenableBuilder( valueListenable: controller.activityController.hasRainedConfetti, - builder: (context, hasRained, __) { + builder: (context, hasRained, _) { return hasRained ? const SizedBox() : StarRainWidget( @@ -650,10 +623,7 @@ class ChatView extends StatelessWidget { // Container( // color: theme.scaffoldBackgroundColor.withAlpha(230), // alignment: Alignment.center, - // child: const Icon( - // Icons.upload_outlined, - // size: 100, - // ), + // child: const Icon(Icons.upload_outlined, size: 100), // ), // Pangea# ], diff --git a/lib/pages/chat/encryption_button.dart b/lib/pages/chat/encryption_button.dart index a18e10609..594ec4e4b 100644 --- a/lib/pages/chat/encryption_button.dart +++ b/lib/pages/chat/encryption_button.dart @@ -15,11 +15,9 @@ class EncryptionButton extends StatelessWidget { Widget build(BuildContext context) { final theme = Theme.of(context); return StreamBuilder( - stream: Matrix.of(context) - .client - .onSync - .stream - .where((s) => s.deviceLists != null), + stream: Matrix.of( + context, + ).client.onSync.stream.where((s) => s.deviceLists != null), builder: (context, snapshot) { final shouldBeEncrypted = room.joinRules != JoinRules.public; return FutureBuilder( diff --git a/lib/pages/chat/event_info_dialog.dart b/lib/pages/chat/event_info_dialog.dart index 558f13b43..e3b458998 100644 --- a/lib/pages/chat/event_info_dialog.dart +++ b/lib/pages/chat/event_info_dialog.dart @@ -13,21 +13,16 @@ import 'package:fluffychat/widgets/avatar.dart'; extension EventInfoDialogExtension on Event { void showInfoDialog(BuildContext context) => showAdaptiveBottomSheet( - context: context, - builder: (context) => - EventInfoDialog(l10n: L10n.of(context), event: this), - ); + context: context, + builder: (context) => EventInfoDialog(l10n: L10n.of(context), event: this), + ); } class EventInfoDialog extends StatelessWidget { final Event event; final L10n l10n; - const EventInfoDialog({ - required this.event, - required this.l10n, - super.key, - }); + const EventInfoDialog({required this.event, required this.l10n, super.key}); String prettyJson(MatrixEvent event) { const decoder = JsonDecoder(); @@ -75,15 +70,9 @@ class EventInfoDialog extends StatelessWidget { trailing: IconButton( icon: const Icon(Icons.copy), onPressed: () { - Clipboard.setData( - ClipboardData( - text: prettyJson(event), - ), - ); + Clipboard.setData(ClipboardData(text: prettyJson(event))); ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(L10n.of(context).copiedToClipboard), - ), + SnackBar(content: Text(L10n.of(context).copiedToClipboard)), ); }, ), @@ -99,9 +88,7 @@ class EventInfoDialog extends StatelessWidget { scrollDirection: Axis.horizontal, child: SelectableText( prettyJson(MatrixEvent.fromJson(event.toJson())), - style: TextStyle( - color: theme.colorScheme.onSurface, - ), + style: TextStyle(color: theme.colorScheme.onSurface), ), ), ), @@ -118,9 +105,7 @@ class EventInfoDialog extends StatelessWidget { scrollDirection: Axis.horizontal, child: SelectableText( prettyJson(originalSource), - style: TextStyle( - color: theme.colorScheme.onSurface, - ), + style: TextStyle(color: theme.colorScheme.onSurface), ), ), ), diff --git a/lib/pages/chat/events/audio_player.dart b/lib/pages/chat/events/audio_player.dart index 1132d5725..f8e32b05b 100644 --- a/lib/pages/chat/events/audio_player.dart +++ b/lib/pages/chat/events/audio_player.dart @@ -128,12 +128,13 @@ class AudioPlayerState extends State { // onPressed: () { // audioPlayer.pause(); // audioPlayer.dispose(); - // matrix.voiceMessageEventId.value = - // matrix.audioPlayer = null; + // matrix.voiceMessageEventId.value = matrix.audioPlayer = + // null; // WidgetsBinding.instance.addPostFrameCallback((_) { - // ScaffoldMessenger.of(matrix.context) - // .clearMaterialBanners(); + // ScaffoldMessenger.of( + // matrix.context, + // ).clearMaterialBanners(); // }); // }, // icon: const Icon(Icons.close_outlined), @@ -163,15 +164,16 @@ class AudioPlayerState extends State { // #Pangea // matrix.voiceMessageEventId.value != widget.event.eventId matrix.voiceMessageEventId.value != widget.eventId - // Pangea# - ? null - : matrix.audioPlayer; + // Pangea# + ? null + : matrix.audioPlayer; if (currentPlayer != null) { // #Pangea currentPlayer.setSpeed(playbackSpeed); _onAudioStateChanged?.cancel(); - _onAudioStateChanged = - matrix.audioPlayer!.playerStateStream.listen((state) { + _onAudioStateChanged = matrix.audioPlayer!.playerStateStream.listen(( + state, + ) { if (state.processingState == ProcessingState.completed) { matrix.audioPlayer!.stop(); matrix.audioPlayer!.seek(Duration.zero); @@ -214,8 +216,9 @@ class AudioPlayerState extends State { ? (progress) { final progressPercentage = progress / fileSize; setState(() { - _downloadProgress = - progressPercentage < 1 ? progressPercentage : null; + _downloadProgress = progressPercentage < 1 + ? progressPercentage + : null; }); } : null, @@ -261,11 +264,9 @@ class AudioPlayerState extends State { }); } catch (e, s) { Logs().v('Could not download audio file', e, s); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(e.toLocalizedString(context)), - ), - ); + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text(e.toLocalizedString(context)))); rethrow; } if (!context.mounted) return; @@ -277,11 +278,12 @@ class AudioPlayerState extends State { final audioPlayer = matrix.audioPlayer = AudioPlayer(); -// #Pangea + // #Pangea audioPlayer.setSpeed(playbackSpeed); _onAudioStateChanged?.cancel(); - _onAudioStateChanged = - matrix.audioPlayer!.playerStateStream.listen((state) { + _onAudioStateChanged = matrix.audioPlayer!.playerStateStream.listen(( + state, + ) { if (state.processingState == ProcessingState.completed) { matrix.audioPlayer!.stop(); matrix.audioPlayer!.seek(Duration.zero); @@ -316,9 +318,8 @@ class AudioPlayerState extends State { // Pangea# audioPlayer.play().onError( - ErrorReporter(context, 'Unable to play audio message') - .onErrorCallback, - ); + ErrorReporter(context, 'Unable to play audio message').onErrorCallback, + ); } void _toggleSpeed() async { @@ -337,8 +338,8 @@ class AudioPlayerState extends State { default: setState(() => playbackSpeed = 1.0); } - // Pangea# if (audioPlayer == null) return; + // Pangea# switch (audioPlayer.speed) { // #Pangea // case 1.0: @@ -377,7 +378,8 @@ class AudioPlayerState extends State { List? _getWaveform() { // #Pangea - final eventWaveForm = widget.matrixFile?.waveform ?? + final eventWaveForm = + widget.matrixFile?.waveform ?? widget.event?.content .tryGetMap('org.matrix.msc1767.audio') ?.tryGetList('waveform'); @@ -406,8 +408,9 @@ class AudioPlayerState extends State { void _onPlayerChange() { if (matrix.audioPlayer == null) return; _onAudioStateChanged?.cancel(); - _onAudioStateChanged = - matrix.audioPlayer?.playerStateStream.listen((state) { + _onAudioStateChanged = matrix.audioPlayer?.playerStateStream.listen(( + state, + ) { if (state.processingState == ProcessingState.completed) { matrix.audioPlayer?.stop(); matrix.audioPlayer?.seek(Duration.zero); @@ -464,10 +467,12 @@ class AudioPlayerState extends State { valueListenable: matrix.voiceMessageEventId, builder: (context, eventId, _) { // #Pangea - // final audioPlayer = - // eventId != widget.event.eventId ? null : matrix.audioPlayer; - final audioPlayer = - eventId != widget.eventId ? null : matrix.audioPlayer; + // final audioPlayer = eventId != widget.event.eventId + // ? null + // : matrix.audioPlayer; + final audioPlayer = eventId != widget.eventId + ? null + : matrix.audioPlayer; // Pangea# // #Pangea @@ -494,7 +499,8 @@ class AudioPlayerState extends State { audioPlayer?.position.inMilliseconds.toDouble() ?? 0.0; if (currentPosition > maxPosition) currentPosition = maxPosition; - final wavePosition = (currentPosition / maxPosition) * + final wavePosition = + (currentPosition / maxPosition) * AudioPlayerWidget.wavesCount; final statusText = audioPlayer == null @@ -503,15 +509,15 @@ class AudioPlayerState extends State { return Padding( padding: const EdgeInsets.all(12.0), child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: .min, + crossAxisAlignment: .start, children: [ ConstrainedBox( constraints: const BoxConstraints( maxWidth: FluffyThemes.columnWidth, ), child: Row( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ SizedBox( width: buttonSize, @@ -556,9 +562,11 @@ class AudioPlayerState extends State { ), child: Row( children: [ - for (var i = 0; - i < AudioPlayerWidget.wavesCount; - i++) + for ( + var i = 0; + i < AudioPlayerWidget.wavesCount; + i++ + ) Expanded( child: Container( height: 32, @@ -566,13 +574,14 @@ class AudioPlayerState extends State { child: Container( margin: const EdgeInsets.symmetric( - horizontal: 1, - ), + horizontal: 1, + ), decoration: BoxDecoration( color: i < wavePosition ? widget.color - : widget.color - .withAlpha(128), + : widget.color.withAlpha( + 128, + ), borderRadius: BorderRadius.circular(64), ), @@ -588,11 +597,13 @@ class AudioPlayerState extends State { height: 32, child: Slider( // #Pangea - // thumbColor: widget.event.senderId == + // thumbColor: + // widget.event.senderId == // widget.event.room.client.userID // ? theme.colorScheme.onPrimary // : theme.colorScheme.primary, - thumbColor: widget.senderId == + thumbColor: + widget.senderId == Matrix.of(context).client.userID ? widget.color : theme.colorScheme.onSurface, @@ -609,13 +620,13 @@ class AudioPlayerState extends State { onChanged: !widget.enableClicks ? null : (position) => audioPlayer == null - ? _onButtonTap() - : audioPlayer.seek( - Duration( - milliseconds: - position.round(), + ? _onButtonTap() + : audioPlayer.seek( + Duration( + milliseconds: position + .round(), + ), ), - ), // onChanged: (position) => audioPlayer == null // ? _onButtonTap() // : audioPlayer.seek( @@ -643,21 +654,20 @@ class AudioPlayerState extends State { // ), Text( statusText, - style: TextStyle( - color: widget.color, - fontSize: 12, - ), + style: TextStyle(color: widget.color, fontSize: 12), ), // Pangea# const SizedBox(width: 8), // #Pangea Material( color: widget.color.withAlpha(64), - borderRadius: - BorderRadius.circular(AppConfig.borderRadius), + borderRadius: BorderRadius.circular( + AppConfig.borderRadius, + ), child: InkWell( - borderRadius: - BorderRadius.circular(AppConfig.borderRadius), + borderRadius: BorderRadius.circular( + AppConfig.borderRadius, + ), onTap: !widget.enableClicks ? null : _toggleSpeed, child: SizedBox( width: 32, @@ -684,8 +694,9 @@ class AudioPlayerState extends State { // ), // secondChild: Material( // color: widget.color.withAlpha(64), - // borderRadius: - // BorderRadius.circular(AppConfig.borderRadius), + // borderRadius: BorderRadius.circular( + // AppConfig.borderRadius, + // ), // child: InkWell( // borderRadius: BorderRadius.circular( // AppConfig.borderRadius, @@ -725,8 +736,9 @@ class AudioPlayerState extends State { ), child: Linkify( text: fileDescription, - textScaleFactor: - MediaQuery.textScalerOf(context).scale(1), + textScaleFactor: MediaQuery.textScalerOf( + context, + ).scale(1), style: TextStyle( color: widget.color, fontSize: widget.fontSize, @@ -806,4 +818,5 @@ class BytesAudioSource extends StreamAudioSource { ); } } + // Pangea# diff --git a/lib/pages/chat/events/cute_events.dart b/lib/pages/chat/events/cute_events.dart index 91648e082..604537711 100644 --- a/lib/pages/chat/events/cute_events.dart +++ b/lib/pages/chat/events/cute_events.dart @@ -37,13 +37,10 @@ class _CuteContentState extends State { return GestureDetector( onTap: addOverlay, child: Column( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: .min, + mainAxisAlignment: .center, children: [ - Text( - widget.event.text, - style: const TextStyle(fontSize: 150), - ), + Text(widget.event.text, style: const TextStyle(fontSize: 150)), if (label != null) Text(label), ], ), @@ -112,10 +109,7 @@ class _CuteEventOverlayState extends State with TickerProviderStateMixin { final List items = List.generate( 50, - (index) => Size( - Random().nextDouble(), - 4 + (Random().nextDouble() * 4), - ), + (index) => Size(Random().nextDouble(), 4 + (Random().nextDouble() * 4)), ); AnimationController? controller; @@ -150,14 +144,13 @@ class _CuteEventOverlayState extends State .map( (position) => Positioned( left: position.width * width, - bottom: (height * + bottom: + (height * .25 * position.height * (controller?.value ?? 0)) - _CuteOverlayContent.size, - child: _CuteOverlayContent( - emoji: widget.emoji, - ), + child: _CuteOverlayContent(emoji: widget.emoji), ), ) .toList(), @@ -186,10 +179,7 @@ class _CuteOverlayContent extends StatelessWidget { Widget build(BuildContext context) { return SizedBox.square( dimension: size, - child: Text( - emoji, - style: const TextStyle(fontSize: 48), - ), + child: Text(emoji, style: const TextStyle(fontSize: 48)), ); } } diff --git a/lib/pages/chat/events/emoji_burst.dart b/lib/pages/chat/events/emoji_burst.dart index 27a96c891..f15773281 100644 --- a/lib/pages/chat/events/emoji_burst.dart +++ b/lib/pages/chat/events/emoji_burst.dart @@ -22,10 +22,7 @@ class BurstPainter extends CustomPainter { final List particles; final double progress; - BurstPainter({ - required this.particles, - required this.progress, - }); + BurstPainter({required this.particles, required this.progress}); @override void paint(Canvas canvas, Size size) { diff --git a/lib/pages/chat/events/html_message.dart b/lib/pages/chat/events/html_message.dart index 89d5fad05..21ee66f10 100644 --- a/lib/pages/chat/events/html_message.dart +++ b/lib/pages/chat/events/html_message.dart @@ -157,20 +157,17 @@ class HtmlMessage extends StatelessWidget { }; // #Pangea - List? get tokens => - pangeaMessageEvent?.messageDisplayRepresentation?.tokens - ?.where( - (t) => - !["SYM"].contains(t.pos) && - !t.lemma.text.contains(RegExp(r'[0-9]')), - ) - .toList(); + List? get tokens => pangeaMessageEvent + ?.messageDisplayRepresentation + ?.tokens + ?.where( + (t) => + !["SYM"].contains(t.pos) && + !t.lemma.text.contains(RegExp(r'[0-9]')), + ) + .toList(); - PangeaToken? getToken( - String text, - int offset, - int length, - ) => + PangeaToken? getToken(String text, int offset, int length) => tokens?.firstWhereOrNull( (token) => token.text.offset == offset && token.text.length == length, ); @@ -204,11 +201,9 @@ class HtmlMessage extends StatelessWidget { replyTagIndex, ); if (closingReplyTagIndex != -1) { - result.replaceRange( - replyTagIndex, - closingReplyTagIndex + 1, - [result.sublist(replyTagIndex, closingReplyTagIndex + 1).join()], - ); + result.replaceRange(replyTagIndex, closingReplyTagIndex + 1, [ + result.sublist(replyTagIndex, closingReplyTagIndex + 1).join(), + ]); } } @@ -240,10 +235,10 @@ class HtmlMessage extends StatelessWidget { } final int tokenLength = tokenSpanText.characters.length; - final before = - result[substringIndex].characters.take(tokenIndex).toString(); - final after = result[substringIndex] - .characters + final before = result[substringIndex].characters + .take(tokenIndex) + .toString(); + final after = result[substringIndex].characters .skip(tokenIndex + tokenLength) .toString(); @@ -372,7 +367,8 @@ class HtmlMessage extends StatelessWidget { if (node is! dom.Element) { return TextSpan(text: node.text); } - final style = atomOneDarkTheme[node.className.split('-').last] ?? + final style = + atomOneDarkTheme[node.className.split('-').last] ?? atomOneDarkTheme['root']; return TextSpan( @@ -382,15 +378,15 @@ class HtmlMessage extends StatelessWidget { } /// Transforms a Node to an InlineSpan. + // #Pangea + // InlineSpan _renderHtml(dom.Node node, BuildContext context, {int depth = 1}) { InlineSpan _renderHtml( dom.Node node, - // #Pangea - // BuildContext context, { BuildContext context, TextStyle textStyle, { - // Pangea# int depth = 1, }) { + // Pangea# // We must not render elements nested more than 100 elements deep: if (depth >= 100) return const TextSpan(); @@ -414,7 +410,8 @@ class HtmlMessage extends StatelessWidget { // #Pangea double fontSize = this.fontSize; if (readingAssistanceMode == ReadingAssistanceMode.practiceMode) { - fontSize = (overlayController != null && overlayController!.maxWidth > 600 + fontSize = + (overlayController != null && overlayController!.maxWidth > 600 ? Theme.of(context).textTheme.titleLarge?.fontSize : Theme.of(context).textTheme.bodyLarge?.fontSize) ?? this.fontSize; @@ -422,13 +419,13 @@ class HtmlMessage extends StatelessWidget { final existingStyle = pangeaMessageEvent != null ? textStyle - .merge( - AppConfig.messageTextStyle( - pangeaMessageEvent!.event, - textColor, - ), - ) - .copyWith(fontSize: fontSize) + .merge( + AppConfig.messageTextStyle( + pangeaMessageEvent!.event, + textColor, + ), + ) + .copyWith(fontSize: fontSize) : textStyle.copyWith(fontSize: fontSize); final renderer = TokenRenderingUtil(); @@ -439,8 +436,8 @@ class HtmlMessage extends StatelessWidget { final newTokens = pangeaMessageEvent != null && !pangeaMessageEvent!.ownMessage - ? TokensUtil.getNewTokensByEvent(pangeaMessageEvent!) - : []; + ? TokensUtil.getNewTokensByEvent(pangeaMessageEvent!) + : []; // Pangea# switch (node.localName) { @@ -461,7 +458,8 @@ class HtmlMessage extends StatelessWidget { : false; final isNew = token != null && newTokens.contains(token.text); - final isFirstNewToken = isNew && + final isFirstNewToken = + isNew && controller.buttonEventID == event.eventId && newTokens.first == token.text; final showShimmer = @@ -479,8 +477,8 @@ class HtmlMessage extends StatelessWidget { WidgetSpan( alignment: readingAssistanceMode == ReadingAssistanceMode.practiceMode - ? PlaceholderAlignment.bottom - : PlaceholderAlignment.middle, + ? PlaceholderAlignment.bottom + : PlaceholderAlignment.middle, child: Column( children: [ if (token != null && overlayController != null) @@ -507,10 +505,10 @@ class HtmlMessage extends StatelessWidget { CompositedTransformTarget( link: token != null ? MatrixState.pAnyState - .layerLinkAndKey( - "message-token-${token.text.uniqueKey}-${event.eventId}", - ) - .link + .layerLinkAndKey( + "message-token-${token.text.uniqueKey}-${event.eventId}", + ) + .link : LayerLink(), child: MouseRegion( cursor: SystemMouseCursors.click, @@ -532,14 +530,15 @@ class HtmlMessage extends StatelessWidget { pangeaMessageEvent?.textDirection, underlineColor: TokenRenderingUtil.underlineColor( - underlineColor, - selected: selected, - highlighted: highlighted, - isNew: isNew, - practiceMode: readingAssistanceMode == - ReadingAssistanceMode.practiceMode, - hovered: hovered, - ), + underlineColor, + selected: selected, + highlighted: highlighted, + isNew: isNew, + practiceMode: + readingAssistanceMode == + ReadingAssistanceMode.practiceMode, + hovered: hovered, + ), ), ); }, @@ -559,8 +558,10 @@ class HtmlMessage extends StatelessWidget { ), curve: Curves.easeOut, child: SizedBox( - height: overlayController! - .practiceController.practiceMode != + height: + overlayController! + .practiceController + .practiceMode != MessagePracticeMode.noneSelected ? 4.0 : 0.0, @@ -589,7 +590,7 @@ class HtmlMessage extends StatelessWidget { final user = room.unsafeGetUserFromMemoryOrFallback(matrixId); return WidgetSpan( // #Pangea - alignment: PlaceholderAlignment.middle, + alignment: .middle, // Pangea# child: MatrixPill( key: Key('user_pill_$matrixId'), @@ -611,7 +612,7 @@ class HtmlMessage extends StatelessWidget { : this.room.client.getRoomByAlias(matrixId); return WidgetSpan( // #Pangea - alignment: PlaceholderAlignment.middle, + alignment: .middle, // Pangea# child: MatrixPill( name: room?.getLocalizedDisplayname() ?? matrixId, @@ -642,9 +643,7 @@ class HtmlMessage extends StatelessWidget { node.nodes, context, // #Pangea - textStyle.merge( - linkStyle.copyWith(height: 1.25), - ), + textStyle.merge(linkStyle.copyWith(height: 1.25)), // Pangea# depth: depth, ), @@ -664,9 +663,9 @@ class HtmlMessage extends StatelessWidget { final isCheckbox = node.className == 'task-list-item'; final checkboxIndex = isCheckbox ? node.rootElement - .getElementsByClassName('task-list-item') - .indexOf(node) + - 1 + .getElementsByClassName('task-list-item') + .indexOf(node) + + 1 : null; final checkedByReaction = !isCheckbox ? null @@ -689,17 +688,13 @@ class HtmlMessage extends StatelessWidget { if (node.parent?.localName == 'ul') // #Pangea // const TextSpan(text: '• '), - TextSpan( - text: '• ', - style: existingStyle, - ), + TextSpan(text: '• ', style: existingStyle), // Pangea# if (node.parent?.localName == 'ol') TextSpan( text: '${(node.parent?.nodes.whereType().toList().indexOf(node) ?? 0) + (int.tryParse(node.parent?.attributes['start'] ?? '1') ?? 1)}. ', // #Pangea - // style: textStyle, style: existingStyle, // Pangea# ), @@ -715,7 +710,8 @@ class HtmlMessage extends StatelessWidget { activeColor: textColor.withAlpha(64), value: staticallyChecked || checkedByReaction != null, - onChanged: eventId == null || + onChanged: + eventId == null || checkboxIndex == null || staticallyChecked || !room.canSendDefaultMessages || @@ -724,28 +720,29 @@ class HtmlMessage extends StatelessWidget { room.client.userID) ? null : (_) => showFutureLoadingDialog( - context: context, - future: () => checkedByReaction != null - ? room.redactEvent( - checkedByReaction.eventId, - ) - : room.checkCheckbox( - eventId, - checkboxIndex, - ), - ), + context: context, + future: () => checkedByReaction != null + ? room.redactEvent( + checkedByReaction.eventId, + ) + : room.checkCheckbox( + eventId, + checkboxIndex, + ), + ), ), ), ), ), + // #Pangea + // ..._renderWithLineBreaks(node.nodes, context, depth: depth), ..._renderWithLineBreaks( node.nodes, context, - // #Pangea textStyle, - // Pangea# depth: depth, ), + // Pangea# ], style: TextStyle(fontSize: fontSize, color: textColor), ), @@ -757,12 +754,7 @@ class HtmlMessage extends StatelessWidget { child: Container( padding: const EdgeInsets.only(left: 8.0), decoration: BoxDecoration( - border: Border( - left: BorderSide( - color: textColor, - width: 5, - ), - ), + border: Border(left: BorderSide(color: textColor, width: 5)), ), child: Text.rich( // #Pangea @@ -788,7 +780,8 @@ class HtmlMessage extends StatelessWidget { ); case 'code': final isInline = node.parent?.localName != 'pre'; - final lang = node.className + final lang = + node.className .split(' ') .singleWhereOrNull( (className) => className.startsWith('language-'), @@ -796,8 +789,9 @@ class HtmlMessage extends StatelessWidget { ?.split('language-') .last ?? 'md'; - final highlightedHtml = - highlight.parse(node.text, language: lang).toHtml(); + final highlightedHtml = highlight + .parse(node.text, language: lang) + .toHtml(); final element = parser.parse(highlightedHtml).body; if (element == null) { return const TextSpan(text: 'Unable to render code block!'); @@ -813,14 +807,9 @@ class HtmlMessage extends StatelessWidget { child: Padding( padding: isInline ? const EdgeInsets.symmetric(horizontal: 4.0) - : const EdgeInsets.symmetric( - horizontal: 8.0, - vertical: 4.0, - ), + : const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4.0), child: Text.rich( - TextSpan( - children: [_renderCodeBlockNode(element)], - ), + TextSpan(children: [_renderCodeBlockNode(element)]), selectionColor: hightlightTextColor.withAlpha(128), ), ), @@ -888,10 +877,7 @@ class HtmlMessage extends StatelessWidget { node, context, textStyle.merge( - TextStyle( - fontSize: fontSize, - color: textColor, - ), + TextStyle(fontSize: fontSize, color: textColor), ), depth: depth, ), @@ -908,10 +894,7 @@ class HtmlMessage extends StatelessWidget { ), ], ), - style: TextStyle( - fontSize: fontSize, - color: textColor, - ), + style: TextStyle(fontSize: fontSize, color: textColor), ), ), ), @@ -957,16 +940,13 @@ class HtmlMessage extends StatelessWidget { default: // #Pangea final style = switch (node.localName) { - 'body' => TextStyle( - fontSize: fontSize, - color: textColor, - ), + 'body' => TextStyle(fontSize: fontSize, color: textColor), 'a' => linkStyle, 'strong' => const TextStyle(fontWeight: FontWeight.bold), 'em' || 'i' => const TextStyle(fontStyle: FontStyle.italic), - 'del' || - 'strikethrough' => - const TextStyle(decoration: TextDecoration.lineThrough), + 'del' || 'strikethrough' => const TextStyle( + decoration: TextDecoration.lineThrough, + ), 'u' => const TextStyle(decoration: TextDecoration.underline), 'h1' => TextStyle(fontSize: fontSize * 1.6, height: 2), 'h2' => TextStyle(fontSize: fontSize * 1.5, height: 2), @@ -975,11 +955,12 @@ class HtmlMessage extends StatelessWidget { 'h5' => TextStyle(fontSize: fontSize * 1.2, height: 1.75), 'h6' => TextStyle(fontSize: fontSize * 1.1, height: 1.5), 'span' => TextStyle( - color: node.attributes['color']?.hexToColor ?? - node.attributes['data-mx-color']?.hexToColor ?? - textColor, - backgroundColor: node.attributes['data-mx-bg-color']?.hexToColor, - ), + color: + node.attributes['color']?.hexToColor ?? + node.attributes['data-mx-color']?.hexToColor ?? + textColor, + backgroundColor: node.attributes['data-mx-bg-color']?.hexToColor, + ), 'sup' => const TextStyle(fontFeatures: [FontFeature.superscripts()]), 'sub' => const TextStyle(fontFeatures: [FontFeature.subscripts()]), _ => null, @@ -1020,9 +1001,9 @@ class HtmlMessage extends StatelessWidget { child: SizedBox( height: overlayController!.practiceController.practiceMode != - MessagePracticeMode.noneSelected - ? 4.0 - : 0.0, + MessagePracticeMode.noneSelected + ? 4.0 + : 0.0, width: 0, ), ), @@ -1032,17 +1013,13 @@ class HtmlMessage extends StatelessWidget { ); // return TextSpan( // style: switch (node.localName) { - // 'body' => TextStyle( - // fontSize: fontSize, - // color: textColor, - // ), + // 'body' => TextStyle(fontSize: fontSize, color: textColor), // 'a' => linkStyle, // 'strong' => const TextStyle(fontWeight: FontWeight.bold), // 'em' || 'i' => const TextStyle(fontStyle: FontStyle.italic), - // 'del' || - // 's' || - // 'strikethrough' => - // const TextStyle(decoration: TextDecoration.lineThrough), + // 'del' || 's' || 'strikethrough' => const TextStyle( + // decoration: TextDecoration.lineThrough, + // ), // 'u' => const TextStyle(decoration: TextDecoration.underline), // 'h1' => TextStyle(fontSize: fontSize * 1.6, height: 2), // 'h2' => TextStyle(fontSize: fontSize * 1.5, height: 2), @@ -1051,25 +1028,19 @@ class HtmlMessage extends StatelessWidget { // 'h5' => TextStyle(fontSize: fontSize * 1.2, height: 1.75), // 'h6' => TextStyle(fontSize: fontSize * 1.1, height: 1.5), // 'span' => TextStyle( - // color: node.attributes['color']?.hexToColor ?? - // node.attributes['data-mx-color']?.hexToColor ?? - // textColor, - // backgroundColor: - // node.attributes['data-mx-bg-color']?.hexToColor, - // ), + // color: + // node.attributes['color']?.hexToColor ?? + // node.attributes['data-mx-color']?.hexToColor ?? + // textColor, + // backgroundColor: node.attributes['data-mx-bg-color']?.hexToColor, + // ), // 'sup' => const TextStyle( - // fontFeatures: [FontFeature.superscripts()], - // ), - // 'sub' => const TextStyle( - // fontFeatures: [FontFeature.subscripts()], - // ), + // fontFeatures: [FontFeature.superscripts()], + // ), + // 'sub' => const TextStyle(fontFeatures: [FontFeature.subscripts()]), // _ => null, // }, - // children: _renderWithLineBreaks( - // node.nodes, - // context, - // depth: depth, - // ), + // children: _renderWithLineBreaks(node.nodes, context, depth: depth), // ); // Pangea# } @@ -1081,12 +1052,10 @@ class HtmlMessage extends StatelessWidget { // final element = parser.parse(html).body ?? dom.Element.html(''); // return Text.rich( // _renderHtml(element, context), - // style: TextStyle( - // fontSize: fontSize, - // color: textColor, - // ), - // maxLines: limitHeight ? 64 : null,Add commentMore actions + // style: TextStyle(fontSize: fontSize, color: textColor), + // maxLines: limitHeight ? 64 : null, // overflow: TextOverflow.fade, + // selectionColor: textColor.withAlpha(128) // ); final parsed = parser.parse(_addTokenTags()).body ?? dom.Element.html(''); return GestureDetector( @@ -1105,15 +1074,9 @@ class HtmlMessage extends StatelessWidget { _renderHtml( parsed, context, - TextStyle( - fontSize: fontSize, - color: textColor, - ), - ), - style: TextStyle( - fontSize: fontSize, - color: textColor, + TextStyle(fontSize: fontSize, color: textColor), ), + style: TextStyle(fontSize: fontSize, color: textColor), maxLines: limitHeight ? 64 : null, overflow: TextOverflow.fade, selectionColor: textColor.withAlpha(128), @@ -1180,13 +1143,9 @@ class MatrixPill extends StatelessWidget { ), ), // child: Row( - // mainAxisSize: MainAxisSize.min, + // mainAxisSize: .min, // children: [ - // Avatar( - // mxContent: avatar, - // name: name, - // size: 16, - // ), + // Avatar(mxContent: avatar, name: name, size: 16), // const SizedBox(width: 6), // Text( // name, diff --git a/lib/pages/chat/events/image_bubble.dart b/lib/pages/chat/events/image_bubble.dart index e93cb9f54..e1c6d934c 100644 --- a/lib/pages/chat/events/image_bubble.dart +++ b/lib/pages/chat/events/image_bubble.dart @@ -47,8 +47,8 @@ class ImageBubble extends StatelessWidget { Widget _buildPlaceholder(BuildContext context) { final String blurHashString = event.infoMap['xyz.amorgan.blurhash'] is String - ? event.infoMap['xyz.amorgan.blurhash'] - : 'LEHV6nWB2yk8pyo0adR*.7kCMdnj'; + ? event.infoMap['xyz.amorgan.blurhash'] + : 'LEHV6nWB2yk8pyo0adR*.7kCMdnj'; return SizedBox( width: width, height: height, @@ -69,11 +69,8 @@ class ImageBubble extends StatelessWidget { if (!tapToView) return; showDialog( context: context, - builder: (_) => ImageViewer( - event, - timeline: timeline, - outerContext: context, - ), + builder: (_) => + ImageViewer(event, timeline: timeline, outerContext: context), ); } @@ -95,7 +92,7 @@ class ImageBubble extends StatelessWidget { } return Column( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, spacing: 8, children: [ Material( @@ -115,7 +112,8 @@ class ImageBubble extends StatelessWidget { child: Hero( tag: event.eventId, // #Pangea - child: event.content['url'] is String && + child: + event.content['url'] is String && !(event.content['url'] as String).startsWith('mxc') ? CachedNetworkImage( imageUrl: event.content['url'] as String, @@ -154,22 +152,21 @@ class ImageBubble extends StatelessWidget { SizedBox( width: width, child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: 16, - vertical: 8, - ), + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), child: Linkify( text: fileDescription, textScaleFactor: MediaQuery.textScalerOf(context).scale(1), style: TextStyle( color: textColor, - fontSize: AppSettings.fontSizeFactor.value * + fontSize: + AppSettings.fontSizeFactor.value * AppConfig.messageFontSize, ), options: const LinkifyOptions(humanize: false), linkStyle: TextStyle( color: linkColor, - fontSize: AppSettings.fontSizeFactor.value * + fontSize: + AppSettings.fontSizeFactor.value * AppConfig.messageFontSize, decoration: TextDecoration.underline, decorationColor: linkColor, diff --git a/lib/pages/chat/events/message.dart b/lib/pages/chat/events/message.dart index a74c86d22..46e565426 100644 --- a/lib/pages/chat/events/message.dart +++ b/lib/pages/chat/events/message.dart @@ -152,7 +152,7 @@ class Message extends StatelessWidget { event.room.activityPlan != null) { return ValueListenableBuilder( valueListenable: controller.activityController.showInstructions, - builder: (context, show, __) { + builder: (context, show, _) { return ActivitySummary( inChat: true, activity: event.room.activityPlan!, @@ -177,7 +177,6 @@ class Message extends StatelessWidget { return ActivityRolesEvent(event: event); } // Pangea# - return StateMessage(event, onExpand: onExpand, isCollapsed: isCollapsed); } @@ -191,10 +190,12 @@ class Message extends StatelessWidget { final alignment = ownMessage ? Alignment.topRight : Alignment.topLeft; var color = theme.colorScheme.surfaceContainerHigh; - final displayTime = event.type == EventTypes.RoomCreate || + final displayTime = + event.type == EventTypes.RoomCreate || nextEvent == null || !event.originServerTs.sameEnvironment(nextEvent!.originServerTs); - final nextEventSameSender = nextEvent != null && + final nextEventSameSender = + nextEvent != null && { EventTypes.Message, EventTypes.Sticker, @@ -203,7 +204,8 @@ class Message extends StatelessWidget { nextEvent!.senderId == event.senderId && !displayTime; - final previousEventSameSender = previousEvent != null && + final previousEventSameSender = + previousEvent != null && { EventTypes.Message, EventTypes.Sticker, @@ -213,26 +215,28 @@ class Message extends StatelessWidget { previousEvent!.originServerTs.sameEnvironment(event.originServerTs); // #Pangea - // final textColor = - // ownMessage ? theme.onBubbleColor : theme.colorScheme.onSurface; + // final textColor = ownMessage + // ? theme.onBubbleColor + // : theme.colorScheme.onSurface; final textColor = ownMessage ? ThemeData.dark().colorScheme.onPrimary : theme.colorScheme.onSurface; // final linkColor = ownMessage // ? theme.brightness == Brightness.light - // ? theme.colorScheme.primaryFixed - // : theme.colorScheme.onTertiaryContainer + // ? theme.colorScheme.primaryFixed + // : theme.colorScheme.onTertiaryContainer // : theme.colorScheme.primary; final linkColor = theme.brightness == Brightness.light ? theme.colorScheme.primary : ownMessage - ? theme.colorScheme.onPrimary - : theme.colorScheme.onSurface; + ? theme.colorScheme.onPrimary + : theme.colorScheme.onSurface; // Pangea# - final rowMainAxisAlignment = - ownMessage ? MainAxisAlignment.end : MainAxisAlignment.start; + final rowMainAxisAlignment = ownMessage + ? MainAxisAlignment.end + : MainAxisAlignment.start; final displayEvent = event.getDisplayEvent(timeline); const hardCorner = Radius.circular(4); @@ -240,12 +244,15 @@ class Message extends StatelessWidget { final borderRadius = BorderRadius.only( topLeft: !ownMessage && nextEventSameSender ? hardCorner : roundedCorner, topRight: ownMessage && nextEventSameSender ? hardCorner : roundedCorner, - bottomLeft: - !ownMessage && previousEventSameSender ? hardCorner : roundedCorner, - bottomRight: - ownMessage && previousEventSameSender ? hardCorner : roundedCorner, + bottomLeft: !ownMessage && previousEventSameSender + ? hardCorner + : roundedCorner, + bottomRight: ownMessage && previousEventSameSender + ? hardCorner + : roundedCorner, ); - final noBubble = ({ + final noBubble = + ({ MessageTypes.Video, MessageTypes.Image, MessageTypes.Sticker, @@ -260,8 +267,9 @@ class Message extends StatelessWidget { if (ownMessage) { // #Pangea - // color = - // displayEvent.status.isError ? Colors.redAccent : theme.bubbleColor; + // color = displayEvent.status.isError + // ? Colors.redAccent + // : theme.bubbleColor; color = displayEvent.status.isError ? Colors.redAccent : Color.alphaBlend( @@ -278,10 +286,7 @@ class Message extends StatelessWidget { if (singleSelected) { sentReactions.addAll( event - .aggregatedEvents( - timeline, - RelationshipTypes.reaction, - ) + .aggregatedEvents(timeline, RelationshipTypes.reaction) .where( (event) => event.senderId == event.room.client.userID && @@ -296,11 +301,15 @@ class Message extends StatelessWidget { ); } - final showReceiptsRow = - event.hasAggregatedEvents(timeline, RelationshipTypes.reaction); + final showReceiptsRow = event.hasAggregatedEvents( + timeline, + RelationshipTypes.reaction, + ); - final threadChildren = - event.aggregatedEvents(timeline, RelationshipTypes.thread); + final threadChildren = event.aggregatedEvents( + timeline, + RelationshipTypes.thread, + ); // #Pangea // final showReactionPicker = @@ -314,9 +323,7 @@ class Message extends StatelessWidget { key: ValueKey(event.eventId), background: const Padding( padding: EdgeInsets.symmetric(horizontal: 12.0), - child: Center( - child: Icon(Icons.check_outlined), - ), + child: Center(child: Icon(Icons.check_outlined)), ), direction: AppSettings.swipeRightToLeftToReply.value ? SwipeDirection.endToStart @@ -333,9 +340,8 @@ class Message extends StatelessWidget { bottom: previousEventSameSender ? 1.0 : 4.0, ), child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: - ownMessage ? CrossAxisAlignment.end : CrossAxisAlignment.start, + mainAxisSize: .min, + crossAxisAlignment: ownMessage ? .end : .start, children: [ // #Pangea // if (displayTime || selected) @@ -349,8 +355,9 @@ class Message extends StatelessWidget { child: Padding( padding: const EdgeInsets.only(top: 4.0), child: Material( - borderRadius: - BorderRadius.circular(AppConfig.borderRadius * 2), + borderRadius: BorderRadius.circular( + AppConfig.borderRadius * 2, + ), color: theme.colorScheme.surface.withAlpha(128), child: Padding( padding: const EdgeInsets.symmetric( @@ -417,13 +424,13 @@ class Message extends StatelessWidget { ), color: selected || highlightMarker ? theme.colorScheme.secondaryContainer - .withAlpha(128) + .withAlpha(128) : Colors.transparent, ), ), ), Row( - crossAxisAlignment: CrossAxisAlignment.start, + crossAxisAlignment: .start, mainAxisAlignment: rowMainAxisAlignment, children: [ // #Pangea @@ -451,18 +458,17 @@ class Message extends StatelessWidget { child: SizedBox( width: 16, height: 16, - child: event.status == - EventStatus.error + child: + event.status == EventStatus.error ? const Icon( Icons.error, color: Colors.red, ) : event.fileSendingStatus != null - ? const CircularProgressIndicator - .adaptive( - strokeWidth: 1, - ) - : null, + ? const CircularProgressIndicator.adaptive( + strokeWidth: 1, + ) + : null, ), ), ) @@ -470,20 +476,21 @@ class Message extends StatelessWidget { FutureBuilder( future: event.fetchSenderUser(), builder: (context, snapshot) { - final user = snapshot.data ?? + final user = + snapshot.data ?? event.senderFromMemoryOrFallback; return Avatar( mxContent: user.avatarUrl, name: user.calcDisplayname(), onTap: () => showMemberActionsPopupMenu( - context: context, - user: user, - onMention: onMention, - // #Pangea - room: controller.room, - // Pangea# - ), + context: context, + user: user, + onMention: onMention, + // #Pangea + room: controller.room, + // Pangea# + ), presenceUserId: user.stateKey, presenceBackgroundColor: wallpaperMode ? Colors.transparent @@ -491,23 +498,22 @@ class Message extends StatelessWidget { // #Pangea miniIcon: user.id == BotName.byEnvironment - ? BotSettingsLanguageIcon( - user: user, - ) - : null, + ? BotSettingsLanguageIcon( + user: user, + ) + : null, presenceOffset: user.id == BotName.byEnvironment - ? const Offset(0, 0) - : null, + ? const Offset(0, 0) + : null, // Pangea# ); }, ), Expanded( child: Column( - crossAxisAlignment: - CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, + crossAxisAlignment: .start, + mainAxisSize: .min, children: [ if (!nextEventSameSender) Padding( @@ -515,16 +521,16 @@ class Message extends StatelessWidget { left: 8.0, bottom: 4, ), - child: ownMessage || + child: + ownMessage || event.room.isDirectChat ? const SizedBox(height: 12) : FutureBuilder( - future: - event.fetchSenderUser(), - builder: - (context, snapshot) { - final displayname = snapshot - .data + future: event + .fetchSenderUser(), + builder: (context, snapshot) { + final displayname = + snapshot.data ?.calcDisplayname() ?? event .senderFromMemoryOrFallback @@ -534,38 +540,39 @@ class Message extends StatelessWidget { // displayname, controller.room .senderDisplayName( - snapshot.data ?? - event - .senderFromMemoryOrFallback, - ), + snapshot.data ?? + event + .senderFromMemoryOrFallback, + ), // Pangea# style: TextStyle( fontSize: 11, fontWeight: FontWeight.bold, - color: (theme.brightness == + color: + (theme.brightness == Brightness .light ? displayname - .color + .color : displayname - .lightColorText), + .lightColorText), shadows: !wallpaperMode - ? null - : [ - const Shadow( - offset: - Offset( + ? null + : [ + const Shadow( + offset: + Offset( 0.0, 0.0, ), - blurRadius: - 3, - color: Colors - .black, - ), - ], + blurRadius: + 3, + color: Colors + .black, + ), + ], ), maxLines: 1, overflow: TextOverflow @@ -576,8 +583,9 @@ class Message extends StatelessWidget { ), Container( alignment: alignment, - padding: - const EdgeInsets.only(left: 8), + padding: const EdgeInsets.only( + left: 8, + ), child: GestureDetector( // #Pangea onTap: () => @@ -595,49 +603,50 @@ class Message extends StatelessWidget { opacity: animateIn ? 0 : event.messageType == - MessageTypes - .BadEncrypted || - event.status.isSending - ? 0.5 - : 1, + MessageTypes + .BadEncrypted || + event.status.isSending + ? 0.5 + : 1, duration: FluffyThemes .animationDuration, curve: FluffyThemes.animationCurve, // #Pangea - child: - SelectionContainer.disabled( + child: SelectionContainer.disabled( child: MouseRegion( cursor: SystemMouseCursors.click, child: ValueListenableBuilder( valueListenable: controller .depressMessageButton, - builder: ( - context, - depressed, - child, - ) => - PressableButton( - buttonHeight: 5, - depressed: !isButton || + builder: + ( + context, depressed, - borderRadius: - borderRadius, - onPressed: () { - showToolbar( - pangeaMessageEvent, - ); - }, - color: color, - visible: - isButton && !noBubble, - builder: - (context, _, __) => - child!, - ), - // Pangea# + child, + ) => PressableButton( + buttonHeight: 5, + depressed: + !isButton || + depressed, + borderRadius: + borderRadius, + onPressed: () { + showToolbar( + pangeaMessageEvent, + ); + }, + color: color, + visible: + isButton && + !noBubble, + builder: + (context, _, _) => + child!, + ), + // Pangea# child: Container( decoration: BoxDecoration( color: noBubble @@ -649,8 +658,7 @@ class Message extends StatelessWidget { clipBehavior: Clip.antiAlias, // #Pangea - child: - CompositedTransformTarget( + child: CompositedTransformTarget( link: MatrixState .pAnyState .layerLinkAndKey( @@ -680,98 +688,87 @@ class Message extends StatelessWidget { ) .key, // Pangea# - decoration: - BoxDecoration( + decoration: BoxDecoration( borderRadius: - BorderRadius - .circular( - AppConfig - .borderRadius, - ), + BorderRadius.circular( + AppConfig + .borderRadius, + ), ), constraints: const BoxConstraints( - maxWidth: FluffyThemes - .columnWidth * - 1.5, - ), + maxWidth: + FluffyThemes + .columnWidth * + 1.5, + ), child: Column( mainAxisSize: - MainAxisSize - .min, + .min, crossAxisAlignment: CrossAxisAlignment .start, children: [ - if (event - .inReplyToEventId( + if (event.inReplyToEventId( includingFallback: false, ) != null) FutureBuilder< - Event?>( + Event? + >( future: event .getReplyEvent( - timeline, - ), - builder: ( - BuildContext - context, - snapshot, - ) { - final replyEvent = snapshot - .hasData - ? snapshot - .data! - : Event( - eventId: event.inReplyToEventId() ?? '\$fake_event_id', - content: { - 'msgtype': 'm.text', - 'body': '...', - }, - senderId: event.senderId, - type: 'm.room.message', - room: event.room, - status: EventStatus.sent, - originServerTs: DateTime.now(), - ); - return Padding( - padding: - const EdgeInsets.only( - left: - 16, - right: - 16, - top: - 8, + timeline, ), - child: - Material( - color: - Colors.transparent, - borderRadius: - ReplyContent.borderRadius, - child: - InkWell( - borderRadius: - ReplyContent.borderRadius, - onTap: () => - scrollToEventId( - replyEvent.eventId, + builder: + ( + BuildContext + context, + snapshot, + ) { + final replyEvent = + snapshot.hasData + ? snapshot.data! + : Event( + eventId: + event.inReplyToEventId() ?? + '\$fake_event_id', + content: { + 'msgtype': 'm.text', + 'body': '...', + }, + senderId: event.senderId, + type: 'm.room.message', + room: event.room, + status: EventStatus.sent, + originServerTs: DateTime.now(), + ); + return Padding( + padding: const EdgeInsets.only( + left: 16, + right: 16, + top: 8, ), - child: - AbsorbPointer( - child: ReplyContent( - replyEvent, - ownMessage: ownMessage, - timeline: timeline, + child: Material( + color: Colors.transparent, + borderRadius: ReplyContent.borderRadius, + child: InkWell( + borderRadius: ReplyContent.borderRadius, + onTap: () => scrollToEventId( + replyEvent.eventId, + ), + child: AbsorbPointer( + child: ReplyContent( + replyEvent, + ownMessage: ownMessage, + timeline: timeline, + ), + ), ), ), - ), - ), - ); - }, + ); + }, ), MessageContent( displayEvent, @@ -800,14 +797,12 @@ class Message extends StatelessWidget { ), if (event .hasAggregatedEvents( - timeline, - RelationshipTypes - .edit, - )) + timeline, + RelationshipTypes + .edit, + )) Padding( - padding: - const EdgeInsets - .only( + padding: const EdgeInsets.only( bottom: 8.0, left: @@ -825,23 +820,18 @@ class Message extends StatelessWidget { Icon( Icons .edit_outlined, - color: - textColor.withAlpha( + color: textColor.withAlpha( 164, ), size: 14, ), Text( - displayEvent - .originServerTs - .localizedTimeShort( + displayEvent.originServerTs.localizedTimeShort( context, ), - style: - TextStyle( - color: - textColor.withAlpha( + style: TextStyle( + color: textColor.withAlpha( 164, ), fontSize: @@ -876,46 +866,43 @@ class Message extends StatelessWidget { // ? Padding( // padding: // const EdgeInsets.all( - // 4.0, - // ), + // 4.0, + // ), // child: Material( // elevation: 4, // borderRadius: // BorderRadius.circular( - // AppConfig.borderRadius, - // ), + // AppConfig + // .borderRadius, + // ), // shadowColor: theme - // .colorScheme.surface + // .colorScheme + // .surface // .withAlpha(128), - // child: - // SingleChildScrollView( + // child: SingleChildScrollView( // scrollDirection: // Axis.horizontal, // child: Row( - // mainAxisSize: - // MainAxisSize.min, + // mainAxisSize: .min, // children: [ - // ...AppConfig - // .defaultReactions - // .map( - // (emoji) => - // IconButton( + // ...AppConfig.defaultReactions.map( + // ( + // emoji, + // ) => IconButton( // padding: // EdgeInsets // .zero, // icon: Center( - // child: - // Opacity( - // opacity: sentReactions - // .contains( - // emoji, - // ) + // child: Opacity( + // opacity: + // sentReactions.contains( + // emoji, + // ) // ? 0.33 // : 1, // child: Text( // emoji, - // style: - // const TextStyle( + // style: const TextStyle( // fontSize: // 20, // ), @@ -927,19 +914,20 @@ class Message extends StatelessWidget { // ), // onPressed: // sentReactions - // .contains( - // emoji, - // ) - // ? null - // : () { - // onSelect( - // event, - // ); - // event.room.sendReaction( - // event.eventId, - // emoji, - // ); - // }, + // .contains( + // emoji, + // ) + // ? null + // : () { + // onSelect( + // event, + // ); + // event.room.sendReaction( + // event + // .eventId, + // emoji, + // ); + // }, // ), // ), // IconButton( @@ -950,72 +938,55 @@ class Message extends StatelessWidget { // tooltip: L10n.of( // context, // ).customReaction, - // onPressed: - // () async { - // final emoji = - // await showAdaptiveBottomSheet< - // String>( + // onPressed: () async { + // final emoji = await showAdaptiveBottomSheet( // context: // context, - // builder: - // (context) => - // Scaffold( - // appBar: - // AppBar( - // title: - // Text( - // L10n.of(context) - // .customReaction, - // ), - // leading: - // CloseButton( - // onPressed: - // () => - // Navigator.of( + // builder: (context) => Scaffold( + // appBar: AppBar( + // title: Text( + // L10n.of( // context, - // ).pop( - // null, - // ), + // ).customReaction, + // ), + // leading: CloseButton( + // onPressed: () => Navigator.of( + // context, + // ).pop(null), // ), // ), - // body: - // SizedBox( + // body: SizedBox( // height: double // .infinity, - // child: - // EmojiPicker( - // onEmojiSelected: ( - // _, - // emoji, - // ) => - // Navigator.of( - // context, - // ).pop( - // emoji - // .emoji, - // ), - // config: - // Config( - // locale: - // Localizations.localeOf(context), - // emojiViewConfig: - // const EmojiViewConfig( + // child: EmojiPicker( + // onEmojiSelected: + // ( + // _, + // emoji, + // ) => + // Navigator.of( + // context, + // ).pop( + // emoji.emoji, + // ), + // config: Config( + // locale: Localizations.localeOf( + // context, + // ), + // emojiViewConfig: const EmojiViewConfig( // backgroundColor: // Colors.transparent, // ), - // bottomActionBarConfig: - // const BottomActionBarConfig( + // bottomActionBarConfig: const BottomActionBarConfig( // enabled: // false, // ), - // categoryViewConfig: - // CategoryViewConfig( + // categoryViewConfig: CategoryViewConfig( // initCategory: // Category.SMILEYS, // backspaceColor: // theme.colorScheme.primary, - // iconColor: - // theme.colorScheme.primary.withAlpha( + // iconColor: theme.colorScheme.primary.withAlpha( // 128, // ), // iconColorSelected: @@ -1025,10 +996,8 @@ class Message extends StatelessWidget { // backgroundColor: // theme.colorScheme.surface, // ), - // skinToneConfig: - // SkinToneConfig( - // dialogBackgroundColor: - // Color.lerp( + // skinToneConfig: SkinToneConfig( + // dialogBackgroundColor: Color.lerp( // theme.colorScheme.surface, // theme.colorScheme.primaryContainer, // 0.75, @@ -1047,17 +1016,18 @@ class Message extends StatelessWidget { // } // if (sentReactions // .contains( - // emoji, - // )) { + // emoji, + // )) { // return; // } // onSelect(event); // await event.room // .sendReaction( - // event.eventId, - // emoji, - // ); + // event + // .eventId, + // emoji, + // ); // }, // ), // ], @@ -1095,6 +1065,7 @@ class Message extends StatelessWidget { // child: MessageReactions(event, timeline), // ), // ), + // Pangea# if (enterThread != null) AnimatedSize( duration: FluffyThemes.animationDuration, @@ -1125,10 +1096,7 @@ class Message extends StatelessWidget { onPressed: () => enterThread(event.eventId), icon: const Icon(Icons.message), label: Text( - '${L10n.of(context).countReplies(threadChildren.length)} | ${threadChildren.first.calcLocalizedBodyFallback( - MatrixLocals(L10n.of(context)), - withSenderNamePrefix: true, - )}', + '${L10n.of(context).countReplies(threadChildren.length)} | ${threadChildren.first.calcLocalizedBodyFallback(MatrixLocals(L10n.of(context)), withSenderNamePrefix: true)}', maxLines: 1, overflow: TextOverflow.ellipsis, ), @@ -1136,6 +1104,7 @@ class Message extends StatelessWidget { ), ), ), + // #Pangea !showReceiptsRow ? const SizedBox.shrink() : Padding( @@ -1174,8 +1143,9 @@ class Message extends StatelessWidget { vertical: 2, ), decoration: BoxDecoration( - borderRadius: - BorderRadius.circular(AppConfig.borderRadius / 3), + borderRadius: BorderRadius.circular( + AppConfig.borderRadius / 3, + ), color: theme.colorScheme.surface.withAlpha(128), ), child: Text( @@ -1246,8 +1216,10 @@ class BubblePainter extends CustomPainter { final scrollableRect = Offset.zero & scrollableBox.size; final bubbleBox = context.findRenderObject() as RenderBox; - final origin = - bubbleBox.localToGlobal(Offset.zero, ancestor: scrollableBox); + final origin = bubbleBox.localToGlobal( + Offset.zero, + ancestor: scrollableBox, + ); final paint = Paint() ..shader = ui.Gradient.linear( scrollableRect.topCenter, diff --git a/lib/pages/chat/events/message_content.dart b/lib/pages/chat/events/message_content.dart index 757fea66a..f1c8fb23d 100644 --- a/lib/pages/chat/events/message_content.dart +++ b/lib/pages/chat/events/message_content.dart @@ -73,9 +73,7 @@ class MessageContent extends StatelessWidget { // if (event.content['can_request_session'] != true) { // ScaffoldMessenger.of(context).showSnackBar( // SnackBar( - // content: Text( - // event.calcLocalizedBodyFallback(MatrixLocals(l10n)), - // ), + // content: Text(event.calcLocalizedBodyFallback(MatrixLocals(l10n))), // ), // ); // return; @@ -114,20 +112,16 @@ class MessageContent extends StatelessWidget { // trailing: const Icon(Icons.lock_outlined), // ), // const Divider(), - // Text( - // event.calcLocalizedBodyFallback( - // MatrixLocals(l10n), - // ), - // ), + // Text(event.calcLocalizedBodyFallback(MatrixLocals(l10n))), // ], // ), // ), // ), // ); // } - void onClick(PangeaToken token) { - token = pangeaMessageEvent?.messageDisplayRepresentation + token = + pangeaMessageEvent?.messageDisplayRepresentation ?.getClosestNonPunctToken(token) ?? token; @@ -157,8 +151,9 @@ class MessageContent extends StatelessWidget { case MessageTypes.Image: case MessageTypes.Sticker: if (event.redacted) continue textmessage; - final maxSize = - event.messageType == MessageTypes.Sticker ? 128.0 : 256.0; + final maxSize = event.messageType == MessageTypes.Sticker + ? 128.0 + : 256.0; final w = event.content .tryGetMap('info') ?.tryGet('w'); @@ -193,12 +188,12 @@ class MessageContent extends StatelessWidget { return CuteContent(event); case MessageTypes.Audio: if (PlatformInfos.isMobile || - PlatformInfos.isMacOS || - PlatformInfos.isWeb - // Disabled until https://github.com/bleonard252/just_audio_mpv/issues/3 - // is fixed - // || PlatformInfos.isLinux - ) { + PlatformInfos.isMacOS || + PlatformInfos.isWeb + // Disabled until https://github.com/bleonard252/just_audio_mpv/issues/3 + // is fixed + // || PlatformInfos.isLinux + ) { return AudioPlayerWidget( event, color: textColor, @@ -244,8 +239,9 @@ class MessageContent extends StatelessWidget { // ); // Pangea# case MessageTypes.Location: - final geoUri = - Uri.tryParse(event.content.tryGet('geo_uri')!); + final geoUri = Uri.tryParse( + event.content.tryGet('geo_uri')!, + ); if (geoUri != null && geoUri.scheme == 'geo') { final latlong = geoUri.path .split(';') @@ -257,7 +253,7 @@ class MessageContent extends StatelessWidget { latlong.first != null && latlong.last != null) { return Column( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ MapBubble( latitude: latlong.first!, @@ -266,8 +262,10 @@ class MessageContent extends StatelessWidget { const SizedBox(height: 6), OutlinedButton.icon( icon: Icon(Icons.location_on_outlined, color: textColor), - onPressed: - UrlLauncher(context, geoUri.toString()).launchUrl, + onPressed: UrlLauncher( + context, + geoUri.toString(), + ).launchUrl, label: Text( L10n.of(context).openInMaps, style: TextStyle(color: textColor), @@ -299,25 +297,25 @@ class MessageContent extends StatelessWidget { html = '* $html'; } - final bigEmotes = event.onlyEmotes && + final bigEmotes = + event.onlyEmotes && event.numberEmotes > 0 && event.numberEmotes <= 3; return Padding( - padding: const EdgeInsets.symmetric( - horizontal: 16, - vertical: 8, - ), + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), child: HtmlMessage( html: html, textColor: textColor, room: event.room, - fontSize: AppSettings.fontSizeFactor.value * + fontSize: + AppSettings.fontSizeFactor.value * AppConfig.messageFontSize * (bigEmotes ? 5 : 1), limitHeight: !selected, linkStyle: TextStyle( color: linkColor, - fontSize: AppSettings.fontSizeFactor.value * + fontSize: + AppSettings.fontSizeFactor.value * AppConfig.messageFontSize, decoration: TextDecoration.underline, decorationColor: linkColor, @@ -335,7 +333,8 @@ class MessageContent extends StatelessWidget { pangeaMessageEvent: pangeaMessageEvent, nextEvent: nextEvent, prevEvent: prevEvent, - onClick: event.isActivityMessage || + onClick: + event.isActivityMessage || readingAssistanceMode == ReadingAssistanceMode.practiceMode ? null @@ -418,16 +417,14 @@ class RedactionWidget extends StatelessWidget { future: event.redactedBecause?.fetchSenderUser(), builder: (context, snapshot) { final reason = event.redactedBecause?.content.tryGet('reason'); - final redactedBy = snapshot.data?.calcDisplayname() ?? + final redactedBy = + snapshot.data?.calcDisplayname() ?? event.redactedBecause?.senderId.localpart ?? L10n.of(context).user; return _ButtonContent( label: reason == null ? L10n.of(context).redactedBy(redactedBy) - : L10n.of(context).redactedByBecause( - redactedBy, - reason, - ), + : L10n.of(context).redactedByBecause(redactedBy, reason), icon: '🗑️', textColor: buttonTextColor.withAlpha(128), onPressed: () => onInfoTab!(event), @@ -456,18 +453,12 @@ class _ButtonContent extends StatelessWidget { @override Widget build(BuildContext context) { return Padding( - padding: const EdgeInsets.symmetric( - horizontal: 16, - vertical: 8, - ), + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), child: InkWell( onTap: onPressed, child: Text( '$icon $label', - style: TextStyle( - color: textColor, - fontSize: fontSize, - ), + style: TextStyle(color: textColor, fontSize: fontSize), ), ), ); diff --git a/lib/pages/chat/events/message_download_content.dart b/lib/pages/chat/events/message_download_content.dart index 18b5c0b07..46d5167ca 100644 --- a/lib/pages/chat/events/message_download_content.dart +++ b/lib/pages/chat/events/message_download_content.dart @@ -27,15 +27,15 @@ class MessageDownloadContent extends StatelessWidget { final filetype = (filename.contains('.') ? filename.split('.').last.toUpperCase() : event.content - .tryGetMap('info') - ?.tryGet('mimetype') - ?.toUpperCase() ?? - 'UNKNOWN'); + .tryGetMap('info') + ?.tryGet('mimetype') + ?.toUpperCase() ?? + 'UNKNOWN'); final sizeString = event.sizeString ?? '?MB'; final fileDescription = event.fileDescription; return Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: .min, + crossAxisAlignment: .start, spacing: 8, children: [ Material( @@ -47,7 +47,7 @@ class MessageDownloadContent extends StatelessWidget { width: 400, padding: const EdgeInsets.all(16.0), child: Row( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, spacing: 16, children: [ CircleAvatar( @@ -56,8 +56,8 @@ class MessageDownloadContent extends StatelessWidget { ), Flexible( child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, + crossAxisAlignment: .start, + mainAxisSize: .min, children: [ Text( filename, @@ -93,13 +93,15 @@ class MessageDownloadContent extends StatelessWidget { textScaleFactor: MediaQuery.textScalerOf(context).scale(1), style: TextStyle( color: textColor, - fontSize: AppSettings.fontSizeFactor.value * + fontSize: + AppSettings.fontSizeFactor.value * AppConfig.messageFontSize, ), options: const LinkifyOptions(humanize: false), linkStyle: TextStyle( color: linkColor, - fontSize: AppSettings.fontSizeFactor.value * + fontSize: + AppSettings.fontSizeFactor.value * AppConfig.messageFontSize, decoration: TextDecoration.underline, decorationColor: linkColor, diff --git a/lib/pages/chat/events/message_reactions.dart b/lib/pages/chat/events/message_reactions.dart index dede458aa..5f5b4aa2b 100644 --- a/lib/pages/chat/events/message_reactions.dart +++ b/lib/pages/chat/events/message_reactions.dart @@ -17,8 +17,10 @@ class MessageReactions extends StatelessWidget { @override Widget build(BuildContext context) { - final allReactionEvents = - event.aggregatedEvents(timeline, RelationshipTypes.reaction); + final allReactionEvents = event.aggregatedEvents( + timeline, + RelationshipTypes.reaction, + ); final reactionMap = {}; final client = Matrix.of(context).client; @@ -113,7 +115,7 @@ class _Reaction extends StatelessWidget { Widget content; if (reactionKey.startsWith('mxc://')) { content = Row( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ MxcImage( uri: Uri.parse(reactionKey), @@ -190,17 +192,14 @@ class _AdaptableReactorsDialog extends StatelessWidget { final Client? client; final _ReactionEntry? reactionEntry; - const _AdaptableReactorsDialog({ - this.client, - this.reactionEntry, - }); + const _AdaptableReactorsDialog({this.client, this.reactionEntry}); Future show(BuildContext context) => showAdaptiveDialog( - context: context, - builder: (context) => this, - barrierDismissible: true, - useRootNavigator: false, - ); + context: context, + builder: (context) => this, + barrierDismissible: true, + useRootNavigator: false, + ); @override Widget build(BuildContext context) { @@ -226,9 +225,6 @@ class _AdaptableReactorsDialog extends StatelessWidget { final title = Center(child: Text(reactionEntry!.key)); - return AlertDialog.adaptive( - title: title, - content: body, - ); + return AlertDialog.adaptive(title: title, content: body); } } diff --git a/lib/pages/chat/events/pangea_message_reactions.dart b/lib/pages/chat/events/pangea_message_reactions.dart index a28f8a130..cda342d23 100644 --- a/lib/pages/chat/events/pangea_message_reactions.dart +++ b/lib/pages/chat/events/pangea_message_reactions.dart @@ -74,8 +74,10 @@ class _PangeaMessageReactionsState extends State { } void _updateReactionMap() { - final allReactionEvents = widget.event - .aggregatedEvents(widget.timeline, RelationshipTypes.reaction); + final allReactionEvents = widget.event.aggregatedEvents( + widget.timeline, + RelationshipTypes.reaction, + ); final newReactionMap = {}; for (final e in allReactionEvents) { @@ -220,14 +222,8 @@ class _ReactionState extends State<_Reaction> with TickerProviderStateMixin { duration: const Duration(milliseconds: 400), vsync: this, ); - _bounceOutAnimation = Tween( - begin: 1.0, - end: 0, - ).animate( - CurvedAnimation( - parent: _bounceOutController, - curve: Curves.easeInBack, - ), + _bounceOutAnimation = Tween(begin: 1.0, end: 0).animate( + CurvedAnimation(parent: _bounceOutController, curve: Curves.easeInBack), ); _burstController = AnimationController( @@ -237,12 +233,7 @@ class _ReactionState extends State<_Reaction> with TickerProviderStateMixin { _burstAnimation = Tween( begin: 0.0, end: 1.0, - ).animate( - CurvedAnimation( - parent: _burstController, - curve: Curves.easeOut, - ), - ); + ).animate(CurvedAnimation(parent: _burstController, curve: Curves.easeOut)); _growController = AnimationController( duration: const Duration(milliseconds: 500), @@ -250,25 +241,33 @@ class _ReactionState extends State<_Reaction> with TickerProviderStateMixin { ); _growScale = TweenSequence([ TweenSequenceItem( - tween: Tween(begin: 0.6, end: 1.18) - .chain(CurveTween(curve: Curves.easeOutBack)), + tween: Tween( + begin: 0.6, + end: 1.18, + ).chain(CurveTween(curve: Curves.easeOutBack)), weight: 60, ), TweenSequenceItem( - tween: Tween(begin: 1.18, end: 1.0) - .chain(CurveTween(curve: Curves.easeIn)), + tween: Tween( + begin: 1.18, + end: 1.0, + ).chain(CurveTween(curve: Curves.easeIn)), weight: 40, ), ]).animate(_growController); _growOffset = TweenSequence([ TweenSequenceItem( - tween: Tween(begin: 0.0, end: -10.0) - .chain(CurveTween(curve: Curves.easeOut)), + tween: Tween( + begin: 0.0, + end: -10.0, + ).chain(CurveTween(curve: Curves.easeOut)), weight: 60, ), TweenSequenceItem( - tween: Tween(begin: -10.0, end: 0.0) - .chain(CurveTween(curve: Curves.easeIn)), + tween: Tween( + begin: -10.0, + end: 0.0, + ).chain(CurveTween(curve: Curves.easeIn)), weight: 40, ), ]).animate(_growController); @@ -391,11 +390,13 @@ class _ReactionState extends State<_Reaction> with TickerProviderStateMixin { AnimatedBuilder( animation: Listenable.merge([_bounceOutAnimation, _growController]), builder: (context, child) { - final isGrowing = _growController.isAnimating || + final isGrowing = + _growController.isAnimating || (_growController.value > 0 && _growController.value < 1.0); final isBouncing = _bounceOutController.isAnimating; - final scale = - isGrowing ? _growScale.value : _bounceOutAnimation.value; + final scale = isGrowing + ? _growScale.value + : _bounceOutAnimation.value; final offsetY = isGrowing ? _growOffset.value : 0.0; return AnimatedSize( @@ -440,7 +441,8 @@ class _ReactionState extends State<_Reaction> with TickerProviderStateMixin { color: widget.reacted == true ? theme.colorScheme.primary : theme - .colorScheme.surfaceContainerHigh, + .colorScheme + .surfaceContainerHigh, width: 1, ), borderRadius: BorderRadius.circular( @@ -503,17 +505,14 @@ class _AdaptableReactorsDialog extends StatelessWidget { final Client? client; final _ReactionEntry? reactionEntry; - const _AdaptableReactorsDialog({ - this.client, - this.reactionEntry, - }); + const _AdaptableReactorsDialog({this.client, this.reactionEntry}); Future show(BuildContext context) => showAdaptiveDialog( - context: context, - builder: (context) => this, - barrierDismissible: true, - useRootNavigator: true, - ); + context: context, + builder: (context) => this, + barrierDismissible: true, + useRootNavigator: true, + ); @override Widget build(BuildContext context) { @@ -542,9 +541,6 @@ class _AdaptableReactorsDialog extends StatelessWidget { final title = Center(child: Text(reactionEntry!.key)); - return AlertDialog.adaptive( - title: title, - content: body, - ); + return AlertDialog.adaptive(title: title, content: body); } } diff --git a/lib/pages/chat/events/poll.dart b/lib/pages/chat/events/poll.dart index af948d70f..e6baeb7ce 100644 --- a/lib/pages/chat/events/poll.dart +++ b/lib/pages/chat/events/poll.dart @@ -24,10 +24,8 @@ class PollWidget extends StatelessWidget { super.key, }); - void _endPoll(BuildContext context) => showFutureLoadingDialog( - context: context, - future: () => event.endPoll(), - ); + void _endPoll(BuildContext context) => + showFutureLoadingDialog(context: context, future: () => event.endPoll()); void _toggleVote( BuildContext context, @@ -60,20 +58,19 @@ class PollWidget extends StatelessWidget { } final responses = event.getPollResponses(timeline); final pollHasBeenEnded = event.getPollHasBeenEnded(timeline); - final canVote = event.room.canSendEvent(PollEventContent.responseType) && + final canVote = + event.room.canSendEvent(PollEventContent.responseType) && !pollHasBeenEnded; final maxPolls = responses.length; final answersVisible = eventContent.pollStartContent.kind == PollKind.disclosed || - pollHasBeenEnded; + pollHasBeenEnded; return Padding( - padding: const EdgeInsets.symmetric( - vertical: 8, - ), + padding: const EdgeInsets.symmetric(vertical: 8), child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: .min, + crossAxisAlignment: .start, children: [ Padding( padding: const EdgeInsets.symmetric(horizontal: 16), @@ -82,13 +79,15 @@ class PollWidget extends StatelessWidget { textScaleFactor: MediaQuery.textScalerOf(context).scale(1), style: TextStyle( color: textColor, - fontSize: AppSettings.fontSizeFactor.value * + fontSize: + AppSettings.fontSizeFactor.value * AppConfig.messageFontSize, ), options: const LinkifyOptions(humanize: false), linkStyle: TextStyle( color: linkColor, - fontSize: AppSettings.fontSizeFactor.value * + fontSize: + AppSettings.fontSizeFactor.value * AppConfig.messageFontSize, decoration: TextDecoration.underline, decorationColor: linkColor, @@ -97,99 +96,101 @@ class PollWidget extends StatelessWidget { ), ), Divider(color: linkColor.withAlpha(64)), - ...eventContent.pollStartContent.answers.map( - (answer) { - final votedUserIds = responses.entries - .where((entry) => entry.value.contains(answer.id)) - .map((entry) => entry.key) - .toSet(); - return Material( - color: Colors.transparent, - clipBehavior: Clip.hardEdge, - child: CheckboxListTile.adaptive( - value: responses[event.room.client.userID!] - ?.contains(answer.id) ?? - false, - contentPadding: const EdgeInsets.symmetric(horizontal: 16), - checkboxScaleFactor: 1.5, - checkboxShape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(32), + ...eventContent.pollStartContent.answers.map((answer) { + final votedUserIds = responses.entries + .where((entry) => entry.value.contains(answer.id)) + .map((entry) => entry.key) + .toSet(); + return Material( + color: Colors.transparent, + clipBehavior: Clip.hardEdge, + child: CheckboxListTile.adaptive( + value: + responses[event.room.client.userID!]?.contains(answer.id) ?? + false, + contentPadding: const EdgeInsets.symmetric(horizontal: 16), + checkboxScaleFactor: 1.5, + checkboxShape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(32), + ), + onChanged: !canVote + ? null + : (_) => _toggleVote( + context, + answer.id, + eventContent.pollStartContent.maxSelections, + ), + title: Text( + answer.mText, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyle( + color: textColor, + fontSize: + AppConfig.messageFontSize * + AppSettings.fontSizeFactor.value, ), - onChanged: !canVote - ? null - : (_) => _toggleVote( - context, - answer.id, - eventContent.pollStartContent.maxSelections, - ), - title: Text( - answer.mText, - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: TextStyle( - color: textColor, - fontSize: AppConfig.messageFontSize * - AppSettings.fontSizeFactor.value, - ), - ), - subtitle: answersVisible - ? Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: Row( - children: [ - Text( - L10n.of(context) - .countVotes(votedUserIds.length), - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: TextStyle( - color: linkColor, - fontSize: + ), + subtitle: answersVisible + ? Column( + crossAxisAlignment: .start, + mainAxisSize: .min, + children: [ + SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Row( + children: [ + Text( + L10n.of( + context, + ).countVotes(votedUserIds.length), + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyle( + color: linkColor, + fontSize: + 12 * AppSettings.fontSizeFactor.value, + ), + ), + const SizedBox(width: 2), + ...votedUserIds.map((userId) { + final user = event.room + .getState(EventTypes.RoomMember, userId) + ?.asUser(event.room); + return Padding( + padding: const EdgeInsets.symmetric( + horizontal: 2.0, + ), + child: Avatar( + mxContent: user?.avatarUrl, + name: + user?.calcDisplayname() ?? + userId.localpart, + size: 12 * AppSettings.fontSizeFactor.value, ), - ), - const SizedBox(width: 2), - ...votedUserIds.map((userId) { - final user = event.room - .getState(EventTypes.RoomMember, userId) - ?.asUser(event.room); - return Padding( - padding: const EdgeInsets.symmetric( - horizontal: 2.0, - ), - child: Avatar( - mxContent: user?.avatarUrl, - name: user?.calcDisplayname() ?? - userId.localpart, - size: 12 * - AppSettings.fontSizeFactor.value, - ), - ); - }), - const SizedBox(width: 2), - ], - ), + ); + }), + const SizedBox(width: 2), + ], ), - LinearProgressIndicator( - color: linkColor, - backgroundColor: linkColor.withAlpha(128), - borderRadius: - BorderRadius.circular(AppConfig.borderRadius), - value: maxPolls == 0 - ? 0 - : votedUserIds.length / maxPolls, + ), + LinearProgressIndicator( + color: linkColor, + backgroundColor: linkColor.withAlpha(128), + borderRadius: BorderRadius.circular( + AppConfig.borderRadius, ), - ], - ) - : null, - ), - ); - }, - ), + value: maxPolls == 0 + ? 0 + : votedUserIds.length / maxPolls, + ), + ], + ) + : null, + ), + ); + }), if (!pollHasBeenEnded && event.senderId == event.room.client.userID) Padding( padding: const EdgeInsets.symmetric(horizontal: 16), diff --git a/lib/pages/chat/events/reaction_listener.dart b/lib/pages/chat/events/reaction_listener.dart index f0f51c0ee..ef260c9fb 100644 --- a/lib/pages/chat/events/reaction_listener.dart +++ b/lib/pages/chat/events/reaction_listener.dart @@ -9,22 +9,22 @@ class ReactionListener { StreamSubscription? _reactionSub; ReactionListener({required this.event, required this.onUpdate}) { - _reactionSub = event.room.client.onSync.stream.where( - (update) { - final room = event.room; - final timelineEvents = update.rooms?.join?[room.id]?.timeline?.events; - if (timelineEvents == null) return false; + _reactionSub = event.room.client.onSync.stream + .where((update) { + final room = event.room; + final timelineEvents = update.rooms?.join?[room.id]?.timeline?.events; + if (timelineEvents == null) return false; - final eventID = event.eventId; - return timelineEvents.any( - (e) => - e.type == EventTypes.Redaction || - (e.type == EventTypes.Reaction && - Event.fromMatrixEvent(e, room).relationshipEventId == - eventID), - ); - }, - ).listen(onUpdate); + final eventID = event.eventId; + return timelineEvents.any( + (e) => + e.type == EventTypes.Redaction || + (e.type == EventTypes.Reaction && + Event.fromMatrixEvent(e, room).relationshipEventId == + eventID), + ); + }) + .listen(onUpdate); } void dispose() { diff --git a/lib/pages/chat/events/reply_content.dart b/lib/pages/chat/events/reply_content.dart index e3c7f9484..fdf7a5c78 100644 --- a/lib/pages/chat/events/reply_content.dart +++ b/lib/pages/chat/events/reply_content.dart @@ -29,27 +29,28 @@ class ReplyContent extends StatelessWidget { final theme = Theme.of(context); final timeline = this.timeline; - final displayEvent = - timeline != null ? replyEvent.getDisplayEvent(timeline) : replyEvent; + final displayEvent = timeline != null + ? replyEvent.getDisplayEvent(timeline) + : replyEvent; final fontSize = AppConfig.messageFontSize * AppSettings.fontSizeFactor.value; final color = theme.brightness == Brightness.dark - // Pangea# + // #Pangea ? ownMessage - ? theme.colorScheme.tertiaryContainer - : theme.colorScheme.onTertiaryContainer + ? theme.colorScheme.tertiaryContainer + : theme.colorScheme.onTertiaryContainer : theme.colorScheme.tertiary; // ? theme.colorScheme.onTertiaryContainer // : ownMessage - // ? theme.colorScheme.tertiaryContainer - // : theme.colorScheme.tertiary; + // ? theme.colorScheme.tertiaryContainer + // : theme.colorScheme.tertiary; // Pangea# return Material( color: Colors.transparent, borderRadius: borderRadius, child: Row( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ Container( width: 5, @@ -62,8 +63,8 @@ class ReplyContent extends StatelessWidget { const SizedBox(width: 6), Flexible( child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: .start, + mainAxisAlignment: .center, children: [ FutureBuilder( initialData: displayEvent.senderFromMemoryOrFallback, @@ -105,8 +106,8 @@ class ReplyContent extends StatelessWidget { // color: theme.brightness == Brightness.dark // ? theme.colorScheme.onSurface // : ownMessage - // ? theme.colorScheme.onTertiary - // : theme.colorScheme.onSurface, + // ? theme.colorScheme.onTertiary + // : theme.colorScheme.onSurface, color: ownMessage ? ThemeData.dark().colorScheme.onPrimary : theme.colorScheme.onSurface, diff --git a/lib/pages/chat/events/room_creation_state_event.dart b/lib/pages/chat/events/room_creation_state_event.dart index 8c4c3519e..ddf97199a 100644 --- a/lib/pages/chat/events/room_creation_state_event.dart +++ b/lib/pages/chat/events/room_creation_state_event.dart @@ -36,14 +36,14 @@ class RoomCreationStateEventState extends State { @override void initState() { super.initState(); - _memberSubscription = event.room.client.onRoomState.stream.where( - (u) { - return u.roomId == event.room.id && - u.state.type == EventTypes.RoomMember; - }, - ).listen((_) { - if (_members > 1) setState(() {}); - }); + _memberSubscription = event.room.client.onRoomState.stream + .where((u) { + return u.roomId == event.room.id && + u.state.type == EventTypes.RoomMember; + }) + .listen((_) { + if (_members > 1) setState(() {}); + }); } @override @@ -75,7 +75,7 @@ class RoomCreationStateEventState extends State { child: Padding( padding: const EdgeInsets.all(16.0), child: Column( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ Avatar( mxContent: event.room.avatar, @@ -106,21 +106,13 @@ class RoomCreationStateEventState extends State { const SizedBox(height: 16.0), const InstructionsInlineTooltip( instructionsEnum: InstructionsEnum.clickMessage, - padding: EdgeInsets.only( - left: 16.0, - right: 16.0, - top: 16.0, - ), + padding: EdgeInsets.only(left: 16.0, right: 16.0, top: 16.0), animate: false, ), if (_members <= 1 && InstructionsEnum.clickMessage.isToggledOff) const InstructionsInlineTooltip( instructionsEnum: InstructionsEnum.emptyChatWarning, - padding: EdgeInsets.only( - left: 16.0, - right: 16.0, - top: 16.0, - ), + padding: EdgeInsets.only(left: 16.0, right: 16.0, top: 16.0), animate: false, ), // Pangea# diff --git a/lib/pages/chat/events/state_message.dart b/lib/pages/chat/events/state_message.dart index eaebc828e..63c9f4be0 100644 --- a/lib/pages/chat/events/state_message.dart +++ b/lib/pages/chat/events/state_message.dart @@ -35,8 +35,9 @@ class StateMessage extends StatelessWidget { padding: const EdgeInsets.all(4), child: Material( color: theme.colorScheme.surface.withAlpha(128), - borderRadius: - BorderRadius.circular(AppConfig.borderRadius / 3), + borderRadius: BorderRadius.circular( + AppConfig.borderRadius / 3, + ), child: Padding( padding: const EdgeInsets.symmetric( horizontal: 8.0, @@ -50,7 +51,8 @@ class StateMessage extends StatelessWidget { // text: event.calcLocalizedBodyFallback( // MatrixLocals(L10n.of(context)), // ), - text: (event.type == EventTypes.RoomMember) && + text: + (event.type == EventTypes.RoomMember) && (event.roomMemberChangeType == RoomMemberChangeType.leave) && (event.stateKey == diff --git a/lib/pages/chat/events/video_player.dart b/lib/pages/chat/events/video_player.dart index d78230b1f..682886032 100644 --- a/lib/pages/chat/events/video_player.dart +++ b/lib/pages/chat/events/video_player.dart @@ -47,8 +47,10 @@ class EventVideoPlayer extends StatelessWidget { PlatformInfos.supportsVideoPlayer && _supportedFormat; // Pangea# - final blurHash = (event.infoMap as Map) - .tryGet('xyz.amorgan.blurhash') ?? + final blurHash = + (event.infoMap as Map).tryGet( + 'xyz.amorgan.blurhash', + ) ?? fallbackBlurHash; final fileDescription = event.fileDescription; const maxDimension = 300.0; @@ -61,11 +63,12 @@ class EventVideoPlayer extends StatelessWidget { final height = videoHeight / modifier; final durationInt = infoMap?.tryGet('duration'); - final duration = - durationInt == null ? null : Duration(milliseconds: durationInt); + final duration = durationInt == null + ? null + : Duration(milliseconds: durationInt); return Column( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, spacing: 8, children: [ Material( @@ -140,22 +143,21 @@ class EventVideoPlayer extends StatelessWidget { SizedBox( width: width, child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: 16, - vertical: 8, - ), + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), child: Linkify( text: fileDescription, textScaleFactor: MediaQuery.textScalerOf(context).scale(1), style: TextStyle( color: textColor, - fontSize: AppSettings.fontSizeFactor.value * + fontSize: + AppSettings.fontSizeFactor.value * AppConfig.messageFontSize, ), options: const LinkifyOptions(humanize: false), linkStyle: TextStyle( color: linkColor, - fontSize: AppSettings.fontSizeFactor.value * + fontSize: + AppSettings.fontSizeFactor.value * AppConfig.messageFontSize, decoration: TextDecoration.underline, decorationColor: linkColor, diff --git a/lib/pages/chat/input_bar.dart b/lib/pages/chat/input_bar.dart index 7dde2eaa7..149dd5f1f 100644 --- a/lib/pages/chat/input_bar.dart +++ b/lib/pages/chat/input_bar.dart @@ -58,11 +58,11 @@ class InputBar extends StatelessWidget { this.autofocus, this.textInputAction, this.readOnly = false, + required this.suggestionEmojis, // #Pangea required this.choreographer, required this.showNextMatch, // Pangea# - required this.suggestionEmojis, super.key, }); @@ -81,10 +81,7 @@ class InputBar extends StatelessWidget { // final commandSearch = commandMatch[1]!.toLowerCase(); // for (final command in room.client.commands.keys) { // if (command.contains(commandSearch)) { - // ret.add({ - // 'type': 'command', - // 'name': command, - // }); + // ret.add({'type': 'command', 'name': command}); // } // if (ret.length > maxResults) return ret; @@ -127,8 +124,8 @@ class InputBar extends StatelessWidget { 'type': 'emote', 'name': emote.key, 'pack': packSearch, - 'pack_avatar_url': - emotePacks[packSearch]!.pack.avatarUrl?.toString(), + 'pack_avatar_url': emotePacks[packSearch]!.pack.avatarUrl + ?.toString(), 'pack_display_name': emotePacks[packSearch]!.pack.displayName ?? packSearch, 'mxc': emote.value.url.toString(), @@ -179,8 +176,9 @@ class InputBar extends StatelessWidget { for (final user in room.getParticipants()) { if ((user.displayName != null && (user.displayName!.toLowerCase().contains(userSearch) || - slugify(user.displayName!.toLowerCase()) - .contains(userSearch))) || + slugify( + user.displayName!.toLowerCase(), + ).contains(userSearch))) || user.id.split(':')[0].toLowerCase().contains(userSearch)) { ret.add({ 'type': 'user', @@ -278,11 +276,7 @@ class InputBar extends StatelessWidget { style: const TextStyle(fontSize: 16), ), ), - title: Text( - label, - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), + title: Text(label, maxLines: 1, overflow: TextOverflow.ellipsis), ), ); } @@ -300,7 +294,7 @@ class InputBar extends StatelessWidget { isThumbnail: false, ), title: Row( - crossAxisAlignment: CrossAxisAlignment.center, + crossAxisAlignment: .center, children: [ Text(suggestion['name']!), Expanded( @@ -331,7 +325,8 @@ class InputBar extends StatelessWidget { onTap: () => onSelected(suggestion), leading: Avatar( mxContent: url, - name: suggestion.tryGet('displayname') ?? + name: + suggestion.tryGet('displayname') ?? suggestion.tryGet('mxid'), size: size, client: client, @@ -343,8 +338,10 @@ class InputBar extends StatelessWidget { } String insertSuggestion(Map suggestion) { - final replaceText = - controller!.text.substring(0, controller!.selection.baseOffset); + final replaceText = controller!.text.substring( + 0, + controller!.selection.baseOffset, + ); var startText = ''; final afterText = replaceText == controller!.text ? '' @@ -434,12 +431,7 @@ class InputBar extends StatelessWidget { if (match.updatedMatch.isITStart) { choreographer.itController.openIT(controller!.text); } else { - OverlayUtil.showIGCMatch( - match, - choreographer, - context, - showNextMatch, - ); + OverlayUtil.showIGCMatch(match, choreographer, context, showNextMatch); // rebuild the text field to highlight the newly selected match choreographer.textController.setSystemText( @@ -483,9 +475,9 @@ class InputBar extends StatelessWidget { optionsBuilder: getSuggestions, // #Pangea // fieldViewBuilder: (context, controller, focusNode, _) => TextField( - fieldViewBuilder: (context, __, focusNode, _) => ValueListenableBuilder( + fieldViewBuilder: (context, _, focusNode, _) => ValueListenableBuilder( valueListenable: choreographer.itController.open, - builder: (context, _, __) { + builder: (context, _, _) { return TextField( // Pangea# controller: controller, @@ -511,10 +503,7 @@ class InputBar extends StatelessWidget { bytes: data, name: content.uri.split('/').last, ); - room.sendFileEvent( - file, - shrinkImageMaxDimension: 1600, - ); + room.sendFileEvent(file, shrinkImageMaxDimension: 1600); }, ), minLines: minLines, @@ -524,7 +513,9 @@ class InputBar extends StatelessWidget { autofocus: autofocus!, inputFormatters: [ // #Pangea - // LengthLimitingTextInputFormatter((maxPDUSize / 3).floor()), + //LengthLimitingTextInputFormatter((maxPDUSize / 3).floor()), + //setting max character count to 1000 + //after max, nothing else can be typed LengthLimitingTextInputFormatter(1000), // Pangea# ], @@ -535,11 +526,14 @@ class InputBar extends StatelessWidget { }, // #Pangea // maxLength: AppSettings.textMessageMaxLength.value, - // decoration: decoration!, + // decoration: decoration, decoration: decoration.copyWith( hint: StreamBuilder( stream: MatrixState - .pangeaController.userController.languageStream.stream, + .pangeaController + .userController + .languageStream + .stream, builder: (context, _) => SizedBox( height: 24, child: ShrinkableText( @@ -548,8 +542,8 @@ class InputBar extends StatelessWidget { : _defaultHintText(context), maxWidth: double.infinity, style: Theme.of(context).textTheme.bodyLarge?.copyWith( - color: Theme.of(context).disabledColor, - ), + color: Theme.of(context).disabledColor, + ), ), ), ), diff --git a/lib/pages/chat/pinned_events.dart b/lib/pages/chat/pinned_events.dart index 38ae4007f..f66ef4700 100644 --- a/lib/pages/chat/pinned_events.dart +++ b/lib/pages/chat/pinned_events.dart @@ -39,7 +39,8 @@ class PinnedEvents extends StatelessWidget { (event) => AdaptiveModalAction( value: event?.eventId ?? '', icon: const Icon(Icons.push_pin_outlined), - label: event?.calcLocalizedBodyFallback( + label: + event?.calcLocalizedBodyFallback( MatrixLocals(L10n.of(context)), withSenderNamePrefix: true, hideReply: true, @@ -68,7 +69,8 @@ class PinnedEvents extends StatelessWidget { builder: (context, snapshot) { final event = snapshot.data; return ChatAppBarListTile( - title: event?.calcLocalizedBodyFallback( + title: + event?.calcLocalizedBodyFallback( MatrixLocals(L10n.of(context)), withSenderNamePrefix: true, hideReply: true, @@ -86,12 +88,12 @@ class PinnedEvents extends StatelessWidget { // : null, tooltip: controller.room.canChangeStateEvent(EventTypes.RoomPinnedEvents) - ? L10n.of(context).unpin - : null, + ? L10n.of(context).unpin + : null, onPressed: controller.room.canChangeStateEvent(EventTypes.RoomPinnedEvents) - ? () => controller.unpinEvent(event!.eventId) - : null, + ? () => controller.unpinEvent(event!.eventId) + : null, // Pangea# ), onTap: () => _displayPinnedEventsDialog(context), diff --git a/lib/pages/chat/recording_input_row.dart b/lib/pages/chat/recording_input_row.dart index 2432db36d..2a88a7845 100644 --- a/lib/pages/chat/recording_input_row.dart +++ b/lib/pages/chat/recording_input_row.dart @@ -46,8 +46,8 @@ class RecordingInputRow extends StatelessWidget { builder: (context, constraints) { const width = 4; return Row( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.end, + mainAxisSize: .min, + mainAxisAlignment: .end, children: state.amplitudeTimeline.reversed .take((constraints.maxWidth / (width + 2)).floor()) .toList() diff --git a/lib/pages/chat/recording_view_model.dart b/lib/pages/chat/recording_view_model.dart index b61b8924f..f46274281 100644 --- a/lib/pages/chat/recording_view_model.dart +++ b/lib/pages/chat/recording_view_model.dart @@ -27,10 +27,7 @@ class EmptyAudioException implements Exception {} class RecordingViewModel extends StatefulWidget { final Widget Function(BuildContext, RecordingViewModelState) builder; - const RecordingViewModel({ - required this.builder, - super.key, - }); + const RecordingViewModel({required this.builder, super.key}); @override RecordingViewModelState createState() => RecordingViewModelState(); @@ -78,10 +75,10 @@ class RecordingViewModelState extends State { // ? AudioEncoder.wav // // Everywhere else we use opus if supported by the platform: // : !PlatformInfos - // .isIOS && // Blocked by https://github.com/llfbandit/record/issues/560 - // await audioRecorder.isEncoderSupported(AudioEncoder.opus) - // ? AudioEncoder.opus - // : AudioEncoder.aacLc; + // .isIOS && // Blocked by https://github.com/llfbandit/record/issues/560 + // await audioRecorder.isEncoderSupported(AudioEncoder.opus) + // ? AudioEncoder.opus + // : AudioEncoder.aacLc; const codec = AudioEncoder.wav; // Pangea# fileName = @@ -136,8 +133,9 @@ class RecordingViewModelState extends State { void _subscribe() { _recorderSubscription?.cancel(); - _recorderSubscription = - Timer.periodic(const Duration(milliseconds: 100), (_) async { + _recorderSubscription = Timer.periodic(const Duration(milliseconds: 100), ( + _, + ) async { final amplitude = await _audioRecorder!.getAmplitude(); var value = 100 + amplitude.current * 2; value = value < 1 ? 1 : value; @@ -188,7 +186,8 @@ class RecordingViewModelState extends State { int duration, List waveform, String? fileName, - ) onSend, + ) + onSend, ) async { _recorderSubscription?.cancel(); final path = await _audioRecorder?.stop(); diff --git a/lib/pages/chat/reply_display.dart b/lib/pages/chat/reply_display.dart index 8d2df4b2d..57ab64ba8 100644 --- a/lib/pages/chat/reply_display.dart +++ b/lib/pages/chat/reply_display.dart @@ -18,9 +18,11 @@ class ReplyDisplay extends StatelessWidget { // #Pangea return ListenableBuilder( - listenable: - Listenable.merge([controller.replyEvent, controller.editEvent]), - builder: (context, __) { + listenable: Listenable.merge([ + controller.replyEvent, + controller.editEvent, + ]), + builder: (context, _) { final editEvent = controller.editEvent.value; final replyEvent = controller.replyEvent.value; // Pangea# @@ -34,9 +36,7 @@ class ReplyDisplay extends StatelessWidget { ? 56 : 0, clipBehavior: Clip.hardEdge, - decoration: BoxDecoration( - color: theme.colorScheme.onInverseSurface, - ), + decoration: BoxDecoration(color: theme.colorScheme.onInverseSurface), child: Row( children: [ IconButton( @@ -85,10 +85,7 @@ class _EditContent extends StatelessWidget { } return Row( children: [ - Icon( - Icons.edit, - color: theme.colorScheme.primary, - ), + Icon(Icons.edit, color: theme.colorScheme.primary), Container(width: 15.0), // #Pangea // Text( @@ -99,9 +96,7 @@ class _EditContent extends StatelessWidget { // ), // overflow: TextOverflow.ellipsis, // maxLines: 1, - // style: TextStyle( - // color: theme.textTheme.bodyMedium!.color, - // ), + // style: TextStyle(color: theme.textTheme.bodyMedium!.color), // ), Flexible( child: Text( @@ -113,9 +108,7 @@ class _EditContent extends StatelessWidget { ), overflow: TextOverflow.ellipsis, maxLines: 1, - style: TextStyle( - color: theme.textTheme.bodyMedium!.color, - ), + style: TextStyle(color: theme.textTheme.bodyMedium!.color), ), ), // Pangea# diff --git a/lib/pages/chat/seen_by_row.dart b/lib/pages/chat/seen_by_row.dart index 52d9f0eb4..3b830b1d6 100644 --- a/lib/pages/chat/seen_by_row.dart +++ b/lib/pages/chat/seen_by_row.dart @@ -20,14 +20,16 @@ class SeenByRow extends StatelessWidget { width: double.infinity, alignment: Alignment.center, child: AnimatedContainer( - constraints: - const BoxConstraints(maxWidth: FluffyThemes.maxTimelineWidth), + constraints: const BoxConstraints( + maxWidth: FluffyThemes.maxTimelineWidth, + ), height: seenByUsers.isEmpty ? 0 : 24, duration: seenByUsers.isEmpty ? Duration.zero : FluffyThemes.animationDuration, curve: FluffyThemes.animationCurve, - alignment: controller.timeline!.events.isNotEmpty && + alignment: + controller.timeline!.events.isNotEmpty && controller.timeline!.events.first.senderId == Matrix.of(context).client.userID ? Alignment.topRight @@ -40,15 +42,15 @@ class SeenByRow extends StatelessWidget { ? seenByUsers.sublist(0, maxAvatars) : seenByUsers) .map( - (user) => Avatar( - mxContent: user.avatarUrl, - name: user.calcDisplayname(), - // #Pangea - userId: user.id, - // Pangea# - size: 16, - ), - ), + (user) => Avatar( + mxContent: user.avatarUrl, + name: user.calcDisplayname(), + size: 16, + // #Pangea + userId: user.id, + // Pangea# + ), + ), if (seenByUsers.length > maxAvatars) SizedBox( width: 16, diff --git a/lib/pages/chat/send_file_dialog.dart b/lib/pages/chat/send_file_dialog.dart index deab14889..57f124b2c 100644 --- a/lib/pages/chat/send_file_dialog.dart +++ b/lib/pages/chat/send_file_dialog.dart @@ -119,8 +119,9 @@ class SendFileDialogState extends State { if (e.error != MatrixError.M_LIMIT_EXCEEDED || retryAfterMs == null) { rethrow; } - final retryAfterDuration = - Duration(milliseconds: retryAfterMs + 1000); + final retryAfterDuration = Duration( + milliseconds: retryAfterMs + 1000, + ); scaffoldMessenger.showSnackBar( SnackBar( @@ -164,8 +165,9 @@ class SendFileDialogState extends State { } Future _calcCombinedFileSize() async { - final lengths = - await Future.wait(widget.files.map((file) => file.length())); + final lengths = await Future.wait( + widget.files.map((file) => file.length()), + ); return lengths.fold(0, (p, length) => p + length).sizeString; } @@ -216,7 +218,7 @@ class SendFileDialogState extends State { width: 256, child: SingleChildScrollView( child: Column( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ const SizedBox(height: 12), if (uniqueFileType == 'image') @@ -243,8 +245,8 @@ class SendFileDialogState extends State { final bytes = snapshot.data; if (bytes == null) { return const Center( - child: CircularProgressIndicator - .adaptive(), + child: + CircularProgressIndicator.adaptive(), ); } if (snapshot.error != null) { @@ -272,8 +274,11 @@ class SendFileDialogState extends State { : null, fit: BoxFit.contain, errorBuilder: (context, e, s) { - Logs() - .w('Unable to preview image', e, s); + Logs().w( + 'Unable to preview image', + e, + s, + ); return const Center( child: SizedBox( width: 256, @@ -303,17 +308,17 @@ class SendFileDialogState extends State { uniqueFileType == null ? Icons.description_outlined : uniqueFileType == 'video' - ? Icons.video_file_outlined - : uniqueFileType == 'audio' - ? Icons.audio_file_outlined - : Icons.description_outlined, + ? Icons.video_file_outlined + : uniqueFileType == 'audio' + ? Icons.audio_file_outlined + : Icons.description_outlined, size: 32, ), const SizedBox(width: 8), Expanded( child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: .min, + crossAxisAlignment: .start, children: [ Text( fileName, @@ -347,10 +352,12 @@ class SendFileDialogState extends State { // Workaround for SwitchListTile.adaptive crashes in CupertinoDialog if ({'image', 'video'}.contains(uniqueFileType)) Row( - crossAxisAlignment: CrossAxisAlignment.center, + crossAxisAlignment: .center, children: [ - if ({TargetPlatform.iOS, TargetPlatform.macOS} - .contains(theme.platform)) + if ({ + TargetPlatform.iOS, + TargetPlatform.macOS, + }.contains(theme.platform)) CupertinoSwitch( value: compressionSupported && compress, onChanged: compressionSupported @@ -367,11 +374,11 @@ class SendFileDialogState extends State { const SizedBox(width: 16), Expanded( child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: .min, + crossAxisAlignment: .start, children: [ Row( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ Text( L10n.of(context).compress, @@ -430,9 +437,7 @@ extension on ScaffoldMessengerState { const SizedBox( width: 16, height: 16, - child: CircularProgressIndicator.adaptive( - strokeWidth: 2, - ), + child: CircularProgressIndicator.adaptive(strokeWidth: 2), ), const SizedBox(width: 16), Text(title), diff --git a/lib/pages/chat/send_location_dialog.dart b/lib/pages/chat/send_location_dialog.dart index 865b909e6..8efc2cb60 100644 --- a/lib/pages/chat/send_location_dialog.dart +++ b/lib/pages/chat/send_location_dialog.dart @@ -14,10 +14,7 @@ import 'package:fluffychat/widgets/future_loading_dialog.dart'; class SendLocationDialog extends StatefulWidget { final Room room; - const SendLocationDialog({ - required this.room, - super.key, - }); + const SendLocationDialog({required this.room, super.key}); @override SendLocationDialogState createState() => SendLocationDialogState(); @@ -102,12 +99,13 @@ class SendLocationDialogState extends State { } else if (denied) { contentWidget = Text(L10n.of(context).locationPermissionDeniedNotice); } else if (error != null) { - contentWidget = - Text(L10n.of(context).errorObtainingLocation(error.toString())); + contentWidget = Text( + L10n.of(context).errorObtainingLocation(error.toString()), + ); } else { contentWidget = Row( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: .min, + mainAxisAlignment: .center, children: [ const CupertinoActivityIndicator(), const SizedBox(width: 12), diff --git a/lib/pages/chat/start_poll_bottom_sheet.dart b/lib/pages/chat/start_poll_bottom_sheet.dart index 5962cd2ed..b90dc473b 100644 --- a/lib/pages/chat/start_poll_bottom_sheet.dart +++ b/lib/pages/chat/start_poll_bottom_sheet.dart @@ -50,14 +50,15 @@ class _StartPollBottomSheetState extends State { } catch (e, s) { Logs().w('Unable to create poll', e, s); if (!mounted) return; - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text(e.toLocalizedString(context))), - ); + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text(e.toLocalizedString(context)))); } } void _updateCanCreate([dynamic _]) { - final newCanCreate = _bodyController.text.trim().isNotEmpty && + final newCanCreate = + _bodyController.text.trim().isNotEmpty && !_answers.any((controller) => controller.text.trim().isEmpty); if (_canCreate != newCanCreate) { setState(() { @@ -71,9 +72,7 @@ class _StartPollBottomSheetState extends State { const maxAnswers = 10; return Scaffold( appBar: AppBar( - leading: CloseButton( - onPressed: Navigator.of(context).pop, - ), + leading: CloseButton(onPressed: Navigator.of(context).pop), title: Text(L10n.of(context).startPoll), ), body: ListView( @@ -119,8 +118,8 @@ class _StartPollBottomSheetState extends State { icon: const Icon(Icons.add_outlined), onPressed: _answers.length < maxAnswers ? () => setState(() { - _answers.add(TextEditingController()); - }) + _answers.add(TextEditingController()); + }) : null, label: Text(L10n.of(context).addAnswerOption), ), diff --git a/lib/pages/chat/sticker_picker_dialog.dart b/lib/pages/chat/sticker_picker_dialog.dart index 4ad721d7a..1e287651f 100644 --- a/lib/pages/chat/sticker_picker_dialog.dart +++ b/lib/pages/chat/sticker_picker_dialog.dart @@ -37,15 +37,17 @@ class StickerPickerDialogState extends State { final filteredImagePackImageEntried = pack.images.entries.toList(); if (searchFilter?.isNotEmpty ?? false) { filteredImagePackImageEntried.removeWhere( - (e) => !(e.key.toLowerCase().contains(searchFilter!.toLowerCase()) || - (e.value.body - ?.toLowerCase() - .contains(searchFilter!.toLowerCase()) ?? - false)), + (e) => + !(e.key.toLowerCase().contains(searchFilter!.toLowerCase()) || + (e.value.body?.toLowerCase().contains( + searchFilter!.toLowerCase(), + ) ?? + false)), ); } - final imageKeys = - filteredImagePackImageEntried.map((e) => e.key).toList(); + final imageKeys = filteredImagePackImageEntried + .map((e) => e.key) + .toList(); if (imageKeys.isEmpty) { return const SizedBox.shrink(); } @@ -81,8 +83,9 @@ class StickerPickerDialogState extends State { key: ValueKey(image.url.toString()), onTap: () { // copy the image - final imageCopy = - ImagePackImageContent.fromJson(image.toJson().copy()); + final imageCopy = ImagePackImageContent.fromJson( + image.toJson().copy(), + ); // set the body, if it doesn't exist, to the key imageCopy.body ??= imageKeys[imageIndex]; widget.onSelected(imageCopy); @@ -136,7 +139,7 @@ class StickerPickerDialogState extends State { SliverFillRemaining( child: Center( child: Column( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ Text(L10n.of(context).noEmotesFound), // #Pangea diff --git a/lib/pages/chat/typing_indicators.dart b/lib/pages/chat/typing_indicators.dart index 640734084..efcdba3b6 100644 --- a/lib/pages/chat/typing_indicators.dart +++ b/lib/pages/chat/typing_indicators.dart @@ -21,8 +21,9 @@ class TypingIndicators extends StatelessWidget { return StreamBuilder( stream: controller.room.client.onSync.stream.where( (syncUpdate) => - syncUpdate.rooms?.join?[controller.room.id]?.ephemeral - ?.any((ephemeral) => ephemeral.type == 'm.typing') ?? + syncUpdate.rooms?.join?[controller.room.id]?.ephemeral?.any( + (ephemeral) => ephemeral.type == 'm.typing', + ) ?? false, ), builder: (context, _) { @@ -33,22 +34,21 @@ class TypingIndicators extends StatelessWidget { width: double.infinity, alignment: Alignment.center, child: AnimatedContainer( - constraints: - const BoxConstraints(maxWidth: FluffyThemes.maxTimelineWidth), + constraints: const BoxConstraints( + maxWidth: FluffyThemes.maxTimelineWidth, + ), height: typingUsers.isEmpty ? 0 : avatarSize + 8, duration: FluffyThemes.animationDuration, curve: FluffyThemes.animationCurve, - alignment: controller.timeline!.events.isNotEmpty && + alignment: + controller.timeline!.events.isNotEmpty && controller.timeline!.events.first.senderId == Matrix.of(context).client.userID ? Alignment.topRight : Alignment.topLeft, clipBehavior: Clip.hardEdge, decoration: const BoxDecoration(), - padding: const EdgeInsets.symmetric( - horizontal: 8.0, - vertical: 4.0, - ), + padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4.0), child: Row( children: [ Container( @@ -123,17 +123,14 @@ class __TypingDotsState extends State<_TypingDots> { @override void initState() { - _timer = Timer.periodic( - animationDuration, - (_) { - if (!mounted) { - return; - } - setState(() { - _tick = (_tick + 1) % 4; - }); - }, - ); + _timer = Timer.periodic(animationDuration, (_) { + if (!mounted) { + return; + } + setState(() { + _tick = (_tick + 1) % 4; + }); + }); super.initState(); } @@ -149,7 +146,7 @@ class __TypingDotsState extends State<_TypingDots> { const size = 8.0; return Row( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ for (var i = 1; i <= 3; i++) AnimatedContainer( diff --git a/lib/pages/chat_access_settings/chat_access_settings_controller.dart b/lib/pages/chat_access_settings/chat_access_settings_controller.dart index 163bbf13c..8b84b8397 100644 --- a/lib/pages/chat_access_settings/chat_access_settings_controller.dart +++ b/lib/pages/chat_access_settings/chat_access_settings_controller.dart @@ -28,15 +28,15 @@ class ChatAccessSettingsController extends State { bool guestAccessLoading = false; Room get room => Matrix.of(context).client.getRoomById(widget.roomId)!; Set get knownSpaceParents => { - ...room.client.rooms.where( - (space) => - space.isSpace && - space.spaceChildren.any((child) => child.roomId == room.id), - ), - ...room.spaceParents - .map((parent) => room.client.getRoomById(parent.roomId ?? '')) - .whereType(), - }; + ...room.client.rooms.where( + (space) => + space.isSpace && + space.spaceChildren.any((child) => child.roomId == room.id), + ), + ...room.spaceParents + .map((parent) => room.client.getRoomById(parent.roomId ?? '')) + .whereType(), + }; String get roomVersion => room @@ -92,8 +92,11 @@ class ChatAccessSettingsController extends State { // #Pangea // await room.setJoinRules( // newJoinRules, - // allowConditionRoomIds: {JoinRules.restricted, JoinRules.knockRestricted} - // .contains(newJoinRules) + // allowConditionRoomIds: + // { + // JoinRules.restricted, + // JoinRules.knockRestricted, + // }.contains(newJoinRules) // ? knownSpaceParents.map((parent) => parent.id).toList() // : null, // ); @@ -104,13 +107,9 @@ class ChatAccessSettingsController extends State { } catch (e, s) { Logs().w('Unable to change join rules', e, s); if (mounted) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text( - e.toLocalizedString(context), - ), - ), - ); + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text(e.toLocalizedString(context)))); } } finally { if (mounted) { @@ -132,13 +131,9 @@ class ChatAccessSettingsController extends State { } catch (e, s) { Logs().w('Unable to change history visibility', e, s); if (mounted) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text( - e.toLocalizedString(context), - ), - ), - ); + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text(e.toLocalizedString(context)))); } } finally { if (mounted) { @@ -160,13 +155,9 @@ class ChatAccessSettingsController extends State { } catch (e, s) { Logs().w('Unable to change guest access', e, s); if (mounted) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text( - e.toLocalizedString(context), - ), - ), - ); + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text(e.toLocalizedString(context)))); } } finally { if (mounted) { @@ -225,8 +216,11 @@ class ChatAccessSettingsController extends State { newRoom = room.client.getRoomById(newRoomId); } - if ({JoinRules.invite, JoinRules.knock, JoinRules.knockRestricted} - .contains(room.joinRules)) { + if ({ + JoinRules.invite, + JoinRules.knock, + JoinRules.knockRestricted, + }.contains(room.joinRules)) { final users = await room.requestParticipants([ Membership.join, Membership.invite, @@ -291,7 +285,8 @@ class ChatAccessSettingsController extends State { cancelLabel: L10n.of(context).no, ); - final altAliases = room + final altAliases = + room .getState(EventTypes.RoomCanonicalAlias) ?.content .tryGetList('alt_aliases') @@ -307,17 +302,13 @@ class ChatAccessSettingsController extends State { await showFutureLoadingDialog( context: context, - future: () => room.client.setRoomStateWithKey( - room.id, - EventTypes.RoomCanonicalAlias, - '', - { - 'alias': canonicalAliasConsent == OkCancelResult.ok - ? alias - : room.canonicalAlias, - if (altAliases.isNotEmpty) 'alt_aliases': altAliases.toList(), - }, - ), + future: () => room.client + .setRoomStateWithKey(room.id, EventTypes.RoomCanonicalAlias, '', { + 'alias': canonicalAliasConsent == OkCancelResult.ok + ? alias + : room.canonicalAlias, + if (altAliases.isNotEmpty) 'alt_aliases': altAliases.toList(), + }), ); } @@ -344,13 +335,9 @@ class ChatAccessSettingsController extends State { } catch (e, s) { Logs().w('Unable to change visibility', e, s); if (mounted) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text( - e.toLocalizedString(context), - ), - ), - ); + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text(e.toLocalizedString(context)))); } } finally { if (mounted) { diff --git a/lib/pages/chat_access_settings/chat_access_settings_page.dart b/lib/pages/chat_access_settings/chat_access_settings_page.dart index 616d13934..a2f040799 100644 --- a/lib/pages/chat_access_settings/chat_access_settings_page.dart +++ b/lib/pages/chat_access_settings/chat_access_settings_page.dart @@ -24,17 +24,19 @@ class ChatAccessSettingsPageView extends StatelessWidget { ), body: MaxWidthBody( child: StreamBuilder( - stream: room.client.onRoomState.stream - .where((update) => update.roomId == controller.room.id), + stream: room.client.onRoomState.stream.where( + (update) => update.roomId == controller.room.id, + ), builder: (context, snapshot) { final canonicalAlias = room.canonicalAlias; - final altAliases = room + final altAliases = + room .getState(EventTypes.RoomCanonicalAlias) ?.content .tryGetList('alt_aliases') ?? []; return Column( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ ListTile( title: Text( @@ -47,12 +49,13 @@ class ChatAccessSettingsPageView extends StatelessWidget { ), RadioGroup( groupValue: room.historyVisibility, - onChanged: controller.historyVisibilityLoading || + onChanged: + controller.historyVisibilityLoading || !room.canChangeHistoryVisibility ? (_) {} : controller.setHistoryVisibility, child: Column( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ for (final historyVisibility in HistoryVisibility.values) RadioListTile.adaptive( @@ -80,12 +83,13 @@ class ChatAccessSettingsPageView extends StatelessWidget { groupValue: room.joinRules, onChanged: controller.setJoinRule, child: Column( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ for (final joinRule in controller.availableJoinRules) if (joinRule != JoinRules.private) RadioListTile.adaptive( - enabled: !controller.joinRulesLoading && + enabled: + !controller.joinRulesLoading && room.canChangeJoinRules, title: Text( joinRule.localizedString( @@ -99,8 +103,10 @@ class ChatAccessSettingsPageView extends StatelessWidget { ), ), Divider(color: theme.dividerColor), - if ({JoinRules.public, JoinRules.knock} - .contains(room.joinRules)) ...[ + if ({ + JoinRules.public, + JoinRules.knock, + }.contains(room.joinRules)) ...[ ListTile( title: Text( L10n.of(context).areGuestsAllowedToJoin, @@ -114,11 +120,12 @@ class ChatAccessSettingsPageView extends StatelessWidget { groupValue: room.guestAccess, onChanged: controller.setGuestAccess, child: Column( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ for (final guestAccess in GuestAccess.values) RadioListTile.adaptive( - enabled: !controller.guestAccessLoading && + enabled: + !controller.guestAccessLoading && room.canChangeGuestAccess, title: Text( guestAccess.getLocalizedString( @@ -148,9 +155,10 @@ class ChatAccessSettingsPageView extends StatelessWidget { if (canonicalAlias.isNotEmpty) _AliasListTile( alias: canonicalAlias, - onDelete: room.canChangeStateEvent( - EventTypes.RoomCanonicalAlias, - ) + onDelete: + room.canChangeStateEvent( + EventTypes.RoomCanonicalAlias, + ) ? () => controller.deleteAlias(canonicalAlias) : null, isCanonicalAlias: true, @@ -158,9 +166,10 @@ class ChatAccessSettingsPageView extends StatelessWidget { for (final alias in altAliases) _AliasListTile( alias: alias, - onDelete: room.canChangeStateEvent( - EventTypes.RoomCanonicalAlias, - ) + onDelete: + room.canChangeStateEvent( + EventTypes.RoomCanonicalAlias, + ) ? () => controller.deleteAlias(alias) : null, ), @@ -172,10 +181,11 @@ class ChatAccessSettingsPageView extends StatelessWidget { return const SizedBox.shrink(); } localAddresses.remove(room.canonicalAlias); - localAddresses - .removeWhere((alias) => altAliases.contains(alias)); + localAddresses.removeWhere( + (alias) => altAliases.contains(alias), + ); return Column( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: localAddresses .map( (alias) => _AliasListTile( @@ -257,10 +267,7 @@ class _AliasListTile extends StatelessWidget { ? const Icon(Icons.star) : const Icon(Icons.link_outlined), title: InkWell( - onTap: () => FluffyShare.share( - 'https://matrix.to/#/$alias', - context, - ), + onTap: () => FluffyShare.share('https://matrix.to/#/$alias', context), child: SelectableText( alias, style: TextStyle( diff --git a/lib/pages/chat_details/chat_details.dart b/lib/pages/chat_details/chat_details.dart index 1c8aec15c..9728fdcf4 100644 --- a/lib/pages/chat_details/chat_details.dart +++ b/lib/pages/chat_details/chat_details.dart @@ -66,12 +66,15 @@ class ChatDetailsController extends State _loadSummaries(); _languageSubscription = MatrixState - .pangeaController.userController.languageStream.stream + .pangeaController + .userController + .languageStream + .stream .listen((update) { - if (update.prevBaseLang != update.baseLang) { - _loadCourseInfo(); - } - }); + if (update.prevBaseLang != update.baseLang) { + _loadCourseInfo(); + } + }); } @override @@ -115,11 +118,7 @@ class ChatDetailsController extends State // Pangea# okLabel: L10n.of(context).ok, cancelLabel: L10n.of(context).cancel, - initialText: room.getLocalizedDisplayname( - MatrixLocals( - L10n.of(context), - ), - ), + initialText: room.getLocalizedDisplayname(MatrixLocals(L10n.of(context))), ); if (input == null) return; final success = await showFutureLoadingDialog( @@ -153,13 +152,11 @@ class ChatDetailsController extends State ); // final success = await showFutureLoadingDialog( // context: context, - // future: () => room.setDescription(input.single), + // future: () => room.setDescription(input), // ); // if (success.error == null) { // ScaffoldMessenger.of(context).showSnackBar( - // SnackBar( - // content: Text(L10n.of(context).chatDescriptionHasBeenChanged), - // ), + // SnackBar(content: Text(L10n.of(context).chatDescriptionHasBeenChanged)), // ); // } // Pangea# @@ -213,10 +210,7 @@ class ChatDetailsController extends State imageQuality: 50, ); if (result == null) return; - file = MatrixFile( - bytes: await result.readAsBytes(), - name: result.path, - ); + file = MatrixFile(bytes: await result.readAsBytes(), name: result.path); } else { final picked = await selectFiles( context, @@ -258,8 +252,9 @@ class ChatDetailsController extends State return L10n.of(context).enterNumber; } if (int.parse(value) < (room.summary.mJoinedMemberCount ?? 1)) { - return L10n.of(context) - .chatCapacitySetTooLow(room.summary.mJoinedMemberCount ?? 1); + return L10n.of( + context, + ).chatCapacitySetTooLow(room.summary.mJoinedMemberCount ?? 1); } return null; }, @@ -275,9 +270,7 @@ class ChatDetailsController extends State ); if (success.error == null) { ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(L10n.of(context).chatCapacityHasBeenChanged), - ), + SnackBar(content: Text(L10n.of(context).chatCapacityHasBeenChanged)), ); setState(() {}); } @@ -309,26 +302,21 @@ class ChatDetailsController extends State context: context, future: () async { final newRoomId = await Matrix.of(context).client.createGroupChat( - visibility: sdk.Visibility.private, - groupName: names, - initialState: [ - RoomDefaults.defaultPowerLevels( - Matrix.of(context).client.userID!, - ), - await Matrix.of(context).client.pangeaJoinRules( - 'knock_restricted', - allow: roomId != null - ? [ - { - "type": "m.room_membership", - "room_id": roomId, - } - ] - : null, - ), - ], - enableEncryption: false, - ); + visibility: sdk.Visibility.private, + groupName: names, + initialState: [ + RoomDefaults.defaultPowerLevels(Matrix.of(context).client.userID!), + await Matrix.of(context).client.pangeaJoinRules( + 'knock_restricted', + allow: roomId != null + ? [ + {"type": "m.room_membership", "room_id": roomId}, + ] + : null, + ), + ], + enableEncryption: false, + ); final client = Matrix.of(context).client; Room? room = client.getRoomById(newRoomId); if (room == null) { diff --git a/lib/pages/chat_details/chat_details_view.dart b/lib/pages/chat_details/chat_details_view.dart index ff72227b0..ec9bbc210 100644 --- a/lib/pages/chat_details/chat_details_view.dart +++ b/lib/pages/chat_details/chat_details_view.dart @@ -29,9 +29,7 @@ class ChatDetailsView extends StatelessWidget { final room = Matrix.of(context).client.getRoomById(controller.roomId!); if (room == null) { return Scaffold( - appBar: AppBar( - title: Text(L10n.of(context).oopsSomethingWentWrong), - ), + appBar: AppBar(title: Text(L10n.of(context).oopsSomethingWentWrong)), body: Center( child: Text(L10n.of(context).youAreNoLongerParticipatingInThisChat), ), @@ -42,13 +40,15 @@ class ChatDetailsView extends StatelessWidget { final roomAvatar = room.avatar; return StreamBuilder( - stream: room.client.onRoomState.stream - .where((update) => update.roomId == room.id), + stream: room.client.onRoomState.stream.where( + (update) => update.roomId == room.id, + ), builder: (context, snapshot) { var members = room.getParticipants().toList() ..sort((b, a) => a.powerLevel.compareTo(b.powerLevel)); members = members.take(10).toList(); - final actualMembersCount = (room.summary.mInvitedMemberCount ?? 0) + + final actualMembersCount = + (room.summary.mInvitedMemberCount ?? 0) + (room.summary.mJoinedMemberCount ?? 0); final canRequestMoreMembers = members.length < actualMembersCount; final iconColor = theme.textTheme.bodyLarge!.color; @@ -57,7 +57,8 @@ class ChatDetailsView extends StatelessWidget { ); return Scaffold( appBar: AppBar( - leading: controller.widget.embeddedCloseButton ?? + leading: + controller.widget.embeddedCloseButton ?? const Center(child: BackButton()), elevation: theme.appBarTheme.elevation, actions: [ @@ -65,19 +66,15 @@ class ChatDetailsView extends StatelessWidget { IconButton( tooltip: L10n.of(context).share, icon: const Icon(Icons.qr_code_rounded), - onPressed: () => showQrCodeViewer( - context, - room.canonicalAlias, - ), + onPressed: () => + showQrCodeViewer(context, room.canonicalAlias), ) else if (directChatMatrixID != null) IconButton( tooltip: L10n.of(context).share, icon: const Icon(Icons.qr_code_rounded), - onPressed: () => showQrCodeViewer( - context, - directChatMatrixID, - ), + onPressed: () => + showQrCodeViewer(context, directChatMatrixID), ), if (controller.widget.embeddedCloseButton == null) ChatSettingsPopupMenu(room, false), @@ -92,7 +89,7 @@ class ChatDetailsView extends StatelessWidget { itemCount: members.length + 1 + (canRequestMoreMembers ? 1 : 0), itemBuilder: (BuildContext context, int i) => i == 0 ? Column( - crossAxisAlignment: CrossAxisAlignment.stretch, + crossAxisAlignment: .stretch, children: [ Row( children: [ @@ -103,9 +100,9 @@ class ChatDetailsView extends StatelessWidget { Hero( tag: controller.widget.embeddedCloseButton != - null - ? 'embedded_content_banner' - : 'content_banner', + null + ? 'embedded_content_banner' + : 'content_banner', child: Avatar( mxContent: room.avatar, name: displayname, @@ -115,10 +112,10 @@ class ChatDetailsView extends StatelessWidget { size: Avatar.defaultSize * 2.5, onTap: roomAvatar != null ? () => showDialog( - context: context, - builder: (_) => - MxcImageViewer(roomAvatar), - ) + context: context, + builder: (_) => + MxcImageViewer(roomAvatar), + ) : null, ), ), @@ -142,8 +139,8 @@ class ChatDetailsView extends StatelessWidget { ), Expanded( child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: .center, + crossAxisAlignment: .start, children: [ TextButton.icon( onPressed: () => room.isDirectChat @@ -151,20 +148,20 @@ class ChatDetailsView extends StatelessWidget { : room.canChangeStateEvent( EventTypes.RoomName, ) - ? controller.setDisplaynameAction() - : FluffyShare.share( - displayname, - context, - copyOnly: true, - ), + ? controller.setDisplaynameAction() + : FluffyShare.share( + displayname, + context, + copyOnly: true, + ), icon: Icon( room.isDirectChat ? Icons.chat_bubble_outline : room.canChangeStateEvent( EventTypes.RoomName, ) - ? Icons.edit_outlined - : Icons.copy_outlined, + ? Icons.edit_outlined + : Icons.copy_outlined, size: 16, ), style: TextButton.styleFrom( @@ -197,9 +194,9 @@ class ChatDetailsView extends StatelessWidget { iconColor: theme.colorScheme.secondary, ), label: Text( - L10n.of(context).countParticipants( - actualMembersCount, - ), + L10n.of( + context, + ).countParticipants(actualMembersCount), maxLines: 1, overflow: TextOverflow.ellipsis, // style: const TextStyle(fontSize: 12), @@ -223,13 +220,14 @@ class ChatDetailsView extends StatelessWidget { ), trailing: room.canChangeStateEvent(EventTypes.RoomTopic) - ? IconButton( - onPressed: controller.setTopicAction, - tooltip: - L10n.of(context).setChatDescription, - icon: const Icon(Icons.edit_outlined), - ) - : null, + ? IconButton( + onPressed: controller.setTopicAction, + tooltip: L10n.of( + context, + ).setChatDescription, + icon: const Icon(Icons.edit_outlined), + ) + : null, ), Padding( padding: const EdgeInsets.symmetric( @@ -239,8 +237,9 @@ class ChatDetailsView extends StatelessWidget { text: room.topic.isEmpty ? L10n.of(context).noChatDescriptionYet : room.topic, - textScaleFactor: - MediaQuery.textScalerOf(context).scale(1), + textScaleFactor: MediaQuery.textScalerOf( + context, + ).scale(1), options: const LinkifyOptions(humanize: false), linkStyle: const TextStyle( color: Colors.blueAccent, @@ -272,14 +271,13 @@ class ChatDetailsView extends StatelessWidget { Icons.admin_panel_settings_outlined, ), ), - title: Text( - L10n.of(context).accessAndVisibility, - ), + title: Text(L10n.of(context).accessAndVisibility), subtitle: Text( L10n.of(context).accessAndVisibilityDescription, ), - onTap: () => context - .push('/rooms/${room.id}/details/access'), + onTap: () => context.push( + '/rooms/${room.id}/details/access', + ), trailing: const Icon(Icons.chevron_right_outlined), ), ListTile( @@ -291,21 +289,20 @@ class ChatDetailsView extends StatelessWidget { backgroundColor: theme.colorScheme.surfaceContainer, foregroundColor: iconColor, - child: const Icon( - Icons.tune_outlined, - ), + child: const Icon(Icons.tune_outlined), ), trailing: const Icon(Icons.chevron_right_outlined), - onTap: () => context - .push('/rooms/${room.id}/details/permissions'), + onTap: () => context.push( + '/rooms/${room.id}/details/permissions', + ), ), ], Divider(color: theme.dividerColor), ListTile( title: Text( - L10n.of(context).countParticipants( - actualMembersCount, - ), + L10n.of( + context, + ).countParticipants(actualMembersCount), style: TextStyle( color: theme.colorScheme.secondary, fontWeight: FontWeight.bold, @@ -329,25 +326,25 @@ class ChatDetailsView extends StatelessWidget { ], ) : i < members.length + 1 - ? ParticipantListItem(members[i - 1]) - : ListTile( - title: Text( - L10n.of(context).loadCountMoreParticipants( - (actualMembersCount - members.length), - ), - ), - leading: CircleAvatar( - backgroundColor: theme.scaffoldBackgroundColor, - child: const Icon( - Icons.group_outlined, - color: Colors.grey, - ), - ), - onTap: () => context.push( - '/rooms/${controller.roomId!}/details/members', - ), - trailing: const Icon(Icons.chevron_right_outlined), + ? ParticipantListItem(members[i - 1]) + : ListTile( + title: Text( + L10n.of(context).loadCountMoreParticipants( + (actualMembersCount - members.length), ), + ), + leading: CircleAvatar( + backgroundColor: theme.scaffoldBackgroundColor, + child: const Icon( + Icons.group_outlined, + color: Colors.grey, + ), + ), + onTap: () => context.push( + '/rooms/${controller.roomId!}/details/members', + ), + trailing: const Icon(Icons.chevron_right_outlined), + ), ), ), ); diff --git a/lib/pages/chat_details/chat_download_provider.dart b/lib/pages/chat_details/chat_download_provider.dart index ce1d9be0a..bda0d1647 100644 --- a/lib/pages/chat_details/chat_download_provider.dart +++ b/lib/pages/chat_details/chat_download_provider.dart @@ -37,11 +37,7 @@ mixin ChatDownloadProvider { await room.download(type, context); } on EmptyChatException { ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text( - L10n.of(context).emptyChatDownloadWarning, - ), - ), + SnackBar(content: Text(L10n.of(context).emptyChatDownloadWarning)), ); } catch (e) { ScaffoldMessenger.of(context).showSnackBar( diff --git a/lib/pages/chat_details/participant_list_item.dart b/lib/pages/chat_details/participant_list_item.dart index bfc5f1914..71100f202 100644 --- a/lib/pages/chat_details/participant_list_item.dart +++ b/lib/pages/chat_details/participant_list_item.dart @@ -28,8 +28,8 @@ class ParticipantListItem extends StatelessWidget { final permissionBatch = user.powerLevel >= 100 ? L10n.of(context).admin : user.powerLevel >= 50 - ? L10n.of(context).moderator - : ''; + ? L10n.of(context).moderator + : ''; return ListTile( onTap: () => showMemberActionsPopupMenu(context: context, user: user), @@ -43,17 +43,12 @@ class ParticipantListItem extends StatelessWidget { ), if (permissionBatch.isNotEmpty) Container( - padding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 6, - ), + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), decoration: BoxDecoration( color: user.powerLevel >= 100 ? theme.colorScheme.tertiary : theme.colorScheme.tertiaryContainer, - borderRadius: BorderRadius.circular( - AppConfig.borderRadius, - ), + borderRadius: BorderRadius.circular(AppConfig.borderRadius), ), child: Text( permissionBatch, @@ -67,8 +62,10 @@ class ParticipantListItem extends StatelessWidget { membershipBatch == null ? const SizedBox.shrink() : Container( - padding: - const EdgeInsets.symmetric(vertical: 4, horizontal: 8), + padding: const EdgeInsets.symmetric( + vertical: 4, + horizontal: 8, + ), margin: const EdgeInsets.symmetric(horizontal: 8), decoration: BoxDecoration( color: theme.colorScheme.secondaryContainer, @@ -87,10 +84,7 @@ class ParticipantListItem extends StatelessWidget { ), // #Pangea subtitle: LevelDisplayName(userId: user.id), - // subtitle: Text( - // user.id, - // maxLines: 1, - // overflow: TextOverflow.ellipsis, + // subtitle: Text(user.id, maxLines: 1, overflow: TextOverflow.ellipsis), // Pangea# leading: Opacity( opacity: user.membership == Membership.join ? 1 : 0.5, diff --git a/lib/pages/chat_encryption_settings/chat_encryption_settings_view.dart b/lib/pages/chat_encryption_settings/chat_encryption_settings_view.dart index 754178c25..d185852be 100644 --- a/lib/pages/chat_encryption_settings/chat_encryption_settings_view.dart +++ b/lib/pages/chat_encryption_settings/chat_encryption_settings_view.dart @@ -42,7 +42,7 @@ class ChatEncryptionSettingsView extends StatelessWidget { ), body: MaxWidthBody( child: Column( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ SwitchListTile( secondary: CircleAvatar( @@ -76,16 +76,14 @@ class ChatEncryptionSettingsView extends StatelessWidget { ListTile( title: Text( L10n.of(context).deviceKeys, - style: const TextStyle( - fontWeight: FontWeight.bold, - ), + style: const TextStyle(fontWeight: FontWeight.bold), ), ), StreamBuilder( - stream: room.client.onRoomState.stream - .where((update) => update.roomId == controller.room.id), - builder: (context, snapshot) => - FutureBuilder>( + stream: room.client.onRoomState.stream.where( + (update) => update.roomId == controller.room.id, + ), + builder: (context, snapshot) => FutureBuilder>( future: room.getUserDeviceKeys(), builder: (BuildContext context, snapshot) { if (snapshot.hasError) { @@ -108,20 +106,21 @@ class ChatEncryptionSettingsView extends StatelessWidget { physics: const NeverScrollableScrollPhysics(), itemCount: deviceKeys.length, itemBuilder: (BuildContext context, int i) => Column( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ if (i == 0 || deviceKeys[i].userId != deviceKeys[i - 1].userId) ...[ const Divider(), FutureBuilder( - future: room.client - .getUserProfile(deviceKeys[i].userId), + future: room.client.getUserProfile( + deviceKeys[i].userId, + ), builder: (context, snapshot) { final displayname = snapshot.data?.displayname ?? - deviceKeys[i].userId.localpart ?? - deviceKeys[i].userId; + deviceKeys[i].userId.localpart ?? + deviceKeys[i].userId; return ListTile( leading: Avatar( name: displayname, @@ -146,14 +145,14 @@ class ChatEncryptionSettingsView extends StatelessWidget { deviceKeys[i].verified ? L10n.of(context).verified : deviceKeys[i].blocked - ? L10n.of(context).blocked - : L10n.of(context).unverified, + ? L10n.of(context).blocked + : L10n.of(context).unverified, style: TextStyle( color: deviceKeys[i].verified ? Colors.green : deviceKeys[i].blocked - ? Colors.red - : Colors.orange, + ? Colors.red + : Colors.orange, ), ), const Text(' | ID: '), @@ -185,9 +184,7 @@ class ChatEncryptionSettingsView extends StatelessWidget { child: Center( child: Text( L10n.of(context).encryptionNotEnabled, - style: const TextStyle( - fontStyle: FontStyle.italic, - ), + style: const TextStyle(fontStyle: FontStyle.italic), ), ), ), diff --git a/lib/pages/chat_list/chat_list.dart b/lib/pages/chat_list/chat_list.dart index 6ab641a34..7daeefea8 100644 --- a/lib/pages/chat_list/chat_list.dart +++ b/lib/pages/chat_list/chat_list.dart @@ -47,13 +47,7 @@ enum PopupMenuAction { archive, } -enum ActiveFilter { - allChats, - messages, - groups, - unread, - spaces, -} +enum ActiveFilter { allChats, messages, groups, unread, spaces } extension LocalizedActiveFilter on ActiveFilter { String toLocalizedString(BuildContext context) { @@ -118,8 +112,8 @@ class ChatListController extends State // } // void clearActiveSpace() => setState(() { - // _activeSpaceId = null; - // }); + // _activeSpaceId = null; + // }); void clearActiveSpace() => context.go("/rooms"); void setActiveSpace(String spaceId) => context.go("/rooms/spaces/$spaceId/details"); @@ -153,13 +147,13 @@ class ChatListController extends State inviteEvent == null ? L10n.of(context).inviteForMe : inviteEvent.content.tryGet('reason') ?? - L10n.of(context).youInvitedBy( - room - .unsafeGetUserFromMemoryOrFallback( - inviteEvent.senderId, - ) - .calcDisplayname(i18n: matrixLocals), - ), + L10n.of(context).youInvitedBy( + room + .unsafeGetUserFromMemoryOrFallback( + inviteEvent.senderId, + ) + .calcDisplayname(i18n: matrixLocals), + ), textAlign: TextAlign.center, ), ), @@ -223,9 +217,7 @@ class ChatListController extends State if (room.membership == Membership.ban) { ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(L10n.of(context).youHaveBeenBannedFromThisChat), - ), + SnackBar(content: Text(L10n.of(context).youHaveBeenBannedFromThisChat)), ); return; } @@ -275,11 +267,9 @@ class ChatListController extends State } } - List get filteredRooms => Matrix.of(context) - .client - .rooms - .where(getRoomFilterByActiveFilter(activeFilter)) - .toList(); + List get filteredRooms => Matrix.of( + context, + ).client.rooms.where(getRoomFilterByActiveFilter(activeFilter)).toList(); bool isSearchMode = false; Future? publicRoomsResponse; @@ -338,8 +328,9 @@ class ChatListController extends State if (searchQuery.isValidMatrixId && searchQuery.sigil == '#' && - roomSearchResult.chunk - .any((room) => room.canonicalAlias == searchQuery) == + roomSearchResult.chunk.any( + (room) => room.canonicalAlias == searchQuery, + ) == false) { final response = await client.getRoomIdByAlias(searchQuery); final roomId = response.roomId; @@ -362,13 +353,9 @@ class ChatListController extends State ); } catch (e, s) { Logs().w('Searching has crashed', e, s); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text( - e.toLocalizedString(context), - ), - ), - ); + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text(e.toLocalizedString(context)))); } if (!isSearchMode) return; setState(() { @@ -452,22 +439,17 @@ class ChatListController extends State showScaffoldDialog( context: context, builder: (context) => ShareScaffoldDialog( - items: files.map( - (file) { - if ({ - SharedMediaType.text, - SharedMediaType.url, - }.contains(file.type)) { - return TextShareItem(file.path); - } - return FileShareItem( - XFile( - file.path.replaceFirst('file://', ''), - mimeType: file.mimeType, - ), - ); - }, - ).toList(), + items: files.map((file) { + if ({SharedMediaType.text, SharedMediaType.url}.contains(file.type)) { + return TextShareItem(file.path); + } + return FileShareItem( + XFile( + file.path.replaceFirst('file://', ''), + mimeType: file.mimeType, + ), + ); + }).toList(), ), ); } @@ -491,24 +473,25 @@ class ChatListController extends State .listen(_processIncomingSharedMedia, onError: print); // For sharing images coming from outside the app while the app is closed - ReceiveSharingIntent.instance - .getInitialMedia() - .then(_processIncomingSharedMedia); + ReceiveSharingIntent.instance.getInitialMedia().then( + _processIncomingSharedMedia, + ); // #Pangea // // For receiving shared Uris - // _intentUriStreamSubscription = - // AppLinks().uriLinkStream.listen(_processIncomingUris); + // _intentUriStreamSubscription = AppLinks().uriLinkStream.listen( + // _processIncomingUris, + // ); // Pangea# if (PlatformInfos.isAndroid) { final shortcuts = FlutterShortcuts(); shortcuts.initialize().then( - (_) => shortcuts.listenAction((action) { - if (!mounted) return; - UrlLauncher(context, action).launchUrl(); - }), - ); + (_) => shortcuts.listenAction((action) { + if (!mounted) return; + UrlLauncher(context, action).launchUrl(); + }), + ); } } @@ -535,8 +518,9 @@ class ChatListController extends State _hackyWebRTCFixForWeb(); WidgetsBinding.instance.addPostFrameCallback((_) async { if (mounted) { - searchServer = - Matrix.of(context).store.getString(_serverStoreNamespace); + searchServer = Matrix.of( + context, + ).store.getString(_serverStoreNamespace); Matrix.of(context).backgroundPush?.setupPush(); UpdateNotifier.showUpdateSnackBar(context); // #Pangea @@ -551,61 +535,54 @@ class ChatListController extends State }); //#Pangea - _invitedSpaceSubscription = Matrix.of(context) - .client - .onSync - .stream + _invitedSpaceSubscription = Matrix.of(context).client.onSync.stream .where((event) => event.rooms?.invite != null) .listen((event) async { - for (final inviteEntry in event.rooms!.invite!.entries) { - if (inviteEntry.value.inviteState == null) continue; - final isSpace = inviteEntry.value.inviteState!.any( - (event) => - event.type == EventTypes.RoomCreate && - event.content['type'] == 'm.space', - ); - final isAnalytics = inviteEntry.value.inviteState!.any( - (event) => - event.type == EventTypes.RoomCreate && - event.content['type'] == PangeaRoomTypes.analytics, - ); - - if (isSpace) { - final spaceId = inviteEntry.key; - final space = Matrix.of(context).client.getRoomById( - spaceId, - ); - - if (space?.classCode?.toLowerCase() == - SpaceCodeRepo.recentCode?.toLowerCase()) { - return; - } - - if (space != null) { - chatListHandleSpaceTap( - context, - space, + for (final inviteEntry in event.rooms!.invite!.entries) { + if (inviteEntry.value.inviteState == null) continue; + final isSpace = inviteEntry.value.inviteState!.any( + (event) => + event.type == EventTypes.RoomCreate && + event.content['type'] == 'm.space', ); - } - } - - if (isAnalytics) { - final analyticsRoom = - Matrix.of(context).client.getRoomById(inviteEntry.key); - try { - await analyticsRoom?.join(); - } catch (err, s) { - ErrorHandler.logError( - m: "Failed to join analytics room", - e: err, - s: s, - data: {"analyticsRoom": analyticsRoom?.id}, + final isAnalytics = inviteEntry.value.inviteState!.any( + (event) => + event.type == EventTypes.RoomCreate && + event.content['type'] == PangeaRoomTypes.analytics, ); + + if (isSpace) { + final spaceId = inviteEntry.key; + final space = Matrix.of(context).client.getRoomById(spaceId); + + if (space?.classCode?.toLowerCase() == + SpaceCodeRepo.recentCode?.toLowerCase()) { + return; + } + + if (space != null) { + chatListHandleSpaceTap(context, space); + } + } + + if (isAnalytics) { + final analyticsRoom = Matrix.of( + context, + ).client.getRoomById(inviteEntry.key); + try { + await analyticsRoom?.join(); + } catch (err, s) { + ErrorHandler.logError( + m: "Failed to join analytics room", + e: err, + s: s, + data: {"analyticsRoom": analyticsRoom?.id}, + ); + } + return; + } } - return; - } - } - }); + }); MatrixState.pangeaController.subscriptionController.subscriptionNotifier .addListener(_onSubscribe); @@ -619,39 +596,39 @@ class ChatListController extends State _roomCapacitySubscription ??= client.onSync.stream .where((u) => u.rooms?.join != null) .listen((update) async { - final roomUpdates = update.rooms!.join!.entries; - for (final entry in roomUpdates) { - final roomID = entry.key; - final roomUpdate = entry.value; - if (roomUpdate.timeline?.events == null) continue; - final events = roomUpdate.timeline!.events; - final memberEvents = events!.where( - (event) => - event.type == EventTypes.RoomMember && - event.senderId == client.userID, - ); - if (memberEvents.isEmpty) continue; - final room = client.getRoomById(roomID); - if (room == null || - room.isSpace || - room.isHiddenRoom || - room.capacity == null || - (room.summary.mJoinedMemberCount ?? 1) <= room.capacity!) { - continue; - } - - await showFutureLoadingDialog( - context: context, - future: () async { - await room.leave(); - if (GoRouterState.of(context).uri.toString().contains(roomID)) { - NavigationUtil.goToSpaceRoute(null, [], context); + final roomUpdates = update.rooms!.join!.entries; + for (final entry in roomUpdates) { + final roomID = entry.key; + final roomUpdate = entry.value; + if (roomUpdate.timeline?.events == null) continue; + final events = roomUpdate.timeline!.events; + final memberEvents = events!.where( + (event) => + event.type == EventTypes.RoomMember && + event.senderId == client.userID, + ); + if (memberEvents.isEmpty) continue; + final room = client.getRoomById(roomID); + if (room == null || + room.isSpace || + room.isHiddenRoom || + room.capacity == null || + (room.summary.mJoinedMemberCount ?? 1) <= room.capacity!) { + continue; } - throw L10n.of(context).roomFull; - }, - ); - } - }); + + await showFutureLoadingDialog( + context: context, + future: () async { + await room.leave(); + if (GoRouterState.of(context).uri.toString().contains(roomID)) { + NavigationUtil.goToSpaceRoute(null, [], context); + } + throw L10n.of(context).roomFull; + }, + ); + } + }); WidgetsBinding.instance.addPostFrameCallback((_) { _joinInvitedSpaces(); @@ -667,9 +644,9 @@ class ChatListController extends State } Future _joinInvitedSpaces() async { - final invitedSpaces = Matrix.of(context).client.rooms.where( - (r) => r.isSpace && r.membership == Membership.invite, - ); + final invitedSpaces = Matrix.of( + context, + ).client.rooms.where((r) => r.isSpace && r.membership == Membership.invite); for (final space in invitedSpaces) { await showInviteDialog(space, context); @@ -693,11 +670,7 @@ class ChatListController extends State } // #Pangea - void chatContextAction( - Room room, - BuildContext posContext, [ - Room? space, - ]) => + void chatContextAction(Room room, BuildContext posContext, [Room? space]) => chatContextMenuAction( room, posContext, @@ -726,8 +699,9 @@ class ChatListController extends State // Offset.zero & overlay.size, // ); - // final displayname = - // room.getLocalizedDisplayname(MatrixLocals(L10n.of(context))); + // final displayname = room.getLocalizedDisplayname( + // MatrixLocals(L10n.of(context)), + // ); // final spacesWithPowerLevels = room.client.rooms // .where( @@ -745,19 +719,17 @@ class ChatListController extends State // PopupMenuItem( // value: ChatContextAction.open, // child: Row( - // mainAxisSize: MainAxisSize.min, + // mainAxisSize: .min, // spacing: 12.0, // children: [ - // Avatar( - // mxContent: room.avatar, - // name: displayname, - // ), + // Avatar(mxContent: room.avatar, name: displayname), // ConstrainedBox( // constraints: const BoxConstraints(maxWidth: 128), // child: Text( // displayname, - // style: - // TextStyle(color: Theme.of(context).colorScheme.onSurface), + // style: TextStyle( + // color: Theme.of(context).colorScheme.onSurface, + // ), // maxLines: 2, // overflow: TextOverflow.ellipsis, // ), @@ -770,7 +742,7 @@ class ChatListController extends State // PopupMenuItem( // value: ChatContextAction.goToSpace, // child: Row( - // mainAxisSize: MainAxisSize.min, + // mainAxisSize: .min, // children: [ // Avatar( // mxContent: space.avatar, @@ -790,7 +762,7 @@ class ChatListController extends State // PopupMenuItem( // value: ChatContextAction.mute, // child: Row( - // mainAxisSize: MainAxisSize.min, + // mainAxisSize: .min, // children: [ // Icon( // room.pushRuleState == PushRuleState.notify @@ -809,7 +781,7 @@ class ChatListController extends State // PopupMenuItem( // value: ChatContextAction.markUnread, // child: Row( - // mainAxisSize: MainAxisSize.min, + // mainAxisSize: .min, // children: [ // Icon( // room.markedUnread @@ -828,7 +800,7 @@ class ChatListController extends State // PopupMenuItem( // value: ChatContextAction.favorite, // child: Row( - // mainAxisSize: MainAxisSize.min, + // mainAxisSize: .min, // children: [ // Icon( // room.isFavourite ? Icons.push_pin : Icons.push_pin_outlined, @@ -846,7 +818,7 @@ class ChatListController extends State // PopupMenuItem( // value: ChatContextAction.addToSpace, // child: Row( - // mainAxisSize: MainAxisSize.min, + // mainAxisSize: .min, // children: [ // const Icon(Icons.group_work_outlined), // const SizedBox(width: 12), @@ -858,7 +830,7 @@ class ChatListController extends State // PopupMenuItem( // value: ChatContextAction.leave, // child: Row( - // mainAxisSize: MainAxisSize.min, + // mainAxisSize: .min, // children: [ // Icon( // Icons.delete_outlined, @@ -880,7 +852,7 @@ class ChatListController extends State // PopupMenuItem( // value: ChatContextAction.block, // child: Row( - // mainAxisSize: MainAxisSize.min, + // mainAxisSize: .min, // children: [ // Icon( // Icons.block_outlined, @@ -963,8 +935,9 @@ class ChatListController extends State // .map( // (space) => AdaptiveModalAction( // value: space, - // label: space - // .getLocalizedDisplayname(MatrixLocals(L10n.of(context))), + // label: space.getLocalizedDisplayname( + // MatrixLocals(L10n.of(context)), + // ), // ), // ) // .toList(), @@ -1032,8 +1005,9 @@ class ChatListController extends State // if (client.prevBatch == null) { if (client.onSync.value?.nextBatch == null) { // Pangea# - await client.onSyncStatus.stream - .firstWhere((status) => status.status == SyncStatus.finished); + await client.onSyncStatus.stream.firstWhere( + (status) => status.status == SyncStatus.finished, + ); if (!mounted) return; setState(() { @@ -1050,8 +1024,9 @@ class ChatListController extends State }); // #Pangea - // if (client.userDeviceKeys[client.userID!]?.deviceKeys.values - // .any((device) => !device.verified && !device.blocked) ?? + // if (client.userDeviceKeys[client.userID!]?.deviceKeys.values.any( + // (device) => !device.verified && !device.blocked, + // ) ?? // false) { // late final ScaffoldFeatureController controller; // final theme = Theme.of(context); @@ -1063,9 +1038,7 @@ class ChatListController extends State // closeIconColor: theme.colorScheme.onErrorContainer, // content: Text( // L10n.of(context).oneOfYourDevicesIsNotVerified, - // style: TextStyle( - // color: theme.colorScheme.onErrorContainer, - // ), + // style: TextStyle(color: theme.colorScheme.onErrorContainer), // ), // action: SnackBarAction( // onPressed: () { @@ -1112,11 +1085,12 @@ class ChatListController extends State // setState(() { // _activeSpaceId = null; // Matrix.of(context).activeBundle = bundle; - // if (!Matrix.of(context) - // .currentBundle! - // .any((client) => client == Matrix.of(context).client)) { - // Matrix.of(context) - // .setActiveClient(Matrix.of(context).currentBundle!.first); + // if (!Matrix.of( + // context, + // ).currentBundle!.any((client) => client == Matrix.of(context).client)) { + // Matrix.of( + // context, + // ).setActiveClient(Matrix.of(context).currentBundle!.first); // } // }); // } @@ -1124,9 +1098,9 @@ class ChatListController extends State void editBundlesForAccount(String? userId, String? activeBundle) async { final l10n = L10n.of(context); - final client = Matrix.of(context) - .widget - .clients[Matrix.of(context).getClientIndexByMatrixId(userId!)]; + final client = Matrix.of( + context, + ).widget.clients[Matrix.of(context).getClientIndexByMatrixId(userId!)]; final action = await showModalActionPopup( context: context, title: L10n.of(context).editBundlesForAccount, @@ -1171,10 +1145,9 @@ class ChatListController extends State String? get secureActiveBundle { if (Matrix.of(context).activeBundle == null || - !Matrix.of(context) - .accountBundles - .keys - .contains(Matrix.of(context).activeBundle)) { + !Matrix.of( + context, + ).accountBundles.keys.contains(Matrix.of(context).activeBundle)) { return Matrix.of(context).accountBundles.keys.first; } return Matrix.of(context).activeBundle; @@ -1200,11 +1173,7 @@ class ChatListController extends State enum EditBundleAction { addToBundle, removeFromBundle } -enum InviteActions { - accept, - decline, - block, -} +enum InviteActions { accept, decline, block } enum ChatContextAction { open, @@ -1223,4 +1192,5 @@ enum ChatContextAction { // #Pangea enum InviteAction { accept, decline, block } + // Pangea# diff --git a/lib/pages/chat_list/chat_list_body.dart b/lib/pages/chat_list/chat_list_body.dart index 2ab970fab..f4095bbd7 100644 --- a/lib/pages/chat_list/chat_list_body.dart +++ b/lib/pages/chat_list/chat_list_body.dart @@ -76,9 +76,7 @@ class ChatListViewBody extends StatelessWidget { const dummyChatCount = 4; final filter = controller.searchController.text.toLowerCase(); return StreamBuilder( - key: ValueKey( - client.userID.toString(), - ), + key: ValueKey(client.userID.toString()), stream: client.onSync.stream .where((s) => s.hasRoomUpdate) .rateLimit(const Duration(seconds: 1)), @@ -97,173 +95,173 @@ class ChatListViewBody extends StatelessWidget { ), // Pangea# SliverList( - delegate: SliverChildListDelegate( - [ - if (controller.isSearchMode) ...[ - // #Pangea - // SearchTitle( - // title: L10n.of(context).publicRooms, - // icon: const Icon(Icons.explore_outlined), - // ), - // PublicRoomsHorizontalList(publicRooms: publicRooms), - // SearchTitle( - // title: L10n.of(context).publicSpaces, - // icon: const Icon(Icons.workspaces_outlined), - // ), - // PublicRoomsHorizontalList(publicRooms: publicSpaces), - // SearchTitle( - // title: L10n.of(context).users, - // icon: const Icon(Icons.group_outlined), - // ), - // AnimatedContainer( - // clipBehavior: Clip.hardEdge, - // decoration: const BoxDecoration(), - // height: userSearchResult == null || - // userSearchResult.results.isEmpty - // ? 0 - // : 106, - // duration: FluffyThemes.animationDuration, - // curve: FluffyThemes.animationCurve, - // child: userSearchResult == null - // ? null - // : ListView.builder( - // scrollDirection: Axis.horizontal, - // itemCount: userSearchResult.results.length, - // itemBuilder: (context, i) => _SearchItem( - // title: - // userSearchResult.results[i].displayName ?? - // userSearchResult - // .results[i].userId.localpart ?? - // L10n.of(context).unknownDevice, - // avatar: userSearchResult.results[i].avatarUrl, - // onPressed: () => UserDialog.show( - // context: context, - // profile: userSearchResult.results[i], - // ), - // ), - // ), - // ), - // Pangea# - ], + delegate: SliverChildListDelegate([ + if (controller.isSearchMode) ...[ // #Pangea - // if (!controller.isSearchMode && - // AppSettings.showPresences.value) - // GestureDetector( - // onLongPress: () => controller.dismissStatusList(), - // child: StatusMessageList( - // onStatusEdit: controller.setStatus, - // ), - // ), - // if (client.rooms.isNotEmpty && !controller.isSearchMode) - // SizedBox( - // height: 64, - // child: ListView( - // padding: const EdgeInsets.symmetric( - // horizontal: 12.0, - // vertical: 12.0, - // ), - // shrinkWrap: true, - // scrollDirection: Axis.horizontal, - // children: [ - // if (AppSettings.separateChatTypes.value) - // ActiveFilter.messages - // else - // ActiveFilter.allChats, - // ActiveFilter.groups, - // ActiveFilter.unread, - // if (spaceDelegateCandidates.isNotEmpty && - // !AppSettings.displayNavigationRail.value && - // !FluffyThemes.isColumnMode(context)) - // ActiveFilter.spaces, - // ] - // .map( - // (filter) => Padding( - // padding: const EdgeInsets.symmetric( - // horizontal: 4.0, - // ), - // child: FilterChip( - // selected: filter == controller.activeFilter, - // onSelected: (_) => - // controller.setActiveFilter(filter), - // label: - // Text(filter.toLocalizedString(context)), - // ), + // SearchTitle( + // title: L10n.of(context).publicRooms, + // icon: const Icon(Icons.explore_outlined), + // ), + // PublicRoomsHorizontalList(publicRooms: publicRooms), + // SearchTitle( + // title: L10n.of(context).publicSpaces, + // icon: const Icon(Icons.workspaces_outlined), + // ), + // PublicRoomsHorizontalList(publicRooms: publicSpaces), + // SearchTitle( + // title: L10n.of(context).users, + // icon: const Icon(Icons.group_outlined), + // ), + // AnimatedContainer( + // clipBehavior: Clip.hardEdge, + // decoration: const BoxDecoration(), + // height: + // userSearchResult == null || + // userSearchResult.results.isEmpty + // ? 0 + // : 106, + // duration: FluffyThemes.animationDuration, + // curve: FluffyThemes.animationCurve, + // child: userSearchResult == null + // ? null + // : ListView.builder( + // scrollDirection: Axis.horizontal, + // itemCount: userSearchResult.results.length, + // itemBuilder: (context, i) => _SearchItem( + // title: + // userSearchResult.results[i].displayName ?? + // userSearchResult + // .results[i] + // .userId + // .localpart ?? + // L10n.of(context).unknownDevice, + // avatar: userSearchResult.results[i].avatarUrl, + // onPressed: () => UserDialog.show( + // context: context, + // profile: userSearchResult.results[i], // ), - // ) - // .toList(), - // ), - // ), - // if (controller.isSearchMode) - // SearchTitle( - // title: L10n.of(context).chats, - // icon: const Icon(Icons.forum_outlined), - // ), - // if (client.prevBatch != null && - // rooms.isEmpty && - // !controller.isSearchMode) ...[ - // Column( - // mainAxisAlignment: MainAxisAlignment.center, - // children: [ - // Stack( - // alignment: Alignment.center, - // children: [ - // const Column( - // mainAxisSize: MainAxisSize.min, - // children: [ - // DummyChatListItem( - // opacity: 0.5, - // animate: false, - // ), - // DummyChatListItem( - // opacity: 0.3, - // animate: false, - // ), - // ], - // ), - // Icon( - // CupertinoIcons.chat_bubble_text_fill, - // size: 128, - // color: theme.colorScheme.secondary, - // ), - // ], - // ), - // Padding( - // padding: const EdgeInsets.all(16.0), - // child: Text( - // client.rooms.isEmpty - // ? L10n.of(context).noChatsFoundHere - // : L10n.of(context).noMoreChatsFound, - // textAlign: TextAlign.center, - // style: TextStyle( - // fontSize: 18, - // color: theme.colorScheme.secondary, // ), // ), - // ), - // ], - // ), - // ], - if (controller.isSearchMode && - rooms - .where( - (room) => room - .getLocalizedDisplayname( - MatrixLocals(L10n.of(context)), - ) - .toLowerCase() - .contains(filter), - ) - .isEmpty) - Padding( - padding: const EdgeInsetsGeometry.all(16.0), - child: Text( - L10n.of(context).emptyChatSearch, - textAlign: TextAlign.center, - ), - ), + // ), // Pangea# ], - ), + // #Pangea + // if (!controller.isSearchMode && + // AppSettings.showPresences.value) + // GestureDetector( + // onLongPress: () => controller.dismissStatusList(), + // child: StatusMessageList( + // onStatusEdit: controller.setStatus, + // ), + // ), + // if (client.rooms.isNotEmpty && !controller.isSearchMode) + // SizedBox( + // height: 64, + // child: ListView( + // padding: const EdgeInsets.symmetric( + // horizontal: 12.0, + // vertical: 12.0, + // ), + // shrinkWrap: true, + // scrollDirection: Axis.horizontal, + // children: + // [ + // if (AppSettings.separateChatTypes.value) + // ActiveFilter.messages + // else + // ActiveFilter.allChats, + // ActiveFilter.groups, + // ActiveFilter.unread, + // if (spaceDelegateCandidates.isNotEmpty && + // !AppSettings + // .displayNavigationRail + // .value && + // !FluffyThemes.isColumnMode(context)) + // ActiveFilter.spaces, + // ] + // .map( + // (filter) => Padding( + // padding: const EdgeInsets.symmetric( + // horizontal: 4.0, + // ), + // child: FilterChip( + // selected: + // filter == controller.activeFilter, + // onSelected: (_) => + // controller.setActiveFilter(filter), + // label: Text( + // filter.toLocalizedString(context), + // ), + // ), + // ), + // ) + // .toList(), + // ), + // ), + // if (controller.isSearchMode) + // SearchTitle( + // title: L10n.of(context).chats, + // icon: const Icon(Icons.forum_outlined), + // ), + // if (client.prevBatch != null && + // rooms.isEmpty && + // !controller.isSearchMode) ...[ + // Column( + // mainAxisAlignment: .center, + // children: [ + // Stack( + // alignment: Alignment.center, + // children: [ + // const Column( + // mainAxisSize: .min, + // children: [ + // DummyChatListItem(opacity: 0.5, animate: false), + // DummyChatListItem(opacity: 0.3, animate: false), + // ], + // ), + // Icon( + // CupertinoIcons.chat_bubble_text_fill, + // size: 128, + // color: theme.colorScheme.secondary, + // ), + // ], + // ), + // Padding( + // padding: const EdgeInsets.all(16.0), + // child: Text( + // client.rooms.isEmpty + // ? L10n.of(context).noChatsFoundHere + // : L10n.of(context).noMoreChatsFound, + // textAlign: TextAlign.center, + // style: TextStyle( + // fontSize: 18, + // color: theme.colorScheme.secondary, + // ), + // ), + // ), + // ], + // ), + // ], + if (controller.isSearchMode && + rooms + .where( + (room) => room + .getLocalizedDisplayname( + MatrixLocals(L10n.of(context)), + ) + .toLowerCase() + .contains(filter), + ) + .isEmpty) + Padding( + padding: const EdgeInsetsGeometry.all(16.0), + child: Text( + L10n.of(context).emptyChatSearch, + textAlign: TextAlign.center, + ), + ), + // Pangea# + ]), ), if (client.prevBatch == null) SliverList( @@ -302,17 +300,16 @@ class ChatListViewBody extends StatelessWidget { vertical: 1, ), child: Material( - borderRadius: - BorderRadius.circular(AppConfig.borderRadius), + borderRadius: BorderRadius.circular( + AppConfig.borderRadius, + ), clipBehavior: Clip.hardEdge, child: ListTile( leading: const BotFace( expression: BotExpression.idle, width: Avatar.defaultSize, ), - trailing: const Icon( - Icons.chat_bubble_outline, - ), + trailing: const Icon(Icons.chat_bubble_outline), title: Text(L10n.of(context).directMessageBotTitle), subtitle: Text(L10n.of(context).directMessageBotDesc), onTap: () async { @@ -338,8 +335,9 @@ class ChatListViewBody extends StatelessWidget { vertical: 1, ), child: Material( - borderRadius: - BorderRadius.circular(AppConfig.borderRadius), + borderRadius: BorderRadius.circular( + AppConfig.borderRadius, + ), clipBehavior: Clip.hardEdge, child: ListTile( contentPadding: const EdgeInsets.only( @@ -366,8 +364,7 @@ class ChatListViewBody extends StatelessWidget { await showFutureLoadingDialog( context: context, future: () async { - final roomId = await Matrix.of(context) - .client + final roomId = await Matrix.of(context).client .startDirectChat( Environment.supportUserId, enableEncryption: false, @@ -391,10 +388,7 @@ class ChatListViewBody extends StatelessWidget { } class PublicRoomsHorizontalList extends StatelessWidget { - const PublicRoomsHorizontalList({ - super.key, - required this.publicRooms, - }); + const PublicRoomsHorizontalList({super.key, required this.publicRooms}); final List? publicRooms; @@ -413,7 +407,8 @@ class PublicRoomsHorizontalList extends StatelessWidget { scrollDirection: Axis.horizontal, itemCount: publicRooms.length, itemBuilder: (context, i) => _SearchItem( - title: publicRooms[i].name ?? + title: + publicRooms[i].name ?? publicRooms[i].canonicalAlias?.localpart ?? L10n.of(context).group, avatar: publicRooms[i].avatarUrl, @@ -444,31 +439,26 @@ class _SearchItem extends StatelessWidget { @override Widget build(BuildContext context) => InkWell( - onTap: onPressed, - child: SizedBox( - width: 84, - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - const SizedBox(height: 8), - Avatar( - mxContent: avatar, - name: title, - ), - Padding( - padding: const EdgeInsets.all(8.0), - child: Text( - title, - maxLines: 2, - textAlign: TextAlign.center, - overflow: TextOverflow.ellipsis, - style: const TextStyle( - fontSize: 12, - ), - ), - ), - ], + onTap: onPressed, + child: SizedBox( + width: 84, + child: Column( + mainAxisSize: .min, + children: [ + const SizedBox(height: 8), + Avatar(mxContent: avatar, name: title), + Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + title, + maxLines: 2, + textAlign: TextAlign.center, + overflow: TextOverflow.ellipsis, + style: const TextStyle(fontSize: 12), + ), ), - ), - ); + ], + ), + ), + ); } diff --git a/lib/pages/chat_list/chat_list_header.dart b/lib/pages/chat_list/chat_list_header.dart index d994059d1..7945aa58a 100644 --- a/lib/pages/chat_list/chat_list_header.dart +++ b/lib/pages/chat_list/chat_list_header.dart @@ -1,4 +1,3 @@ -// #Pangea // import 'package:flutter/material.dart'; // import 'package:matrix/matrix.dart'; @@ -35,19 +34,19 @@ // title: StreamBuilder( // stream: client.onSyncStatus.stream, // builder: (context, snapshot) { -// final status = client.onSyncStatus.value ?? +// final status = +// client.onSyncStatus.value ?? // const SyncStatusUpdate(SyncStatus.waitingForResponse); -// final hide = client.onSync.value != null && +// final hide = +// client.onSync.value != null && // status.status != SyncStatus.error && // client.prevBatch != null; // return TextField( // controller: controller.searchController, // focusNode: controller.searchFocusNode, // textInputAction: TextInputAction.search, -// onChanged: (text) => controller.onSearchEnter( -// text, -// globalSearch: globalSearch, -// ), +// onChanged: (text) => +// controller.onSearchEnter(text, globalSearch: globalSearch), // decoration: InputDecoration( // filled: true, // fillColor: theme.colorScheme.secondaryContainer, @@ -67,19 +66,19 @@ // ), // prefixIcon: hide // ? controller.isSearchMode -// ? IconButton( -// tooltip: L10n.of(context).cancel, -// icon: const Icon(Icons.close_outlined), -// onPressed: controller.cancelSearch, -// color: theme.colorScheme.onPrimaryContainer, -// ) -// : IconButton( -// onPressed: controller.startSearch, -// icon: Icon( -// Icons.search_outlined, +// ? IconButton( +// tooltip: L10n.of(context).cancel, +// icon: const Icon(Icons.close_outlined), +// onPressed: controller.cancelSearch, // color: theme.colorScheme.onPrimaryContainer, -// ), -// ) +// ) +// : IconButton( +// onPressed: controller.startSearch, +// icon: Icon( +// Icons.search_outlined, +// color: theme.colorScheme.onPrimaryContainer, +// ), +// ) // : Container( // margin: const EdgeInsets.all(12), // width: 8, @@ -98,37 +97,34 @@ // ), // suffixIcon: controller.isSearchMode && globalSearch // ? controller.isSearching -// ? const Padding( -// padding: EdgeInsets.symmetric( -// vertical: 10.0, -// horizontal: 12, -// ), -// child: SizedBox.square( -// dimension: 24, -// child: CircularProgressIndicator.adaptive( -// strokeWidth: 2, +// ? const Padding( +// padding: EdgeInsets.symmetric( +// vertical: 10.0, +// horizontal: 12, // ), -// ), -// ) -// : TextButton.icon( -// onPressed: controller.setServer, -// style: TextButton.styleFrom( -// shape: RoundedRectangleBorder( -// borderRadius: BorderRadius.circular(99), +// child: SizedBox.square( +// dimension: 24, +// child: CircularProgressIndicator.adaptive( +// strokeWidth: 2, +// ), // ), -// textStyle: const TextStyle(fontSize: 12), -// ), -// icon: const Icon(Icons.edit_outlined, size: 16), -// label: Text( -// controller.searchServer ?? -// Matrix.of(context).client.homeserver!.host, -// maxLines: 2, -// ), -// ) -// : SizedBox( -// width: 0, -// child: ClientChooserButton(controller), -// ), +// ) +// : TextButton.icon( +// onPressed: controller.setServer, +// style: TextButton.styleFrom( +// shape: RoundedRectangleBorder( +// borderRadius: BorderRadius.circular(99), +// ), +// textStyle: const TextStyle(fontSize: 12), +// ), +// icon: const Icon(Icons.edit_outlined, size: 16), +// label: Text( +// controller.searchServer ?? +// Matrix.of(context).client.homeserver!.host, +// maxLines: 2, +// ), +// ) +// : SizedBox(width: 0, child: ClientChooserButton(controller)), // ), // ); // }, @@ -139,4 +135,3 @@ // @override // Size get preferredSize => const Size.fromHeight(56); // } -// Pangea# diff --git a/lib/pages/chat_list/chat_list_item.dart b/lib/pages/chat_list/chat_list_item.dart index 66b4d338d..351f4dc60 100644 --- a/lib/pages/chat_list/chat_list_item.dart +++ b/lib/pages/chat_list/chat_list_item.dart @@ -56,8 +56,9 @@ class ChatListItem extends StatelessWidget { final directChatMatrixId = room.directChatMatrixID; final isDirectChat = directChatMatrixId != null; final hasNotifications = room.notificationCount > 0; - final backgroundColor = - activeChat ? theme.colorScheme.secondaryContainer : null; + final backgroundColor = activeChat + ? theme.colorScheme.secondaryContainer + : null; final displayname = room.getLocalizedDisplayname( MatrixLocals(L10n.of(context)), ); @@ -78,10 +79,7 @@ class ChatListItem extends StatelessWidget { final space = this.space; return Padding( - padding: const EdgeInsets.symmetric( - horizontal: 8, - vertical: 1, - ), + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 1), child: Material( borderRadius: BorderRadius.circular(AppConfig.borderRadius), clipBehavior: Clip.hardEdge, @@ -110,7 +108,8 @@ class ChatListItem extends StatelessWidget { child: Avatar( border: BorderSide( width: 2, - color: backgroundColor ?? + color: + backgroundColor ?? theme.colorScheme.surface, ), borderRadius: BorderRadius.circular( @@ -132,14 +131,15 @@ class ChatListItem extends StatelessWidget { child: Avatar( border: space == null ? room.isSpace - ? BorderSide( - width: 1, - color: theme.dividerColor, - ) - : null + ? BorderSide( + width: 1, + color: theme.dividerColor, + ) + : null : BorderSide( width: 2, - color: backgroundColor ?? + color: + backgroundColor ?? theme.colorScheme.surface, ), // #Pangea @@ -148,7 +148,8 @@ class ChatListItem extends StatelessWidget { // AppConfig.borderRadius / 4, // ) // : null, - borderRadius: borderRadius ?? + borderRadius: + borderRadius ?? (room.isSpace ? BorderRadius.circular( AppConfig.borderRadius / 4, @@ -208,10 +209,7 @@ class ChatListItem extends StatelessWidget { if (isMuted) const Padding( padding: EdgeInsets.only(left: 4.0), - child: Icon( - Icons.notifications_off_outlined, - size: 16, - ), + child: Icon(Icons.notifications_off_outlined, size: 16), ), if (room.isFavourite) Padding( @@ -228,8 +226,9 @@ class ChatListItem extends StatelessWidget { Padding( padding: const EdgeInsets.only(left: 4.0), child: Text( - room.latestEventReceivedTime - .localizedTimeShort(context), + room.latestEventReceivedTime.localizedTimeShort( + context, + ), style: TextStyle( fontSize: 12, color: theme.colorScheme.outline, @@ -239,8 +238,8 @@ class ChatListItem extends StatelessWidget { ], ), subtitle: Row( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: .start, + mainAxisAlignment: .center, children: [ if (typingText.isEmpty && ownMessage && @@ -266,134 +265,129 @@ class ChatListItem extends StatelessWidget { ), ) : room.lastEvent?.relationshipType == - RelationshipTypes.thread - ? Container( - decoration: BoxDecoration( - border: Border.all( + RelationshipTypes.thread + ? Container( + decoration: BoxDecoration( + border: Border.all( + color: theme.colorScheme.outline, + ), + borderRadius: BorderRadius.circular( + AppConfig.borderRadius, + ), + ), + padding: const EdgeInsets.symmetric( + horizontal: 8.0, + ), + margin: const EdgeInsets.only(right: 4.0), + child: Row( + mainAxisSize: .min, + children: [ + Icon( + Icons.message_outlined, + size: 12, + color: theme.colorScheme.outline, + ), + const SizedBox(width: 4), + Text( + L10n.of(context).thread, + style: TextStyle( + fontSize: 12, color: theme.colorScheme.outline, ), - borderRadius: BorderRadius.circular( - AppConfig.borderRadius, - ), ), - padding: - const EdgeInsets.symmetric(horizontal: 8.0), - margin: const EdgeInsets.only(right: 4.0), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Icon( - Icons.message_outlined, - size: 12, - color: theme.colorScheme.outline, - ), - const SizedBox(width: 4), - Text( - L10n.of(context).thread, - style: TextStyle( - fontSize: 12, - color: theme.colorScheme.outline, - ), - ), - ], - ), - ) - : const SizedBox.shrink(), + ], + ), + ) + : const SizedBox.shrink(), ), Expanded( child: room.isSpace && room.membership == Membership.join ? Text( // #Pangea - // L10n.of(context) - // .countChats(room.spaceChildren.length), + // L10n.of( + // context, + // ).countChats(room.spaceChildren.length), L10n.of(context).countChats(room.spaceChildCount), // Pangea# style: TextStyle(color: theme.colorScheme.outline), ) : typingText.isNotEmpty - ? Text( - typingText, - style: TextStyle( - color: theme.colorScheme.primary, - ), - maxLines: 1, - softWrap: false, - ) - // #Pangea - : room.lastEvent != null - ? ChatListItemSubtitle( - room: room, - style: TextStyle( - fontWeight: unread || room.hasNewMessages - ? FontWeight.bold - : null, - color: theme.colorScheme.onSurfaceVariant, - ), + ? Text( + typingText, + style: TextStyle(color: theme.colorScheme.primary), + maxLines: 1, + softWrap: false, + ) + // #Pangea + : room.lastEvent != null + ? ChatListItemSubtitle( + room: room, + style: TextStyle( + fontWeight: unread || room.hasNewMessages + ? FontWeight.bold + : null, + color: theme.colorScheme.onSurfaceVariant, + ), + ) + // Pangea# + : FutureBuilder( + key: ValueKey( + '${lastEvent?.eventId}_${lastEvent?.type}_${lastEvent?.redacted}', + ), + future: needLastEventSender + ? lastEvent.calcLocalizedBody( + MatrixLocals(L10n.of(context)), + hideReply: true, + hideEdit: true, + plaintextBody: true, + removeMarkdown: true, + withSenderNamePrefix: + (!isDirectChat || + directChatMatrixId != + room.lastEvent?.senderId), ) - // Pangea# - : FutureBuilder( - key: ValueKey( - '${lastEvent?.eventId}_${lastEvent?.type}_${lastEvent?.redacted}', - ), - future: needLastEventSender - ? lastEvent.calcLocalizedBody( - MatrixLocals(L10n.of(context)), - hideReply: true, - hideEdit: true, - plaintextBody: true, - removeMarkdown: true, - withSenderNamePrefix: - (!isDirectChat || - directChatMatrixId != - room.lastEvent - ?.senderId), - ) - : null, - initialData: - lastEvent?.calcLocalizedBodyFallback( - MatrixLocals(L10n.of(context)), - hideReply: true, - hideEdit: true, - plaintextBody: true, - removeMarkdown: true, - withSenderNamePrefix: (!isDirectChat || - directChatMatrixId != - room.lastEvent?.senderId), - ), - builder: (context, snapshot) => Text( - room.membership == Membership.invite - ? room - .getState( - EventTypes.RoomMember, - room.client.userID!, - ) - ?.content - .tryGet('reason') ?? - (isDirectChat - ? L10n.of(context) - .newChatRequest - // #Pangea - // : L10n.of(context) - // .inviteGroupChat) - : L10n.of(context).inviteChat) - // Pangea# - : snapshot.data ?? - L10n.of(context).noMessagesYet, - softWrap: false, - maxLines: - room.notificationCount >= 1 ? 2 : 1, - overflow: TextOverflow.ellipsis, - style: TextStyle( - color: unread || room.hasNewMessages - ? theme.colorScheme.onSurface - : theme.colorScheme.outline, - decoration: - room.lastEvent?.redacted == true - ? TextDecoration.lineThrough - : null, - ), - ), - ), + : null, + initialData: lastEvent?.calcLocalizedBodyFallback( + MatrixLocals(L10n.of(context)), + hideReply: true, + hideEdit: true, + plaintextBody: true, + removeMarkdown: true, + withSenderNamePrefix: + (!isDirectChat || + directChatMatrixId != + room.lastEvent?.senderId), + ), + builder: (context, snapshot) => Text( + room.membership == Membership.invite + ? room + .getState( + EventTypes.RoomMember, + room.client.userID!, + ) + ?.content + .tryGet('reason') ?? + (isDirectChat + ? L10n.of(context).newChatRequest + // #Pangea + // : L10n.of(context).inviteGroupChat) + : L10n.of(context).inviteChat) + // Pangea# + : snapshot.data ?? + L10n.of(context).noMessagesYet, + softWrap: false, + maxLines: room.notificationCount >= 1 ? 2 : 1, + overflow: TextOverflow.ellipsis, + style: TextStyle( + color: unread || room.hasNewMessages + ? theme.colorScheme.onSurface + : theme.colorScheme.outline, + decoration: room.lastEvent?.redacted == true + ? TextDecoration.lineThrough + : null, + ), + ), + ), ), const SizedBox(width: 8), UnreadBubble(room: room), @@ -402,27 +396,27 @@ class ChatListItem extends StatelessWidget { onTap: onTap, trailing: onForget == null ? room.membership == Membership.invite - ? IconButton( - tooltip: L10n.of(context).declineInvitation, - icon: const Icon(Icons.delete_forever_outlined), - color: theme.colorScheme.error, - onPressed: () async { - final consent = await showOkCancelAlertDialog( - context: context, - title: L10n.of(context).declineInvitation, - message: L10n.of(context).areYouSure, - okLabel: L10n.of(context).yes, - isDestructive: true, - ); - if (consent != OkCancelResult.ok) return; - if (!context.mounted) return; - await showFutureLoadingDialog( - context: context, - future: room.leave, - ); - }, - ) - : null + ? IconButton( + tooltip: L10n.of(context).declineInvitation, + icon: const Icon(Icons.delete_forever_outlined), + color: theme.colorScheme.error, + onPressed: () async { + final consent = await showOkCancelAlertDialog( + context: context, + title: L10n.of(context).declineInvitation, + message: L10n.of(context).areYouSure, + okLabel: L10n.of(context).yes, + isDestructive: true, + ); + if (consent != OkCancelResult.ok) return; + if (!context.mounted) return; + await showFutureLoadingDialog( + context: context, + future: room.leave, + ); + }, + ) + : null : IconButton( icon: const Icon(Icons.delete_outlined), onPressed: onForget, diff --git a/lib/pages/chat_list/chat_list_view.dart b/lib/pages/chat_list/chat_list_view.dart index ef756dc45..9011648d5 100644 --- a/lib/pages/chat_list/chat_list_view.dart +++ b/lib/pages/chat_list/chat_list_view.dart @@ -36,10 +36,7 @@ class ChatListView extends StatelessWidget { // onGoToChats: controller.clearActiveSpace, // onGoToSpaceId: controller.setActiveSpace, // ), - // Container( - // color: Theme.of(context).dividerColor, - // width: 1, - // ), + // Container(color: Theme.of(context).dividerColor, width: 1), // ], // Pangea# Expanded( @@ -52,8 +49,8 @@ class ChatListView extends StatelessWidget { // body: ChatListViewBody(controller), body: ChatListViewBodyWrapper(controller: controller), // Pangea# - floatingActionButton: !controller.isSearchMode && - controller.activeSpaceId == null + floatingActionButton: + !controller.isSearchMode && controller.activeSpaceId == null ? FloatingActionButton.extended( onPressed: () => context.go('/rooms/newprivatechat'), // #Pangea diff --git a/lib/pages/chat_list/client_chooser_button.dart b/lib/pages/chat_list/client_chooser_button.dart index 83276dfeb..87a7314c1 100644 --- a/lib/pages/chat_list/client_chooser_button.dart +++ b/lib/pages/chat_list/client_chooser_button.dart @@ -25,8 +25,8 @@ // (a, b) => a!.isValidMatrixId == b!.isValidMatrixId // ? 0 // : a.isValidMatrixId && !b.isValidMatrixId -// ? -1 -// : 1, +// ? -1 +// : 1, // ); // return >[ // PopupMenuItem( @@ -97,8 +97,8 @@ // PopupMenuItem( // value: null, // child: Column( -// crossAxisAlignment: CrossAxisAlignment.start, -// mainAxisSize: MainAxisSize.min, +// crossAxisAlignment: .start, +// mainAxisSize: .min, // children: [ // Text( // bundle!, @@ -123,7 +123,8 @@ // children: [ // Avatar( // mxContent: snapshot.data?.avatarUrl, -// name: snapshot.data?.displayName ?? +// name: +// snapshot.data?.displayName ?? // client.userID!.localpart, // size: 32, // ), @@ -193,10 +194,7 @@ // ); // } -// void _clientSelected( -// Object object, -// BuildContext context, -// ) async { +// void _clientSelected(Object object, BuildContext context) async { // if (object is Client) { // controller.setActiveClient(object); // } else if (object is String) { diff --git a/lib/pages/chat_list/navi_rail_item.dart b/lib/pages/chat_list/navi_rail_item.dart index 19eb929e8..fc51891f6 100644 --- a/lib/pages/chat_list/navi_rail_item.dart +++ b/lib/pages/chat_list/navi_rail_item.dart @@ -59,13 +59,13 @@ class NaviRailItem extends StatelessWidget { // #Pangea // return SizedBox( // height: 72, + // width: FluffyThemes.navRailWidth, return Row( mainAxisSize: MainAxisSize.min, children: [ SizedBox( height: width - (isColumnMode ? 16.0 : 12.0), width: width, - // width: FluffyThemes.navRailWidth, // Pangea# child: Stack( children: [ @@ -76,8 +76,8 @@ class NaviRailItem extends StatelessWidget { child: AnimatedContainer( width: isSelected ? FluffyThemes.isColumnMode(context) - ? 8 - : 4 + ? 8 + : 4 : 0, duration: FluffyThemes.animationDuration, curve: FluffyThemes.animationCurve, @@ -97,10 +97,10 @@ class NaviRailItem extends StatelessWidget { curve: FluffyThemes.animationCurve, // #Pangea // child: Material( - // borderRadius: borderRadius, - // color: isSelected - // ? theme.colorScheme.primaryContainer - // : theme.colorScheme.surfaceContainerHigh, + // borderRadius: borderRadius, + // color: isSelected + // ? theme.colorScheme.primaryContainer + // : theme.colorScheme.surfaceContainerHigh, child: UnreadRoomsBadge( filter: unreadBadgeFilter ?? (_) => false, badgePosition: BadgePosition.topEnd( @@ -110,7 +110,8 @@ class NaviRailItem extends StatelessWidget { child: Container( alignment: Alignment.center, decoration: BoxDecoration( - color: backgroundColor ?? + color: + backgroundColor ?? (isSelected ? theme.colorScheme.primaryContainer : theme.colorScheme.surfaceContainerHigh), @@ -151,6 +152,7 @@ class NaviRailItem extends StatelessWidget { ], ), ), + // #Pangea if (expanded) Flexible( child: Container( @@ -174,6 +176,7 @@ class NaviRailItem extends StatelessWidget { ), ), ), + // Pangea# ], ); }, diff --git a/lib/pages/chat_list/search_title.dart b/lib/pages/chat_list/search_title.dart index 496a5feec..95bb5364d 100644 --- a/lib/pages/chat_list/search_title.dart +++ b/lib/pages/chat_list/search_title.dart @@ -22,14 +22,8 @@ class SearchTitle extends StatelessWidget { return Material( shape: Border( - top: BorderSide( - color: theme.dividerColor, - width: 1, - ), - bottom: BorderSide( - color: theme.dividerColor, - width: 1, - ), + top: BorderSide(color: theme.dividerColor, width: 1), + bottom: BorderSide(color: theme.dividerColor, width: 1), ), color: color ?? theme.colorScheme.surface, child: InkWell( @@ -38,10 +32,7 @@ class SearchTitle extends StatelessWidget { child: Align( alignment: Alignment.centerLeft, child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: 16, - vertical: 8, - ), + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), child: IconTheme( data: theme.iconTheme.copyWith(size: 16), child: Row( diff --git a/lib/pages/chat_list/space_view.dart b/lib/pages/chat_list/space_view.dart index a16220c4e..16058eb74 100644 --- a/lib/pages/chat_list/space_view.dart +++ b/lib/pages/chat_list/space_view.dart @@ -28,12 +28,7 @@ enum AddRoomType { chat, subspace } enum SpaceChildAction { edit, moveToSpace, removeFromSpace } -enum SpaceActions { - settings, - invite, - members, - leave, -} +enum SpaceActions { settings, invite, members, leave } class SpaceView extends StatefulWidget { final String spaceId; @@ -124,8 +119,9 @@ class _SpaceViewState extends State { } catch (e, s) { Logs().w('Unable to load hierarchy', e, s); if (!mounted) return; - ScaffoldMessenger.of(context) - .showSnackBar(SnackBar(content: Text(e.toLocalizedString(context)))); + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text(e.toLocalizedString(context)))); setState(() { _isLoading = false; }); @@ -141,9 +137,7 @@ class _SpaceViewState extends State { builder: (_) => PublicRoomDialog( chunk: item, via: space?.spaceChildren - .firstWhereOrNull( - (child) => child.roomId == item.roomId, - ) + .firstWhereOrNull((child) => child.roomId == item.roomId) ?.via, ), ); @@ -224,8 +218,9 @@ class _SpaceViewState extends State { if (roomType == AddRoomType.subspace) { roomId = await client.createSpace( name: names, - visibility: - isPublicSpace ? sdk.Visibility.public : sdk.Visibility.private, + visibility: isPublicSpace + ? sdk.Visibility.public + : sdk.Visibility.private, ); } else { roomId = await client.createGroupChat( @@ -234,8 +229,9 @@ class _SpaceViewState extends State { preset: isPublicSpace ? CreateRoomPreset.publicChat : CreateRoomPreset.privateChat, - visibility: - isPublicSpace ? sdk.Visibility.public : sdk.Visibility.private, + visibility: isPublicSpace + ? sdk.Visibility.public + : sdk.Visibility.private, initialState: isPublicSpace ? null : [ @@ -289,7 +285,7 @@ class _SpaceViewState extends State { PopupMenuItem( value: SpaceChildAction.moveToSpace, child: Row( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ const Icon(Icons.move_down_outlined), const SizedBox(width: 12), @@ -300,7 +296,7 @@ class _SpaceViewState extends State { PopupMenuItem( value: SpaceChildAction.edit, child: Row( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ const Icon(Icons.edit_outlined), const SizedBox(width: 12), @@ -311,7 +307,7 @@ class _SpaceViewState extends State { PopupMenuItem( value: SpaceChildAction.removeFromSpace, child: Row( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ const Icon(Icons.group_remove_outlined), const SizedBox(width: 12), @@ -344,8 +340,9 @@ class _SpaceViewState extends State { .map( (space) => AdaptiveModalAction( value: space, - label: space - .getLocalizedDisplayname(MatrixLocals(L10n.of(context))), + label: space.getLocalizedDisplayname( + MatrixLocals(L10n.of(context)), + ), ), ) .toList(), @@ -392,19 +389,12 @@ class _SpaceViewState extends State { final displayname = room?.getLocalizedDisplayname() ?? L10n.of(context).nothingFound; const avatarSize = Avatar.defaultSize / 1.5; - final isAdmin = room?.canChangeStateEvent( - EventTypes.SpaceChild, - ) == - true; + final isAdmin = room?.canChangeStateEvent(EventTypes.SpaceChild) == true; return Scaffold( appBar: AppBar( leading: FluffyThemes.isColumnMode(context) ? null - : Center( - child: CloseButton( - onPressed: widget.onBack, - ), - ), + : Center(child: CloseButton(onPressed: widget.onBack)), automaticallyImplyLeading: false, titleSpacing: FluffyThemes.isColumnMode(context) ? null : 0, title: ListTile( @@ -432,7 +422,7 @@ class _SpaceViewState extends State { PopupMenuItem( value: AddRoomType.chat, child: Row( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ const Icon(Icons.group_add_outlined), const SizedBox(width: 12), @@ -443,7 +433,7 @@ class _SpaceViewState extends State { PopupMenuItem( value: AddRoomType.subspace, child: Row( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ const Icon(Icons.workspaces_outlined), const SizedBox(width: 12), @@ -460,7 +450,7 @@ class _SpaceViewState extends State { PopupMenuItem( value: SpaceActions.settings, child: Row( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ const Icon(Icons.settings_outlined), const SizedBox(width: 12), @@ -471,7 +461,7 @@ class _SpaceViewState extends State { PopupMenuItem( value: SpaceActions.invite, child: Row( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ const Icon(Icons.person_add_outlined), const SizedBox(width: 12), @@ -482,7 +472,7 @@ class _SpaceViewState extends State { PopupMenuItem( value: SpaceActions.members, child: Row( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ const Icon(Icons.group_outlined), const SizedBox(width: 12), @@ -497,7 +487,7 @@ class _SpaceViewState extends State { PopupMenuItem( value: SpaceActions.leave, child: Row( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ const Icon(Icons.delete_outlined), const SizedBox(width: 12), @@ -510,12 +500,7 @@ class _SpaceViewState extends State { ], ), body: room == null - ? const Center( - child: Icon( - Icons.search_outlined, - size: 80, - ), - ) + ? const Center(child: Icon(Icons.search_outlined, size: 80)) : StreamBuilder( stream: room.client.onSync.stream .where((s) => s.hasRoomUpdate) @@ -573,7 +558,8 @@ class _SpaceViewState extends State { ); } final item = _discoveredChildren[i]; - final displayname = item.name ?? + final displayname = + item.name ?? item.canonicalAlias ?? L10n.of(context).emptyChat; if (!displayname.toLowerCase().contains(filter)) { @@ -589,27 +575,31 @@ class _SpaceViewState extends State { vertical: 1, ), child: Material( - borderRadius: - BorderRadius.circular(AppConfig.borderRadius), + borderRadius: BorderRadius.circular( + AppConfig.borderRadius, + ), clipBehavior: Clip.hardEdge, - color: joinedRoom != null && + color: + joinedRoom != null && widget.activeChat == joinedRoom.id ? theme.colorScheme.secondaryContainer : Colors.transparent, child: HoverBuilder( builder: (context, hovered) => ListTile( - visualDensity: - const VisualDensity(vertical: -0.5), - contentPadding: - const EdgeInsets.symmetric(horizontal: 8), + visualDensity: const VisualDensity( + vertical: -0.5, + ), + contentPadding: const EdgeInsets.symmetric( + horizontal: 8, + ), onTap: joinedRoom != null ? () => widget.onChatTab(joinedRoom!) : () => _joinChildRoom(item), onLongPress: isAdmin ? () => _showSpaceChildEditMenu( - context, - item.roomId, - ) + context, + item.roomId, + ) : null, leading: hovered && isAdmin ? SizedBox.square( @@ -618,16 +608,18 @@ class _SpaceViewState extends State { splashRadius: avatarSize, iconSize: 14, style: IconButton.styleFrom( - foregroundColor: theme.colorScheme + foregroundColor: theme + .colorScheme .onTertiaryContainer, backgroundColor: theme - .colorScheme.tertiaryContainer, + .colorScheme + .tertiaryContainer, ), onPressed: () => _showSpaceChildEditMenu( - context, - item.roomId, - ), + context, + item.roomId, + ), icon: const Icon(Icons.edit_outlined), ), ) @@ -637,11 +629,13 @@ class _SpaceViewState extends State { name: '#', backgroundColor: theme.colorScheme.surfaceContainer, - textColor: item.name?.darkColor ?? + textColor: + item.name?.darkColor ?? theme.colorScheme.onSurface, border: item.roomType == 'm.space' ? BorderSide( - color: theme.colorScheme + color: theme + .colorScheme .surfaceContainerHighest, ) : null, diff --git a/lib/pages/chat_list/status_msg_list.dart b/lib/pages/chat_list/status_msg_list.dart index 92be34d51..aa604748a 100644 --- a/lib/pages/chat_list/status_msg_list.dart +++ b/lib/pages/chat_list/status_msg_list.dart @@ -13,10 +13,7 @@ import '../../widgets/adaptive_dialogs/user_dialog.dart'; class StatusMessageList extends StatelessWidget { final void Function() onStatusEdit; - const StatusMessageList({ - required this.onStatusEdit, - super.key, - }); + const StatusMessageList({required this.onStatusEdit, super.key}); static const double height = 116; @@ -24,10 +21,7 @@ class StatusMessageList extends StatelessWidget { final client = Matrix.of(context).client; if (profile.userId == client.userID) return onStatusEdit(); - UserDialog.show( - context: context, - profile: profile, - ); + UserDialog.show(context: context, profile: profile); return; } @@ -56,8 +50,9 @@ class StatusMessageList extends StatelessWidget { ), ), builder: (context, snapshot) { - final presences = - snapshot.data?.where(isInterestingPresence).toList(); + final presences = snapshot.data + ?.where(isInterestingPresence) + .toList(); // If no other presences than the own entry is interesting, we // hide the presence header. @@ -131,7 +126,8 @@ class PresenceAvatar extends StatelessWidget { final theme = Theme.of(context); final profile = snapshot.data; - final displayName = profile?.displayName ?? + final displayName = + profile?.displayName ?? presence.userid.localpart ?? presence.userid; final statusMsg = presence.statusMsg; @@ -163,11 +159,13 @@ class PresenceAvatar extends StatelessWidget { decoration: BoxDecoration( // #Pangea // gradient: presence.gradient, - gradient: gradient ?? + gradient: + gradient ?? (showPresence ? presence.gradient : null), // Pangea# - borderRadius: - BorderRadius.circular(avatarSize), + borderRadius: BorderRadius.circular( + avatarSize, + ), ), alignment: Alignment.center, child: Container( @@ -175,8 +173,9 @@ class PresenceAvatar extends StatelessWidget { alignment: Alignment.center, decoration: BoxDecoration( color: theme.colorScheme.surface, - borderRadius: - BorderRadius.circular(avatarSize), + borderRadius: BorderRadius.circular( + avatarSize, + ), ), padding: const EdgeInsets.all(3.0), child: Avatar( @@ -217,7 +216,7 @@ class PresenceAvatar extends StatelessWidget { ), ), // #Pangea - if (floatingIndicator != null) floatingIndicator!, + ?floatingIndicator, // Pangea# if (statusMsg != null) ...[ Positioned( @@ -226,9 +225,8 @@ class PresenceAvatar extends StatelessWidget { right: 8, child: Column( spacing: 2, - crossAxisAlignment: - CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, + crossAxisAlignment: .start, + mainAxisSize: .min, children: [ Material( elevation: statusMsgBubbleElevation, @@ -254,8 +252,9 @@ class PresenceAvatar extends StatelessWidget { ), ), Padding( - padding: - const EdgeInsets.only(left: 8.0), + padding: const EdgeInsets.only( + left: 8.0, + ), child: Material( color: statusMsgBubbleColor, elevation: statusMsgBubbleElevation, @@ -270,8 +269,9 @@ class PresenceAvatar extends StatelessWidget { ), ), Padding( - padding: - const EdgeInsets.only(left: 13.0), + padding: const EdgeInsets.only( + left: 13.0, + ), child: Material( color: statusMsgBubbleColor, elevation: statusMsgBubbleElevation, @@ -304,9 +304,7 @@ class PresenceAvatar extends StatelessWidget { textAlign: TextAlign.center, maxLines: 1, overflow: TextOverflow.ellipsis, - style: const TextStyle( - fontSize: 11, - ), + style: const TextStyle(fontSize: 11), ), ), ], @@ -320,10 +318,12 @@ class PresenceAvatar extends StatelessWidget { extension on Client { Set get interestingPresences { - final allHeroes = rooms.map((room) => room.summary.mHeroes).fold( - {}, - (previousValue, element) => previousValue..addAll(element ?? {}), - ); + final allHeroes = rooms + .map((room) => room.summary.mHeroes) + .fold( + {}, + (previousValue, element) => previousValue..addAll(element ?? {}), + ); allHeroes.add(userID!); return allHeroes; } @@ -341,31 +341,23 @@ extension on CachedPresence { LinearGradient get gradient => presence.isOnline == true ? LinearGradient( - colors: [ - Colors.green, - Colors.green.shade200, - Colors.green.shade900, - ], + colors: [Colors.green, Colors.green.shade200, Colors.green.shade900], begin: Alignment.topLeft, end: Alignment.bottomRight, ) : presence.isUnavailable - ? LinearGradient( - colors: [ - Colors.yellow, - Colors.yellow.shade200, - Colors.yellow.shade900, - ], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ) - : LinearGradient( - colors: [ - Colors.grey, - Colors.grey.shade200, - Colors.grey.shade900, - ], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ); + ? LinearGradient( + colors: [ + Colors.yellow, + Colors.yellow.shade200, + Colors.yellow.shade900, + ], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ) + : LinearGradient( + colors: [Colors.grey, Colors.grey.shade200, Colors.grey.shade900], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ); } diff --git a/lib/pages/chat_list/unread_bubble.dart b/lib/pages/chat_list/unread_bubble.dart index 964094f97..29266ff0f 100644 --- a/lib/pages/chat_list/unread_bubble.dart +++ b/lib/pages/chat_list/unread_bubble.dart @@ -15,8 +15,8 @@ class UnreadBubble extends StatelessWidget { final hasNotifications = room.notificationCount > 0; final unreadBubbleSize = unread || room.hasNewMessages ? room.notificationCount > 0 - ? 20.0 - : 14.0 + ? 20.0 + : 14.0 : 0.0; return AnimatedContainer( duration: FluffyThemes.animationDuration, @@ -27,13 +27,13 @@ class UnreadBubble extends StatelessWidget { width: !hasNotifications && !unread && !room.hasNewMessages ? 0 : (unreadBubbleSize - 9) * room.notificationCount.toString().length + - 9, + 9, decoration: BoxDecoration( color: room.highlightCount > 0 ? theme.colorScheme.error : hasNotifications || room.markedUnread - ? theme.colorScheme.primary - : theme.colorScheme.primaryContainer, + ? theme.colorScheme.primary + : theme.colorScheme.primaryContainer, borderRadius: BorderRadius.circular(7), ), child: hasNotifications @@ -43,8 +43,8 @@ class UnreadBubble extends StatelessWidget { color: room.highlightCount > 0 ? theme.colorScheme.onError : hasNotifications - ? theme.colorScheme.onPrimary - : theme.colorScheme.onPrimaryContainer, + ? theme.colorScheme.onPrimary + : theme.colorScheme.onPrimaryContainer, fontSize: 13, fontWeight: FontWeight.w500, ), diff --git a/lib/pages/chat_members/chat_members.dart b/lib/pages/chat_members/chat_members.dart index a43c2f22a..7c785e84c 100644 --- a/lib/pages/chat_members/chat_members.dart +++ b/lib/pages/chat_members/chat_members.dart @@ -15,11 +15,7 @@ class ChatMembersPage extends StatefulWidget { // #Pangea // const ChatMembersPage({required this.roomId, super.key}); - const ChatMembersPage({ - required this.roomId, - this.filter, - super.key, - }); + const ChatMembersPage({required this.roomId, this.filter, super.key}); // Pangea# @override @@ -58,8 +54,7 @@ class ChatMembersController extends State { void setFilter([dynamic _]) async { final filter = filterController.text.toLowerCase().trim(); - final members = this - .members + final members = this.members ?.where((member) => member.membership == membershipFilter) .toList(); @@ -71,14 +66,15 @@ class ChatMembersController extends State { return; } setState(() { - filteredMembers = members - ?.where( - (user) => - user.displayName?.toLowerCase().contains(filter) ?? - user.id.toLowerCase().contains(filter), - ) - .toList() - ?..sort((b, a) => a.powerLevel.compareTo(b.powerLevel)); + filteredMembers = + members + ?.where( + (user) => + user.displayName?.toLowerCase().contains(filter) ?? + user.id.toLowerCase().contains(filter), + ) + .toList() + ?..sort((b, a) => a.powerLevel.compareTo(b.powerLevel)); }); } @@ -88,8 +84,7 @@ class ChatMembersController extends State { setState(() { error = null; }); - final participants = await Matrix.of(context) - .client + final participants = await Matrix.of(context).client .getRoomById(widget.roomId) ?.requestParticipants( // #Pangea @@ -107,9 +102,7 @@ class ChatMembersController extends State { // #Pangea final availableFilters = (participants ?? []) - .map( - (p) => p.membership, - ) + .map((p) => p.membership) .toSet(); if (availableFilters.length == 1 && @@ -123,8 +116,11 @@ class ChatMembersController extends State { }); setFilter(); } catch (e, s) { - Logs() - .d('Unable to request participants. Try again in 3 seconds...', e, s); + Logs().d( + 'Unable to request participants. Try again in 3 seconds...', + e, + s, + ); setState(() { error = e; }); @@ -138,14 +134,12 @@ class ChatMembersController extends State { super.initState(); refreshMembers(); - _updateSub = Matrix.of(context) - .client - .onSync - .stream + _updateSub = Matrix.of(context).client.onSync.stream .where( (syncUpdate) => - syncUpdate.rooms?.join?[widget.roomId]?.timeline?.events - ?.any((state) => state.type == EventTypes.RoomMember) ?? + syncUpdate.rooms?.join?[widget.roomId]?.timeline?.events?.any( + (state) => state.type == EventTypes.RoomMember, + ) ?? false, ) .listen(refreshMembers); diff --git a/lib/pages/chat_members/chat_members_view.dart b/lib/pages/chat_members/chat_members_view.dart index e4c812e8a..89707a100 100644 --- a/lib/pages/chat_members/chat_members_view.dart +++ b/lib/pages/chat_members/chat_members_view.dart @@ -17,13 +17,12 @@ class ChatMembersView extends StatelessWidget { @override Widget build(BuildContext context) { - final room = - Matrix.of(context).client.getRoomById(controller.widget.roomId); + final room = Matrix.of( + context, + ).client.getRoomById(controller.widget.roomId); if (room == null) { return Scaffold( - appBar: AppBar( - title: Text(L10n.of(context).oopsSomethingWentWrong), - ), + appBar: AppBar(title: Text(L10n.of(context).oopsSomethingWentWrong)), body: Center( child: Text(L10n.of(context).youAreNoLongerParticipatingInThisChat), ), @@ -32,7 +31,8 @@ class ChatMembersView extends StatelessWidget { final members = controller.filteredMembers; - final roomCount = (room.summary.mJoinedMemberCount ?? 0) + + final roomCount = + (room.summary.mJoinedMemberCount ?? 0) + (room.summary.mInvitedMemberCount ?? 0); final error = controller.error; @@ -41,16 +41,12 @@ class ChatMembersView extends StatelessWidget { return Scaffold( appBar: AppBar( leading: const Center(child: BackButton()), - title: Text( - L10n.of(context).countParticipants(roomCount), - ), + title: Text(L10n.of(context).countParticipants(roomCount)), actions: [ if (room.canInvite) IconButton( onPressed: () => context.go('/rooms/${room.id}/invite'), - icon: const Icon( - Icons.person_add_outlined, - ), + icon: const Icon(Icons.person_add_outlined), ), ], ), @@ -62,7 +58,7 @@ class ChatMembersView extends StatelessWidget { child: Padding( padding: const EdgeInsets.all(16.0), child: Column( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ const Icon(Icons.error_outline), Text(error.toLocalizedString(context)), @@ -77,120 +73,117 @@ class ChatMembersView extends StatelessWidget { ), ) : members == null - ? const Center( - child: Padding( - padding: EdgeInsets.all(16.0), - child: CircularProgressIndicator.adaptive(), - ), - ) - : ListView.builder( - shrinkWrap: true, - itemCount: members.length + 1, - itemBuilder: (context, i) { - if (i == 0) { - final availableFilters = Membership.values - .where( - (membership) => - controller.members?.any( - (member) => member.membership == membership, - ) ?? - false, - ) - .toList(); - availableFilters - .sort((a, b) => a == Membership.join ? -1 : 1); - return Column( - mainAxisSize: MainAxisSize.min, - children: [ - Padding( - padding: const EdgeInsets.all(16.0), - child: TextField( - controller: controller.filterController, - onChanged: controller.setFilter, - decoration: InputDecoration( - filled: true, - fillColor: - theme.colorScheme.secondaryContainer, - border: OutlineInputBorder( - borderSide: BorderSide.none, - borderRadius: BorderRadius.circular(99), - ), - hintStyle: TextStyle( - color: theme.colorScheme.onPrimaryContainer, - fontWeight: FontWeight.normal, - ), - prefixIcon: const Icon(Icons.search_outlined), - hintText: L10n.of(context).search, + ? const Center( + child: Padding( + padding: EdgeInsets.all(16.0), + child: CircularProgressIndicator.adaptive(), + ), + ) + : ListView.builder( + shrinkWrap: true, + itemCount: members.length + 1, + itemBuilder: (context, i) { + if (i == 0) { + final availableFilters = Membership.values + .where( + (membership) => + controller.members?.any( + (member) => member.membership == membership, + ) ?? + false, + ) + .toList(); + availableFilters.sort( + (a, b) => a == Membership.join ? -1 : 1, + ); + return Column( + mainAxisSize: .min, + children: [ + Padding( + padding: const EdgeInsets.all(16.0), + child: TextField( + controller: controller.filterController, + onChanged: controller.setFilter, + decoration: InputDecoration( + filled: true, + fillColor: theme.colorScheme.secondaryContainer, + border: OutlineInputBorder( + borderSide: BorderSide.none, + borderRadius: BorderRadius.circular(99), + ), + hintStyle: TextStyle( + color: theme.colorScheme.onPrimaryContainer, + fontWeight: FontWeight.normal, + ), + prefixIcon: const Icon(Icons.search_outlined), + hintText: L10n.of(context).search, + ), + ), + ), + if (availableFilters.length > 1) + SizedBox( + height: 64, + child: ListView.builder( + padding: const EdgeInsets.symmetric( + horizontal: 12.0, + vertical: 12.0, + ), + scrollDirection: Axis.horizontal, + itemCount: availableFilters.length, + itemBuilder: (context, i) => Padding( + padding: const EdgeInsets.symmetric( + horizontal: 4.0, + ), + child: FilterChip( + label: Text(switch (availableFilters[i]) { + Membership.ban => L10n.of(context).banned, + Membership.invite => + L10n.of(context).countInvited( + room.summary.mInvitedMemberCount ?? + controller.members + ?.where( + (member) => + member.membership == + Membership.invite, + ) + .length ?? + 0, + ), + Membership.join => + L10n.of(context).countParticipants( + room.summary.mJoinedMemberCount ?? + controller.members + ?.where( + (member) => + member.membership == + Membership.join, + ) + .length ?? + 0, + ), + Membership.knock => L10n.of( + context, + ).knocking, + Membership.leave => L10n.of( + context, + ).leftTheChat, + }), + selected: + controller.membershipFilter == + availableFilters[i], + onSelected: (_) => controller + .setMembershipFilter(availableFilters[i]), ), ), ), - if (availableFilters.length > 1) - SizedBox( - height: 64, - child: ListView.builder( - padding: const EdgeInsets.symmetric( - horizontal: 12.0, - vertical: 12.0, - ), - scrollDirection: Axis.horizontal, - itemCount: availableFilters.length, - itemBuilder: (context, i) => Padding( - padding: const EdgeInsets.symmetric( - horizontal: 4.0, - ), - child: FilterChip( - label: Text( - switch (availableFilters[i]) { - Membership.ban => - L10n.of(context).banned, - Membership.invite => - L10n.of(context).countInvited( - room.summary - .mInvitedMemberCount ?? - controller.members - ?.where( - (member) => - member.membership == - Membership.invite, - ) - .length ?? - 0, - ), - Membership.join => - L10n.of(context).countParticipants( - room.summary.mJoinedMemberCount ?? - controller.members - ?.where( - (member) => - member.membership == - Membership.join, - ) - .length ?? - 0, - ), - Membership.knock => - L10n.of(context).knocking, - Membership.leave => - L10n.of(context).leftTheChat, - }, - ), - selected: controller.membershipFilter == - availableFilters[i], - onSelected: (_) => - controller.setMembershipFilter( - availableFilters[i], - ), - ), - ), - ), - ), - ], - ); - } - i--; - return ParticipantListItem(members[i]); - }, - ), + ), + ], + ); + } + i--; + return ParticipantListItem(members[i]); + }, + ), ), ); } diff --git a/lib/pages/chat_permissions_settings/chat_permissions_settings.dart b/lib/pages/chat_permissions_settings/chat_permissions_settings.dart index cc24f2e1e..10aa9cfb5 100644 --- a/lib/pages/chat_permissions_settings/chat_permissions_settings.dart +++ b/lib/pages/chat_permissions_settings/chat_permissions_settings.dart @@ -38,9 +38,9 @@ class ChatPermissionsSettingsController extends State { }) async { final room = Matrix.of(context).client.getRoomById(roomId!)!; if (!room.canSendEvent(EventTypes.RoomPowerLevels)) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text(L10n.of(context).noPermission)), - ); + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text(L10n.of(context).noPermission))); return; } newLevel ??= await showPermissionChooser( @@ -72,12 +72,13 @@ class ChatPermissionsSettingsController extends State { } Stream get onChanged => Matrix.of(context).client.onSync.stream.where( - (e) => - (e.rooms?.join?.containsKey(roomId) ?? false) && - (e.rooms!.join![roomId!]?.timeline?.events - ?.any((s) => s.type == EventTypes.RoomPowerLevels) ?? - false), - ); + (e) => + (e.rooms?.join?.containsKey(roomId) ?? false) && + (e.rooms!.join![roomId!]?.timeline?.events?.any( + (s) => s.type == EventTypes.RoomPowerLevels, + ) ?? + false), + ); // #Pangea Map get defaultPowerLevels { @@ -96,10 +97,7 @@ class ChatPermissionsSettingsController extends State { return room.isSpace ? spacePowerLevels : chatPowerLevels; } - int getDefaultValue( - String permissionKey, { - String? category, - }) { + int getDefaultValue(String permissionKey, {String? category}) { final room = Matrix.of(context).client.getRoomById(roomId!); if (room == null) return 0; final powerLevelsContent = Map.from( diff --git a/lib/pages/chat_permissions_settings/chat_permissions_settings_view.dart b/lib/pages/chat_permissions_settings/chat_permissions_settings_view.dart index 64d2000bc..21c0e370c 100644 --- a/lib/pages/chat_permissions_settings/chat_permissions_settings_view.dart +++ b/lib/pages/chat_permissions_settings/chat_permissions_settings_view.dart @@ -65,11 +65,12 @@ class ChatPermissionsSettingsView extends StatelessWidget { (key, value) => MapEntry(key, controller.getDefaultValue(key)), ); - Map missingEventsPowerLevels = Map.from( - defaults.tryGetMap('events') ?? {}, - )..removeWhere( - (k, v) => v is! int || eventsPowerLevels.containsKey(k), - ); + Map missingEventsPowerLevels = + Map.from( + defaults.tryGetMap('events') ?? {}, + )..removeWhere( + (k, v) => v is! int || eventsPowerLevels.containsKey(k), + ); missingEventsPowerLevels = missingEventsPowerLevels.map( (key, value) => MapEntry( @@ -95,9 +96,7 @@ class ChatPermissionsSettingsView extends StatelessWidget { children: [ ListTile( leading: const Icon(Icons.info_outlined), - subtitle: Text( - L10n.of(context).chatPermissionsDescription, - ), + subtitle: Text(L10n.of(context).chatPermissionsDescription), ), Divider(color: theme.dividerColor), ListTile( @@ -113,7 +112,7 @@ class ChatPermissionsSettingsView extends StatelessWidget { ), ), Column( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ for (final entry in powerLevels.entries) PermissionsListTile( @@ -148,13 +147,13 @@ class ChatPermissionsSettingsView extends StatelessWidget { const key = 'rooms'; final value = powerLevelsContent.containsKey('notifications') - ? powerLevelsContent - .tryGetMap( - 'notifications', - ) - ?.tryGet('rooms') ?? - 0 - : 0; + ? powerLevelsContent + .tryGetMap( + 'notifications', + ) + ?.tryGet('rooms') ?? + 0 + : 0; return PermissionsListTile( permissionKey: key, permission: value, diff --git a/lib/pages/chat_permissions_settings/permission_list_tile.dart b/lib/pages/chat_permissions_settings/permission_list_tile.dart index d05f5de5a..bb61c5bb8 100644 --- a/lib/pages/chat_permissions_settings/permission_list_tile.dart +++ b/lib/pages/chat_permissions_settings/permission_list_tile.dart @@ -116,8 +116,8 @@ class PermissionsListTile extends StatelessWidget { final color = permission >= 100 ? Colors.orangeAccent : permission >= 50 - ? Colors.blueAccent - : Colors.greenAccent; + ? Colors.blueAccent + : Colors.greenAccent; return ListTile( title: Text( getLocalizedPowerLevelString(context), @@ -150,14 +150,12 @@ class PermissionsListTile extends StatelessWidget { DropdownMenuItem( value: permission >= 100 ? permission : 100, child: Text( - L10n.of(context) - .adminLevel(permission >= 100 ? permission : 100), + L10n.of( + context, + ).adminLevel(permission >= 100 ? permission : 100), ), ), - DropdownMenuItem( - value: null, - child: Text(L10n.of(context).custom), - ), + DropdownMenuItem(value: null, child: Text(L10n.of(context).custom)), ], ), ), diff --git a/lib/pages/chat_search/chat_search_files_tab.dart b/lib/pages/chat_search/chat_search_files_tab.dart index 81fdf5196..229cb6a6e 100644 --- a/lib/pages/chat_search/chat_search_files_tab.dart +++ b/lib/pages/chat_search/chat_search_files_tab.dart @@ -11,10 +11,8 @@ import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart'; class ChatSearchFilesTab extends StatelessWidget { final Room room; final Stream<(List, String?)>? searchStream; - final void Function({ - String? prevBatch, - List? previousSearchResult, - }) startSearch; + final void Function({String? prevBatch, List? previousSearchResult}) + startSearch; const ChatSearchFilesTab({ required this.room, @@ -32,15 +30,13 @@ class ChatSearchFilesTab extends StatelessWidget { final events = snapshot.data?.$1; if (searchStream == null || events == null) { return Column( - mainAxisAlignment: MainAxisAlignment.center, + mainAxisAlignment: .center, children: [ const CircularProgressIndicator.adaptive(strokeWidth: 2), const SizedBox(height: 8), Text( L10n.of(context).searchIn( - room.getLocalizedDisplayname( - MatrixLocals(L10n.of(context)), - ), + room.getLocalizedDisplayname(MatrixLocals(L10n.of(context))), ), ), ], @@ -49,7 +45,7 @@ class ChatSearchFilesTab extends StatelessWidget { if (events.isEmpty) { return Column( - mainAxisAlignment: MainAxisAlignment.center, + mainAxisAlignment: .center, children: [ const Icon(Icons.file_present_outlined, size: 64), const SizedBox(height: 8), @@ -68,9 +64,7 @@ class ChatSearchFilesTab extends StatelessWidget { return const Padding( padding: EdgeInsets.all(16.0), child: Center( - child: CircularProgressIndicator.adaptive( - strokeWidth: 2, - ), + child: CircularProgressIndicator.adaptive(strokeWidth: 2), ), ); } @@ -90,35 +84,35 @@ class ChatSearchFilesTab extends StatelessWidget { prevBatch: nextBatch, previousSearchResult: events, ), - icon: const Icon( - Icons.arrow_downward_outlined, - ), + icon: const Icon(Icons.arrow_downward_outlined), label: Text(L10n.of(context).searchMore), ), ), ); } final event = events[i]; - final filename = event.content.tryGet('filename') ?? + final filename = + event.content.tryGet('filename') ?? event.content.tryGet('body') ?? L10n.of(context).unknownEvent('File'); final filetype = (filename.contains('.') ? filename.split('.').last.toUpperCase() : event.content - .tryGetMap('info') - ?.tryGet('mimetype') - ?.toUpperCase() ?? - 'UNKNOWN'); + .tryGetMap('info') + ?.tryGet('mimetype') + ?.toUpperCase() ?? + 'UNKNOWN'); final sizeString = event.sizeString; final prevEvent = i > 0 ? events[i - 1] : null; final sameEnvironment = prevEvent == null ? false - : prevEvent.originServerTs - .sameEnvironment(event.originServerTs); + : prevEvent.originServerTs.sameEnvironment( + event.originServerTs, + ); return Padding( padding: const EdgeInsets.all(8.0), child: Column( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ if (!sameEnvironment) ...[ Row( @@ -148,8 +142,9 @@ class ChatSearchFilesTab extends StatelessWidget { const SizedBox(height: 4), ], Material( - borderRadius: - BorderRadius.circular(AppConfig.borderRadius), + borderRadius: BorderRadius.circular( + AppConfig.borderRadius, + ), color: theme.colorScheme.onInverseSurface, clipBehavior: Clip.hardEdge, child: ListTile( diff --git a/lib/pages/chat_search/chat_search_images_tab.dart b/lib/pages/chat_search/chat_search_images_tab.dart index 566e44cc1..ecd66a312 100644 --- a/lib/pages/chat_search/chat_search_images_tab.dart +++ b/lib/pages/chat_search/chat_search_images_tab.dart @@ -13,10 +13,8 @@ import 'package:fluffychat/widgets/mxc_image.dart'; class ChatSearchImagesTab extends StatelessWidget { final Room room; final Stream<(List, String?)>? searchStream; - final void Function({ - String? prevBatch, - List? previousSearchResult, - }) startSearch; + final void Function({String? prevBatch, List? previousSearchResult}) + startSearch; const ChatSearchImagesTab({ required this.room, @@ -35,15 +33,13 @@ class ChatSearchImagesTab extends StatelessWidget { final events = snapshot.data?.$1; if (searchStream == null || events == null) { return Column( - mainAxisAlignment: MainAxisAlignment.center, + mainAxisAlignment: .center, children: [ const CircularProgressIndicator.adaptive(strokeWidth: 2), const SizedBox(height: 8), Text( L10n.of(context).searchIn( - room.getLocalizedDisplayname( - MatrixLocals(L10n.of(context)), - ), + room.getLocalizedDisplayname(MatrixLocals(L10n.of(context))), ), ), ], @@ -51,7 +47,7 @@ class ChatSearchImagesTab extends StatelessWidget { } if (events.isEmpty) { return Column( - mainAxisAlignment: MainAxisAlignment.center, + mainAxisAlignment: .center, children: [ const Icon(Icons.photo_outlined, size: 64), const SizedBox(height: 8), @@ -80,9 +76,7 @@ class ChatSearchImagesTab extends StatelessWidget { return const Padding( padding: EdgeInsets.all(16.0), child: Center( - child: CircularProgressIndicator.adaptive( - strokeWidth: 2, - ), + child: CircularProgressIndicator.adaptive(strokeWidth: 2), ), ); } @@ -102,9 +96,7 @@ class ChatSearchImagesTab extends StatelessWidget { prevBatch: nextBatch, previousSearchResult: events, ), - icon: const Icon( - Icons.arrow_downward_outlined, - ), + icon: const Icon(Icons.arrow_downward_outlined), label: Text(L10n.of(context).searchMore), ), ), @@ -113,16 +105,13 @@ class ChatSearchImagesTab extends StatelessWidget { final monthEvents = eventsByMonthList[i].value; return Column( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ const SizedBox(height: 4), Row( children: [ Expanded( - child: Container( - height: 1, - color: theme.dividerColor, - ), + child: Container(height: 1, color: theme.dividerColor), ), Padding( padding: const EdgeInsets.all(8.0), @@ -135,10 +124,7 @@ class ChatSearchImagesTab extends StatelessWidget { ), ), Expanded( - child: Container( - height: 1, - color: theme.dividerColor, - ), + child: Container(height: 1, color: theme.dividerColor), ), ], ), @@ -150,39 +136,35 @@ class ChatSearchImagesTab extends StatelessWidget { clipBehavior: Clip.hardEdge, padding: const EdgeInsets.all(padding), crossAxisCount: 3, - children: monthEvents.map( - (event) { - if (event.messageType == MessageTypes.Video) { - return Material( - clipBehavior: Clip.hardEdge, - borderRadius: borderRadius, - child: EventVideoPlayer(event), - ); - } - return InkWell( - onTap: () => showDialog( - context: context, - builder: (_) => ImageViewer( - event, - outerContext: context, - ), - ), + children: monthEvents.map((event) { + if (event.messageType == MessageTypes.Video) { + return Material( + clipBehavior: Clip.hardEdge, borderRadius: borderRadius, - child: Material( - clipBehavior: Clip.hardEdge, - borderRadius: borderRadius, - child: MxcImage( - event: event, - width: 128, - height: 128, - fit: BoxFit.cover, - animated: true, - isThumbnail: true, - ), - ), + child: EventVideoPlayer(event), ); - }, - ).toList(), + } + return InkWell( + onTap: () => showDialog( + context: context, + builder: (_) => + ImageViewer(event, outerContext: context), + ), + borderRadius: borderRadius, + child: Material( + clipBehavior: Clip.hardEdge, + borderRadius: borderRadius, + child: MxcImage( + event: event, + width: 128, + height: 128, + fit: BoxFit.cover, + animated: true, + isThumbnail: true, + ), + ), + ); + }).toList(), ), ], ); diff --git a/lib/pages/chat_search/chat_search_message_tab.dart b/lib/pages/chat_search/chat_search_message_tab.dart index 5896b5943..c254791ae 100644 --- a/lib/pages/chat_search/chat_search_message_tab.dart +++ b/lib/pages/chat_search/chat_search_message_tab.dart @@ -14,10 +14,8 @@ class ChatSearchMessageTab extends StatelessWidget { final String searchQuery; final Room room; final Stream<(List, String?)>? searchStream; - final void Function({ - String? prevBatch, - List? previousSearchResult, - }) startSearch; + final void Function({String? prevBatch, List? previousSearchResult}) + startSearch; const ChatSearchMessageTab({ required this.searchQuery, @@ -36,15 +34,13 @@ class ChatSearchMessageTab extends StatelessWidget { final theme = Theme.of(context); if (searchStream == null) { return Column( - mainAxisAlignment: MainAxisAlignment.center, + mainAxisAlignment: .center, children: [ const Icon(Icons.search_outlined, size: 64), const SizedBox(height: 8), Text( L10n.of(context).searchIn( - room.getLocalizedDisplayname( - MatrixLocals(L10n.of(context)), - ), + room.getLocalizedDisplayname(MatrixLocals(L10n.of(context))), ), ), ], @@ -63,19 +59,15 @@ class ChatSearchMessageTab extends StatelessWidget { return SelectionArea( child: ListView.separated( itemCount: events.length + 1, - separatorBuilder: (context, _) => Divider( - color: theme.dividerColor, - height: 1, - ), + separatorBuilder: (context, _) => + Divider(color: theme.dividerColor, height: 1), itemBuilder: (context, i) { if (i == events.length) { if (snapshot.connectionState != ConnectionState.done) { return const Padding( padding: EdgeInsets.all(16.0), child: Center( - child: CircularProgressIndicator.adaptive( - strokeWidth: 2, - ), + child: CircularProgressIndicator.adaptive(strokeWidth: 2), ), ); } @@ -95,9 +87,7 @@ class ChatSearchMessageTab extends StatelessWidget { prevBatch: nextBatch, previousSearchResult: events, ), - icon: const Icon( - Icons.arrow_downward_outlined, - ), + icon: const Icon(Icons.arrow_downward_outlined), label: Text(L10n.of(context).searchMore), ), ), @@ -142,19 +132,18 @@ class _MessageSearchResultListTile extends StatelessWidget { return ListTile( title: Row( children: [ + // #Pangea + // Avatar(mxContent: sender.avatarUrl, name: displayname, size: 16), Avatar( mxContent: sender.avatarUrl, name: displayname, - // #Pangea userId: sender.id, - // Pangea# size: 16, ), + // Pangea# const SizedBox(width: 8), // #Pangea - // Text( - // displayname, - // ), + // Text(displayname), // Expanded( // child: Text( // ' | ${event.originServerTs.localizedTimeShort(context)}', @@ -188,24 +177,17 @@ class _MessageSearchResultListTile extends StatelessWidget { .calcLocalizedBodyFallback( plaintextBody: true, removeMarkdown: true, - MatrixLocals( - L10n.of(context), - ), + MatrixLocals(L10n.of(context)), ) .trim(), maxLines: 7, overflow: TextOverflow.ellipsis, ), trailing: IconButton( - icon: const Icon( - Icons.chevron_right_outlined, - ), + icon: const Icon(Icons.chevron_right_outlined), // #Pangea // onPressed: () => context.go( - // '/${Uri( - // pathSegments: ['rooms', room.id], - // queryParameters: {'event': event.eventId}, - // )}', + // '/${Uri(pathSegments: ['rooms', room.id], queryParameters: {'event': event.eventId})}', // ), onPressed: () => NavigationUtil.goToSpaceRoute( room.id, diff --git a/lib/pages/chat_search/chat_search_page.dart b/lib/pages/chat_search/chat_search_page.dart index f4a25e35d..353563d45 100644 --- a/lib/pages/chat_search/chat_search_page.dart +++ b/lib/pages/chat_search/chat_search_page.dart @@ -75,11 +75,10 @@ class ChatSearchController extends State .map( (result) => ( { - for (final event in result.$1) event.eventId: event, - // #Pangea - // }.values.toList(), - } - .values + for (final event in result.$1) event.eventId: event, + // #Pangea + // }.values.toList(), + }.values .toList() .where( (e) => !e.hasAggregatedEvents( diff --git a/lib/pages/chat_search/chat_search_view.dart b/lib/pages/chat_search/chat_search_view.dart index 8776582b4..fc55dc4cb 100644 --- a/lib/pages/chat_search/chat_search_view.dart +++ b/lib/pages/chat_search/chat_search_view.dart @@ -48,9 +48,7 @@ class ChatSearchView extends StatelessWidget { if (FluffyThemes.isThreeColumnMode(context)) const SizedBox(height: 16), Padding( - padding: const EdgeInsets.symmetric( - horizontal: 16, - ), + padding: const EdgeInsets.symmetric(horizontal: 16), child: TextField( controller: controller.searchController, onSubmitted: (_) => controller.restartSearch(), diff --git a/lib/pages/device_settings/device_settings.dart b/lib/pages/device_settings/device_settings.dart index 2114e999c..12c1d1fce 100644 --- a/lib/pages/device_settings/device_settings.dart +++ b/lib/pages/device_settings/device_settings.dart @@ -59,10 +59,7 @@ class DevicesSettingsController extends State { .tryGetMap('org.matrix.msc2965.authentication') ?.tryGet('account'); if (accountManageUrl != null) { - launchUrlString( - accountManageUrl, - mode: LaunchMode.inAppBrowserView, - ); + launchUrlString(accountManageUrl, mode: LaunchMode.inAppBrowserView); return; } if (await showOkCancelAlertDialog( @@ -86,10 +83,7 @@ class DevicesSettingsController extends State { context: context, delay: false, future: () => matrix.client.uiaRequestBackground( - (auth) => matrix.client.deleteDevices( - deviceIds, - auth: auth, - ), + (auth) => matrix.client.deleteDevices(deviceIds, auth: auth), ), ); reload(); @@ -106,9 +100,9 @@ class DevicesSettingsController extends State { if (displayName == null) return; final success = await showFutureLoadingDialog( context: context, - future: () => Matrix.of(context) - .client - .updateDevice(device.deviceId, displayName: displayName), + future: () => Matrix.of( + context, + ).client.updateDevice(device.deviceId, displayName: displayName), ); if (success.error == null) { reload(); @@ -130,8 +124,10 @@ class DevicesSettingsController extends State { .deviceKeys[device.deviceId]! .startVerification(); req.onUpdate = () { - if ({KeyVerificationState.error, KeyVerificationState.done} - .contains(req.state)) { + if ({ + KeyVerificationState.error, + KeyVerificationState.done, + }.contains(req.state)) { setState(() {}); } }; @@ -162,9 +158,7 @@ class DevicesSettingsController extends State { bool _isOwnDevice(Device userDevice) => userDevice.deviceId == Matrix.of(context).client.deviceID; - Device? get thisDevice => devices!.firstWhereOrNull( - _isOwnDevice, - ); + Device? get thisDevice => devices!.firstWhereOrNull(_isOwnDevice); List get notThisDevice => List.from(devices!) ..removeWhere(_isOwnDevice) diff --git a/lib/pages/device_settings/device_settings_view.dart b/lib/pages/device_settings/device_settings_view.dart index 74e190397..232ae06c9 100644 --- a/lib/pages/device_settings/device_settings_view.dart +++ b/lib/pages/device_settings/device_settings_view.dart @@ -27,7 +27,7 @@ class DevicesSettingsView extends StatelessWidget { if (snapshot.hasError) { return Center( child: Column( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ const Icon(Icons.error_outlined), Text(snapshot.error.toString()), @@ -47,7 +47,7 @@ class DevicesSettingsView extends StatelessWidget { itemBuilder: (BuildContext context, int i) { if (i == 0) { return Column( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ if (controller.chatBackupEnabled == false) Padding( @@ -57,8 +57,9 @@ class DevicesSettingsView extends StatelessWidget { child: Icon(Icons.info_outlined), ), subtitle: Text( - L10n.of(context) - .noticeChatBackupDeviceVerification, + L10n.of( + context, + ).noticeChatBackupDeviceVerification, ), ), ), diff --git a/lib/pages/device_settings/user_device_list_item.dart b/lib/pages/device_settings/user_device_list_item.dart index 02c915916..095a4335c 100644 --- a/lib/pages/device_settings/user_device_list_item.dart +++ b/lib/pages/device_settings/user_device_list_item.dart @@ -9,13 +9,7 @@ import '../../utils/date_time_extension.dart'; import '../../utils/matrix_sdk_extensions/device_extension.dart'; import '../../widgets/matrix.dart'; -enum UserDeviceListItemAction { - rename, - remove, - verify, - block, - unblock, -} +enum UserDeviceListItemAction { rename, remove, verify, block, unblock } class UserDeviceListItem extends StatelessWidget { final Device userDevice; @@ -38,7 +32,8 @@ class UserDeviceListItem extends StatelessWidget { @override Widget build(BuildContext context) { final client = Matrix.of(context).client; - final keys = client.userDeviceKeys[Matrix.of(context).client.userID] + final keys = client + .userDeviceKeys[Matrix.of(context).client.userID] ?.deviceKeys[userDevice.deviceId]; final isOwnDevice = userDevice.deviceId == client.deviceID; @@ -113,10 +108,10 @@ class UserDeviceListItem extends StatelessWidget { backgroundColor: keys == null ? Colors.grey[700] : keys.blocked - ? Colors.red - : keys.verified - ? Colors.green - : Colors.orange, + ? Colors.red + : keys.verified + ? Colors.green + : Colors.orange, child: Icon(userDevice.icon), ), title: Text( @@ -126,8 +121,9 @@ class UserDeviceListItem extends StatelessWidget { ), subtitle: Text( L10n.of(context).lastActiveAgo( - DateTime.fromMillisecondsSinceEpoch(userDevice.lastSeenTs ?? 0) - .localizedTimeShort(context), + DateTime.fromMillisecondsSinceEpoch( + userDevice.lastSeenTs ?? 0, + ).localizedTimeShort(context), ), style: const TextStyle(fontWeight: FontWeight.w300), ), @@ -137,14 +133,14 @@ class UserDeviceListItem extends StatelessWidget { keys.blocked ? L10n.of(context).blocked : keys.verified - ? L10n.of(context).verified - : L10n.of(context).unverified, + ? L10n.of(context).verified + : L10n.of(context).unverified, style: TextStyle( color: keys.blocked ? Colors.red : keys.verified - ? Colors.green - : Colors.orange, + ? Colors.green + : Colors.orange, ), ), ), diff --git a/lib/pages/dialer/dialer.dart b/lib/pages/dialer/dialer.dart index 8f314808b..d3cca97c1 100644 --- a/lib/pages/dialer/dialer.dart +++ b/lib/pages/dialer/dialer.dart @@ -70,9 +70,7 @@ class _StreamView extends StatelessWidget { @override Widget build(BuildContext context) { return Container( - decoration: const BoxDecoration( - color: Colors.black54, - ), + decoration: const BoxDecoration(color: Colors.black54), child: Stack( alignment: Alignment.center, children: [ @@ -133,9 +131,8 @@ class Calling extends StatefulWidget { class MyCallingPage extends State { Room? get room => call.room; - String get displayName => call.room.getLocalizedDisplayname( - MatrixLocals(L10n.of(widget.context)), - ); + String get displayName => + call.room.getLocalizedDisplayname(MatrixLocals(L10n.of(widget.context))); String get callId => widget.callId; @@ -219,10 +216,7 @@ class MyCallingPage extends State { } void cleanUp() { - Timer( - const Duration(seconds: 2), - () => widget.onClear?.call(), - ); + Timer(const Duration(seconds: 2), () => widget.onClear?.call()); if (call.type == CallType.kVideo) { try { unawaited(WakelockPlus.disable()); @@ -295,8 +289,9 @@ class MyCallingPage extends State { androidNotificationOptions: AndroidNotificationOptions( channelId: 'notification_channel_id', channelName: 'Foreground Notification', - channelDescription: - L10n.of(widget.context).foregroundServiceRunning, + channelDescription: L10n.of( + widget.context, + ).foregroundServiceRunning, ), iosNotificationOptions: const IOSNotificationOptions(), foregroundTaskOptions: ForegroundTaskOptions( @@ -434,9 +429,7 @@ class MyCallingPage extends State { hangupButton, ]; case CallState.kEnded: - return [ - hangupButton, - ]; + return [hangupButton]; case CallState.kFledgling: case CallState.kWaitLocalMedia: case CallState.kCreateOffer: @@ -458,28 +451,20 @@ class MyCallingPage extends State { if (call.localHold || call.remoteOnHold) { var title = ''; if (call.localHold) { - title = '${call.room.getLocalizedDisplayname( - MatrixLocals(L10n.of(widget.context)), - )} held the call.'; + title = + '${call.room.getLocalizedDisplayname(MatrixLocals(L10n.of(widget.context)))} held the call.'; } else if (call.remoteOnHold) { title = 'You held the call.'; } stackWidgets.add( Center( child: Column( - mainAxisAlignment: MainAxisAlignment.center, + mainAxisAlignment: .center, children: [ - const Icon( - Icons.pause, - size: 48.0, - color: Colors.white, - ), + const Icon(Icons.pause, size: 48.0, color: Colors.white), Text( title, - style: const TextStyle( - color: Colors.white, - fontSize: 24.0, - ), + style: const TextStyle(color: Colors.white, fontSize: 24.0), ), ], ), @@ -488,7 +473,8 @@ class MyCallingPage extends State { return stackWidgets; } - var primaryStream = call.remoteScreenSharingStream ?? + var primaryStream = + call.remoteScreenSharingStream ?? call.localScreenSharingStream ?? call.remoteUserMediaStream ?? call.localUserMediaStream; @@ -527,8 +513,10 @@ class MyCallingPage extends State { SizedBox( width: _localVideoWidth, height: _localVideoHeight, - child: - _StreamView(remoteUserMediaStream!, matrixClient: widget.client), + child: _StreamView( + remoteUserMediaStream!, + matrixClient: widget.client, + ), ), ); secondaryStreamViews.add(const SizedBox(height: 10)); @@ -569,9 +557,7 @@ class MyCallingPage extends State { child: Container( width: _localVideoWidth, margin: _localVideoMargin, - child: Column( - children: secondaryStreamViews, - ), + child: Column(children: secondaryStreamViews), ), ), ); @@ -592,16 +578,14 @@ class MyCallingPage extends State { width: 320.0, height: 150.0, child: Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, + mainAxisAlignment: .spaceAround, children: _buildActionButtons(isFloating), ), ), body: OrientationBuilder( builder: (BuildContext context, Orientation orientation) { return Container( - decoration: const BoxDecoration( - color: Colors.black87, - ), + decoration: const BoxDecoration(color: Colors.black87), child: Stack( children: [ ..._buildContent(orientation, isFloating), diff --git a/lib/pages/dialer/pip/pip_view.dart b/lib/pages/dialer/pip/pip_view.dart index d8ad23f4c..1cf1e5ecc 100644 --- a/lib/pages/dialer/pip/pip_view.dart +++ b/lib/pages/dialer/pip/pip_view.dart @@ -9,10 +9,7 @@ class PIPView extends StatefulWidget { final double? floatingHeight; final bool avoidKeyboard; - final Widget Function( - BuildContext context, - bool isFloating, - ) builder; + final Widget Function(BuildContext context, bool isFloating) builder; const PIPView({ super.key, @@ -95,10 +92,7 @@ class PIPViewState extends State with TickerProviderStateMixin { void _onPanUpdate(DragUpdateDetails details) { if (!_isDragging) return; setState(() { - _dragOffset = _dragOffset.translate( - details.delta.dx, - details.delta.dy, - ); + _dragOffset = _dragOffset.translate(details.delta.dx, details.delta.dy); }); } @@ -182,9 +176,7 @@ class PIPViewState extends State with TickerProviderStateMixin { _dragAnimationController, ]), builder: (context, child) { - final animationCurve = CurveTween( - curve: Curves.easeInOutQuad, - ); + final animationCurve = CurveTween(curve: Curves.easeInOutQuad); final dragAnimationValue = animationCurve.transform( _dragAnimationController.value, ); @@ -265,21 +257,13 @@ class PIPViewState extends State with TickerProviderStateMixin { } } -enum PIPViewCorner { - topLeft, - topRight, - bottomLeft, - bottomRight, -} +enum PIPViewCorner { topLeft, topRight, bottomLeft, bottomRight } class _CornerDistance { final PIPViewCorner corner; final double distance; - _CornerDistance({ - required this.corner, - required this.distance, - }); + _CornerDistance({required this.corner, required this.distance}); } PIPViewCorner _calculateNearestCorner({ @@ -288,15 +272,9 @@ PIPViewCorner _calculateNearestCorner({ }) { _CornerDistance calculateDistance(PIPViewCorner corner) { final distance = offsets[corner]! - .translate( - -offset.dx, - -offset.dy, - ) + .translate(-offset.dx, -offset.dy) .distanceSquared; - return _CornerDistance( - corner: corner, - distance: distance, - ); + return _CornerDistance(corner: corner, distance: distance); } final distances = PIPViewCorner.values.map(calculateDistance).toList(); diff --git a/lib/pages/homeserver_picker/homeserver_picker.dart b/lib/pages/homeserver_picker/homeserver_picker.dart index 1a11bdfb0..9a85951ce 100644 --- a/lib/pages/homeserver_picker/homeserver_picker.dart +++ b/lib/pages/homeserver_picker/homeserver_picker.dart @@ -44,8 +44,10 @@ class HomeserverPickerController extends State { /// well-known information and forwards to the login page depending on the /// login type. Future checkHomeserverAction({bool legacyPasswordLogin = false}) async { - final homeserverInput = - homeserverController.text.trim().toLowerCase().replaceAll(' ', '-'); + final homeserverInput = homeserverController.text + .trim() + .toLowerCase() + .replaceAll(' ', '-'); if (homeserverInput.isEmpty) { final client = await Matrix.of(context).getLoginClient(); @@ -115,14 +117,12 @@ class HomeserverPickerController extends State { void ssoLoginAction() async { final redirectUrl = kIsWeb - ? Uri.parse(html.window.location.href) - .resolveUri( - Uri(pathSegments: ['auth.html']), - ) - .toString() + ? Uri.parse( + html.window.location.href, + ).resolveUri(Uri(pathSegments: ['auth.html'])).toString() : isDefaultPlatform - ? '${AppConfig.appOpenUrlScheme.toLowerCase()}://login' - : 'http://localhost:3001//login'; + ? '${AppConfig.appOpenUrlScheme.toLowerCase()}://login' + : 'http://localhost:3001//login'; final client = await Matrix.of(context).getLoginClient(); final url = client.homeserver!.replace( path: '/_matrix/client/v3/login/sso/redirect', diff --git a/lib/pages/homeserver_picker/homeserver_picker_view.dart b/lib/pages/homeserver_picker/homeserver_picker_view.dart index dc411f738..48f581ade 100644 --- a/lib/pages/homeserver_picker/homeserver_picker_view.dart +++ b/lib/pages/homeserver_picker/homeserver_picker_view.dart @@ -14,18 +14,16 @@ import 'homeserver_picker.dart'; class HomeserverPickerView extends StatelessWidget { final HomeserverPickerController controller; - const HomeserverPickerView( - this.controller, { - super.key, - }); + const HomeserverPickerView(this.controller, {super.key}); @override Widget build(BuildContext context) { final theme = Theme.of(context); return LoginScaffold( - enforceMobileMode: - Matrix.of(context).widget.clients.any((client) => client.isLogged()), + enforceMobileMode: Matrix.of( + context, + ).widget.clients.any((client) => client.isLogged()), appBar: AppBar( centerTitle: true, title: Text( @@ -41,7 +39,7 @@ class HomeserverPickerView extends StatelessWidget { PopupMenuItem( value: MoreLoginActions.importBackup, child: Row( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ const Icon(Icons.import_export_outlined), const SizedBox(width: 12), @@ -52,7 +50,7 @@ class HomeserverPickerView extends StatelessWidget { PopupMenuItem( value: MoreLoginActions.privacy, child: Row( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ const Icon(Icons.privacy_tip_outlined), const SizedBox(width: 12), @@ -63,7 +61,7 @@ class HomeserverPickerView extends StatelessWidget { PopupMenuItem( value: MoreLoginActions.about, child: Row( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ const Icon(Icons.info_outlined), const SizedBox(width: 12), @@ -99,8 +97,9 @@ class HomeserverPickerView extends StatelessWidget { padding: const EdgeInsets.symmetric(horizontal: 32.0), child: SelectableLinkify( text: L10n.of(context).appIntroduction, - textScaleFactor: - MediaQuery.textScalerOf(context).scale(1), + textScaleFactor: MediaQuery.textScalerOf( + context, + ).scale(1), textAlign: TextAlign.center, linkStyle: TextStyle( color: theme.colorScheme.secondary, @@ -113,8 +112,8 @@ class HomeserverPickerView extends StatelessWidget { Padding( padding: const EdgeInsets.all(32.0), child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisSize: .min, + crossAxisAlignment: .stretch, children: [ TextField( onSubmitted: (_) => @@ -146,11 +145,13 @@ class HomeserverPickerView extends StatelessWidget { L10n.of(context).whatIsAHomeserver, ), content: Linkify( - text: L10n.of(context) - .homeserverDescription, + text: L10n.of( + context, + ).homeserverDescription, textScaleFactor: - MediaQuery.textScalerOf(context) - .scale(1), + MediaQuery.textScalerOf( + context, + ).scale(1), options: const LinkifyOptions( humanize: false, ), @@ -168,8 +169,9 @@ class HomeserverPickerView extends StatelessWidget { Uri.https('servers.joinmatrix.org'), ), child: Text( - L10n.of(context) - .discoverHomeservers, + L10n.of( + context, + ).discoverHomeservers, ), ), AdaptiveDialogAction( @@ -205,8 +207,8 @@ class HomeserverPickerView extends StatelessWidget { onPressed: controller.isLoading ? null : () => controller.checkHomeserverAction( - legacyPasswordLogin: true, - ), + legacyPasswordLogin: true, + ), child: Text(L10n.of(context).loginWithMatrixId), ), ], diff --git a/lib/pages/image_viewer/image_viewer.dart b/lib/pages/image_viewer/image_viewer.dart index 3ae3410a1..1dba46b28 100644 --- a/lib/pages/image_viewer/image_viewer.dart +++ b/lib/pages/image_viewer/image_viewer.dart @@ -32,7 +32,8 @@ class ImageViewerController extends State { @override void initState() { super.initState(); - allEvents = widget.timeline?.events + allEvents = + widget.timeline?.events .where( (event) => { MessageTypes.Image, @@ -44,8 +45,9 @@ class ImageViewerController extends State { .reversed .toList() ?? [widget.event]; - var index = - allEvents.indexWhere((event) => event.eventId == widget.event.eventId); + var index = allEvents.indexWhere( + (event) => event.eventId == widget.event.eventId, + ); if (index < 0) index = 0; pageController = PageController(initialPage: index); } @@ -93,11 +95,10 @@ class ImageViewerController extends State { /// Forward this image to another room. void forwardAction() => showScaffoldDialog( - context: context, - builder: (context) => ShareScaffoldDialog( - items: [ContentShareItem(currentEvent.content)], - ), - ); + context: context, + builder: (context) => + ShareScaffoldDialog(items: [ContentShareItem(currentEvent.content)]), + ); /// Save this file with a system call. void saveFileAction(BuildContext context) => currentEvent.saveFile(context); diff --git a/lib/pages/image_viewer/image_viewer_view.dart b/lib/pages/image_viewer/image_viewer_view.dart index f6cfa96f2..7eb529494 100644 --- a/lib/pages/image_viewer/image_viewer_view.dart +++ b/lib/pages/image_viewer/image_viewer_view.dart @@ -124,7 +124,7 @@ class ImageViewerView extends StatelessWidget { Align( alignment: Alignment.centerRight, child: Column( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ if (controller.canGoBack) Padding( diff --git a/lib/pages/image_viewer/video_player.dart b/lib/pages/image_viewer/video_player.dart index beb2e9c5b..4140f41d0 100644 --- a/lib/pages/image_viewer/video_player.dart +++ b/lib/pages/image_viewer/video_player.dart @@ -20,10 +20,7 @@ import '../../widgets/mxc_image.dart'; class EventVideoPlayer extends StatefulWidget { final Event event; - const EventVideoPlayer( - this.event, { - super.key, - }); + const EventVideoPlayer(this.event, {super.key}); @override EventVideoPlayerState createState() => EventVideoPlayerState(); @@ -71,8 +68,9 @@ class EventVideoPlayerState extends State { : (progress) { final progressPercentage = progress / fileSize; setState(() { - _downloadProgress = - progressPercentage < 1 ? progressPercentage : null; + _downloadProgress = progressPercentage < 1 + ? progressPercentage + : null; }); }, ); @@ -117,11 +115,9 @@ class EventVideoPlayerState extends State { ); }); } on IOException catch (e) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(e.toLocalizedString(context)), - ), - ); + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text(e.toLocalizedString(context)))); // #Pangea setState(() => _error = e); // Pangea# @@ -159,8 +155,10 @@ class EventVideoPlayerState extends State { @override Widget build(BuildContext context) { final hasThumbnail = widget.event.hasThumbnail; - final blurHash = (widget.event.infoMap as Map) - .tryGet('xyz.amorgan.blurhash') ?? + final blurHash = + (widget.event.infoMap as Map).tryGet( + 'xyz.amorgan.blurhash', + ) ?? fallbackBlurHash; final infoMap = widget.event.content.tryGetMap('info'); final videoWidth = infoMap?.tryGet('w') ?? 400; diff --git a/lib/pages/invitation_selection/invitation_selection.dart b/lib/pages/invitation_selection/invitation_selection.dart index 0c0d27fe5..1701a1a0f 100644 --- a/lib/pages/invitation_selection/invitation_selection.dart +++ b/lib/pages/invitation_selection/invitation_selection.dart @@ -12,10 +12,7 @@ import '../../utils/localized_exception_extension.dart'; class InvitationSelection extends StatefulWidget { final String roomId; - const InvitationSelection({ - super.key, - required this.roomId, - }); + const InvitationSelection({super.key, required this.roomId}); @override InvitationSelectionController createState() => @@ -47,8 +44,8 @@ class InvitationSelectionController extends State { .toList(); contacts.sort( (a, b) => a.calcDisplayname().toLowerCase().compareTo( - b.calcDisplayname().toLowerCase(), - ), + b.calcDisplayname().toLowerCase(), + ), ); return contacts; } @@ -91,9 +88,9 @@ class InvitationSelectionController extends State { try { response = await matrix.client.searchUserDirectory(text, limit: 10); } catch (e) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text((e).toLocalizedString(context))), - ); + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text((e).toLocalizedString(context)))); return; } finally { setState(() => loading = false); diff --git a/lib/pages/invitation_selection/invitation_selection_view.dart b/lib/pages/invitation_selection/invitation_selection_view.dart index f4a84d5c8..4db33841f 100644 --- a/lib/pages/invitation_selection/invitation_selection_view.dart +++ b/lib/pages/invitation_selection/invitation_selection_view.dart @@ -16,13 +16,12 @@ class InvitationSelectionView extends StatelessWidget { @override Widget build(BuildContext context) { - final room = - Matrix.of(context).client.getRoomById(controller.widget.roomId); + final room = Matrix.of( + context, + ).client.getRoomById(controller.widget.roomId); if (room == null) { return Scaffold( - appBar: AppBar( - title: Text(L10n.of(context).oopsSomethingWentWrong), - ), + appBar: AppBar(title: Text(L10n.of(context).oopsSomethingWentWrong)), body: Center( child: Text(L10n.of(context).youAreNoLongerParticipatingInThisChat), ), @@ -76,11 +75,14 @@ class InvitationSelectionView extends StatelessWidget { ), ), StreamBuilder( - stream: room.client.onRoomState.stream - .where((update) => update.roomId == room.id), + stream: room.client.onRoomState.stream.where( + (update) => update.roomId == room.id, + ), builder: (context, snapshot) { - final participants = - room.getParticipants().map((user) => user.id).toSet(); + final participants = room + .getParticipants() + .map((user) => user.id) + .toSet(); return controller.foundProfiles.isNotEmpty ? ListView.builder( physics: const NeverScrollableScrollPhysics(), @@ -88,17 +90,21 @@ class InvitationSelectionView extends StatelessWidget { itemCount: controller.foundProfiles.length, itemBuilder: (BuildContext context, int i) => _InviteContactListTile( - profile: controller.foundProfiles[i], - isMember: participants - .contains(controller.foundProfiles[i].userId), - onTap: () => controller.inviteAction( - context, - controller.foundProfiles[i].userId, - controller.foundProfiles[i].displayName ?? - controller.foundProfiles[i].userId.localpart ?? - L10n.of(context).user, - ), - ), + profile: controller.foundProfiles[i], + isMember: participants.contains( + controller.foundProfiles[i].userId, + ), + onTap: () => controller.inviteAction( + context, + controller.foundProfiles[i].userId, + controller.foundProfiles[i].displayName ?? + controller + .foundProfiles[i] + .userId + .localpart ?? + L10n.of(context).user, + ), + ), ) : FutureBuilder>( future: controller.getContacts(context), @@ -117,23 +123,26 @@ class InvitationSelectionView extends StatelessWidget { itemCount: contacts.length, itemBuilder: (BuildContext context, int i) => _InviteContactListTile( - user: contacts[i], - profile: Profile( - avatarUrl: contacts[i].avatarUrl, - displayName: contacts[i].displayName ?? - contacts[i].id.localpart ?? - L10n.of(context).user, - userId: contacts[i].id, - ), - isMember: participants.contains(contacts[i].id), - onTap: () => controller.inviteAction( - context, - contacts[i].id, - contacts[i].displayName ?? - contacts[i].id.localpart ?? - L10n.of(context).user, - ), - ), + user: contacts[i], + profile: Profile( + avatarUrl: contacts[i].avatarUrl, + displayName: + contacts[i].displayName ?? + contacts[i].id.localpart ?? + L10n.of(context).user, + userId: contacts[i].id, + ), + isMember: participants.contains( + contacts[i].id, + ), + onTap: () => controller.inviteAction( + context, + contacts[i].id, + contacts[i].displayName ?? + contacts[i].id.localpart ?? + L10n.of(context).user, + ), + ), ); }, ); @@ -169,10 +178,7 @@ class _InviteContactListTile extends StatelessWidget { mxContent: profile.avatarUrl, name: profile.displayName, presenceUserId: profile.userId, - onTap: () => UserDialog.show( - context: context, - profile: profile, - ), + onTap: () => UserDialog.show(context: context, profile: profile), ), title: Text( profile.displayName ?? profile.userId.localpart ?? l10n.user, @@ -183,9 +189,7 @@ class _InviteContactListTile extends StatelessWidget { profile.userId, maxLines: 1, overflow: TextOverflow.ellipsis, - style: TextStyle( - color: theme.colorScheme.secondary, - ), + style: TextStyle(color: theme.colorScheme.secondary), ), trailing: TextButton.icon( onPressed: isMember ? null : onTap, diff --git a/lib/pages/key_verification/key_verification_dialog.dart b/lib/pages/key_verification/key_verification_dialog.dart index 3562163c2..10121f9b9 100644 --- a/lib/pages/key_verification/key_verification_dialog.dart +++ b/lib/pages/key_verification/key_verification_dialog.dart @@ -15,17 +15,14 @@ import 'package:fluffychat/widgets/future_loading_dialog.dart'; class KeyVerificationDialog extends StatefulWidget { Future show(BuildContext context) => showAdaptiveDialog( - context: context, - builder: (context) => this, - barrierDismissible: false, - ); + context: context, + builder: (context) => this, + barrierDismissible: false, + ); final KeyVerification request; - const KeyVerificationDialog({ - super.key, - required this.request, - }); + const KeyVerificationDialog({super.key, required this.request}); @override KeyVerificationPageState createState() => KeyVerificationPageState(); @@ -57,8 +54,10 @@ class KeyVerificationPageState extends State { void dispose() { widget.request.onUpdate = originalOnUpdate; // don't want to get updates anymore - if (![KeyVerificationState.error, KeyVerificationState.done] - .contains(widget.request.state)) { + if (![ + KeyVerificationState.error, + KeyVerificationState.done, + ].contains(widget.request.state)) { widget.request.cancel('m.user'); } super.dispose(); @@ -98,8 +97,9 @@ class KeyVerificationPageState extends State { final theme = Theme.of(context); User? user; - final directChatId = - widget.request.client.getDirectChatFromUserId(widget.request.userId); + final directChatId = widget.request.client.getDirectChatFromUserId( + widget.request.userId, + ); if (directChatId != null) { user = widget.request.client .getRoomById(directChatId)! @@ -122,7 +122,7 @@ class KeyVerificationPageState extends State { body = Container( margin: const EdgeInsets.only(left: 8.0, right: 8.0), child: Column( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ Text( L10n.of(context).askSSSSSign, @@ -152,17 +152,13 @@ class KeyVerificationPageState extends State { ); buttons.add( AdaptiveDialogAction( - child: Text( - L10n.of(context).submit, - ), + child: Text(L10n.of(context).submit), onPressed: () => checkInput(textEditingController.text), ), ); buttons.add( AdaptiveDialogAction( - child: Text( - L10n.of(context).skip, - ), + child: Text(L10n.of(context).skip), onPressed: () => widget.request.openSSSS(skip: true), ), ); @@ -170,7 +166,7 @@ class KeyVerificationPageState extends State { case KeyVerificationState.askAccept: title = Text(L10n.of(context).newVerificationRequest); body = Column( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ const SizedBox(height: 16), Avatar( @@ -179,16 +175,14 @@ class KeyVerificationPageState extends State { size: Avatar.defaultSize * 2, ), const SizedBox(height: 16), - Text( - L10n.of(context).askVerificationRequest(displayName), - ), + Text(L10n.of(context).askVerificationRequest(displayName)), ], ); buttons.add( AdaptiveDialogAction( onPressed: () => widget.request.rejectVerification().then( - (_) => Navigator.of(context, rootNavigator: false).pop(false), - ), + (_) => Navigator.of(context, rootNavigator: false).pop(false), + ), child: Text( L10n.of(context).reject, style: TextStyle(color: theme.colorScheme.error), @@ -211,10 +205,7 @@ class KeyVerificationPageState extends State { Stack( alignment: Alignment.center, children: [ - Avatar( - mxContent: user?.avatarUrl, - name: displayName, - ), + Avatar(mxContent: user?.avatarUrl, name: displayName), const SizedBox( width: Avatar.defaultSize + 2, height: Avatar.defaultSize + 2, @@ -258,16 +249,15 @@ class KeyVerificationPageState extends State { title = Text(L10n.of(context).compareNumbersMatch); final numbers = widget.request.sasNumbers; final numbstr = '${numbers[0]}-${numbers[1]}-${numbers[2]}'; - compareWidget = - TextSpan(text: numbstr, style: const TextStyle(fontSize: 40)); + compareWidget = TextSpan( + text: numbstr, + style: const TextStyle(fontSize: 40), + ); } body = Column( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ - Text.rich( - compareWidget, - textAlign: TextAlign.center, - ), + Text.rich(compareWidget, textAlign: TextAlign.center), ], ); buttons.add( @@ -291,15 +281,12 @@ class KeyVerificationPageState extends State { ? L10n.of(context).waitingPartnerEmoji : L10n.of(context).waitingPartnerNumbers; body = Column( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ const SizedBox(height: 16), const CircularProgressIndicator.adaptive(strokeWidth: 2), const SizedBox(height: 16), - Text( - acceptText, - textAlign: TextAlign.center, - ), + Text(acceptText, textAlign: TextAlign.center), ], ); break; @@ -315,9 +302,7 @@ class KeyVerificationPageState extends State { ); buttons.add( AdaptiveDialogAction( - child: Text( - L10n.of(context).close, - ), + child: Text(L10n.of(context).close), onPressed: () => Navigator.of(context, rootNavigator: false).pop(true), ), @@ -326,7 +311,7 @@ class KeyVerificationPageState extends State { case KeyVerificationState.error: title = const Text(''); body = Column( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ const SizedBox(height: 16), Icon(Icons.cancel, color: theme.colorScheme.error, size: 64.0), @@ -340,9 +325,7 @@ class KeyVerificationPageState extends State { ); buttons.add( AdaptiveDialogAction( - child: Text( - L10n.of(context).close, - ), + child: Text(L10n.of(context).close), onPressed: () => Navigator.of(context, rootNavigator: false).pop(false), ), @@ -355,9 +338,7 @@ class KeyVerificationPageState extends State { content: SizedBox( height: 256, width: 256, - child: ListView( - children: [body], - ), + child: ListView(children: [body]), ), actions: buttons, ); @@ -399,7 +380,7 @@ class _Emoji extends StatelessWidget { @override Widget build(BuildContext context) { return Column( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ Text(emoji.emoji, style: const TextStyle(fontSize: 50)), Padding( diff --git a/lib/pages/login/login.dart b/lib/pages/login/login.dart index 1354566fc..c80612e77 100644 --- a/lib/pages/login/login.dart +++ b/lib/pages/login/login.dart @@ -20,10 +20,7 @@ class Login extends StatefulWidget { // const Login({required this.client, super.key}); final bool withEmail; - const Login({ - super.key, - this.withEmail = false, - }); + const Login({super.key, this.withEmail = false}); // Pangea# @override @@ -58,22 +55,24 @@ class LoginController extends State { // TODO: implement initState super.initState(); loadingSignIn = true; - checkHomeServerAction().then((client) { - if (mounted) { - setState(() { - loadingSignIn = false; - this.client = client; + checkHomeServerAction() + .then((client) { + if (mounted) { + setState(() { + loadingSignIn = false; + this.client = client; + }); + } + }) + .catchError((e) { + final String err = e.toString(); + if (mounted) { + setState(() { + loadingSignIn = false; + passwordError = err.toLocalizedString(context); + }); + } }); - } - }).catchError((e) { - final String err = e.toString(); - if (mounted) { - setState(() { - loadingSignIn = false; - passwordError = err.toLocalizedString(context); - }); - } - }); usernameController.addListener(() => setState(() {})); passwordController.addListener(() => setState(() {})); @@ -194,8 +193,9 @@ class LoginController extends State { // final dialogResult = await showOkCancelAlertDialog( // context: context, // useRootNavigator: false, - // title: L10n.of(context) - // .noMatrixServer(newDomain.toString(), oldHomeserver.toString()), + // title: L10n.of( + // context, + // ).noMatrixServer(newDomain.toString(), oldHomeserver.toString()), // okLabel: L10n.of(context).ok, // cancelLabel: L10n.of(context).cancel, // ); @@ -228,8 +228,10 @@ class LoginController extends State { return client; } - final String homeServer = - AppConfig.defaultHomeserver.trim().toLowerCase().replaceAll(' ', '-'); + final String homeServer = AppConfig.defaultHomeserver + .trim() + .toLowerCase() + .replaceAll(' ', '-'); var homeserver = Uri.parse(homeServer); if (homeserver.scheme.isEmpty) { homeserver = Uri.https(homeServer, ''); @@ -257,8 +259,9 @@ class LoginController extends State { message: L10n.of(context).enterAnEmailAddress, okLabel: L10n.of(context).ok, cancelLabel: L10n.of(context).cancel, - initialText: - usernameController.text.isEmail ? usernameController.text : '', + initialText: usernameController.text.isEmail + ? usernameController.text + : '', hintText: L10n.of(context).enterAnEmailAddress, keyboardType: TextInputType.emailAddress, ); @@ -366,9 +369,10 @@ class LoginController extends State { // #Pangea // extension on String { extension LoginExtension on String { -// Pangea# - static final RegExp _phoneRegex = - RegExp(r'^[+]*[(]{0,1}[0-9]{1,4}[)]{0,1}[-\s\./0-9]*$'); + // Pangea# + static final RegExp _phoneRegex = RegExp( + r'^[+]*[(]{0,1}[0-9]{1,4}[)]{0,1}[-\s\./0-9]*$', + ); static final RegExp _emailRegex = RegExp(r'(.+)@(.+)\.(.+)'); bool get isEmail => _emailRegex.hasMatch(this); diff --git a/lib/pages/login/login_view.dart b/lib/pages/login/login_view.dart index 7904e545f..1c2bc5a43 100644 --- a/lib/pages/login/login_view.dart +++ b/lib/pages/login/login_view.dart @@ -21,13 +21,13 @@ // final titleParts = title.split(homeserver); // return LoginScaffold( -// enforceMobileMode: -// Matrix.of(context).widget.clients.any((client) => client.isLogged()), +// enforceMobileMode: Matrix.of( +// context, +// ).widget.clients.any((client) => client.isLogged()), // appBar: AppBar( -// leading: -// controller.loadingSignIn ? null : const Center(child: BackButton()), -// automaticallyImplyLeading: !controller.loadingSignIn, -// titleSpacing: !controller.loadingSignIn ? 0 : null, +// leading: controller.loading ? null : const Center(child: BackButton()), +// automaticallyImplyLeading: !controller.loading, +// titleSpacing: !controller.loading ? 0 : null, // title: Text.rich( // TextSpan( // children: [ @@ -56,14 +56,14 @@ // Padding( // padding: const EdgeInsets.symmetric(horizontal: 24.0), // child: TextField( -// readOnly: controller.loadingSignIn, +// readOnly: controller.loading, // autocorrect: false, // autofocus: true, // onChanged: controller.checkWellKnownWithCoolDown, // controller: controller.usernameController, // textInputAction: TextInputAction.next, // keyboardType: TextInputType.emailAddress, -// autofillHints: controller.loadingSignIn +// autofillHints: controller.loading // ? null // : [AutofillHints.username], // decoration: InputDecoration( @@ -79,9 +79,9 @@ // Padding( // padding: const EdgeInsets.symmetric(horizontal: 24.0), // child: TextField( -// readOnly: controller.loadingSignIn, +// readOnly: controller.loading, // autocorrect: false, -// autofillHints: controller.loadingSignIn +// autofillHints: controller.loading // ? null // : [AutofillHints.password], // controller: controller.passwordController, @@ -114,9 +114,8 @@ // backgroundColor: theme.colorScheme.primary, // foregroundColor: theme.colorScheme.onPrimary, // ), -// onPressed: -// controller.loadingSignIn ? null : controller.login, -// child: controller.loadingSignIn +// onPressed: controller.loading ? null : controller.login, +// child: controller.loading // ? const LinearProgressIndicator() // : Text(L10n.of(context).login), // ), @@ -125,7 +124,7 @@ // Padding( // padding: const EdgeInsets.symmetric(horizontal: 24.0), // child: TextButton( -// onPressed: controller.loadingSignIn +// onPressed: controller.loading // ? () {} // : controller.passwordForgotten, // style: TextButton.styleFrom( diff --git a/lib/pages/new_group/new_group.dart b/lib/pages/new_group/new_group.dart index 0de58fbe0..f34d0b43a 100644 --- a/lib/pages/new_group/new_group.dart +++ b/lib/pages/new_group/new_group.dart @@ -8,27 +8,12 @@ import 'package:matrix/matrix.dart'; import 'package:fluffychat/l10n/l10n.dart'; import 'package:fluffychat/pages/new_group/new_group_view.dart'; -import 'package:fluffychat/pangea/chat/constants/default_power_level.dart'; -import 'package:fluffychat/pangea/common/utils/error_handler.dart'; -import 'package:fluffychat/pangea/common/utils/firebase_analytics.dart'; -import 'package:fluffychat/pangea/extensions/join_rule_extension.dart'; -import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart'; -import 'package:fluffychat/pangea/spaces/client_spaces_extension.dart'; import 'package:fluffychat/utils/file_selector.dart'; import 'package:fluffychat/widgets/matrix.dart'; class NewGroup extends StatefulWidget { - // #Pangea - final String? spaceId; - // Pangea# final CreateGroupType createGroupType; - const NewGroup({ - // #Pangea - this.spaceId, - // Pangea# - this.createGroupType = CreateGroupType.group, - super.key, - }); + const NewGroup({this.createGroupType = CreateGroupType.group, super.key}); @override NewGroupController createState() => NewGroupController(); @@ -37,14 +22,8 @@ class NewGroup extends StatefulWidget { class NewGroupController extends State { TextEditingController nameController = TextEditingController(); - // #Pangea - // bool publicGroup = false; - // bool groupCanBeFound = false; - final GlobalKey formKey = GlobalKey(); - final FocusNode focusNode = FocusNode(); - - bool get canSubmit => nameController.text.trim().isNotEmpty; - // Pangea# + bool publicGroup = false; + bool groupCanBeFound = false; Uint8List? avatar; @@ -62,27 +41,10 @@ class NewGroupController extends State { void setCreateGroupType(Set b) => setState(() => _createGroupType = b.single); - // #Pangea - // void setPublicGroup(bool b) => - // setState(() => publicGroup = groupCanBeFound = b); + void setPublicGroup(bool b) => + setState(() => publicGroup = groupCanBeFound = b); - @override - void initState() { - super.initState(); - nameController.addListener(() => setState(() {})); - } - - @override - void dispose() { - nameController.dispose(); - focusNode.dispose(); - super.dispose(); - } - // Pangea# - - // #Pangea - // void setGroupCanBeFound(bool b) => setState(() => groupCanBeFound = b); - // Pangea# + void setGroupCanBeFound(bool b) => setState(() => groupCanBeFound = b); void selectPhoto() async { final photo = await selectFiles( @@ -101,134 +63,56 @@ class NewGroupController extends State { Future _createGroup() async { if (!mounted) return; final roomId = await Matrix.of(context).client.createGroupChat( - // #Pangea - // visibility: - // groupCanBeFound ? sdk.Visibility.public : sdk.Visibility.private, - // preset: publicGroup - // ? sdk.CreateRoomPreset.publicChat - // : sdk.CreateRoomPreset.privateChat, - preset: sdk.CreateRoomPreset.publicChat, - visibility: sdk.Visibility.private, - // Pangea# - groupName: - nameController.text.isNotEmpty ? nameController.text : null, - initialState: [ - if (avatar != null) - sdk.StateEvent( - type: sdk.EventTypes.RoomAvatar, - content: {'url': avatarUrl.toString()}, - ), - // #Pangea - RoomDefaults.defaultPowerLevels( - Matrix.of(context).client.userID!, - ), - await Matrix.of(context).client.pangeaJoinRules( - widget.spaceId != null - ? 'knock_restricted' - : JoinRules.public - .toString() - .replaceAll('JoinRules.', ''), - allow: widget.spaceId != null - ? [ - { - "type": "m.room_membership", - "room_id": widget.spaceId, - } - ] - : null, - ), - // Pangea# - ], - // #Pangea - enableEncryption: false, - // Pangea# - ); + visibility: groupCanBeFound + ? sdk.Visibility.public + : sdk.Visibility.private, + preset: publicGroup + ? sdk.CreateRoomPreset.publicChat + : sdk.CreateRoomPreset.privateChat, + groupName: nameController.text.isNotEmpty ? nameController.text : null, + initialState: [ + if (avatar != null) + sdk.StateEvent( + type: sdk.EventTypes.RoomAvatar, + content: {'url': avatarUrl.toString()}, + ), + ], + ); if (!mounted) return; - // #Pangea - final client = Matrix.of(context).client; - Room? room = client.getRoomById(roomId); - if (room == null) { - await client.waitForRoomInSync(roomId); - room = client.getRoomById(roomId); - } - if (room == null) return; - - if (widget.spaceId != null) { - try { - final space = client.getRoomById(widget.spaceId!); - await space?.addToSpace(room.id); - if (room.pangeaSpaceParents.isEmpty) { - await client.waitForRoomInSync(roomId); - } - } catch (err) { - ErrorHandler.logError( - e: "Failed to add room to space", - data: {"spaceId": widget.spaceId, "error": err}, - ); - } - } context.go('/rooms/$roomId/invite'); - // Pangea# } Future _createSpace() async { if (!mounted) return; - // #Pangea - // final spaceId = await Matrix.of(context).client.createRoom( - // preset: publicGroup - // ? sdk.CreateRoomPreset.publicChat - // : sdk.CreateRoomPreset.privateChat, - // creationContent: {'type': RoomCreationTypes.mSpace}, - // visibility: publicGroup ? sdk.Visibility.public : null, - // roomAliasName: publicGroup - // ? nameController.text.trim().toLowerCase().replaceAll(' ', '_') - // : null, - // name: nameController.text.trim(), - // powerLevelContentOverride: {'events_default': 100}, - // initialState: [ - // if (avatar != null) - // sdk.StateEvent( - // type: sdk.EventTypes.RoomAvatar, - // content: {'url': avatarUrl.toString()}, - // ), - // ], - // ); - // if (!mounted) return; - // context.pop(spaceId); - final spaceId = await Matrix.of(context).client.createPangeaSpace( - name: nameController.text, - visibility: sdk.Visibility.private, - joinRules: sdk.JoinRules.knock, - avatarUrl: avatarUrl.toString(), - ); - + final spaceId = await Matrix.of(context).client.createRoom( + preset: publicGroup + ? sdk.CreateRoomPreset.publicChat + : sdk.CreateRoomPreset.privateChat, + creationContent: {'type': RoomCreationTypes.mSpace}, + visibility: publicGroup ? sdk.Visibility.public : null, + roomAliasName: publicGroup + ? nameController.text.trim().toLowerCase().replaceAll(' ', '_') + : null, + name: nameController.text.trim(), + powerLevelContentOverride: {'events_default': 100}, + initialState: [ + if (avatar != null) + sdk.StateEvent( + type: sdk.EventTypes.RoomAvatar, + content: {'url': avatarUrl.toString()}, + ), + ], + ); if (!mounted) return; - - final room = Matrix.of(context).client.getRoomById(spaceId); - if (room == null) return; - final spaceCode = room.classCode; - if (spaceCode != null) { - GoogleAnalytics.createClass(room.name, spaceCode); - } - - context.go("/rooms/spaces/$spaceId/details"); - // Pangea# + context.pop(spaceId); } void submitAction([dynamic _]) async { final client = Matrix.of(context).client; try { - // #Pangea - if (!formKey.currentState!.validate()) { - focusNode.requestFocus(); - return; - } - - // if (nameController.text.trim().isEmpty && - // createGroupType == CreateGroupType.space) { - if (!canSubmit) { - // Pangea# + if (nameController.text.trim().isEmpty && + createGroupType == CreateGroupType.space) { setState(() => error = L10n.of(context).pleaseFillOut); return; } diff --git a/lib/pages/new_group/new_group_view.dart b/lib/pages/new_group/new_group_view.dart index b12dff279..61f86736b 100644 --- a/lib/pages/new_group/new_group_view.dart +++ b/lib/pages/new_group/new_group_view.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:fluffychat/config/themes.dart'; import 'package:fluffychat/l10n/l10n.dart'; import 'package:fluffychat/pages/new_group/new_group.dart'; +import 'package:fluffychat/utils/localized_exception_extension.dart'; import 'package:fluffychat/widgets/avatar.dart'; import 'package:fluffychat/widgets/layouts/max_width_body.dart'; @@ -13,14 +14,10 @@ class NewGroupView extends StatelessWidget { @override Widget build(BuildContext context) { - // #Pangea - // final theme = Theme.of(context); - // Pangea# + final theme = Theme.of(context); final avatar = controller.avatar; - // #Pangea - // final error = controller.error; - // Pangea# + final error = controller.error; return Scaffold( appBar: AppBar( leading: Center( @@ -30,47 +27,32 @@ class NewGroupView extends StatelessWidget { ), title: Text( controller.createGroupType == CreateGroupType.space - // #Pangea - // ? L10n.of(context).newSpace - ? L10n.of(context).newCourse - // : L10n.of(context).createGroup, - : L10n.of(context).newChat, - // Pangea# + ? L10n.of(context).newSpace + : L10n.of(context).createGroup, ), ), body: MaxWidthBody( - // #Pangea - showBorder: false, - padding: const EdgeInsets.only( - left: 32.0, - right: 32.0, - bottom: 32.0, - ), - // Pangea# child: Column( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ - // #Pangea - // Simplying options here - // Padding( - // padding: const EdgeInsets.all(16.0), - // child: SegmentedButton( - // selected: {controller.createGroupType}, - // onSelectionChanged: controller.setCreateGroupType, - // segments: [ - // ButtonSegment( - // value: CreateGroupType.group, - // label: Text(L10n.of(context).group), - // ), - // ButtonSegment( - // value: CreateGroupType.space, - // label: Text(L10n.of(context).space), - // ), - // ], - // ), - // ), - // const SizedBox(height: 16), - // Pangea# + Padding( + padding: const EdgeInsets.all(16.0), + child: SegmentedButton( + selected: {controller.createGroupType}, + onSelectionChanged: controller.setCreateGroupType, + segments: [ + ButtonSegment( + value: CreateGroupType.group, + label: Text(L10n.of(context).group), + ), + ButtonSegment( + value: CreateGroupType.space, + label: Text(L10n.of(context).space), + ), + ], + ), + ), + const SizedBox(height: 16), InkWell( borderRadius: BorderRadius.circular(90), onTap: controller.loading ? null : controller.selectPhoto, @@ -92,107 +74,82 @@ class NewGroupView extends StatelessWidget { const SizedBox(height: 32), Padding( padding: const EdgeInsets.symmetric(horizontal: 24.0), - // #Pangea - // child: TextField( - child: Form( - key: controller.formKey, - child: TextFormField( - // Pangea# - autofocus: true, - controller: controller.nameController, - autocorrect: false, - readOnly: controller.loading, - decoration: InputDecoration( - prefixIcon: const Icon(Icons.people_outlined), - labelText: - controller.createGroupType == CreateGroupType.space - // #Pangea - // ? L10n.of(context).spaceName - ? L10n.of(context).courseName - // : L10n.of(context).groupName, - : L10n.of(context).chatName, - // Pangea# - ), - // #Pangea - onFieldSubmitted: (value) { - controller.loading ? null : controller.submitAction(); - }, - validator: (value) => controller.canSubmit - ? null - : L10n.of(context).pleaseFillOut, - focusNode: controller.focusNode, - // Pangea# + child: TextField( + autofocus: true, + controller: controller.nameController, + autocorrect: false, + readOnly: controller.loading, + decoration: InputDecoration( + prefixIcon: const Icon(Icons.people_outlined), + labelText: controller.createGroupType == CreateGroupType.space + ? L10n.of(context).spaceName + : L10n.of(context).groupName, ), ), ), const SizedBox(height: 16), - // #Pangea - // SwitchListTile.adaptive( - // contentPadding: const EdgeInsets.symmetric(horizontal: 32), - // secondary: const Icon(Icons.public_outlined), - // title: Text( - // controller.createGroupType == CreateGroupType.space - // ? L10n.of(context).spaceIsPublic - // : L10n.of(context).groupIsPublic, - // ), - // value: controller.publicGroup, - // onChanged: controller.loading ? null : controller.setPublicGroup, - // ), - // AnimatedSize( - // duration: FluffyThemes.animationDuration, - // curve: FluffyThemes.animationCurve, - // child: controller.publicGroup - // ? SwitchListTile.adaptive( - // contentPadding: - // const EdgeInsets.symmetric(horizontal: 32), - // secondary: const Icon(Icons.search_outlined), - // title: Text(L10n.of(context).groupCanBeFoundViaSearch), - // value: controller.groupCanBeFound, - // onChanged: controller.loading - // ? null - // : controller.setGroupCanBeFound, - // ) - // : const SizedBox.shrink(), - // ), - // AnimatedSize( - // duration: FluffyThemes.animationDuration, - // curve: FluffyThemes.animationCurve, - // child: controller.createGroupType == CreateGroupType.space - // ? const SizedBox.shrink() - // : SwitchListTile.adaptive( - // contentPadding: - // const EdgeInsets.symmetric(horizontal: 32), - // secondary: Icon( - // Icons.lock_outlined, - // color: theme.colorScheme.onSurface, - // ), - // title: Text( - // L10n.of(context).enableEncryption, - // style: TextStyle( - // color: theme.colorScheme.onSurface, - // ), - // ), - // value: !controller.publicGroup, - // onChanged: null, - // ), - // ), - // Pangea# + SwitchListTile.adaptive( + contentPadding: const EdgeInsets.symmetric(horizontal: 32), + secondary: const Icon(Icons.public_outlined), + title: Text( + controller.createGroupType == CreateGroupType.space + ? L10n.of(context).spaceIsPublic + : L10n.of(context).groupIsPublic, + ), + value: controller.publicGroup, + onChanged: controller.loading ? null : controller.setPublicGroup, + ), + AnimatedSize( + duration: FluffyThemes.animationDuration, + curve: FluffyThemes.animationCurve, + child: controller.publicGroup + ? SwitchListTile.adaptive( + contentPadding: const EdgeInsets.symmetric( + horizontal: 32, + ), + secondary: const Icon(Icons.search_outlined), + title: Text(L10n.of(context).groupCanBeFoundViaSearch), + value: controller.groupCanBeFound, + onChanged: controller.loading + ? null + : controller.setGroupCanBeFound, + ) + : const SizedBox.shrink(), + ), + AnimatedSize( + duration: FluffyThemes.animationDuration, + curve: FluffyThemes.animationCurve, + child: controller.createGroupType == CreateGroupType.space + ? const SizedBox.shrink() + : SwitchListTile.adaptive( + contentPadding: const EdgeInsets.symmetric( + horizontal: 32, + ), + secondary: Icon( + Icons.lock_outlined, + color: theme.colorScheme.onSurface, + ), + title: Text( + L10n.of(context).enableEncryption, + style: TextStyle(color: theme.colorScheme.onSurface), + ), + value: !controller.publicGroup, + onChanged: null, + ), + ), AnimatedSize( duration: FluffyThemes.animationDuration, curve: FluffyThemes.animationCurve, child: controller.createGroupType == CreateGroupType.space ? ListTile( - contentPadding: - const EdgeInsets.symmetric(horizontal: 32), + contentPadding: const EdgeInsets.symmetric( + horizontal: 32, + ), trailing: const Padding( padding: EdgeInsets.symmetric(horizontal: 16.0), child: Icon(Icons.info_outlined), ), - // #Pangea - // subtitle: Text(L10n.of(context).newSpaceDescription), - subtitle: - Text(L10n.of(context).updatedNewSpaceDescription), - // Pangea# + subtitle: Text(L10n.of(context).newSpaceDescription), ) : const SizedBox.shrink(), ), @@ -201,42 +158,35 @@ class NewGroupView extends StatelessWidget { child: SizedBox( width: double.infinity, child: ElevatedButton( - onPressed: - controller.loading ? null : controller.submitAction, + onPressed: controller.loading + ? null + : controller.submitAction, child: controller.loading ? const LinearProgressIndicator() : Text( controller.createGroupType == CreateGroupType.space - // #Pangea - // ? L10n.of(context).createNewSpace - ? L10n.of(context).createNewCourse - // : L10n.of(context).createGroupAndInviteUsers, - : L10n.of(context).createChatAndInviteUsers, - // Pangea# + ? L10n.of(context).createNewSpace + : L10n.of(context).createGroupAndInviteUsers, ), ), ), ), - // #Pangea - // AnimatedSize( - // duration: FluffyThemes.animationDuration, - // curve: FluffyThemes.animationCurve, - // child: error == null - // ? const SizedBox.shrink() - // : ListTile( - // leading: Icon( - // Icons.warning_outlined, - // color: theme.colorScheme.error, - // ), - // title: Text( - // error.toLocalizedString(context), - // style: TextStyle( - // color: theme.colorScheme.error, - // ), - // ), - // ), - // ), - // Pangea# + AnimatedSize( + duration: FluffyThemes.animationDuration, + curve: FluffyThemes.animationCurve, + child: error == null + ? const SizedBox.shrink() + : ListTile( + leading: Icon( + Icons.warning_outlined, + color: theme.colorScheme.error, + ), + title: Text( + error.toLocalizedString(context), + style: TextStyle(color: theme.colorScheme.error), + ), + ), + ), ], ), ), diff --git a/lib/pages/new_private_chat/new_private_chat.dart b/lib/pages/new_private_chat/new_private_chat.dart index 4c7984ce2..08cd4530a 100644 --- a/lib/pages/new_private_chat/new_private_chat.dart +++ b/lib/pages/new_private_chat/new_private_chat.dart @@ -54,8 +54,9 @@ class NewPrivateChatController extends State { Future> _searchUser(String searchTerm) async { // #Pangea - // final result = - // await Matrix.of(context).client.searchUserDirectory(searchTerm); + // final result = await Matrix.of( + // context, + // ).client.searchUserDirectory(searchTerm); final result = await Matrix.of(context).client.searchUser(searchTerm); // Pangea# final profiles = result.results; @@ -79,9 +80,7 @@ class NewPrivateChatController extends State { if (info.version.sdkInt < 21) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: Text( - L10n.of(context).unsupportedAndroidVersionLong, - ), + content: Text(L10n.of(context).unsupportedAndroidVersionLong), ), ); return; @@ -99,15 +98,13 @@ class NewPrivateChatController extends State { await Clipboard.setData( ClipboardData(text: Matrix.of(context).client.userID!), ); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text(L10n.of(context).copiedToClipboard)), - ); + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text(L10n.of(context).copiedToClipboard))); } - void openUserModal(Profile profile) => UserDialog.show( - context: context, - profile: profile, - ); + void openUserModal(Profile profile) => + UserDialog.show(context: context, profile: profile); @override Widget build(BuildContext context) => NewPrivateChatView(this); diff --git a/lib/pages/new_private_chat/new_private_chat_view.dart b/lib/pages/new_private_chat/new_private_chat_view.dart index b7aec47bb..94bda0fa5 100644 --- a/lib/pages/new_private_chat/new_private_chat_view.dart +++ b/lib/pages/new_private_chat/new_private_chat_view.dart @@ -38,8 +38,10 @@ class NewPrivateChatView extends StatelessWidget { // #Pangea // actions: [ // TextButton( - // onPressed: - // UrlLauncher(context, AppConfig.startChatTutorial).launchUrl, + // onPressed: UrlLauncher( + // context, + // AppConfig.startChatTutorial, + // ).launchUrl, // child: Text(L10n.of(context).help), // ), // ], @@ -103,186 +105,196 @@ class NewPrivateChatView extends StatelessWidget { ), ), Expanded( - child: AnimatedCrossFade( + child: AnimatedSwitcher( duration: FluffyThemes.animationDuration, - crossFadeState: searchResponse == null - ? CrossFadeState.showFirst - : CrossFadeState.showSecond, - firstChild: ListView( - children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 18.0), - child: SelectableText.rich( - TextSpan( - children: [ - TextSpan( - text: L10n.of(context).yourGlobalUserIdIs, + child: searchResponse == null + ? ListView( + children: [ + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 18.0, ), - TextSpan( - text: Matrix.of(context).client.userID, - style: const TextStyle( - fontWeight: FontWeight.w600, + child: SelectableText.rich( + TextSpan( + children: [ + TextSpan( + text: L10n.of(context).yourGlobalUserIdIs, + ), + TextSpan( + text: Matrix.of(context).client.userID, + style: const TextStyle( + fontWeight: FontWeight.w600, + ), + ), + ], + ), + style: TextStyle( + color: theme.colorScheme.onSurface, + fontSize: 12, ), ), - ], - ), - style: TextStyle( - color: theme.colorScheme.onSurface, - fontSize: 12, - ), - ), - ), - const SizedBox(height: 8), - ListTile( - leading: CircleAvatar( - backgroundColor: theme.colorScheme.secondaryContainer, - foregroundColor: theme.colorScheme.onSecondaryContainer, - child: Icon(Icons.adaptive.share_outlined), - ), - title: Text(L10n.of(context).shareInviteLink), - onTap: controller.inviteAction, - ), - // #Pangea - // ListTile( - // leading: CircleAvatar( - // backgroundColor: theme.colorScheme.tertiaryContainer, - // foregroundColor: theme.colorScheme.onTertiaryContainer, - // child: const Icon(Icons.group_add_outlined), - // ), - // title: Text(L10n.of(context).createGroup), - // onTap: () => context.go('/rooms/newgroup'), - // ), - // Pangea# - if (PlatformInfos.isMobile) - ListTile( - leading: CircleAvatar( - backgroundColor: theme.colorScheme.primaryContainer, - foregroundColor: theme.colorScheme.onPrimaryContainer, - child: const Icon(Icons.qr_code_scanner_outlined), - ), - title: Text(L10n.of(context).scanQrCode), - onTap: controller.openScannerAction, - ), - Center( - child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: 64.0, - vertical: 24.0, - ), - child: Material( - shape: RoundedRectangleBorder( - borderRadius: - BorderRadius.circular(AppConfig.borderRadius), - side: BorderSide( - width: 3, - color: theme.colorScheme.primary, - ), ), - color: Colors.transparent, - clipBehavior: Clip.hardEdge, - child: InkWell( - borderRadius: - BorderRadius.circular(AppConfig.borderRadius), - onTap: () => showQrCodeViewer( - context, - userId, + const SizedBox(height: 8), + ListTile( + leading: CircleAvatar( + backgroundColor: + theme.colorScheme.secondaryContainer, + foregroundColor: + theme.colorScheme.onSecondaryContainer, + child: Icon(Icons.adaptive.share_outlined), ), + title: Text(L10n.of(context).shareInviteLink), + onTap: controller.inviteAction, + ), + // #Pangea + // ListTile( + // leading: CircleAvatar( + // backgroundColor: + // theme.colorScheme.tertiaryContainer, + // foregroundColor: + // theme.colorScheme.onTertiaryContainer, + // child: const Icon(Icons.group_add_outlined), + // ), + // title: Text(L10n.of(context).createGroup), + // onTap: () => context.go('/rooms/newgroup'), + // ), + // Pangea# + if (PlatformInfos.isMobile) + ListTile( + leading: CircleAvatar( + backgroundColor: + theme.colorScheme.primaryContainer, + foregroundColor: + theme.colorScheme.onPrimaryContainer, + child: const Icon( + Icons.qr_code_scanner_outlined, + ), + ), + title: Text(L10n.of(context).scanQrCode), + onTap: controller.openScannerAction, + ), + Center( child: Padding( - padding: const EdgeInsets.all(16.0), - child: ConstrainedBox( - constraints: - const BoxConstraints(maxWidth: 200), - child: PrettyQrView.data( - // #Pangea - // data: 'https://matrix.to/#/$userId', - data: Environment.frontendURL, - // Pangea# - decoration: PrettyQrDecoration( - shape: PrettyQrSmoothSymbol( - roundFactor: 1, - color: theme.colorScheme.primary, + padding: const EdgeInsets.symmetric( + horizontal: 64.0, + vertical: 24.0, + ), + child: Material( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular( + AppConfig.borderRadius, + ), + side: BorderSide( + width: 3, + color: theme.colorScheme.primary, + ), + ), + color: Colors.transparent, + clipBehavior: Clip.hardEdge, + child: InkWell( + borderRadius: BorderRadius.circular( + AppConfig.borderRadius, + ), + onTap: () => + showQrCodeViewer(context, userId), + child: Padding( + padding: const EdgeInsets.all(16.0), + child: ConstrainedBox( + constraints: const BoxConstraints( + maxWidth: 200, + ), + child: PrettyQrView.data( + // #Pangea + // data: 'https://matrix.to/#/$userId', + data: Environment.frontendURL, + // Pangea# + decoration: PrettyQrDecoration( + shape: PrettyQrSmoothSymbol( + roundFactor: 1, + color: theme.colorScheme.primary, + ), + ), + ), ), ), ), ), ), ), - ), + ], + ) + : FutureBuilder( + future: searchResponse, + builder: (context, snapshot) { + final result = snapshot.data; + final error = snapshot.error; + if (error != null) { + return Column( + mainAxisAlignment: .center, + children: [ + Text( + error.toLocalizedString(context), + textAlign: TextAlign.center, + style: TextStyle( + color: theme.colorScheme.error, + ), + ), + const SizedBox(height: 12), + OutlinedButton.icon( + onPressed: controller.searchUsers, + icon: const Icon(Icons.refresh_outlined), + label: Text(L10n.of(context).tryAgain), + ), + ], + ); + } + if (result == null) { + return const Center( + child: CircularProgressIndicator.adaptive(), + ); + } + if (result.isEmpty) { + return Column( + mainAxisAlignment: .center, + children: [ + const Icon(Icons.search_outlined, size: 86), + Padding( + padding: const EdgeInsets.all(16.0), + child: Text( + L10n.of(context).noUsersFoundWithQuery( + controller.controller.text, + ), + style: TextStyle( + color: theme.colorScheme.primary, + ), + textAlign: TextAlign.center, + ), + ), + ], + ); + } + return ListView.builder( + itemCount: result.length, + itemBuilder: (context, i) { + final contact = result[i]; + final displayname = + contact.displayName ?? + contact.userId.localpart ?? + contact.userId; + return ListTile( + leading: Avatar( + name: displayname, + mxContent: contact.avatarUrl, + presenceUserId: contact.userId, + ), + title: Text(displayname), + subtitle: Text(contact.userId), + onTap: () => controller.openUserModal(contact), + ); + }, + ); + }, ), - ), - ], - ), - secondChild: FutureBuilder( - future: searchResponse, - builder: (context, snapshot) { - final result = snapshot.data; - final error = snapshot.error; - if (error != null) { - return Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - error.toLocalizedString(context), - textAlign: TextAlign.center, - style: TextStyle( - color: theme.colorScheme.error, - ), - ), - const SizedBox(height: 12), - OutlinedButton.icon( - onPressed: controller.searchUsers, - icon: const Icon(Icons.refresh_outlined), - label: Text(L10n.of(context).tryAgain), - ), - ], - ); - } - if (result == null) { - return const Center( - child: CircularProgressIndicator.adaptive(), - ); - } - if (result.isEmpty) { - return Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Icon(Icons.search_outlined, size: 86), - Padding( - padding: const EdgeInsets.all(16.0), - child: Text( - L10n.of(context).noUsersFoundWithQuery( - controller.controller.text, - ), - style: TextStyle( - color: theme.colorScheme.primary, - ), - textAlign: TextAlign.center, - ), - ), - ], - ); - } - return ListView.builder( - itemCount: result.length, - itemBuilder: (context, i) { - final contact = result[i]; - final displayname = contact.displayName ?? - contact.userId.localpart ?? - contact.userId; - return ListTile( - leading: Avatar( - name: displayname, - mxContent: contact.avatarUrl, - presenceUserId: contact.userId, - ), - title: Text(displayname), - subtitle: Text(contact.userId), - onTap: () => controller.openUserModal(contact), - ); - }, - ); - }, - ), ), ), ], diff --git a/lib/pages/onboarding/enable_notifications.dart b/lib/pages/onboarding/enable_notifications.dart index e3586033a..d8c67c1dd 100644 --- a/lib/pages/onboarding/enable_notifications.dart +++ b/lib/pages/onboarding/enable_notifications.dart @@ -30,17 +30,9 @@ class EnableNotificationsController extends State { Future _setProfile() async { final client = Matrix.of(context).client; try { - profile = await client.getProfileFromUserId( - client.userID!, - ); + profile = await client.getProfileFromUserId(client.userID!); } catch (e, s) { - ErrorHandler.logError( - e: e, - s: s, - data: { - 'userId': client.userID, - }, - ); + ErrorHandler.logError(e: e, s: s, data: {'userId': client.userID}); } finally { if (mounted) setState(() {}); } @@ -58,21 +50,14 @@ class EnableNotificationsController extends State { return PangeaLoginScaffold( customAppBar: AppBar( title: ConstrainedBox( - constraints: const BoxConstraints( - maxWidth: 450, - ), + constraints: const BoxConstraints(maxWidth: 450), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ BackButton( - onPressed: () => pLogoutAction( - context, - bypassWarning: true, - ), - ), - const SizedBox( - width: 40.0, + onPressed: () => pLogoutAction(context, bypassWarning: true), ), + const SizedBox(width: 40.0), ], ), ), @@ -90,10 +75,9 @@ class EnableNotificationsController extends State { Matrix.of(context).client.userID?.localpart ?? "", ), - style: Theme.of(context) - .textTheme - .titleLarge - ?.copyWith(fontWeight: FontWeight.bold), + style: Theme.of( + context, + ).textTheme.titleLarge?.copyWith(fontWeight: FontWeight.bold), ), Text( L10n.of(context).enableNotificationsTitle, @@ -103,14 +87,13 @@ class EnableNotificationsController extends State { onPressed: _requestNotificationPermission, style: ElevatedButton.styleFrom( backgroundColor: Theme.of(context).colorScheme.primaryContainer, - foregroundColor: - Theme.of(context).colorScheme.onPrimaryContainer, + foregroundColor: Theme.of( + context, + ).colorScheme.onPrimaryContainer, ), child: Row( mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text(L10n.of(context).enableNotificationsDesc), - ], + children: [Text(L10n.of(context).enableNotificationsDesc)], ), ), TextButton( diff --git a/lib/pages/onboarding/space_code_onboarding.dart b/lib/pages/onboarding/space_code_onboarding.dart index 54c50f557..5f998404e 100644 --- a/lib/pages/onboarding/space_code_onboarding.dart +++ b/lib/pages/onboarding/space_code_onboarding.dart @@ -39,17 +39,9 @@ class SpaceCodeOnboardingState extends State { Future _setProfile() async { try { - profile = await client.getProfileFromUserId( - client.userID!, - ); + profile = await client.getProfileFromUserId(client.userID!); } catch (e, s) { - ErrorHandler.logError( - e: e, - s: s, - data: { - 'userId': client.userID, - }, - ); + ErrorHandler.logError(e: e, s: s, data: {'userId': client.userID}); } finally { if (mounted) setState(() {}); } diff --git a/lib/pages/onboarding/space_code_onboarding_view.dart b/lib/pages/onboarding/space_code_onboarding_view.dart index bbd57d5eb..e4de82b76 100644 --- a/lib/pages/onboarding/space_code_onboarding_view.dart +++ b/lib/pages/onboarding/space_code_onboarding_view.dart @@ -9,28 +9,19 @@ import 'package:fluffychat/pangea/login/pages/pangea_login_scaffold.dart'; class SpaceCodeOnboardingView extends StatelessWidget { final SpaceCodeOnboardingState controller; - const SpaceCodeOnboardingView({ - super.key, - required this.controller, - }); + const SpaceCodeOnboardingView({super.key, required this.controller}); @override Widget build(BuildContext context) { return PangeaLoginScaffold( customAppBar: AppBar( title: ConstrainedBox( - constraints: const BoxConstraints( - maxWidth: 450, - ), + constraints: const BoxConstraints(maxWidth: 450), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - BackButton( - onPressed: Navigator.of(context).pop, - ), - const SizedBox( - width: 40.0, - ), + BackButton(onPressed: Navigator.of(context).pop), + const SizedBox(width: 40.0), ], ), ), @@ -48,10 +39,9 @@ class SpaceCodeOnboardingView extends StatelessWidget { controller.client.userID?.localpart ?? "", ), - style: Theme.of(context) - .textTheme - .titleLarge - ?.copyWith(fontWeight: FontWeight.bold), + style: Theme.of( + context, + ).textTheme.titleLarge?.copyWith(fontWeight: FontWeight.bold), ), Text( L10n.of(context).joinSpaceOnboardingDesc, @@ -70,14 +60,13 @@ class SpaceCodeOnboardingView extends StatelessWidget { : null, style: ElevatedButton.styleFrom( backgroundColor: Theme.of(context).colorScheme.primaryContainer, - foregroundColor: - Theme.of(context).colorScheme.onPrimaryContainer, + foregroundColor: Theme.of( + context, + ).colorScheme.onPrimaryContainer, ), child: Row( mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text(L10n.of(context).join), - ], + children: [Text(L10n.of(context).join)], ), ), TextButton( diff --git a/lib/pages/settings/settings.dart b/lib/pages/settings/settings.dart index aa9c5126a..8daa4330f 100644 --- a/lib/pages/settings/settings.dart +++ b/lib/pages/settings/settings.dart @@ -26,9 +26,9 @@ class SettingsController extends State { bool profileUpdated = false; void updateProfile() => setState(() { - profileUpdated = true; - profileFuture = null; - }); + profileUpdated = true; + profileFuture = null; + }); void setDisplaynameAction() async { final profile = await profileFuture; @@ -132,15 +132,9 @@ class SettingsController extends State { imageQuality: 50, ); if (result == null) return; - file = MatrixFile( - bytes: await result.readAsBytes(), - name: result.path, - ); + file = MatrixFile(bytes: await result.readAsBytes(), name: result.path); } else { - final result = await selectFiles( - context, - type: FileSelectorType.images, - ); + final result = await selectFiles(context, type: FileSelectorType.images); final pickedFile = result.firstOrNull; if (pickedFile == null) return; file = MatrixFile( @@ -182,8 +176,8 @@ class SettingsController extends State { await client.encryption?.crossSigning.isCached() ?? false; final needsBootstrap = await client.encryption?.keyManager.isCached() == false || - client.encryption?.crossSigning.enabled == false || - crossSigning == false; + client.encryption?.crossSigning.enabled == false || + crossSigning == false; final isUnknownSession = client.isUnknownSession; setState(() { showChatBackupBanner = needsBootstrap || isUnknownSession; @@ -242,9 +236,7 @@ class SettingsController extends State { @override Widget build(BuildContext context) { final client = Matrix.of(context).client; - profileFuture ??= client.getProfileFromUserId( - client.userID!, - ); + profileFuture ??= client.getProfileFromUserId(client.userID!); return SettingsView(this); } } diff --git a/lib/pages/settings/settings_view.dart b/lib/pages/settings/settings_view.dart index 4a7f90bc0..5f87b994f 100644 --- a/lib/pages/settings/settings_view.dart +++ b/lib/pages/settings/settings_view.dart @@ -8,14 +8,14 @@ import 'package:url_launcher/url_launcher_string.dart'; import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/l10n/l10n.dart'; +import 'package:fluffychat/pages/settings/settings.dart'; import 'package:fluffychat/pangea/common/config/environment.dart'; import 'package:fluffychat/utils/fluffy_share.dart'; import 'package:fluffychat/widgets/avatar.dart'; import 'package:fluffychat/widgets/future_loading_dialog.dart'; import 'package:fluffychat/widgets/local_notifications_extension.dart'; import 'package:fluffychat/widgets/matrix.dart'; -import '../../widgets/mxc_image_viewer.dart'; -import 'settings.dart'; +import 'package:fluffychat/widgets/mxc_image_viewer.dart'; class SettingsView extends StatelessWidget { final SettingsController controller; @@ -28,8 +28,9 @@ class SettingsView extends StatelessWidget { // #Pangea // final showChatBackupBanner = controller.showChatBackupBanner; // Pangea# - final activeRoute = - GoRouter.of(context).routeInformationProvider.value.uri.path; + final activeRoute = GoRouter.of( + context, + ).routeInformationProvider.value.uri.path; // #Pangea // final accountManageUrl = Matrix.of(context) // .client @@ -47,10 +48,7 @@ class SettingsView extends StatelessWidget { // onGoToChats: () => context.go('/rooms'), // onGoToSpaceId: (spaceId) => context.go('/rooms?spaceId=$spaceId'), // ), - // Container( - // color: Theme.of(context).dividerColor, - // width: 1, - // ), + // Container(color: Theme.of(context).dividerColor, width: 1), // ], // Pangea# Expanded( @@ -61,9 +59,7 @@ class SettingsView extends StatelessWidget { // : AppBar( // title: Text(L10n.of(context).settings), // leading: Center( - // child: BackButton( - // onPressed: () => context.go('/rooms'), - // ), + // child: BackButton(onPressed: () => context.go('/rooms')), // ), // ), // Pangea# @@ -80,7 +76,8 @@ class SettingsView extends StatelessWidget { builder: (context, snapshot) { final profile = snapshot.data; final avatar = profile?.avatarUrl; - final mxid = Matrix.of(context).client.userID ?? + final mxid = + Matrix.of(context).client.userID ?? L10n.of(context).user; final displayname = profile?.displayName ?? mxid.localpart ?? mxid; @@ -106,10 +103,10 @@ class SettingsView extends StatelessWidget { size: Avatar.defaultSize * 2.5, onTap: avatar != null ? () => showDialog( - context: context, - builder: (_) => - MxcImageViewer(avatar), - ) + context: context, + builder: (_) => + MxcImageViewer(avatar), + ) : null, ), if (profile != null) @@ -130,8 +127,8 @@ class SettingsView extends StatelessWidget { ), Expanded( child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: .center, + crossAxisAlignment: .start, children: [ TextButton.icon( onPressed: controller.setDisplaynameAction, @@ -148,9 +145,7 @@ class SettingsView extends StatelessWidget { displayname, maxLines: 1, overflow: TextOverflow.ellipsis, - style: const TextStyle( - fontSize: 18, - ), + style: const TextStyle(fontSize: 18), ), ), TextButton.icon( @@ -205,16 +200,14 @@ class SettingsView extends StatelessWidget { // title: Text(L10n.of(context).chatBackup), // onChanged: controller.firstRunBootstrapAction, // ), - // Divider( - // color: theme.dividerColor, - // ), + // Divider(color: theme.dividerColor), ListTile( leading: const Icon(Icons.language_outlined), title: Text(L10n.of(context).learningSettings), tileColor: activeRoute.startsWith('/rooms/settings/learning') - ? theme.colorScheme.surfaceContainerHigh - : null, + ? theme.colorScheme.surfaceContainerHigh + : null, onTap: () => context.go('/rooms/settings/learning'), ), // Pangea# @@ -229,16 +222,19 @@ class SettingsView extends StatelessWidget { ListTile( leading: const Icon(Icons.notifications_outlined), title: Text(L10n.of(context).notifications), - tileColor: activeRoute - .startsWith('/rooms/settings/notifications') + tileColor: + activeRoute.startsWith( + '/rooms/settings/notifications', + ) ? theme.colorScheme.surfaceContainerHigh : null, onTap: () => context.go('/rooms/settings/notifications'), // #Pangea trailing: ValueListenableBuilder( - valueListenable: - Matrix.of(context).notifPermissionNotifier, - builder: (context, _, __) => FutureBuilder( + valueListenable: Matrix.of( + context, + ).notifPermissionNotifier, + builder: (context, _, _) => FutureBuilder( future: Matrix.of(context).notificationsEnabled, builder: (context, snapshot) { return snapshot.data != false @@ -258,8 +254,8 @@ class SettingsView extends StatelessWidget { onTap: () => context.go('/rooms/settings/devices'), tileColor: activeRoute.startsWith('/rooms/settings/devices') - ? theme.colorScheme.surfaceContainerHigh - : null, + ? theme.colorScheme.surfaceContainerHigh + : null, ), ListTile( leading: const Icon(Icons.forum_outlined), @@ -276,8 +272,8 @@ class SettingsView extends StatelessWidget { onTap: () => context.go('/rooms/settings/subscription'), tileColor: activeRoute.startsWith('/rooms/settings/subscription') - ? theme.colorScheme.surfaceContainerHigh - : null, + ? theme.colorScheme.surfaceContainerHigh + : null, ), // Pangea# ListTile( @@ -286,8 +282,8 @@ class SettingsView extends StatelessWidget { onTap: () => context.go('/rooms/settings/security'), tileColor: activeRoute.startsWith('/rooms/settings/security') - ? theme.colorScheme.surfaceContainerHigh - : null, + ? theme.colorScheme.surfaceContainerHigh + : null, ), Divider(color: theme.dividerColor), // #Pangea @@ -299,11 +295,11 @@ class SettingsView extends StatelessWidget { await showFutureLoadingDialog( context: context, future: () async { - final roomId = - await Matrix.of(context).client.startDirectChat( - Environment.supportUserId, - enableEncryption: false, - ); + final roomId = await Matrix.of(context).client + .startDirectChat( + Environment.supportUserId, + enableEncryption: false, + ); context.go('/rooms/$roomId'); }, ); @@ -332,8 +328,9 @@ class SettingsView extends StatelessWidget { ); ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: - Text(L10n.of(context).copiedToClipboard), + content: Text( + L10n.of(context).copiedToClipboard, + ), ), ); }, @@ -376,8 +373,8 @@ class SettingsView extends StatelessWidget { // onTap: () => context.go('/rooms/settings/homeserver'), // tileColor: // activeRoute.startsWith('/rooms/settings/homeserver') - // ? theme.colorScheme.surfaceContainerHigh - // : null, + // ? theme.colorScheme.surfaceContainerHigh + // : null, // ), // ListTile( // leading: const Icon(Icons.privacy_tip_outlined), diff --git a/lib/pages/settings_3pid/settings_3pid.dart b/lib/pages/settings_3pid/settings_3pid.dart index 9014c4155..616cc2eeb 100644 --- a/lib/pages/settings_3pid/settings_3pid.dart +++ b/lib/pages/settings_3pid/settings_3pid.dart @@ -34,10 +34,10 @@ class Settings3PidController extends State { final response = await showFutureLoadingDialog( context: context, future: () => Matrix.of(context).client.requestTokenToRegisterEmail( - clientSecret, - input, - Settings3Pid.sendAttempt++, - ), + clientSecret, + input, + Settings3Pid.sendAttempt++, + ), ); if (response.error != null) return; final ok = await showOkAlertDialog( @@ -55,12 +55,10 @@ class Settings3PidController extends State { context: context, delay: false, future: () => Matrix.of(context).client.uiaRequestBackground( - (auth) => Matrix.of(context).client.add3PID( - clientSecret, - response.result!.sid, - auth: auth, - ), - ), + (auth) => Matrix.of( + context, + ).client.add3PID(clientSecret, response.result!.sid, auth: auth), + ), // #Pangea showError: (e) => !e.toString().contains("Request has been canceled"), // Pangea# @@ -84,10 +82,9 @@ class Settings3PidController extends State { } final success = await showFutureLoadingDialog( context: context, - future: () => Matrix.of(context).client.delete3pidFromAccount( - identifier.address, - identifier.medium, - ), + future: () => Matrix.of( + context, + ).client.delete3pidFromAccount(identifier.address, identifier.medium), ); if (success.error != null) return; setState(() => request = null); diff --git a/lib/pages/settings_3pid/settings_3pid_view.dart b/lib/pages/settings_3pid/settings_3pid_view.dart index c466b0a24..d01fdc6bf 100644 --- a/lib/pages/settings_3pid/settings_3pid_view.dart +++ b/lib/pages/settings_3pid/settings_3pid_view.dart @@ -33,67 +33,71 @@ class Settings3PidView extends StatelessWidget { withScrolling: false, child: FutureBuilder?>( future: controller.request, - builder: ( - BuildContext context, - AsyncSnapshot?> snapshot, - ) { - if (snapshot.hasError) { - return Center( - child: Text( - snapshot.error.toString(), - textAlign: TextAlign.center, - ), - ); - } - if (!snapshot.hasData) { - return const Center( - child: CircularProgressIndicator.adaptive(strokeWidth: 2), - ); - } - final identifier = snapshot.data!; - return Column( - children: [ - ListTile( - leading: CircleAvatar( - backgroundColor: theme.scaffoldBackgroundColor, - foregroundColor: - identifier.isEmpty ? Colors.orange : Colors.grey, - child: Icon( - identifier.isEmpty - ? Icons.warning_outlined - : Icons.info_outlined, + builder: + ( + BuildContext context, + AsyncSnapshot?> snapshot, + ) { + if (snapshot.hasError) { + return Center( + child: Text( + snapshot.error.toString(), + textAlign: TextAlign.center, ), - ), - title: Text( - identifier.isEmpty - ? L10n.of(context).noPasswordRecoveryDescription - : L10n.of(context) - .withTheseAddressesRecoveryDescription, - ), - ), - const Divider(), - Expanded( - child: ListView.builder( - itemCount: identifier.length, - itemBuilder: (BuildContext context, int i) => ListTile( + ); + } + if (!snapshot.hasData) { + return const Center( + child: CircularProgressIndicator.adaptive(strokeWidth: 2), + ); + } + final identifier = snapshot.data!; + return Column( + children: [ + ListTile( leading: CircleAvatar( backgroundColor: theme.scaffoldBackgroundColor, - foregroundColor: Colors.grey, - child: Icon(identifier[i].iconData), + foregroundColor: identifier.isEmpty + ? Colors.orange + : Colors.grey, + child: Icon( + identifier.isEmpty + ? Icons.warning_outlined + : Icons.info_outlined, + ), ), - title: Text(identifier[i].address), - trailing: IconButton( - tooltip: L10n.of(context).delete, - icon: const Icon(Icons.delete_forever_outlined), - color: Colors.red, - onPressed: () => controller.delete3Pid(identifier[i]), + title: Text( + identifier.isEmpty + ? L10n.of(context).noPasswordRecoveryDescription + : L10n.of( + context, + ).withTheseAddressesRecoveryDescription, ), ), - ), - ), - ], - ); - }, + const Divider(), + Expanded( + child: ListView.builder( + itemCount: identifier.length, + itemBuilder: (BuildContext context, int i) => ListTile( + leading: CircleAvatar( + backgroundColor: theme.scaffoldBackgroundColor, + foregroundColor: Colors.grey, + child: Icon(identifier[i].iconData), + ), + title: Text(identifier[i].address), + trailing: IconButton( + tooltip: L10n.of(context).delete, + icon: const Icon(Icons.delete_forever_outlined), + color: Colors.red, + onPressed: () => + controller.delete3Pid(identifier[i]), + ), + ), + ), + ), + ], + ); + }, ), ), ); diff --git a/lib/pages/settings_emotes/import_archive_dialog.dart b/lib/pages/settings_emotes/import_archive_dialog.dart index 12bc0a09c..46bca4d3a 100644 --- a/lib/pages/settings_emotes/import_archive_dialog.dart +++ b/lib/pages/settings_emotes/import_archive_dialog.dart @@ -46,11 +46,7 @@ class _ImportEmoteArchiveDialogState extends State { return AlertDialog( title: Text(L10n.of(context).importEmojis), content: _loading - ? Center( - child: CircularProgressIndicator( - value: _progress, - ), - ) + ? Center(child: CircularProgressIndicator(value: _progress)) : SingleChildScrollView( child: Wrap( alignment: WrapAlignment.spaceEvenly, @@ -79,8 +75,8 @@ class _ImportEmoteArchiveDialogState extends State { onPressed: _loading ? null : _importMap.isNotEmpty - ? _addEmotePack - : null, + ? _addEmotePack + : null, child: Text(L10n.of(context).importNow), ), ], @@ -91,12 +87,8 @@ class _ImportEmoteArchiveDialogState extends State { _importMap = Map.fromEntries( widget.archive.files .where((e) => e.isFile) - .map( - (e) => MapEntry(e, e.name.emoteNameFromPath), - ) - .sorted( - (a, b) => a.value.compareTo(b.value), - ), + .map((e) => MapEntry(e, e.name.emoteNameFromPath)) + .sorted((a, b) => a.value.compareTo(b.value)), ); } @@ -148,10 +140,7 @@ class _ImportEmoteArchiveDialogState extends State { final imageCode = entry.value; try { - var mxcFile = MatrixImageFile( - bytes: file.content, - name: file.name, - ); + var mxcFile = MatrixImageFile(bytes: file.content, name: file.name); final thumbnail = (await mxcFile.generateThumbnail( nativeImplementations: ClientManager.nativeImplementations, @@ -162,14 +151,12 @@ class _ImportEmoteArchiveDialogState extends State { mxcFile = thumbnail; } final uri = await Matrix.of(context).client.uploadContent( - mxcFile.bytes, - filename: mxcFile.name, - contentType: mxcFile.mimeType, - ); + mxcFile.bytes, + filename: mxcFile.name, + contentType: mxcFile.mimeType, + ); - final info = { - ...mxcFile.info, - }; + final info = {...mxcFile.info}; // normalize width / height to 256, required for stickers if (info['w'] is int && info['h'] is int) { @@ -184,9 +171,9 @@ class _ImportEmoteArchiveDialogState extends State { } widget.controller.pack!.images[imageCode] = ImagePackImageContent.fromJson({ - 'url': uri.toString(), - 'info': info, - }); + 'url': uri.toString(), + 'info': info, + }); successfulUploads.add(file.name); } catch (e) { Logs().d('Could not upload emote $imageCode'); @@ -204,8 +191,9 @@ class _ImportEmoteArchiveDialogState extends State { // in case we have unhandled / duplicated emotes left, don't pop if (mounted) setState(() {}); if (_importMap.isEmpty) { - WidgetsBinding.instance - .addPostFrameCallback((_) => Navigator.of(context).pop()); + WidgetsBinding.instance.addPostFrameCallback( + (_) => Navigator.of(context).pop(), + ); } } } @@ -250,21 +238,20 @@ class _EmojiImportPreviewState extends State<_EmojiImportPreview> { if (hasError) return _ImageFileError(name: widget.entry.key.name); return Column( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, + mainAxisSize: .min, + mainAxisAlignment: .center, + crossAxisAlignment: .center, children: [ Image.memory( widget.entry.key.content, height: 64, width: 64, errorBuilder: (context, e, s) { - WidgetsBinding.instance - .addPostFrameCallback((_) => _setRenderError()); - - return _ImageFileError( - name: widget.entry.key.name, + WidgetsBinding.instance.addPostFrameCallback( + (_) => _setRenderError(), ); + + return _ImageFileError(name: widget.entry.key.name); }, ), SizedBox( @@ -323,9 +310,9 @@ class _ImageFileError extends StatelessWidget { child: Tooltip( message: name, child: Column( - mainAxisAlignment: MainAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: .start, + mainAxisSize: .min, + crossAxisAlignment: .center, children: [ const Icon(Icons.error), Text( @@ -347,8 +334,7 @@ extension on String { /// Used to compute emote name proposal based on file name String get emoteNameFromPath { // ... removing leading path - return split(RegExp(r'[/\\]')) - .last + return split(RegExp(r'[/\\]')).last // ... removing file extension .split('.') .first diff --git a/lib/pages/settings_emotes/settings_emotes.dart b/lib/pages/settings_emotes/settings_emotes.dart index ffe039ee6..06090351c 100644 --- a/lib/pages/settings_emotes/settings_emotes.dart +++ b/lib/pages/settings_emotes/settings_emotes.dart @@ -53,10 +53,7 @@ class EmotesSettingsController extends State { final event = key == null ? null - : room?.getState( - 'im.ponies.room_emotes', - key, - ); + : room?.getState('im.ponies.room_emotes', key); final eventPack = event?.content.tryGetMap('pack'); packDisplayNameController.text = eventPack?.tryGet('display_name') ?? ''; @@ -69,13 +66,11 @@ class EmotesSettingsController extends State { ImagePackContent _getPack() { final client = Matrix.of(context).client; - final event = (room != null + final event = + (room != null ? room!.getState('im.ponies.room_emotes', stateKey ?? '') : client.accountData['im.ponies.user_emotes']) ?? - BasicEvent( - type: 'm.dummy', - content: {}, - ); + BasicEvent(type: 'm.dummy', content: {}); // make sure we work on a *copy* of the event return BasicEvent.fromJson(event.toJson()).parsedImagePackContent; } @@ -122,7 +117,8 @@ class EmotesSettingsController extends State { return; } final client = Matrix.of(context).client; - final content = client.accountData['im.ponies.emote_rooms']?.content ?? + final content = + client.accountData['im.ponies.emote_rooms']?.content ?? {}; if (active) { if (content['rooms'] is! Map) { @@ -156,14 +152,15 @@ class EmotesSettingsController extends State { TextEditingController(); void removeImageAction(String oldImageCode) => setState(() { - pack!.images.remove(oldImageCode); - showSave = true; - }); + pack!.images.remove(oldImageCode); + showSave = true; + }); void toggleUsage(String imageCode, ImagePackUsage usage) { setState(() { - final usages = - pack!.images[imageCode]!.usage ??= List.from(ImagePackUsage.values); + final usages = pack!.images[imageCode]!.usage ??= List.from( + ImagePackUsage.values, + ); if (!usages.remove(usage)) usages.add(usage); showSave = true; }); @@ -263,9 +260,7 @@ class EmotesSettingsController extends State { if (packKeys?.contains(name) ?? false) { ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(L10n.of(context).stickerPackNameAlreadyExists), - ), + SnackBar(content: Text(L10n.of(context).stickerPackNameAlreadyExists)), ); return; } @@ -314,20 +309,19 @@ class EmotesSettingsController extends State { bytes: await pickedFile.readAsBytes(), name: pickedFile.name, ); - file = await file.generateThumbnail( + file = + await file.generateThumbnail( nativeImplementations: ClientManager.nativeImplementations, ) ?? file; final uri = await Matrix.of(context).client.uploadContent( - file.bytes, - filename: file.name, - contentType: file.mimeType, - ); + file.bytes, + filename: file.name, + contentType: file.mimeType, + ); setState(() { - final info = { - ...file.info, - }; + final info = {...file.info}; // normalize width / height to 256, required for stickers if (info['w'] is int && info['h'] is int) { final ratio = info['w'] / info['h']; @@ -340,11 +334,9 @@ class EmotesSettingsController extends State { } } final imageCode = pickedFile.name.split('.').first; - pack!.images[imageCode] = - ImagePackImageContent.fromJson({ - 'url': uri.toString(), - 'info': info, - }); + pack!.images[imageCode] = ImagePackImageContent.fromJson( + {'url': uri.toString(), 'info': info}, + ); }); } }, @@ -361,10 +353,7 @@ class EmotesSettingsController extends State { } Future importEmojiZip() async { - final result = await selectFiles( - context, - type: FileSelectorType.zip, - ); + final result = await selectFiles(context, type: FileSelectorType.zip); if (result.isEmpty) return; @@ -376,10 +365,8 @@ class EmotesSettingsController extends State { context: context, // breaks [Matrix.of] calls otherwise useRootNavigator: false, - builder: (context) => ImportEmoteArchiveDialog( - controller: this, - archive: archive, - ), + builder: (context) => + ImportEmoteArchiveDialog(controller: this, archive: archive), ); setState(() {}); } @@ -402,11 +389,7 @@ class EmotesSettingsController extends State { ); archive.addFile( - ArchiveFile( - name, - response.bodyBytes.length, - response.bodyBytes, - ), + ArchiveFile(name, response.bodyBytes.length, response.bodyBytes), ); } final fileName = diff --git a/lib/pages/settings_emotes/settings_emotes_view.dart b/lib/pages/settings_emotes/settings_emotes_view.dart index 92a8b25c4..a5baf3979 100644 --- a/lib/pages/settings_emotes/settings_emotes_view.dart +++ b/lib/pages/settings_emotes/settings_emotes_view.dart @@ -23,9 +23,7 @@ class EmotesSettingsView extends StatelessWidget { Widget build(BuildContext context) { if (controller.widget.roomId != null && controller.room == null) { return Scaffold( - appBar: AppBar( - title: Text(L10n.of(context).oopsSomethingWentWrong), - ), + appBar: AppBar(title: Text(L10n.of(context).oopsSomethingWentWrong)), body: Center( child: Text(L10n.of(context).youAreNoLongerParticipatingInThisChat), ), @@ -110,10 +108,7 @@ class EmotesSettingsView extends StatelessWidget { horizontal: 4.0, ), child: FilterChip( - label: const Icon( - Icons.add_outlined, - size: 20, - ), + label: const Icon(Icons.add_outlined, size: 20), onSelected: controller.showSave ? null : (_) => controller.createImagePack(), @@ -122,23 +117,24 @@ class EmotesSettingsView extends StatelessWidget { } i--; final key = packKeys[i]; - final event = controller.room - ?.getState('im.ponies.room_emotes', packKeys[i]); + final event = controller.room?.getState( + 'im.ponies.room_emotes', + packKeys[i], + ); - final eventPack = - event?.content.tryGetMap('pack'); + final eventPack = event?.content + .tryGetMap('pack'); final packName = eventPack?.tryGet('display_name') ?? - eventPack?.tryGet('name') ?? - (key.isNotEmpty ? key : 'Default'); + eventPack?.tryGet('name') ?? + (key.isNotEmpty ? key : 'Default'); return Padding( - padding: const EdgeInsets.symmetric( - horizontal: 4.0, - ), + padding: const EdgeInsets.symmetric(horizontal: 4.0), child: FilterChip( label: Text(packName), - selected: controller.stateKey == key || + selected: + controller.stateKey == key || (controller.stateKey == null && key.isEmpty), onSelected: controller.showSave ? null @@ -153,8 +149,8 @@ class EmotesSettingsView extends StatelessWidget { ), body: MaxWidthBody( child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisSize: .min, + crossAxisAlignment: .stretch, children: [ if (controller.room != null) ...[ const SizedBox(height: 16), @@ -188,9 +184,10 @@ class EmotesSettingsView extends StatelessWidget { ? null : IconButton( icon: const Icon(Icons.link_outlined), - onPressed: () => - UrlLauncher(context, attributionUrl.toString()) - .launchUrl(), + onPressed: () => UrlLauncher( + context, + attributionUrl.toString(), + ).launchUrl(), ), ), ), @@ -283,25 +280,23 @@ class EmotesSettingsView extends StatelessWidget { ), onSubmitted: (s) => controller.submitImageAction( - imageCode, - image, - textEditingController, - ), + imageCode, + image, + textEditingController, + ), ), ), ), ), if (!controller.readonly) PopupMenuButton( - onSelected: (usage) => controller.toggleUsage( - imageCode, - usage, - ), + onSelected: (usage) => + controller.toggleUsage(imageCode, usage), itemBuilder: (context) => [ PopupMenuItem( value: ImagePackUsage.sticker, child: Row( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ if (image.usage?.contains( ImagePackUsage.sticker, @@ -316,7 +311,7 @@ class EmotesSettingsView extends StatelessWidget { PopupMenuItem( value: ImagePackUsage.emoticon, child: Row( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ if (image.usage?.contains( ImagePackUsage.emoticon, @@ -363,10 +358,8 @@ class _EmoteImage extends StatelessWidget { final key = 'sticker_preview_$mxc'; return InkWell( borderRadius: BorderRadius.circular(4), - onTap: () => showDialog( - context: context, - builder: (_) => MxcImageViewer(mxc), - ), + onTap: () => + showDialog(context: context, builder: (_) => MxcImageViewer(mxc)), child: MxcImage( key: ValueKey(key), cacheKey: key, diff --git a/lib/pages/settings_homeserver/settings_homeserver.dart b/lib/pages/settings_homeserver/settings_homeserver.dart index 76ca08232..13843336d 100644 --- a/lib/pages/settings_homeserver/settings_homeserver.dart +++ b/lib/pages/settings_homeserver/settings_homeserver.dart @@ -17,7 +17,7 @@ class SettingsHomeserver extends StatefulWidget { class SettingsHomeserverController extends State { Future<({String name, String version, Uri federationBaseUrl})> - fetchServerInfo() async { + fetchServerInfo() async { final client = Matrix.of(context).client; final domain = client.userID!.domain!; final httpClient = client.httpClient; @@ -37,15 +37,10 @@ class SettingsHomeserverController extends State { } final serverVersionResult = await http.get( - federationBaseUrl.resolveUri( - Uri(path: '/_matrix/federation/v1/version'), - ), + federationBaseUrl.resolveUri(Uri(path: '/_matrix/federation/v1/version')), ); final { - 'server': { - 'name': String name, - 'version': String version, - }, + 'server': {'name': String name, 'version': String version}, } = Map>.from( jsonDecode(serverVersionResult.body), ); diff --git a/lib/pages/settings_homeserver/settings_homeserver_view.dart b/lib/pages/settings_homeserver/settings_homeserver_view.dart index ee02337f0..3728b1e0c 100644 --- a/lib/pages/settings_homeserver/settings_homeserver_view.dart +++ b/lib/pages/settings_homeserver/settings_homeserver_view.dart @@ -30,15 +30,16 @@ class SettingsHomeserverView extends StatelessWidget { automaticallyImplyLeading: !FluffyThemes.isColumnMode(context), centerTitle: FluffyThemes.isColumnMode(context), title: Text( - L10n.of(context) - .aboutHomeserver(client.userID?.domain ?? 'Homeserver'), + L10n.of( + context, + ).aboutHomeserver(client.userID?.domain ?? 'Homeserver'), ), ), body: MaxWidthBody( withScrolling: true, child: SelectionArea( child: Column( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ ListTile( title: Text( @@ -68,9 +69,7 @@ class SettingsHomeserverView extends StatelessWidget { } if (data == null) { return const Center( - child: CircularProgressIndicator.adaptive( - strokeWidth: 2, - ), + child: CircularProgressIndicator.adaptive(strokeWidth: 2), ); } final supportPage = data.supportPage; @@ -85,7 +84,7 @@ class SettingsHomeserverView extends StatelessWidget { ); } return Column( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ if (supportPage != null) ListTile( @@ -93,32 +92,28 @@ class SettingsHomeserverView extends StatelessWidget { subtitle: Text(supportPage.toString()), ), if (contacts != null) - ...contacts.map( - (contact) { - return ListTile( - title: Text( - contact.role.localizedString( - L10n.of(context), - ), - ), - subtitle: Column( - mainAxisSize: MainAxisSize.min, - children: [ - if (contact.emailAddress != null) - TextButton( - onPressed: () {}, - child: Text(contact.emailAddress!), - ), - if (contact.matrixId != null) - TextButton( - onPressed: () {}, - child: Text(contact.matrixId!), - ), - ], - ), - ); - }, - ), + ...contacts.map((contact) { + return ListTile( + title: Text( + contact.role.localizedString(L10n.of(context)), + ), + subtitle: Column( + mainAxisSize: .min, + children: [ + if (contact.emailAddress != null) + TextButton( + onPressed: () {}, + child: Text(contact.emailAddress!), + ), + if (contact.matrixId != null) + TextButton( + onPressed: () {}, + child: Text(contact.matrixId!), + ), + ], + ), + ); + }), ], ); }, @@ -129,7 +124,7 @@ class SettingsHomeserverView extends StatelessWidget { final error = snapshot.error; if (error != null) { return Column( - mainAxisAlignment: MainAxisAlignment.center, + mainAxisAlignment: .center, children: [ Icon( Icons.error_outlined, @@ -139,9 +134,7 @@ class SettingsHomeserverView extends StatelessWidget { Text( error.toLocalizedString(context), textAlign: TextAlign.center, - style: TextStyle( - color: theme.colorScheme.error, - ), + style: TextStyle(color: theme.colorScheme.error), ), ], ); @@ -149,13 +142,11 @@ class SettingsHomeserverView extends StatelessWidget { final data = snapshot.data; if (data == null) { return const Center( - child: CircularProgressIndicator.adaptive( - strokeWidth: 2, - ), + child: CircularProgressIndicator.adaptive(strokeWidth: 2), ); } return Column( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ ListTile( title: Text(L10n.of(context).name), @@ -169,8 +160,9 @@ class SettingsHomeserverView extends StatelessWidget { title: const Text('Federation Base URL'), subtitle: Linkify( text: data.federationBaseUrl.toString(), - textScaleFactor: - MediaQuery.textScalerOf(context).scale(1), + textScaleFactor: MediaQuery.textScalerOf( + context, + ).scale(1), options: const LinkifyOptions(humanize: false), linkStyle: TextStyle( color: theme.colorScheme.primary, @@ -191,7 +183,7 @@ class SettingsHomeserverView extends StatelessWidget { final error = snapshot.error; if (error != null) { return Column( - mainAxisAlignment: MainAxisAlignment.center, + mainAxisAlignment: .center, children: [ Icon( Icons.error_outlined, @@ -201,9 +193,7 @@ class SettingsHomeserverView extends StatelessWidget { Text( error.toLocalizedString(context), textAlign: TextAlign.center, - style: TextStyle( - color: theme.colorScheme.error, - ), + style: TextStyle(color: theme.colorScheme.error), ), ], ); @@ -211,14 +201,12 @@ class SettingsHomeserverView extends StatelessWidget { final wellKnown = snapshot.data; if (wellKnown == null) { return const Center( - child: CircularProgressIndicator.adaptive( - strokeWidth: 2, - ), + child: CircularProgressIndicator.adaptive(strokeWidth: 2), ); } final identityServer = wellKnown.mIdentityServer; return Column( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ ListTile( title: Text( @@ -233,8 +221,9 @@ class SettingsHomeserverView extends StatelessWidget { title: const Text('Base URL'), subtitle: Linkify( text: wellKnown.mHomeserver.baseUrl.toString(), - textScaleFactor: - MediaQuery.textScalerOf(context).scale(1), + textScaleFactor: MediaQuery.textScalerOf( + context, + ).scale(1), options: const LinkifyOptions(humanize: false), linkStyle: TextStyle( color: theme.colorScheme.primary, @@ -248,8 +237,9 @@ class SettingsHomeserverView extends StatelessWidget { title: const Text('Identity Server:'), subtitle: Linkify( text: identityServer.baseUrl.toString(), - textScaleFactor: - MediaQuery.textScalerOf(context).scale(1), + textScaleFactor: MediaQuery.textScalerOf( + context, + ).scale(1), options: const LinkifyOptions(humanize: false), linkStyle: TextStyle( color: theme.colorScheme.primary, @@ -262,15 +252,17 @@ class SettingsHomeserverView extends StatelessWidget { (entry) => ListTile( title: Text(entry.key), subtitle: Material( - borderRadius: - BorderRadius.circular(AppConfig.borderRadius), + borderRadius: BorderRadius.circular( + AppConfig.borderRadius, + ), color: theme.colorScheme.surfaceContainer, child: SingleChildScrollView( padding: const EdgeInsets.all(16), scrollDirection: Axis.horizontal, child: Text( - const JsonEncoder.withIndent(' ') - .convert(entry.value), + const JsonEncoder.withIndent( + ' ', + ).convert(entry.value), style: TextStyle( color: theme.colorScheme.onSurface, ), diff --git a/lib/pages/settings_ignore_list/settings_ignore_list_view.dart b/lib/pages/settings_ignore_list/settings_ignore_list_view.dart index 19bd17c27..7dee64d11 100644 --- a/lib/pages/settings_ignore_list/settings_ignore_list_view.dart +++ b/lib/pages/settings_ignore_list/settings_ignore_list_view.dart @@ -36,12 +36,12 @@ class SettingsIgnoreListView extends StatelessWidget { return const Center(child: CircularProgressIndicator.adaptive()); } return Column( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ Padding( padding: const EdgeInsets.all(16.0), child: Column( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ TextField( controller: controller.controller, @@ -68,9 +68,7 @@ class SettingsIgnoreListView extends StatelessWidget { ], ), ), - Divider( - color: theme.dividerColor, - ), + Divider(color: theme.dividerColor), Expanded( child: ListView.builder( itemCount: client.ignoredUsers.length, diff --git a/lib/pages/settings_notifications/push_rule_extensions.dart b/lib/pages/settings_notifications/push_rule_extensions.dart index b531f6529..464c6a5fa 100644 --- a/lib/pages/settings_notifications/push_rule_extensions.dart +++ b/lib/pages/settings_notifications/push_rule_extensions.dart @@ -122,6 +122,7 @@ extension PushRuleExtension on PushRule { // '.im.vector.jitsi', ]; } + // Pangea# } diff --git a/lib/pages/settings_notifications/settings_notifications.dart b/lib/pages/settings_notifications/settings_notifications.dart index 06d3f7348..dd1a67577 100644 --- a/lib/pages/settings_notifications/settings_notifications.dart +++ b/lib/pages/settings_notifications/settings_notifications.dart @@ -47,11 +47,8 @@ class SettingsNotificationsController extends State { final success = await showFutureLoadingDialog( context: context, future: () => Matrix.of(context).client.deletePusher( - PusherId( - appId: pusher.appId, - pushkey: pusher.pushkey, - ), - ), + PusherId(appId: pusher.appId, pushkey: pusher.pushkey), + ), ); if (success.error != null) return; @@ -68,10 +65,7 @@ class SettingsNotificationsController extends State { isLoading = true; }); try { - final updateFromSync = Matrix.of(context) - .client - .onSync - .stream + final updateFromSync = Matrix.of(context).client.onSync.stream .where( (syncUpdate) => syncUpdate.accountData?.any( @@ -80,17 +74,16 @@ class SettingsNotificationsController extends State { false, ) .first; - await Matrix.of(context).client.setPushRuleEnabled( - kind, - pushRule.ruleId, - !pushRule.enabled, - ); + await Matrix.of( + context, + ).client.setPushRuleEnabled(kind, pushRule.ruleId, !pushRule.enabled); await updateFromSync; } catch (e, s) { Logs().w('Unable to toggle push rule', e, s); if (!mounted) return; - ScaffoldMessenger.of(context) - .showSnackBar(SnackBar(content: Text(e.toLocalizedString(context)))); + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text(e.toLocalizedString(context)))); } finally { if (mounted) { setState(() { @@ -118,9 +111,7 @@ class SettingsNotificationsController extends State { scrollDirection: Axis.horizontal, child: SelectableText( prettyJson(rule.toJson()), - style: TextStyle( - color: theme.colorScheme.onSurface, - ), + style: TextStyle(color: theme.colorScheme.onSurface), ), ), ), @@ -160,10 +151,7 @@ class SettingsNotificationsController extends State { isLoading = true; }); try { - final updateFromSync = Matrix.of(context) - .client - .onSync - .stream + final updateFromSync = Matrix.of(context).client.onSync.stream .where( (syncUpdate) => syncUpdate.accountData?.any( @@ -172,17 +160,14 @@ class SettingsNotificationsController extends State { false, ) .first; - await Matrix.of(context).client.deletePushRule( - kind, - rule.ruleId, - ); + await Matrix.of(context).client.deletePushRule(kind, rule.ruleId); await updateFromSync; } catch (e, s) { Logs().w('Unable to delete push rule', e, s); if (!mounted) return; - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text(e.toLocalizedString(context))), - ); + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text(e.toLocalizedString(context)))); } finally { if (mounted) { setState(() { @@ -195,8 +180,9 @@ class SettingsNotificationsController extends State { } // #Pangea - final ValueNotifier volumeNotifier = - ValueNotifier(AppSettings.volume.value); + final ValueNotifier volumeNotifier = ValueNotifier( + AppSettings.volume.value, + ); void updateVolume(double value) { volumeNotifier.value = value; diff --git a/lib/pages/settings_notifications/settings_notifications_view.dart b/lib/pages/settings_notifications/settings_notifications_view.dart index e4e14aa79..f2c211877 100644 --- a/lib/pages/settings_notifications/settings_notifications_view.dart +++ b/lib/pages/settings_notifications/settings_notifications_view.dart @@ -38,12 +38,12 @@ class SettingsNotificationsView extends StatelessWidget { body: MaxWidthBody( child: StreamBuilder( stream: Matrix.of(context).client.onSync.stream.where( - (syncUpdate) => - syncUpdate.accountData?.any( - (accountData) => accountData.type == 'm.push_rules', - ) ?? - false, - ), + (syncUpdate) => + syncUpdate.accountData?.any( + (accountData) => accountData.type == 'm.push_rules', + ) ?? + false, + ), builder: (BuildContext context, _) { final theme = Theme.of(context); return SelectionArea( @@ -116,8 +116,9 @@ class SettingsNotificationsView extends StatelessWidget { // #Pangea // for (final rule in category.rules) for (final rule in category.rules.where( - (rule) => PushRuleExtension.defaultPushRuleIds - .contains(rule.ruleId), + (rule) => PushRuleExtension.defaultPushRuleIds.contains( + rule.ruleId, + ), )) // Pangea# ListTile( @@ -156,14 +157,14 @@ class SettingsNotificationsView extends StatelessWidget { onChanged: controller.isLoading ? null : rule.ruleId != '.m.rule.master' && - Matrix.of(context) - .client - .allPushNotificationsMuted - ? null - : (_) => controller.togglePushRule( - category.kind, - rule, - ), + Matrix.of( + context, + ).client.allPushNotificationsMuted + ? null + : (_) => controller.togglePushRule( + category.kind, + rule, + ), ), ), Divider(color: theme.dividerColor), @@ -178,8 +179,9 @@ class SettingsNotificationsView extends StatelessWidget { ), ), FutureBuilder?>( - future: controller.pusherFuture ??= - Matrix.of(context).client.getPushers(), + future: controller.pusherFuture ??= Matrix.of( + context, + ).client.getPushers(), builder: (context, snapshot) { if (snapshot.hasError) { Center( diff --git a/lib/pages/settings_password/settings_password.dart b/lib/pages/settings_password/settings_password.dart index bc2400c8c..413f80259 100644 --- a/lib/pages/settings_password/settings_password.dart +++ b/lib/pages/settings_password/settings_password.dart @@ -55,13 +55,11 @@ class SettingsPasswordController extends State { try { final scaffoldMessenger = ScaffoldMessenger.of(context); await Matrix.of(context).client.changePassword( - newPassword1Controller.text, - oldPassword: oldPasswordController.text, - ); + newPassword1Controller.text, + oldPassword: oldPasswordController.text, + ); scaffoldMessenger.showSnackBar( - SnackBar( - content: Text(L10n.of(context).passwordHasBeenChanged), - ), + SnackBar(content: Text(L10n.of(context).passwordHasBeenChanged)), ); if (mounted) context.pop(); } catch (e) { diff --git a/lib/pages/settings_password/settings_password_view.dart b/lib/pages/settings_password/settings_password_view.dart index b52a22340..fc0904a98 100644 --- a/lib/pages/settings_password/settings_password_view.dart +++ b/lib/pages/settings_password/settings_password_view.dart @@ -15,9 +15,7 @@ class SettingsPasswordView extends StatelessWidget { final theme = Theme.of(context); return Scaffold( - appBar: AppBar( - title: Text(L10n.of(context).changePassword), - ), + appBar: AppBar(title: Text(L10n.of(context).changePassword)), body: ListTileTheme( iconColor: theme.colorScheme.onSurface, child: MaxWidthBody( @@ -69,8 +67,9 @@ class SettingsPasswordView extends StatelessWidget { SizedBox( width: double.infinity, child: ElevatedButton( - onPressed: - controller.loading ? null : controller.changePassword, + onPressed: controller.loading + ? null + : controller.changePassword, child: controller.loading ? const LinearProgressIndicator() : Text(L10n.of(context).changePassword), diff --git a/lib/pages/settings_security/settings_security.dart b/lib/pages/settings_security/settings_security.dart index c1708e9f5..f24d34ab8 100644 --- a/lib/pages/settings_security/settings_security.dart +++ b/lib/pages/settings_security/settings_security.dart @@ -118,13 +118,13 @@ class SettingsSecurityController extends State { // await showFutureLoadingDialog( // context: context, // future: () => Matrix.of(context).client.deactivateAccount( - // auth: AuthenticationPassword( - // password: input, - // identifier: AuthenticationUserIdentifier( - // user: Matrix.of(context).client.userID!, - // ), - // ), + // auth: AuthenticationPassword( + // password: input, + // identifier: AuthenticationUserIdentifier( + // user: Matrix.of(context).client.userID!, // ), + // ), + // ), // ); // Pangea# @@ -133,10 +133,8 @@ class SettingsSecurityController extends State { delay: false, future: () => Matrix.of(context).client.uiaRequestBackground( - (auth) => Matrix.of(context).client.deactivateAccount( - auth: auth, - ), - ), + (auth) => Matrix.of(context).client.deactivateAccount(auth: auth), + ), ); if (!resp.isError) { @@ -148,9 +146,7 @@ class SettingsSecurityController extends State { void changeShareKeysWith(ShareKeysWith? shareKeysWith) async { if (shareKeysWith == null) return; - AppSettings.shareKeysWith.setItem( - shareKeysWith.name, - ); + AppSettings.shareKeysWith.setItem(shareKeysWith.name); Matrix.of(context).client.shareKeysWith = shareKeysWith; setState(() {}); } diff --git a/lib/pages/settings_security/settings_security_view.dart b/lib/pages/settings_security/settings_security_view.dart index 039fd97eb..2d38a5c4e 100644 --- a/lib/pages/settings_security/settings_security_view.dart +++ b/lib/pages/settings_security/settings_security_view.dart @@ -33,10 +33,9 @@ class SettingsSecurityView extends StatelessWidget { iconColor: theme.colorScheme.onSurface, child: MaxWidthBody( child: FutureBuilder( - future: Matrix.of(context) - .client - .getCapabilities() - .timeout(const Duration(seconds: 10)), + future: Matrix.of( + context, + ).client.getCapabilities().timeout(const Duration(seconds: 10)), builder: (context, snapshot) { final capabilities = snapshot.data; final error = snapshot.error; @@ -61,8 +60,9 @@ class SettingsSecurityView extends StatelessWidget { ), SettingsSwitchListTile.adaptive( title: L10n.of(context).sendTypingNotifications, - subtitle: - L10n.of(context).sendTypingNotificationsDescription, + subtitle: L10n.of( + context, + ).sendTypingNotificationsDescription, setting: AppSettings.sendTypingNotifications, ), SettingsSwitchListTile.adaptive( @@ -103,14 +103,16 @@ class SettingsSecurityView extends StatelessWidget { ), ListTile( title: Material( - borderRadius: - BorderRadius.circular(AppConfig.borderRadius / 2), + borderRadius: BorderRadius.circular( + AppConfig.borderRadius / 2, + ), color: theme.colorScheme.onInverseSurface, child: DropdownButton( isExpanded: true, padding: const EdgeInsets.symmetric(horizontal: 8.0), - borderRadius: - BorderRadius.circular(AppConfig.borderRadius / 2), + borderRadius: BorderRadius.circular( + AppConfig.borderRadius / 2, + ), underline: const SizedBox.shrink(), value: Matrix.of(context).client.shareKeysWith, items: ShareKeysWith.values diff --git a/lib/pages/settings_style/settings_style.dart b/lib/pages/settings_style/settings_style.dart index 3ec628c53..f3d559a0d 100644 --- a/lib/pages/settings_style/settings_style.dart +++ b/lib/pages/settings_style/settings_style.dart @@ -26,10 +26,7 @@ class SettingsStyleController extends State { void setWallpaper() async { final client = Matrix.of(context).client; - final picked = await selectFiles( - context, - type: FileSelectorType.images, - ); + final picked = await selectFiles(context, type: FileSelectorType.images); final pickedFile = picked.firstOrNull; if (pickedFile == null) return; @@ -103,14 +100,11 @@ class SettingsStyleController extends State { } void deleteChatWallpaper() => showFutureLoadingDialog( - context: context, - future: () => Matrix.of(context).client.setApplicationAccountConfig( - const ApplicationAccountConfig( - wallpaperUrl: null, - wallpaperBlur: null, - ), - ), - ); + context: context, + future: () => Matrix.of(context).client.setApplicationAccountConfig( + const ApplicationAccountConfig(wallpaperUrl: null, wallpaperBlur: null), + ), + ); ThemeMode get currentTheme => ThemeController.of(context).themeMode; Color? get currentColor => ThemeController.of(context).primaryColor; diff --git a/lib/pages/settings_style/settings_style_view.dart b/lib/pages/settings_style/settings_style_view.dart index aa32e6828..ef2f94f08 100644 --- a/lib/pages/settings_style/settings_style_view.dart +++ b/lib/pages/settings_style/settings_style_view.dart @@ -38,7 +38,7 @@ class SettingsStyleView extends StatelessWidget { backgroundColor: theme.colorScheme.surface, body: MaxWidthBody( child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, + crossAxisAlignment: .stretch, children: [ Padding( padding: const EdgeInsets.all(12.0), @@ -65,9 +65,7 @@ class SettingsStyleView extends StatelessWidget { ], ), ), - Divider( - color: theme.dividerColor, - ), + Divider(color: theme.dividerColor), ListTile( title: Text( L10n.of(context).setColorTheme, @@ -81,10 +79,11 @@ class SettingsStyleView extends StatelessWidget { builder: (light, dark) { final systemColor = Theme.of(context).brightness == Brightness.light - ? light?.primary - : dark?.primary; - final colors = - List.from(SettingsStyleController.customColors); + ? light?.primary + : dark?.primary; + final colors = List.from( + SettingsStyleController.customColors, + ); if (systemColor == null) { colors.remove(null); } @@ -108,8 +107,9 @@ class SettingsStyleView extends StatelessWidget { child: Material( color: color ?? systemColor, elevation: 6, - borderRadius: - BorderRadius.circular(colorPickerSize), + borderRadius: BorderRadius.circular( + colorPickerSize, + ), child: SizedBox( width: colorPickerSize, height: colorPickerSize, @@ -118,9 +118,9 @@ class SettingsStyleView extends StatelessWidget { child: Icon( Icons.check, size: 16, - color: Theme.of(context) - .colorScheme - .onPrimary, + color: Theme.of( + context, + ).colorScheme.onPrimary, ), ) : null, @@ -133,9 +133,7 @@ class SettingsStyleView extends StatelessWidget { ); }, ), - Divider( - color: theme.dividerColor, - ), + Divider(color: theme.dividerColor), ListTile( title: Text( L10n.of(context).messagesStyle, @@ -159,7 +157,7 @@ class SettingsStyleView extends StatelessWidget { final accountConfig = client.applicationAccountConfig; return Column( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ AnimatedContainer( duration: FluffyThemes.animationDuration, @@ -188,14 +186,16 @@ class SettingsStyleView extends StatelessWidget { ), ), Column( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ const SizedBox(height: 16), StateMessage( Event( eventId: 'style_dummy', - room: - Room(id: '!style_dummy', client: client), + room: Room( + id: '!style_dummy', + client: client, + ), content: {'membership': 'join'}, type: EventTypes.RoomMember, senderId: client.userID!, @@ -228,7 +228,8 @@ class SettingsStyleView extends StatelessWidget { 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor', style: TextStyle( color: theme.onBubbleColor, - fontSize: AppConfig.messageFontSize * + fontSize: + AppConfig.messageFontSize * AppSettings.fontSizeFactor.value, ), ), @@ -261,7 +262,8 @@ class SettingsStyleView extends StatelessWidget { 'Lorem ipsum dolor sit amet', style: TextStyle( color: theme.colorScheme.onSurface, - fontSize: AppConfig.messageFontSize * + fontSize: + AppConfig.messageFontSize * AppSettings.fontSizeFactor.value, ), ), @@ -274,9 +276,7 @@ class SettingsStyleView extends StatelessWidget { ], ), ), - Divider( - color: theme.dividerColor, - ), + Divider(color: theme.dividerColor), ListTile( title: TextButton.icon( style: TextButton.styleFrom( @@ -324,9 +324,7 @@ class SettingsStyleView extends StatelessWidget { ), ListTile( title: Text(L10n.of(context).fontSize), - trailing: Text( - '× ${AppSettings.fontSizeFactor.value}', - ), + trailing: Text('× ${AppSettings.fontSizeFactor.value}'), ), Slider.adaptive( min: 0.5, @@ -337,9 +335,7 @@ class SettingsStyleView extends StatelessWidget { onChanged: controller.changeFontSizeFactor, ), // #Pangea - // Divider( - // color: theme.dividerColor, - // ), + // Divider(color: theme.dividerColor), // ListTile( // title: Text( // L10n.of(context).overview, diff --git a/lib/pangea/activity_generator/media_enum.dart b/lib/pangea/activity_generator/media_enum.dart index e6e3ed515..555bf090b 100644 --- a/lib/pangea/activity_generator/media_enum.dart +++ b/lib/pangea/activity_generator/media_enum.dart @@ -2,12 +2,7 @@ import 'package:flutter/material.dart'; import 'package:fluffychat/l10n/l10n.dart'; -enum MediaEnum { - images, - videos, - voiceMessages, - nan, -} +enum MediaEnum { images, videos, voiceMessages, nan } extension MediaEnumExtension on MediaEnum { //fromString diff --git a/lib/pangea/activity_planner/activity_plan_model.dart b/lib/pangea/activity_planner/activity_plan_model.dart index 4546aaacd..8dd68655f 100644 --- a/lib/pangea/activity_planner/activity_plan_model.dart +++ b/lib/pangea/activity_planner/activity_plan_model.dart @@ -41,27 +41,29 @@ class ActivityPlanModel { this.endAt, this.duration, this.isDeprecatedModel = false, - }) : description = (description == null || description.isEmpty) - ? learningObjective - : description, - _roles = roles, - _imageURL = imageURL; + }) : description = (description == null || description.isEmpty) + ? learningObjective + : description, + _roles = roles, + _imageURL = imageURL; List get placeholderImages => [ - "${AppConfig.assetsBaseURL}/Space%20template%202.png", - "${AppConfig.assetsBaseURL}/Space%20template%203.png", - "${AppConfig.assetsBaseURL}/Space%20template%204.png", - ]; + "${AppConfig.assetsBaseURL}/Space%20template%202.png", + "${AppConfig.assetsBaseURL}/Space%20template%203.png", + "${AppConfig.assetsBaseURL}/Space%20template%204.png", + ]; - String get randomPlaceholder => placeholderImages[ - Random(title.hashCode).nextInt(placeholderImages.length)]; + String get randomPlaceholder => + placeholderImages[Random( + title.hashCode, + ).nextInt(placeholderImages.length)]; Uri? get imageURL => _imageURL != null ? Uri.tryParse("${Environment.cmsApi}$_imageURL") : Uri.tryParse(randomPlaceholder); Map get roles { - if (_roles != null) return _roles!; + if (_roles != null) return _roles; final defaultRoles = {}; for (int i = 0; i < req.numberOfParticipants; i++) { defaultRoles['role_$i'] = ActivityRole( @@ -75,18 +77,16 @@ class ActivityPlanModel { } factory ActivityPlanModel.fromJson(Map json) { - final req = - ActivityPlanRequest.fromJson(json[ModelKey.activityPlanRequest]); + final req = ActivityPlanRequest.fromJson( + json[ModelKey.activityPlanRequest], + ); Map? roles; final roleContent = json['roles']; if (roleContent is Map) { roles = Map.from( json['roles'].map( - (key, value) => MapEntry( - key, - ActivityRole.fromJson(value), - ), + (key, value) => MapEntry(key, ActivityRole.fromJson(value)), ), ); } @@ -97,7 +97,8 @@ class ActivityPlanModel { instructions: json[ModelKey.activityPlanInstructions], req: req, title: json[ModelKey.activityPlanTitle], - description: json[ModelKey.description] ?? + description: + json[ModelKey.description] ?? json[ModelKey.activityPlanLearningObjective], learningObjective: json[ModelKey.activityPlanLearningObjective], vocab: List.from( @@ -135,9 +136,7 @@ class ActivityPlanModel { 'hours': duration?.inHours.remainder(24) ?? 0, 'minutes': duration?.inMinutes.remainder(60) ?? 0, }, - 'roles': _roles?.map( - (key, value) => MapEntry(key, value.toJson()), - ), + 'roles': _roles?.map((key, value) => MapEntry(key, value.toJson())), }; } @@ -187,16 +186,10 @@ class Vocab { final String lemma; final String pos; - Vocab({ - required this.lemma, - required this.pos, - }); + Vocab({required this.lemma, required this.pos}); factory Vocab.fromJson(Map json) { - return Vocab( - lemma: json[ModelKey.lemma], - pos: json['pos'], - ); + return Vocab(lemma: json[ModelKey.lemma], pos: json['pos']); } PangeaToken asToken() { @@ -215,10 +208,7 @@ class Vocab { } Map toJson() { - return { - ModelKey.lemma: lemma, - 'pos': pos, - }; + return {ModelKey.lemma: lemma, 'pos': pos}; } @override @@ -261,11 +251,6 @@ class ActivityRole { } Map toJson() { - return { - 'id': id, - 'name': name, - 'goal': goal, - 'avatar_url': avatarUrl, - }; + return {'id': id, 'name': name, 'goal': goal, 'avatar_url': avatarUrl}; } } diff --git a/lib/pangea/activity_sessions/activity_participant_indicator.dart b/lib/pangea/activity_sessions/activity_participant_indicator.dart index c5871e820..c85f619b8 100644 --- a/lib/pangea/activity_sessions/activity_participant_indicator.dart +++ b/lib/pangea/activity_sessions/activity_participant_indicator.dart @@ -49,13 +49,14 @@ class ActivityParticipantIndicator extends StatelessWidget { return MouseRegion( cursor: SystemMouseCursors.basic, child: GestureDetector( - onTap: onTap ?? + onTap: + onTap ?? (user != null ? () => showMemberActionsPopupMenu( - context: context, - user: user!, - room: room, - ) + context: context, + user: user!, + room: room, + ) : null), child: AbsorbPointer( absorbing: !selectable, @@ -63,38 +64,38 @@ class ActivityParticipantIndicator extends StatelessWidget { builder: (context, hovered) { final avatar = userId != null ? user?.avatarUrl == null || - user!.avatarUrl!.toString().startsWith("mxc") - ? Avatar( - mxContent: - user?.avatarUrl != null ? user!.avatarUrl! : null, - name: userId!.localpart, - size: 60.0, - userId: userId, - miniIcon: - room != null && user?.id == BotName.byEnvironment - ? BotSettingsLanguageIcon(user: user!) - : null, - presenceOffset: - room != null && user?.id == BotName.byEnvironment - ? const Offset(0, 0) - : null, - ) - : ClipRRect( - borderRadius: BorderRadius.circular(30), - child: CachedNetworkImage( - imageUrl: user!.avatarUrl!.toString(), - width: 60.0, - height: 60.0, - fit: BoxFit.cover, - ), - ) + user!.avatarUrl!.toString().startsWith("mxc") + ? Avatar( + mxContent: user?.avatarUrl != null + ? user!.avatarUrl! + : null, + name: userId!.localpart, + size: 60.0, + userId: userId, + miniIcon: + room != null && + user?.id == BotName.byEnvironment + ? BotSettingsLanguageIcon(user: user!) + : null, + presenceOffset: + room != null && + user?.id == BotName.byEnvironment + ? const Offset(0, 0) + : null, + ) + : ClipRRect( + borderRadius: BorderRadius.circular(30), + child: CachedNetworkImage( + imageUrl: user!.avatarUrl!.toString(), + width: 60.0, + height: 60.0, + fit: BoxFit.cover, + ), + ) : CircleAvatar( radius: 30.0, backgroundColor: theme.colorScheme.primaryContainer, - child: const Icon( - Icons.question_mark, - size: 30.0, - ), + child: const Icon(Icons.question_mark, size: 30.0), ); return Opacity( opacity: opacity, @@ -103,7 +104,8 @@ class ActivityParticipantIndicator extends StatelessWidget { borderRadius: borderRadius, child: Container( alignment: Alignment.center, - padding: padding ?? + padding: + padding ?? const EdgeInsets.symmetric( vertical: 4.0, horizontal: 8.0, @@ -121,9 +123,7 @@ class ActivityParticipantIndicator extends StatelessWidget { avatar, Text( name, - style: const TextStyle( - fontSize: 12.0, - ), + style: const TextStyle(fontSize: 12.0), maxLines: 2, overflow: TextOverflow.ellipsis, textAlign: TextAlign.center, @@ -132,12 +132,13 @@ class ActivityParticipantIndicator extends StatelessWidget { userId?.localpart ?? L10n.of(context).openRoleLabel, style: TextStyle( fontSize: 12.0, - color: (Theme.of(context).brightness == + color: + (Theme.of(context).brightness == Brightness.light ? (userId?.localpart?.darkColor ?? - name.darkColor) + name.darkColor) : (userId?.localpart?.lightColorText ?? - name.lightColorText)), + name.lightColorText)), ), textAlign: TextAlign.center, maxLines: 1, diff --git a/lib/pangea/activity_sessions/activity_participant_list.dart b/lib/pangea/activity_sessions/activity_participant_list.dart index a29c3f23a..530d52f4f 100644 --- a/lib/pangea/activity_sessions/activity_participant_list.dart +++ b/lib/pangea/activity_sessions/activity_participant_list.dart @@ -42,8 +42,9 @@ class ActivityParticipantList extends StatelessWidget { room: room, builder: (context, participants) { final theme = Theme.of(context); - final availableRoles = - activity.roles.values.sorted((a, b) => a.id.compareTo(b.id)); + final availableRoles = activity.roles.values.sorted( + (a, b) => a.id.compareTo(b.id), + ); final remainingMembers = participants.participants.where( (p) => !assignedRoles.values.any((r) => r.userId == p.id), @@ -56,9 +57,10 @@ class ActivityParticipantList extends StatelessWidget { builder: (context, constraints) { const minItemWidth = 125.0; - final rows = (availableRoles.length / - (constraints.maxWidth / minItemWidth)) - .ceil(); + final rows = + (availableRoles.length / + (constraints.maxWidth / minItemWidth)) + .ceil(); final entriesPerRow = (availableRoles.length / rows).ceil(); @@ -78,7 +80,8 @@ class ActivityParticipantList extends StatelessWidget { ? isSelected!(availableRole.id) : false; - final assignedRole = assignedRoles[availableRole.id] ?? + final assignedRole = + assignedRoles[availableRole.id] ?? (selected ? ActivityRoleModel( id: availableRole.id, @@ -89,11 +92,11 @@ class ActivityParticipantList extends StatelessWidget { final User? user = participants.participants.firstWhereOrNull( - (u) => u.id == assignedRole?.userId, - ) ?? - course?.getParticipants().firstWhereOrNull( - (u) => u.id == assignedRole?.userId, - ); + (u) => u.id == assignedRole?.userId, + ) ?? + course?.getParticipants().firstWhereOrNull( + (u) => u.id == assignedRole?.userId, + ); final selectable = canSelect != null ? canSelect!(availableRole.id) @@ -156,9 +159,7 @@ class ActivityParticipantList extends StatelessWidget { userId: member.id, ), ConstrainedBox( - constraints: const BoxConstraints( - maxWidth: 80.0, - ), + constraints: const BoxConstraints(maxWidth: 80.0), child: Text( member.calcDisplayname(), style: TextStyle( diff --git a/lib/pangea/activity_sessions/activity_role_model.dart b/lib/pangea/activity_sessions/activity_role_model.dart index 1e862068b..96294259e 100644 --- a/lib/pangea/activity_sessions/activity_role_model.dart +++ b/lib/pangea/activity_sessions/activity_role_model.dart @@ -30,10 +30,7 @@ class ActivityRoleModel { return l10n.finishedTheActivity(displayName); } - return l10n.joinedTheActivity( - displayName, - role ?? l10n.participant, - ); + return l10n.joinedTheActivity(displayName, role ?? l10n.participant); } factory ActivityRoleModel.fromJson(Map json) { diff --git a/lib/pangea/activity_sessions/activity_roles_model.dart b/lib/pangea/activity_sessions/activity_roles_model.dart index ff8b392ae..ae26e39aa 100644 --- a/lib/pangea/activity_sessions/activity_roles_model.dart +++ b/lib/pangea/activity_sessions/activity_roles_model.dart @@ -32,17 +32,14 @@ class ActivityRolesModel { } Map toJson() { - return { - "roles": roles.map((id, role) => MapEntry(id, role.toJson())), - }; + return {"roles": roles.map((id, role) => MapEntry(id, role.toJson()))}; } static ActivityRolesModel fromJson(Map json) { - final roles = (json['roles'] as Map?) - ?.map((id, value) => MapEntry(id, ActivityRoleModel.fromJson(value))); - - return ActivityRolesModel( - roles ?? {}, + final roles = (json['roles'] as Map?)?.map( + (id, value) => MapEntry(id, ActivityRoleModel.fromJson(value)), ); + + return ActivityRolesModel(roles ?? {}); } } diff --git a/lib/pangea/activity_sessions/activity_room_extension.dart b/lib/pangea/activity_sessions/activity_room_extension.dart index e48a8cfd5..f4d9ab1e0 100644 --- a/lib/pangea/activity_sessions/activity_room_extension.dart +++ b/lib/pangea/activity_sessions/activity_room_extension.dart @@ -41,10 +41,7 @@ extension ActivityRoomExtension on Room { ErrorHandler.logError( e: e, s: s, - data: { - "roomID": id, - "stateEvent": stateEvent.content, - }, + data: {"roomID": id, "stateEvent": stateEvent.content}, ); return null; } @@ -60,10 +57,7 @@ extension ActivityRoomExtension on Room { ErrorHandler.logError( e: e, s: s, - data: { - "roomID": id, - "stateEvent": stateEvent.content, - }, + data: {"roomID": id, "stateEvent": stateEvent.content}, ); return null; } @@ -80,10 +74,7 @@ extension ActivityRoomExtension on Room { ErrorHandler.logError( e: e, s: s, - data: { - "roomID": id, - "stateEvent": content, - }, + data: {"roomID": id, "stateEvent": content}, ); } return null; @@ -187,9 +178,7 @@ extension ActivityRoomExtension on Room { ); } - Future setActivitySummary( - ActivitySummaryModel summary, - ) async { + Future setActivitySummary(ActivitySummaryModel summary) async { await client.setRoomStateWithKey( id, PangeaEventTypes.activitySummary, @@ -250,10 +239,16 @@ extension ActivityRoomExtension on Room { ) : ActivitySummaryResultsMessage( userId: event.senderId, - sent: - pangeaMessage.getSpeechToTextLocal()!.transcript.text.trim(), - written: - pangeaMessage.getSpeechToTextLocal()!.transcript.text.trim(), + sent: pangeaMessage + .getSpeechToTextLocal()! + .transcript + .text + .trim(), + written: pangeaMessage + .getSpeechToTextLocal()! + .transcript + .text + .trim(), time: event.originServerTs, tool: [], ); @@ -277,10 +272,7 @@ extension ActivityRoomExtension on Room { ); await setActivitySummary( - ActivitySummaryModel( - summary: resp, - analytics: analytics, - ), + ActivitySummaryModel(summary: resp, analytics: analytics), ); ActivitySummaryRepo.delete(id, activityPlan!); @@ -299,10 +291,7 @@ extension ActivityRoomExtension on Room { if (activitySummary?.summary == null) { await setActivitySummary( - ActivitySummaryModel( - errorAt: DateTime.now(), - analytics: analytics, - ), + ActivitySummaryModel(errorAt: DateTime.now(), analytics: analytics), ); } } @@ -381,9 +370,7 @@ extension ActivityRoomExtension on Room { // if the user is in the chat (not null && membership is join), // then the activity is not finished for them - final user = getParticipants().firstWhereOrNull( - (u) => u.id == r.userId, - ); + final user = getParticipants().firstWhereOrNull((u) => u.id == r.userId); return user == null || user.membership != Membership.join; }); } @@ -404,6 +391,6 @@ extension ActivityRoomExtension on Room { // helper functions for activity course context Room? get courseParent => pangeaSpaceParents.firstWhereOrNull( - (parent) => parent.coursePlan != null, - ); + (parent) => parent.coursePlan != null, + ); } diff --git a/lib/pangea/activity_sessions/activity_session_analytics_repo.dart b/lib/pangea/activity_sessions/activity_session_analytics_repo.dart index 9de51dbba..50155dbba 100644 --- a/lib/pangea/activity_sessions/activity_session_analytics_repo.dart +++ b/lib/pangea/activity_sessions/activity_session_analytics_repo.dart @@ -15,8 +15,9 @@ class CachedActivityAnalytics { } class ActivitySessionAnalyticsRepo { - static final GetStorage _activityAnalyticsStorage = - GetStorage('activity_analytics_storage'); + static final GetStorage _activityAnalyticsStorage = GetStorage( + 'activity_analytics_storage', + ); static Duration cacheDuration = const Duration(minutes: 30); @@ -31,8 +32,9 @@ class ActivitySessionAnalyticsRepo { return null; } - final lastUseTimestamp = - DateTime.parse(json['last_use_timestamp'] as String); + final lastUseTimestamp = DateTime.parse( + json['last_use_timestamp'] as String, + ); final analyticsJson = json['analytics'] as Map; final analytics = ActivitySummaryAnalyticsModel.fromJson(analyticsJson); return CachedActivityAnalytics(timestamp, lastUseTimestamp, analytics); diff --git a/lib/pangea/activity_sessions/activity_session_chat/activity_analytics_chip.dart b/lib/pangea/activity_sessions/activity_session_chat/activity_analytics_chip.dart index afeb7d792..53cac76f2 100644 --- a/lib/pangea/activity_sessions/activity_session_chat/activity_analytics_chip.dart +++ b/lib/pangea/activity_sessions/activity_session_chat/activity_analytics_chip.dart @@ -3,11 +3,7 @@ import 'package:flutter/material.dart'; class ActivityAnalyticsChip extends StatelessWidget { final IconData icon; final String text; - const ActivityAnalyticsChip( - this.icon, - this.text, { - super.key, - }); + const ActivityAnalyticsChip(this.icon, this.text, {super.key}); @override Widget build(BuildContext context) { @@ -23,12 +19,7 @@ class ActivityAnalyticsChip extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ Icon(icon, size: 12.0), - Text( - text, - style: const TextStyle( - fontSize: 12.0, - ), - ), + Text(text, style: const TextStyle(fontSize: 12.0)), ], ), ); diff --git a/lib/pangea/activity_sessions/activity_session_chat/activity_chat_controller.dart b/lib/pangea/activity_sessions/activity_session_chat/activity_chat_controller.dart index d5a38e17b..0f9b7d634 100644 --- a/lib/pangea/activity_sessions/activity_session_chat/activity_chat_controller.dart +++ b/lib/pangea/activity_sessions/activity_session_chat/activity_chat_controller.dart @@ -17,10 +17,7 @@ class ActivityChatController { final String userID; final Room room; - ActivityChatController({ - required this.userID, - required this.room, - }) { + ActivityChatController({required this.userID, required this.room}) { init(); } @@ -36,8 +33,13 @@ class ActivityChatController { void init() { _updateUsedVocab(); - _analyticsSubscription = MatrixState.pangeaController.matrixState - .analyticsDataService.updateDispatcher.constructUpdateStream.stream + _analyticsSubscription = MatrixState + .pangeaController + .matrixState + .analyticsDataService + .updateDispatcher + .constructUpdateStream + .stream .listen((_) => _updateUsedVocab()); } @@ -80,7 +82,8 @@ class ActivityChatController { try { final analytics = await getActivityAnalytics(); if (!_disposed) { - usedVocab.value = analytics.constructs[userID] + usedVocab.value = + analytics.constructs[userID] ?.constructsOfType(ConstructTypeEnum.vocab) .map((id) => id.lemma.toLowerCase()) .toSet() ?? diff --git a/lib/pangea/activity_sessions/activity_session_chat/activity_chat_extension.dart b/lib/pangea/activity_sessions/activity_session_chat/activity_chat_extension.dart index fa917769a..30ce61385 100644 --- a/lib/pangea/activity_sessions/activity_session_chat/activity_chat_extension.dart +++ b/lib/pangea/activity_sessions/activity_session_chat/activity_chat_extension.dart @@ -30,8 +30,10 @@ extension ActivityMenuLogic on ChatController { (event) => event.senderId == userID && event.type == EventTypes.Message && - {MessageTypes.Text, MessageTypes.Audio} - .contains(event.messageType), + { + MessageTypes.Text, + MessageTypes.Audio, + }.contains(event.messageType), ) .length; diff --git a/lib/pangea/activity_sessions/activity_session_chat/activity_finished_status_message.dart b/lib/pangea/activity_sessions/activity_session_chat/activity_finished_status_message.dart index dbd0b0578..5a85ec999 100644 --- a/lib/pangea/activity_sessions/activity_session_chat/activity_finished_status_message.dart +++ b/lib/pangea/activity_sessions/activity_session_chat/activity_finished_status_message.dart @@ -15,10 +15,7 @@ import 'package:fluffychat/widgets/matrix.dart'; class ActivityFinishedStatusMessage extends StatelessWidget { final ChatController controller; - const ActivityFinishedStatusMessage({ - super.key, - required this.controller, - }); + const ActivityFinishedStatusMessage({super.key, required this.controller}); void _onArchive(BuildContext context) { _archiveToAnalytics(); @@ -38,16 +35,13 @@ class ActivityFinishedStatusMessage extends StatelessWidget { final langModel = PLanguageStore.byLangCode(lang)!; await controller.room.archiveActivity(); await MatrixState - .pangeaController.matrixState.analyticsDataService.updateService + .pangeaController + .matrixState + .analyticsDataService + .updateService .sendActivityAnalytics(controller.room.id, langModel); } catch (e, s) { - ErrorHandler.logError( - e: e, - s: s, - data: { - 'roomId': controller.room.id, - }, - ); + ErrorHandler.logError(e: e, s: s, data: {'roomId': controller.room.id}); } } @@ -66,15 +60,13 @@ class ActivityFinishedStatusMessage extends StatelessWidget { final theme = Theme.of(context); final isSubscribed = MatrixState.pangeaController.subscriptionController.isSubscribed != - false; + false; return Container( padding: const EdgeInsets.all(12.0), decoration: BoxDecoration( color: theme.colorScheme.surface, - border: Border( - top: BorderSide(color: theme.dividerColor), - ), + border: Border(top: BorderSide(color: theme.dividerColor)), ), child: Center( child: ConstrainedBox( @@ -99,9 +91,7 @@ class ActivityFinishedStatusMessage extends StatelessWidget { onArchive: () => _onArchive(context), ), if (!controller.room.isActivityFinished) - _WaitSection( - onContinue: controller.room.continueActivity, - ), + _WaitSection(onContinue: controller.room.continueActivity), ], ), ), @@ -114,10 +104,7 @@ class _SummarySection extends StatelessWidget { final ChatController controller; final bool isSubscribed; - const _SummarySection({ - required this.controller, - required this.isSubscribed, - }); + const _SummarySection({required this.controller, required this.isSubscribed}); ActivitySummaryModel? get summary => controller.room.activitySummary; @@ -153,8 +140,9 @@ class _SummarySection extends StatelessWidget { return ErrorIndicator( message: L10n.of(context).subscribeToUnlockActivitySummaries, onTap: () { - MatrixState.pangeaController.subscriptionController - .showPaywall(context); + MatrixState.pangeaController.subscriptionController.showPaywall( + context, + ); }, ); } @@ -192,10 +180,7 @@ class _ArchiveSection extends StatelessWidget { final bool enabled; final VoidCallback onArchive; - const _ArchiveSection({ - required this.enabled, - required this.onArchive, - }); + const _ArchiveSection({required this.enabled, required this.onArchive}); @override Widget build(BuildContext context) { @@ -212,10 +197,7 @@ class _ArchiveSection extends StatelessWidget { ElevatedButton( onPressed: enabled ? onArchive : null, style: ElevatedButton.styleFrom( - padding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 8, - ), + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), foregroundColor: theme.colorScheme.onPrimaryContainer, backgroundColor: theme.colorScheme.primaryContainer, ), @@ -250,24 +232,16 @@ class _WaitSection extends StatelessWidget { children: [ Text( L10n.of(context).waitingForOthersToFinish, - style: const TextStyle( - fontSize: 12, - fontStyle: FontStyle.italic, - ), + style: const TextStyle(fontSize: 12, fontStyle: FontStyle.italic), textAlign: TextAlign.center, ), ElevatedButton( onPressed: onContinue, style: ElevatedButton.styleFrom( - padding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 8, - ), + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), foregroundColor: theme.colorScheme.onSurface, backgroundColor: theme.colorScheme.surface, - side: BorderSide( - color: theme.colorScheme.primaryContainer, - ), + side: BorderSide(color: theme.colorScheme.primaryContainer), ), child: Text( L10n.of(context).waitNotDone, diff --git a/lib/pangea/activity_sessions/activity_session_chat/activity_menu_button.dart b/lib/pangea/activity_sessions/activity_session_chat/activity_menu_button.dart index 90940a60d..b2f72cdce 100644 --- a/lib/pangea/activity_sessions/activity_session_chat/activity_menu_button.dart +++ b/lib/pangea/activity_sessions/activity_session_chat/activity_menu_button.dart @@ -17,10 +17,7 @@ import 'package:fluffychat/widgets/matrix.dart'; class ActivityMenuButton extends StatefulWidget { final ChatController controller; - const ActivityMenuButton({ - super.key, - required this.controller, - }); + const ActivityMenuButton({super.key, required this.controller}); @override State createState() => _ActivityMenuButtonState(); diff --git a/lib/pangea/activity_sessions/activity_session_chat/activity_roles_event_widget.dart b/lib/pangea/activity_sessions/activity_session_chat/activity_roles_event_widget.dart index 6a52cfc37..9ab643b7f 100644 --- a/lib/pangea/activity_sessions/activity_session_chat/activity_roles_event_widget.dart +++ b/lib/pangea/activity_sessions/activity_session_chat/activity_roles_event_widget.dart @@ -10,10 +10,7 @@ import 'package:fluffychat/pangea/activity_sessions/activity_role_model.dart'; class ActivityRolesEvent extends StatelessWidget { final Event event; - const ActivityRolesEvent({ - super.key, - required this.event, - }); + const ActivityRolesEvent({super.key, required this.event}); @override Widget build(BuildContext context) { @@ -27,11 +24,10 @@ class ActivityRolesEvent extends StatelessWidget { .toSet(); final previousRoles = - (event.prevContent?['roles'] as Map?) - ?.values - .map((v) => ActivityRoleModel.fromJson(v)) - .toSet() ?? - {}; + (event.prevContent?['roles'] as Map?)?.values + .map((v) => ActivityRoleModel.fromJson(v)) + .toSet() ?? + {}; difference = currentRoles.difference(previousRoles); } catch (e) { @@ -45,8 +41,8 @@ class ActivityRolesEvent extends StatelessWidget { return Column( children: difference.map((role) { final user = event.room.getParticipants().firstWhereOrNull( - (u) => u.id == role.userId, - ); + (u) => u.id == role.userId, + ); final displayName = user?.calcDisplayname() ?? role.userId.localpart ?? role.userId; @@ -74,8 +70,9 @@ class ActivityRolesEvent extends StatelessWidget { overflow: TextOverflow.ellipsis, style: TextStyle( fontSize: 12 * AppSettings.fontSizeFactor.value, - decoration: - event.redacted ? TextDecoration.lineThrough : null, + decoration: event.redacted + ? TextDecoration.lineThrough + : null, ), ), ), diff --git a/lib/pangea/activity_sessions/activity_session_chat/activity_session_popup_menu.dart b/lib/pangea/activity_sessions/activity_session_chat/activity_session_popup_menu.dart index b28b6813a..8dd0c102f 100644 --- a/lib/pangea/activity_sessions/activity_session_chat/activity_session_popup_menu.dart +++ b/lib/pangea/activity_sessions/activity_session_chat/activity_session_popup_menu.dart @@ -31,11 +31,7 @@ class ActivitySessionPopupMenuState extends State widget.onLeave(); break; case ActivityPopupMenuActions.invite: - NavigationUtil.goToSpaceRoute( - widget.room.id, - ['invite'], - context, - ); + NavigationUtil.goToSpaceRoute(widget.room.id, ['invite'], context); break; case ActivityPopupMenuActions.download: downloadChatAction(widget.room.id, context); diff --git a/lib/pangea/activity_sessions/activity_session_chat/activity_stats_menu.dart b/lib/pangea/activity_sessions/activity_session_chat/activity_stats_menu.dart index ef96f27e4..341eaf6be 100644 --- a/lib/pangea/activity_sessions/activity_session_chat/activity_stats_menu.dart +++ b/lib/pangea/activity_sessions/activity_session_chat/activity_stats_menu.dart @@ -16,10 +16,7 @@ import 'package:fluffychat/widgets/future_loading_dialog.dart'; class ActivityStatsMenu extends StatelessWidget { final ChatController controller; - const ActivityStatsMenu( - this.controller, { - super.key, - }); + const ActivityStatsMenu(this.controller, {super.key}); int _getAssignedRolesCount() { final assignedRoles = controller.room.assignedRoles; @@ -125,9 +122,7 @@ class ActivityStatsMenu extends StatelessWidget { }, child: Container( width: double.infinity, - decoration: BoxDecoration( - color: theme.colorScheme.surface, - ), + decoration: BoxDecoration(color: theme.colorScheme.surface), padding: const EdgeInsets.all(12.0), child: Column( spacing: 12.0, @@ -191,9 +186,7 @@ class ActivityStatsMenu extends StatelessWidget { children: [ Text( L10n.of(context).endForAll, - style: TextStyle( - fontSize: isColumnMode ? 16.0 : 12.0, - ), + style: TextStyle(fontSize: isColumnMode ? 16.0 : 12.0), ), ], ), @@ -212,9 +205,7 @@ class ActivityStatsMenu extends StatelessWidget { children: [ Text( L10n.of(context).endActivity, - style: TextStyle( - fontSize: isColumnMode ? 16.0 : 12.0, - ), + style: TextStyle(fontSize: isColumnMode ? 16.0 : 12.0), ), ], ), diff --git a/lib/pangea/activity_sessions/activity_session_chat/activity_vocab_widget.dart b/lib/pangea/activity_sessions/activity_session_chat/activity_vocab_widget.dart index 0a05e5c47..c03693cc1 100644 --- a/lib/pangea/activity_sessions/activity_session_chat/activity_vocab_widget.dart +++ b/lib/pangea/activity_sessions/activity_session_chat/activity_vocab_widget.dart @@ -44,7 +44,7 @@ class ActivityVocabWidget extends StatelessWidget { return ValueListenableBuilder( valueListenable: usedVocab!, - builder: (context, used, __) => _VocabChips( + builder: (context, used, _) => _VocabChips( vocab: vocab, targetId: targetId, langCode: langCode, @@ -83,10 +83,7 @@ class _VocabChipsState extends State<_VocabChips> with TokenRenderingMixin { super.dispose(); } - void _onTap( - Vocab v, - bool isNew, - ) { + void _onTap(Vocab v, bool isNew) { setState(() { _selectedVocab = v; }); @@ -139,57 +136,54 @@ class _VocabChipsState extends State<_VocabChips> with TokenRenderingMixin { spacing: 4.0, runSpacing: 4.0, children: [ - ...widget.vocab.map( - (v) { - final target = "${widget.targetId}-${v.lemma}"; - final color = widget.usedVocab.contains(v.lemma.toLowerCase()) - ? Color.alphaBlend( - Theme.of(context).colorScheme.surface.withAlpha(150), - AppConfig.gold, - ) - : Theme.of(context).colorScheme.primary.withAlpha(20); + ...widget.vocab.map((v) { + final target = "${widget.targetId}-${v.lemma}"; + final color = widget.usedVocab.contains(v.lemma.toLowerCase()) + ? Color.alphaBlend( + Theme.of(context).colorScheme.surface.withAlpha(150), + AppConfig.gold, + ) + : Theme.of(context).colorScheme.primary.withAlpha(20); - final linkAndKey = MatrixState.pAnyState.layerLinkAndKey(target); - final isNew = newTokens - .any((t) => t.content.toLowerCase() == v.lemma.toLowerCase()); + final linkAndKey = MatrixState.pAnyState.layerLinkAndKey(target); + final isNew = newTokens.any( + (t) => t.content.toLowerCase() == v.lemma.toLowerCase(), + ); - return CompositedTransformTarget( - link: linkAndKey.link, - child: InkWell( - key: linkAndKey.key, - borderRadius: BorderRadius.circular( - 24.0, - ), - onTap: () => _onTap(v, isNew), - child: HoverBuilder( - builder: (context, hovered) => Container( - padding: const EdgeInsets.symmetric( - horizontal: 8.0, - vertical: 4.0, + return CompositedTransformTarget( + link: linkAndKey.link, + child: InkWell( + key: linkAndKey.key, + borderRadius: BorderRadius.circular(24.0), + onTap: () => _onTap(v, isNew), + child: HoverBuilder( + builder: (context, hovered) => Container( + padding: const EdgeInsets.symmetric( + horizontal: 8.0, + vertical: 4.0, + ), + decoration: BoxDecoration( + color: color, + borderRadius: BorderRadius.circular(20), + ), + child: UnderlineText( + text: v.lemma, + style: TextStyle( + color: Theme.of(context).colorScheme.onSurface, + fontSize: 14.0, ), - decoration: BoxDecoration( - color: color, - borderRadius: BorderRadius.circular(20), - ), - child: UnderlineText( - text: v.lemma, - style: TextStyle( - color: Theme.of(context).colorScheme.onSurface, - fontSize: 14.0, - ), - underlineColor: TokenRenderingUtil.underlineColor( - Theme.of(context).colorScheme.primary.withAlpha(200), - isNew: isNew, - selected: _selectedVocab == v, - hovered: hovered, - ), + underlineColor: TokenRenderingUtil.underlineColor( + Theme.of(context).colorScheme.primary.withAlpha(200), + isNew: isNew, + selected: _selectedVocab == v, + hovered: hovered, ), ), ), ), - ); - }, - ), + ), + ); + }), ], ); } diff --git a/lib/pangea/activity_sessions/activity_session_chat/load_activity_summary_widget.dart b/lib/pangea/activity_sessions/activity_session_chat/load_activity_summary_widget.dart index 9cfef83b2..47e553fbf 100644 --- a/lib/pangea/activity_sessions/activity_session_chat/load_activity_summary_widget.dart +++ b/lib/pangea/activity_sessions/activity_session_chat/load_activity_summary_widget.dart @@ -40,8 +40,9 @@ class LoadActivitySummaryWidgetState extends State { // The summary state event is waiting (<= 10 seconds since request) // Wait for 10 seconds (or time remaining until not waiting). If summary still not there, run request. if (_summaryEvent!.isLoading) { - final remainingTime = - DateTime.now().difference(_summaryEvent!.requestedAt!).inSeconds; + final remainingTime = DateTime.now() + .difference(_summaryEvent!.requestedAt!) + .inSeconds; await Future.delayed( Duration(seconds: remainingTime < 10 ? 10 - remainingTime : 0), diff --git a/lib/pangea/activity_sessions/activity_session_details_row.dart b/lib/pangea/activity_sessions/activity_session_details_row.dart index 0e5d44a8b..29057b818 100644 --- a/lib/pangea/activity_sessions/activity_session_details_row.dart +++ b/lib/pangea/activity_sessions/activity_session_details_row.dart @@ -21,12 +21,8 @@ class ActivitySessionDetailsRow extends StatelessWidget { child: Row( spacing: 12.0, children: [ - if (leading != null) leading!, - if (icon != null) - Icon( - icon, - size: iconSize ?? 24.0, - ), + ?leading, + if (icon != null) Icon(icon, size: iconSize ?? 24.0), Expanded(child: child), ], ), diff --git a/lib/pangea/activity_sessions/activity_session_start/activity_session_start_page.dart b/lib/pangea/activity_sessions/activity_session_start/activity_session_start_page.dart index ecfaeae14..070d8d521 100644 --- a/lib/pangea/activity_sessions/activity_session_start/activity_session_start_page.dart +++ b/lib/pangea/activity_sessions/activity_session_start/activity_session_start_page.dart @@ -101,21 +101,17 @@ class ActivitySessionStartController extends State } Room? get activityRoom => widget.roomId != null - ? Matrix.of(context).client.getRoomById( - widget.roomId!, - ) + ? Matrix.of(context).client.getRoomById(widget.roomId!) : null; Room? get courseParent => widget.parentId != null - ? Matrix.of(context).client.getRoomById( - widget.parentId!, - ) + ? Matrix.of(context).client.getRoomById(widget.parentId!) : null; bool get isBotRoomMember => activityRoom?.getParticipants().any( - (p) => p.id == BotName.byEnvironment, - ) ?? + (p) => p.id == BotName.byEnvironment, + ) ?? false; SessionState get state { @@ -140,8 +136,9 @@ class ActivitySessionStartController extends State String? get descriptionText { switch (state) { case SessionState.confirmedRole: - return L10n.of(context) - .waitingToFillRole(activityRoom!.numRemainingRoles); + return L10n.of( + context, + ).waitingToFillRole(activityRoom!.numRemainingRoles); case SessionState.selectedRole: return activity!.roles[_selectedRoleId!]!.goal; case SessionState.notStarted: @@ -157,10 +154,8 @@ class ActivitySessionStartController extends State } } - bool get enableButtons => [ - SessionState.notStarted, - SessionState.selectedRole, - ].contains(state); + bool get enableButtons => + [SessionState.notStarted, SessionState.selectedRole].contains(state); Map get assignedRoles { if (activityRoom != null && activityRoom!.membership == Membership.join) { @@ -176,7 +171,8 @@ class ActivitySessionStartController extends State } final availableRoles = activity!.roles; - final assignedRoles = activityRoom?.assignedRoles ?? + final assignedRoles = + activityRoom?.assignedRoles ?? roomSummaries?[widget.roomId]?.joinedUsersWithRoles ?? {}; final unassignedIds = availableRoles.keys @@ -191,7 +187,8 @@ class ActivitySessionStartController extends State } final availableRoles = activity!.roles; - final assignedRoles = activityRoom?.assignedRoles ?? + final assignedRoles = + activityRoom?.assignedRoles ?? roomSummaries?[widget.roomId]?.activityRoles?.roles ?? {}; final unassignedIds = availableRoles.keys @@ -237,7 +234,7 @@ class ActivitySessionStartController extends State } Map> - get activityStatuses => activitySessionStatuses(widget.activityId); + get activityStatuses => activitySessionStatuses(widget.activityId); void toggleInstructions() { setState(() { @@ -252,7 +249,8 @@ class ActivitySessionStartController extends State } Future neededCourseParticipants() async { - final courseParticipants = await courseParent?.requestParticipants( + final courseParticipants = + await courseParent?.requestParticipants( [Membership.join, Membership.invite, Membership.knock], false, true, @@ -352,9 +350,7 @@ class ActivitySessionStartController extends State await client.joinRoom( widget.roomId!, serverName: courseParent?.spaceChildren - .firstWhereOrNull( - (child) => child.roomId == widget.roomId, - ) + .firstWhereOrNull((child) => child.roomId == widget.roomId) ?.via, ); @@ -363,9 +359,11 @@ class ActivitySessionStartController extends State } if (activityRoom == null || activityRoom!.membership != Membership.join) { - throw Exception("Failed to join activity room. " - "Room ID: ${widget.roomId}, " - "Membership status: ${activityRoom?.membership}"); + throw Exception( + "Failed to join activity room. " + "Room ID: ${widget.roomId}, " + "Membership status: ${activityRoom?.membership}", + ); } } @@ -379,20 +377,14 @@ class ActivitySessionStartController extends State true, ); - await activityRoom!.joinActivity( - activity!.roles[_selectedRoleId!]!, - ); + await activityRoom!.joinActivity(activity!.roles[_selectedRoleId!]!); } catch (e) { if (e is! RoleException) { rethrow; } } - NavigationUtil.goToSpaceRoute( - widget.roomId, - [], - context, - ); + NavigationUtil.goToSpaceRoute(widget.roomId, [], context); } Future confirmRoleSelection() async { @@ -400,15 +392,11 @@ class ActivitySessionStartController extends State if (activityRoom?.membership == Membership.join) { await showFutureLoadingDialog( context: context, - future: () => activityRoom!.joinActivity( - activity!.roles[_selectedRoleId!]!, - ), + future: () => + activityRoom!.joinActivity(activity!.roles[_selectedRoleId!]!), ); } else if (widget.roomId != null) { - await showFutureLoadingDialog( - context: context, - future: joinActivity, - ); + await showFutureLoadingDialog(context: context, future: joinActivity); } else { final resp = await showFutureLoadingDialog( context: context, @@ -419,11 +407,7 @@ class ActivitySessionStartController extends State ); if (!resp.isError) { - NavigationUtil.goToSpaceRoute( - resp.result, - [], - context, - ); + NavigationUtil.goToSpaceRoute(resp.result, [], context); } } } @@ -440,9 +424,7 @@ class ActivitySessionStartController extends State await courseParent!.client.joinRoom( sessionId, via: courseParent?.spaceChildren - .firstWhereOrNull( - (child) => child.roomId == sessionId, - ) + .firstWhereOrNull((child) => child.roomId == sessionId) ?.via, ); joinedSessionId = sessionId; @@ -478,9 +460,7 @@ class ActivitySessionStartController extends State await courseParent!.client.joinRoom( roomId, via: courseParent?.spaceChildren - .firstWhereOrNull( - (child) => child.roomId == roomId, - ) + .firstWhereOrNull((child) => child.roomId == roomId) ?.via, ); @@ -511,27 +491,21 @@ class ActivitySessionStartController extends State if (mounted) setState(() {}); }); - await activityRoom!.courseParent!.sendEvent( - { - "body": L10n.of(context).pingParticipantsNotification( - activityRoom!.client.userID!.localpart ?? - activityRoom!.client.userID!, - activityRoom!.getLocalizedDisplayname(MatrixLocals(L10n.of(context))), - ), - "msgtype": "m.text", - "pangea.activity.session_room_id": activityRoom!.id, - "pangea.activity.id": widget.activityId, - }, - ); + await activityRoom!.courseParent!.sendEvent({ + "body": L10n.of(context).pingParticipantsNotification( + activityRoom!.client.userID!.localpart ?? activityRoom!.client.userID!, + activityRoom!.getLocalizedDisplayname(MatrixLocals(L10n.of(context))), + ), + "msgtype": "m.text", + "pangea.activity.session_room_id": activityRoom!.id, + "pangea.activity.id": widget.activityId, + }); if (mounted) { setState(() {}); ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: Text( - L10n.of(context).pingSent, - textAlign: TextAlign.center, - ), + content: Text(L10n.of(context).pingSent, textAlign: TextAlign.center), duration: const Duration(milliseconds: 2000), ), ); @@ -546,10 +520,7 @@ class ActivitySessionStartController extends State ); if (resp.isError && resp.error is TimeoutException) { - showDialog( - context: context, - builder: (_) => const BotJoinErrorDialog(), - ); + showDialog(context: context, builder: (_) => const BotJoinErrorDialog()); } } @@ -572,9 +543,7 @@ class ActivitySessionStartController extends State ) .first; activityRoom!.invite(BotName.byEnvironment); - await future.timeout( - const Duration(seconds: 5), - ); + await future.timeout(const Duration(seconds: 5)); } @override diff --git a/lib/pangea/activity_sessions/activity_session_start/activity_sessions_start_view.dart b/lib/pangea/activity_sessions/activity_session_start/activity_sessions_start_view.dart index eb11a47fa..a1ff1a22f 100644 --- a/lib/pangea/activity_sessions/activity_session_start/activity_sessions_start_view.dart +++ b/lib/pangea/activity_sessions/activity_session_start/activity_sessions_start_view.dart @@ -28,10 +28,7 @@ import 'package:fluffychat/widgets/member_actions_popup_menu_button.dart'; class ActivitySessionStartView extends StatelessWidget { final ActivitySessionStartController controller; - const ActivitySessionStartView( - this.controller, { - super.key, - }); + const ActivitySessionStartView(this.controller, {super.key}); @override Widget build(BuildContext context) { @@ -40,17 +37,13 @@ class ActivitySessionStartView extends StatelessWidget { backgroundColor: theme.colorScheme.primaryContainer, foregroundColor: theme.colorScheme.onPrimaryContainer, padding: const EdgeInsets.all(8.0), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(20.0), - ), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20.0)), ); return StreamBuilder( - stream: Matrix.of(context) - .client - .onRoomState - .stream - .rateLimit(const Duration(seconds: 1)), + stream: Matrix.of( + context, + ).client.onRoomState.stream.rateLimit(const Duration(seconds: 1)), builder: (context, snapshot) { return Scaffold( appBar: AppBar( @@ -64,9 +57,7 @@ class ActivitySessionStartView extends StatelessWidget { overflow: TextOverflow.ellipsis, textAlign: TextAlign.center, style: !FluffyThemes.isColumnMode(context) - ? const TextStyle( - fontSize: 16, - ) + ? const TextStyle(fontSize: 16) : null, ), ), @@ -108,9 +99,13 @@ class ActivitySessionStartView extends StatelessWidget { feedbackText: feedback, userId: Matrix.of(context).client.userID!, userL1: MatrixState - .pangeaController.userController.userL1Code!, + .pangeaController + .userController + .userL1Code!, userL2: MatrixState - .pangeaController.userController.userL2Code!, + .pangeaController + .userController + .userL2Code!, ), ), ); @@ -142,189 +137,184 @@ class ActivitySessionStartView extends StatelessWidget { child: controller.loading ? const Center(child: CircularProgressIndicator.adaptive()) : controller.error != null - ? Center( - child: ErrorIndicator( - message: L10n.of(context).activityNotFound, - ), - ) - : Column( - children: [ - Expanded( - child: SingleChildScrollView( - controller: controller.scrollController, - child: Container( - constraints: const BoxConstraints( - maxWidth: 600.0, + ? Center( + child: ErrorIndicator( + message: L10n.of(context).activityNotFound, + ), + ) + : Column( + children: [ + Expanded( + child: SingleChildScrollView( + controller: controller.scrollController, + child: Container( + constraints: const BoxConstraints(maxWidth: 600.0), + padding: const EdgeInsets.all(12.0), + child: Column( + children: [ + ActivitySummary( + activity: controller.activity!, + room: controller.activityRoom, + course: controller.courseParent, + showInstructions: controller.showInstructions, + toggleInstructions: + controller.toggleInstructions, + onTapParticipant: controller.selectRole, + isParticipantSelected: + controller.isParticipantSelected, + isParticipantShimmering: + controller.isParticipantShimmering, + canSelectParticipant: + controller.canSelectParticipant, + assignedRoles: controller.assignedRoles, ), - padding: const EdgeInsets.all(12.0), - child: Column( - children: [ - ActivitySummary( - activity: controller.activity!, - room: controller.activityRoom, - course: controller.courseParent, - showInstructions: - controller.showInstructions, - toggleInstructions: - controller.toggleInstructions, - onTapParticipant: controller.selectRole, - isParticipantSelected: - controller.isParticipantSelected, - isParticipantShimmering: - controller.isParticipantShimmering, - canSelectParticipant: - controller.canSelectParticipant, - assignedRoles: controller.assignedRoles, - ), - if (controller.courseParent != null && - controller.state == - SessionState.notStarted) - _ActivityStatuses( - statuses: controller.activityStatuses, - space: controller.courseParent!, - onTap: controller.joinActivityByRoomId, - ), - ], - ), - ), + if (controller.courseParent != null && + controller.state == SessionState.notStarted) + _ActivityStatuses( + statuses: controller.activityStatuses, + space: controller.courseParent!, + onTap: controller.joinActivityByRoomId, + ), + ], ), ), - AnimatedSize( - duration: FluffyThemes.animationDuration, - child: Container( - decoration: BoxDecoration( - border: Border( - top: BorderSide(color: theme.dividerColor), - ), - color: theme.colorScheme.surface, - ), - padding: const EdgeInsets.all(24.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Flexible( - child: ConstrainedBox( - constraints: const BoxConstraints( - maxWidth: FluffyThemes.maxTimelineWidth, - ), - child: Column( - spacing: 16.0, - children: [ - if (controller.descriptionText != - null) - Text( - controller.descriptionText!, - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - ), - textAlign: TextAlign.center, - ), - if (controller.state == - SessionState.notStarted) - _ActivityStartButtons( - controller, - buttonStyle, - ) - else if (controller.state == - SessionState.confirmedRole) ...[ - if (controller.courseParent != null) - ElevatedButton( - style: buttonStyle, - onPressed: controller - .canPingParticipants - ? () { - showFutureLoadingDialog( - context: context, - future: controller - .pingCourse, - ); - } - : null, - child: Row( - mainAxisAlignment: - MainAxisAlignment.center, - children: [ - Text( - L10n.of(context) - .pingParticipants, - ), - ], - ), - ), - if (controller - .activityRoom!.isRoomAdmin) ...[ - if (!controller.isBotRoomMember) - ElevatedButton( - style: buttonStyle, - onPressed: - controller.playWithBot, - child: Row( - mainAxisAlignment: - MainAxisAlignment - .center, - children: [ - Text( - L10n.of(context) - .playWithBot, - ), - ], - ), - ), - ElevatedButton( - style: buttonStyle, - onPressed: () { - NavigationUtil.goToSpaceRoute( - controller.activityRoom!.id, - ['invite'], + ), + ), + AnimatedSize( + duration: FluffyThemes.animationDuration, + child: Container( + decoration: BoxDecoration( + border: Border( + top: BorderSide(color: theme.dividerColor), + ), + color: theme.colorScheme.surface, + ), + padding: const EdgeInsets.all(24.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Flexible( + child: ConstrainedBox( + constraints: const BoxConstraints( + maxWidth: FluffyThemes.maxTimelineWidth, + ), + child: Column( + spacing: 16.0, + children: [ + if (controller.descriptionText != null) + Text( + controller.descriptionText!, + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600, + ), + textAlign: TextAlign.center, + ), + if (controller.state == + SessionState.notStarted) + _ActivityStartButtons( + controller, + buttonStyle, + ) + else if (controller.state == + SessionState.confirmedRole) ...[ + if (controller.courseParent != null) + ElevatedButton( + style: buttonStyle, + onPressed: + controller.canPingParticipants + ? () { + showFutureLoadingDialog( + context: context, + future: + controller.pingCourse, + ); + } + : null, + child: Row( + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + Text( + L10n.of( context, - ); - }, - child: Row( - mainAxisAlignment: - MainAxisAlignment.center, - children: [ - Text( - L10n.of(context) - .inviteFriends, - ), - ], + ).pingParticipants, ), - ), - ], - ] else + ], + ), + ), + if (controller + .activityRoom! + .isRoomAdmin) ...[ + if (!controller.isBotRoomMember) ElevatedButton( style: buttonStyle, - onPressed: - controller.enableButtons - ? controller - .confirmRoleSelection - : null, + onPressed: controller.playWithBot, child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( - controller.activityRoom - ?.isRoomAdmin ?? - true - ? L10n.of(context).start - : L10n.of(context) - .confirm, + L10n.of( + context, + ).playWithBot, ), ], ), ), + ElevatedButton( + style: buttonStyle, + onPressed: () { + NavigationUtil.goToSpaceRoute( + controller.activityRoom!.id, + ['invite'], + context, + ); + }, + child: Row( + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + Text( + L10n.of( + context, + ).inviteFriends, + ), + ], + ), + ), ], - ), - ), + ] else + ElevatedButton( + style: buttonStyle, + onPressed: controller.enableButtons + ? controller.confirmRoleSelection + : null, + child: Row( + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + Text( + controller + .activityRoom + ?.isRoomAdmin ?? + true + ? L10n.of(context).start + : L10n.of(context).confirm, + ), + ], + ), + ), + ], ), - ], + ), ), - ), + ], ), - ], + ), ), + ], + ), ), ); }, @@ -335,10 +325,7 @@ class ActivitySessionStartView extends StatelessWidget { class _ActivityStartButtons extends StatelessWidget { final ActivitySessionStartController controller; final ButtonStyle buttonStyle; - const _ActivityStartButtons( - this.controller, - this.buttonStyle, - ); + const _ActivityStartButtons(this.controller, this.buttonStyle); @override Widget build(BuildContext context) { @@ -368,16 +355,12 @@ class _ActivityStartButtons extends StatelessWidget { style: buttonStyle, onPressed: controller.courseParent?.canInvite ?? false ? () => context.push( - "/rooms/spaces/${controller.courseParent!.id}/invite", - ) + "/rooms/spaces/${controller.courseParent!.id}/invite", + ) : null, child: Row( mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - L10n.of(context).inviteFriendsToCourse, - ), - ], + children: [Text(L10n.of(context).inviteFriendsToCourse)], ), ), ElevatedButton( @@ -387,11 +370,7 @@ class _ActivityStartButtons extends StatelessWidget { ), child: Row( mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - L10n.of(context).pickDifferentActivity, - ), - ], + children: [Text(L10n.of(context).pickDifferentActivity)], ), ), ] else if (joinedActivityRoom != null) ...[ @@ -406,9 +385,7 @@ class _ActivityStartButtons extends StatelessWidget { }, child: Row( mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text(L10n.of(context).continueText), - ], + children: [Text(L10n.of(context).continueText)], ), ), ] else ...[ @@ -436,20 +413,12 @@ class _ActivityStartButtons extends StatelessWidget { ); if (!resp.isError) { - NavigationUtil.goToSpaceRoute( - resp.result, - [], - context, - ); + NavigationUtil.goToSpaceRoute(resp.result, [], context); } }, child: Row( mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - L10n.of(context).joinOpenSession, - ), - ], + children: [Text(L10n.of(context).joinOpenSession)], ), ), ], @@ -480,81 +449,78 @@ class _ActivityStatuses extends StatelessWidget { ), child: Column( children: [ - ...ActivitySummaryStatus.values.map( - (status) { - final entry = statuses[status]; - if (entry!.isEmpty) { - return const SizedBox.shrink(); - } + ...ActivitySummaryStatus.values.map((status) { + final entry = statuses[status]; + if (entry!.isEmpty) { + return const SizedBox.shrink(); + } - return Padding( - padding: const EdgeInsetsGeometry.symmetric( - horizontal: 20.0, - vertical: 16.0, - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.all(16.0), - child: Text( - status.label(L10n.of(context), entry.length), - style: theme.textTheme.titleMedium?.copyWith( - fontWeight: FontWeight.bold, - ), + return Padding( + padding: const EdgeInsetsGeometry.symmetric( + horizontal: 20.0, + vertical: 16.0, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.all(16.0), + child: Text( + status.label(L10n.of(context), entry.length), + style: theme.textTheme.titleMedium?.copyWith( + fontWeight: FontWeight.bold, ), ), - ...entry.entries.map((e) { - // if user is in the room, use the room info instead of the - // room summary response to get real-time activity roles info - final roomId = e.key; - final room = - Matrix.of(context).client.getRoomById(roomId); + ), + ...entry.entries.map((e) { + // if user is in the room, use the room info instead of the + // room summary response to get real-time activity roles info + final roomId = e.key; + final room = Matrix.of(context).client.getRoomById(roomId); - final activityPlan = - room?.activityPlan ?? e.value.activityPlan; + final activityPlan = + room?.activityPlan ?? e.value.activityPlan; - // If activity is completed, show all roles, even for users who have left the - // room (like the bot). Otherwise, show only joined users with roles - Map activityRoles = - status == ActivitySummaryStatus.completed - ? (e.value.activityRoles?.roles ?? {}) - : e.value.joinedUsersWithRoles; + // If activity is completed, show all roles, even for users who have left the + // room (like the bot). Otherwise, show only joined users with roles + Map activityRoles = + status == ActivitySummaryStatus.completed + ? (e.value.activityRoles?.roles ?? {}) + : e.value.joinedUsersWithRoles; - // If the user is in the activity room and it's not completed, use the room's - // state events to determine roles to update them in real-time - if (room?.assignedRoles != null && - status != ActivitySummaryStatus.completed) { - activityRoles = room!.assignedRoles!; - } + // If the user is in the activity room and it's not completed, use the room's + // state events to determine roles to update them in real-time + if (room?.assignedRoles != null && + status != ActivitySummaryStatus.completed) { + activityRoles = room!.assignedRoles!; + } - return ListTile( - title: OpenRolesIndicator( - roles: (activityPlan?.roles.values ?? []) - .sorted((a, b) => a.id.compareTo(b.id)) - .toList(), - assignedRoles: activityRoles.values.toList(), - size: 40.0, - spacing: 8.0, - space: space, - onUserTap: (user, context) { - showMemberActionsPopupMenu( - context: context, - user: user, - ); - }, - ), - trailing: space.isRoomAdmin - ? const Icon(Icons.arrow_forward) - : null, - onTap: space.isRoomAdmin ? () => onTap(roomId) : null, - ); - }), - ], - ), - ); - }, - ), + return ListTile( + title: OpenRolesIndicator( + roles: (activityPlan?.roles.values ?? []) + .sorted((a, b) => a.id.compareTo(b.id)) + .toList(), + assignedRoles: activityRoles.values.toList(), + size: 40.0, + spacing: 8.0, + space: space, + onUserTap: (user, context) { + showMemberActionsPopupMenu( + context: context, + user: user, + ); + }, + ), + trailing: space.isRoomAdmin + ? const Icon(Icons.arrow_forward) + : null, + onTap: space.isRoomAdmin ? () => onTap(roomId) : null, + ); + }), + ], + ), + ); + }), ], ), ); diff --git a/lib/pangea/activity_sessions/activity_session_start/bot_join_error_dialog.dart b/lib/pangea/activity_sessions/activity_session_start/bot_join_error_dialog.dart index 6a3ee5572..274bc9161 100644 --- a/lib/pangea/activity_sessions/activity_session_start/bot_join_error_dialog.dart +++ b/lib/pangea/activity_sessions/activity_session_start/bot_join_error_dialog.dart @@ -9,19 +9,14 @@ class BotJoinErrorDialog extends StatelessWidget { @override Widget build(BuildContext context) { return Dialog( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12.0), - ), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12.0)), child: Container( width: 300.0, padding: const EdgeInsets.all(16.0), child: Column( mainAxisSize: MainAxisSize.min, children: [ - const BotFace( - width: 100, - expression: BotExpression.addled, - ), + const BotFace(width: 100, expression: BotExpression.addled), const SizedBox(height: 8), Text( L10n.of(context).botActivityJoinFailMessage, diff --git a/lib/pangea/activity_sessions/activity_summary_widget.dart b/lib/pangea/activity_sessions/activity_summary_widget.dart index 7ef14d940..345393658 100644 --- a/lib/pangea/activity_sessions/activity_summary_widget.dart +++ b/lib/pangea/activity_sessions/activity_summary_widget.dart @@ -114,9 +114,7 @@ class ActivitySummary extends StatelessWidget { style: theme.textTheme.bodyMedium, ), Padding( - padding: const EdgeInsets.symmetric( - vertical: 4.0, - ), + padding: const EdgeInsets.symmetric(vertical: 4.0), child: Row( spacing: 4.0, mainAxisSize: MainAxisSize.min, diff --git a/lib/pangea/activity_sessions/activity_user_summaries_widget.dart b/lib/pangea/activity_sessions/activity_user_summaries_widget.dart index 39db710db..9177cd2d4 100644 --- a/lib/pangea/activity_sessions/activity_user_summaries_widget.dart +++ b/lib/pangea/activity_sessions/activity_user_summaries_widget.dart @@ -17,10 +17,7 @@ import 'package:fluffychat/widgets/avatar.dart'; class ActivityUserSummaries extends StatelessWidget { final ChatController controller; - const ActivityUserSummaries({ - super.key, - required this.controller, - }); + const ActivityUserSummaries({super.key, required this.controller}); Room get room => controller.room; @@ -36,8 +33,10 @@ class ActivityUserSummaries extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ Padding( - padding: - const EdgeInsets.symmetric(horizontal: 12.0, vertical: 4.0), + padding: const EdgeInsets.symmetric( + horizontal: 12.0, + vertical: 4.0, + ), child: Center( child: Material( color: Theme.of(context).colorScheme.surface.withAlpha(128), @@ -51,24 +50,15 @@ class ActivityUserSummaries extends StatelessWidget { spacing: 4.0, mainAxisSize: MainAxisSize.min, children: [ - Text( - L10n.of(context).activityFinishedMessage, - ), - Text( - summary.summary, - textAlign: TextAlign.center, - ), + Text(L10n.of(context).activityFinishedMessage), + Text(summary.summary, textAlign: TextAlign.center), ], ), ), ), ), ), - const Padding( - padding: EdgeInsets.symmetric( - vertical: 8.0, - ), - ), + const Padding(padding: EdgeInsets.symmetric(vertical: 8.0)), ButtonControlledCarouselView( summary: summary, controller: controller, @@ -88,11 +78,7 @@ class ButtonControlledCarouselView extends StatelessWidget { required this.controller, }); - void _scrollToUser( - ActivityRoleModel role, - int index, - double cardWidth, - ) { + void _scrollToUser(ActivityRoleModel role, int index, double cardWidth) { controller.activityController.highlightRole(role); final scrollController = controller.activityController.carouselController; @@ -123,8 +109,8 @@ class ButtonControlledCarouselView extends StatelessWidget { @override Widget build(BuildContext context) { final room = controller.room; - final superlatives = - room.activitySummary?.analytics?.generateSuperlatives(); + final superlatives = room.activitySummary?.analytics + ?.generateSuperlatives(); final availableRoles = room.activityPlan!.roles; final assignedRoles = room.assignedRoles ?? {}; final userSummaries = summary.participants @@ -156,8 +142,8 @@ class ButtonControlledCarouselView extends StatelessWidget { itemBuilder: (context, i) { final p = userSummaries[i]; final user = room.getParticipants().firstWhereOrNull( - (u) => u.id == p.participantId, - ); + (u) => u.id == p.participantId, + ); final userRole = assignedRoles.values.firstWhere( (role) => role.userId == p.participantId, ); @@ -193,9 +179,7 @@ class ButtonControlledCarouselView extends StatelessWidget { Flexible( child: Text( "${userRole.role ?? L10n.of(context).participant} | ${user?.calcDisplayname() ?? p.participantId.localpart}", - style: const TextStyle( - fontSize: 14.0, - ), + style: const TextStyle(fontSize: 14.0), overflow: TextOverflow.ellipsis, ), ), @@ -222,18 +206,14 @@ class ButtonControlledCarouselView extends StatelessWidget { children: [ Text( p.cefrLevel, - style: const TextStyle( - fontSize: 14.0, - ), + style: const TextStyle(fontSize: 14.0), ), //const SizedBox(width: 8), if (superlatives != null && (superlatives['vocab']!.contains( p.participantId, ))) ...[ - const SuperlativeTile( - icon: Symbols.dictionary, - ), + const SuperlativeTile(icon: Symbols.dictionary), ], if (superlatives != null && (superlatives['grammar']!.contains( @@ -247,9 +227,7 @@ class ButtonControlledCarouselView extends StatelessWidget { (superlatives['xp']!.contains( p.participantId, ))) ...[ - const SuperlativeTile( - icon: Icons.star, - ), + const SuperlativeTile(icon: Icons.star), ], if (p.superlatives.isNotEmpty) ...[ Text( @@ -273,7 +251,7 @@ class ButtonControlledCarouselView extends StatelessWidget { height: 125.0, child: ValueListenableBuilder( valueListenable: controller.activityController.highlightedRole, - builder: (context, highlightedRole, __) { + builder: (context, highlightedRole, _) { return ListView.builder( shrinkWrap: true, scrollDirection: Axis.horizontal, @@ -281,8 +259,8 @@ class ButtonControlledCarouselView extends StatelessWidget { itemBuilder: (context, index) { final p = userSummaries[index]; final user = room.getParticipants().firstWhereOrNull( - (u) => u.id == p.participantId, - ); + (u) => u.id == p.participantId, + ); final userRole = assignedRoles.values.firstWhere( (role) => role.userId == p.participantId, ); @@ -315,10 +293,7 @@ class ButtonControlledCarouselView extends StatelessWidget { class SuperlativeTile extends StatelessWidget { final IconData icon; - const SuperlativeTile({ - super.key, - required this.icon, - }); + const SuperlativeTile({super.key, required this.icon}); @override Widget build(BuildContext context) { @@ -327,12 +302,7 @@ class SuperlativeTile extends StatelessWidget { children: [ Icon(icon, size: 14, color: Theme.of(context).colorScheme.onSurface), const SizedBox(width: 2), - const Text( - "1st", - style: TextStyle( - fontSize: 14.0, - ), - ), + const Text("1st", style: TextStyle(fontSize: 14.0)), ], ); } @@ -340,9 +310,7 @@ class SuperlativeTile extends StatelessWidget { class _SummaryText extends StatefulWidget { final String text; - const _SummaryText({ - required this.text, - }); + const _SummaryText({required this.text}); @override State<_SummaryText> createState() => _SummaryTextState(); @@ -364,10 +332,7 @@ class _SummaryTextState extends State<_SummaryText> { thumbVisibility: true, child: SingleChildScrollView( controller: _scrollController, - child: Text( - widget.text, - style: const TextStyle(fontSize: 14.0), - ), + child: Text(widget.text, style: const TextStyle(fontSize: 14.0)), ), ); } diff --git a/lib/pangea/activity_suggestions/activity_suggestion_card.dart b/lib/pangea/activity_suggestions/activity_suggestion_card.dart index 51378853f..db02a6c57 100644 --- a/lib/pangea/activity_suggestions/activity_suggestion_card.dart +++ b/lib/pangea/activity_suggestions/activity_suggestion_card.dart @@ -36,9 +36,7 @@ class ActivitySuggestionCard extends StatelessWidget { child: ClipRRect( borderRadius: BorderRadius.circular(12.0), child: Container( - decoration: BoxDecoration( - color: theme.colorScheme.surfaceContainer, - ), + decoration: BoxDecoration(color: theme.colorScheme.surfaceContainer), child: Column( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -61,9 +59,7 @@ class ActivitySuggestionCard extends StatelessWidget { children: [ Text( activity.title, - style: TextStyle( - fontSize: fontSize, - ), + style: TextStyle(fontSize: fontSize), maxLines: 3, overflow: TextOverflow.ellipsis, ), diff --git a/lib/pangea/activity_summary/activity_summary_analytics_model.dart b/lib/pangea/activity_summary/activity_summary_analytics_model.dart index 32344a7c4..dc182bad7 100644 --- a/lib/pangea/activity_summary/activity_summary_analytics_model.dart +++ b/lib/pangea/activity_summary/activity_summary_analytics_model.dart @@ -79,14 +79,18 @@ class ActivitySummaryAnalyticsModel { for (final userId in userIds) { //vocab - final vocabCount = - uniqueConstructCountForUser(userId, ConstructTypeEnum.vocab); + final vocabCount = uniqueConstructCountForUser( + userId, + ConstructTypeEnum.vocab, + ); allVocabs[userId] = vocabCount; if (vocabCount > maxVocab) maxVocab = vocabCount; //grammar - final grammarCount = - uniqueConstructCountForUser(userId, ConstructTypeEnum.morph); + final grammarCount = uniqueConstructCountForUser( + userId, + ConstructTypeEnum.morph, + ); allGrammars[userId] = grammarCount; if (grammarCount > maxGrammar) maxGrammar = grammarCount; @@ -135,9 +139,8 @@ class ActivitySummaryAnalyticsModel { } Map toJson() => { - for (final entry in constructs.entries) - entry.key: entry.value.toJsonList(), - }; + for (final entry in constructs.entries) entry.key: entry.value.toJsonList(), + }; } class ConstructUsage { @@ -149,9 +152,9 @@ class ConstructUsage { void increment() => timesUsed++; Map toJson() => { - ...identifier.toJson(), - 'times_used': timesUsed, - }; + ...identifier.toJson(), + 'times_used': timesUsed, + }; } class UserConstructAnalytics { @@ -161,11 +164,11 @@ class UserConstructAnalytics { UserConstructAnalytics(this.userId) : usages = {}; /// Unique constructs of a given type - Set constructsOfType(ConstructTypeEnum type) => - usages.values - .map((u) => u.identifier) - .where((id) => id.type == type) - .toSet(); + Set constructsOfType(ConstructTypeEnum type) => usages + .values + .map((u) => u.identifier) + .where((id) => id.type == type) + .toSet(); void addUsage(ConstructIdentifier id) { usages[id.string] ??= ConstructUsage(id); diff --git a/lib/pangea/activity_summary/activity_summary_model.dart b/lib/pangea/activity_summary/activity_summary_model.dart index b3e350556..1805059e5 100644 --- a/lib/pangea/activity_summary/activity_summary_model.dart +++ b/lib/pangea/activity_summary/activity_summary_model.dart @@ -31,8 +31,9 @@ class ActivitySummaryModel { requestedAt: json['requested_at'] != null ? DateTime.parse(json['requested_at']) : null, - errorAt: - json['error_at'] != null ? DateTime.parse(json['error_at']) : null, + errorAt: json['error_at'] != null + ? DateTime.parse(json['error_at']) + : null, analytics: json['analytics'] != null ? ActivitySummaryAnalyticsModel.fromJson(json['analytics']) : null, diff --git a/lib/pangea/activity_summary/activity_summary_repo.dart b/lib/pangea/activity_summary/activity_summary_repo.dart index aadfedcb9..9d67950a2 100644 --- a/lib/pangea/activity_summary/activity_summary_repo.dart +++ b/lib/pangea/activity_summary/activity_summary_repo.dart @@ -68,10 +68,7 @@ class ActivitySummaryRepo { return ActivitySummaryResponseModel.fromJson(decodedBody); } - static void delete( - String roomId, - ActivityPlanModel activity, - ) async { + static void delete(String roomId, ActivityPlanModel activity) async { final storageKey = _storageKey(roomId, activity); _cache.remove(storageKey); } diff --git a/lib/pangea/activity_summary/activity_summary_request_model.dart b/lib/pangea/activity_summary/activity_summary_request_model.dart index 606e5a56b..e019697c0 100644 --- a/lib/pangea/activity_summary/activity_summary_request_model.dart +++ b/lib/pangea/activity_summary/activity_summary_request_model.dart @@ -44,10 +44,7 @@ class ContentFeedbackModel { final String feedback; final ActivitySummaryResponseModel content; - ContentFeedbackModel({ - required this.feedback, - required this.content, - }); + ContentFeedbackModel({required this.feedback, required this.content}); factory ContentFeedbackModel.fromJson(Map json) { return ContentFeedbackModel( @@ -57,10 +54,7 @@ class ContentFeedbackModel { } Map toJson() { - return { - 'feedback': feedback, - 'content': content.toJson(), - }; + return {'feedback': feedback, 'content': content.toJson()}; } } diff --git a/lib/pangea/activity_summary/activity_summary_response_model.dart b/lib/pangea/activity_summary/activity_summary_response_model.dart index 497fa1846..4393fbd69 100644 --- a/lib/pangea/activity_summary/activity_summary_response_model.dart +++ b/lib/pangea/activity_summary/activity_summary_response_model.dart @@ -16,8 +16,9 @@ class ParticipantSummaryModel { participantId: json['participant_id'] as String, feedback: json['feedback'] as String, cefrLevel: json['cefr_level'] as String, - superlatives: - (json['superlatives'] as List).map((e) => e as String).toList(), + superlatives: (json['superlatives'] as List) + .map((e) => e as String) + .toList(), ); } diff --git a/lib/pangea/analytics_data/analytics_data_service.dart b/lib/pangea/analytics_data/analytics_data_service.dart index bd371aa81..8b260386c 100644 --- a/lib/pangea/analytics_data/analytics_data_service.dart +++ b/lib/pangea/analytics_data/analytics_data_service.dart @@ -28,10 +28,7 @@ class _AnalyticsClient { final Client client; final AnalyticsDatabase database; - _AnalyticsClient({ - required this.client, - required this.database, - }); + _AnalyticsClient({required this.client, required this.database}); } class AnalyticsStreamUpdate { @@ -124,8 +121,8 @@ class AnalyticsDataService { _invalidateCaches(); final analyticsUserId = await _analyticsClientGetter.database.getUserID(); - final lastUpdated = - await _analyticsClientGetter.database.getLastUpdated(); + final lastUpdated = await _analyticsClientGetter.database + .getLastUpdated(); if (analyticsUserId != client.userID || lastUpdated == null) { await _clearDatabase(); @@ -133,8 +130,9 @@ class AnalyticsDataService { } final resp = await client.getUserProfile(client.userID!); - final analyticsProfile = - AnalyticsProfileModel.fromJson(resp.additionalProperties); + final analyticsProfile = AnalyticsProfileModel.fromJson( + resp.additionalProperties, + ); _syncController?.dispose(); _syncController = AnalyticsSyncController( @@ -168,10 +166,12 @@ class AnalyticsDataService { } Future _initMergeTable() async { - final vocab = await _analyticsClientGetter.database - .getAggregatedConstructs(ConstructTypeEnum.vocab); - final morph = await _analyticsClientGetter.database - .getAggregatedConstructs(ConstructTypeEnum.morph); + final vocab = await _analyticsClientGetter.database.getAggregatedConstructs( + ConstructTypeEnum.vocab, + ); + final morph = await _analyticsClientGetter.database.getAggregatedConstructs( + ConstructTypeEnum.morph, + ); final blocked = blockedConstructs; _mergeTable.addConstructs(vocab, blocked); @@ -225,8 +225,8 @@ class AnalyticsDataService { await _ensureInitialized(); if (_cachedDerivedStats == null || _derivedCacheVersion != _cacheVersion) { - _cachedDerivedStats = - await _analyticsClientGetter.database.getDerivedStats(); + _cachedDerivedStats = await _analyticsClientGetter.database + .getDerivedStats(); _derivedCacheVersion = _cacheVersion; } @@ -318,8 +318,8 @@ class AnalyticsDataService { Future> getAggregatedConstructs( ConstructTypeEnum type, ) async { - final combined = - await _analyticsClientGetter.database.getAggregatedConstructs(type); + final combined = await _analyticsClientGetter.database + .getAggregatedConstructs(type); final stopwatch = Stopwatch()..start(); @@ -390,8 +390,9 @@ class AnalyticsDataService { AnalyticsUpdate update, ) async { final events = []; - final addedConstructs = - update.addedConstructs.where((c) => c.category != 'other').toList(); + final addedConstructs = update.addedConstructs + .where((c) => c.category != 'other') + .toList(); final updateIds = addedConstructs.map((c) => c.identifier).toList(); final prevData = await derivedData; @@ -401,13 +402,12 @@ class AnalyticsDataService { await _ensureInitialized(); final blocked = blockedConstructs; - final newUnusedConstructs = - updateIds.where((id) => !hasUsedConstruct(id)).toSet(); + final newUnusedConstructs = updateIds + .where((id) => !hasUsedConstruct(id)) + .toSet(); _mergeTable.addConstructsByUses(addedConstructs, blocked); - await _analyticsClientGetter.database.updateLocalAnalytics( - addedConstructs, - ); + await _analyticsClientGetter.database.updateLocalAnalytics(addedConstructs); final newConstructs = await getConstructUses(updateIds); @@ -464,13 +464,7 @@ class AnalyticsDataService { final prevLevel = prevConstruct.lemmaCategory; final newLevel = entry.value.lemmaCategory; if (newLevel.xpNeeded > prevLevel.xpNeeded) { - events.add( - ConstructLevelUpEvent( - entry.key, - newLevel, - update.targetID, - ), - ); + events.add(ConstructLevelUpEvent(entry.key, newLevel, update.targetID)); } } @@ -491,22 +485,18 @@ class AnalyticsDataService { _invalidateCaches(); final blocked = blockedConstructs; for (final event in events) { - _mergeTable.addConstructsByUses( - event.content.uses, - blocked, - ); + _mergeTable.addConstructsByUses(event.content.uses, blocked); } await _analyticsClientGetter.database.updateServerAnalytics(events); } - Future updateBlockedConstructs( - ConstructIdentifier constructId, - ) async { + Future updateBlockedConstructs(ConstructIdentifier constructId) async { await _ensureInitialized(); _mergeTable.removeConstruct(constructId); - final construct = - await _analyticsClientGetter.database.getConstructUse([constructId]); + final construct = await _analyticsClientGetter.database.getConstructUse([ + constructId, + ]); final derived = await derivedData; final newXP = derived.totalXP - construct.points; @@ -522,10 +512,7 @@ class AnalyticsDataService { _invalidateCaches(); updateDispatcher.sendConstructAnalyticsUpdate( - AnalyticsUpdate( - [], - blockedConstruct: constructId, - ), + AnalyticsUpdate([], blockedConstruct: constructId), ); } diff --git a/lib/pangea/analytics_data/analytics_database.dart b/lib/pangea/analytics_data/analytics_database.dart index 870bd9f61..7355b7db5 100644 --- a/lib/pangea/analytics_data/analytics_database.dart +++ b/lib/pangea/analytics_data/analytics_database.dart @@ -122,12 +122,8 @@ class AnalyticsDatabase with DatabaseFileStorage { _lastEventTimestampBox = _collection.openBox( _lastEventTimestampBoxName, ); - _serverConstructsBox = _collection.openBox( - _serverConstructsBoxName, - ); - _localConstructsBox = _collection.openBox( - _localConstructsBoxName, - ); + _serverConstructsBox = _collection.openBox(_serverConstructsBoxName); + _localConstructsBox = _collection.openBox(_localConstructsBoxName); _aggregatedServerVocabConstructsBox = _collection.openBox( _aggregatedServerVocabConstructsBoxName, ); @@ -140,9 +136,7 @@ class AnalyticsDatabase with DatabaseFileStorage { _aggregatedLocalMorphConstructsBox = _collection.openBox( _aggregatedLocalMorphConstructsBoxName, ); - _derivedStatsBox = _collection.openBox( - _derivedStatsBoxName, - ); + _derivedStatsBox = _collection.openBox(_derivedStatsBoxName); } Future delete() async { @@ -185,8 +179,9 @@ class AnalyticsDatabase with DatabaseFileStorage { } Future getLastEventTimestamp() async { - final timestampString = - await _lastEventTimestampBox.get('last_event_timestamp'); + final timestampString = await _lastEventTimestampBox.get( + 'last_event_timestamp', + ); if (timestampString == null) return null; return DateTime.parse(timestampString); } @@ -195,9 +190,7 @@ class AnalyticsDatabase with DatabaseFileStorage { final raw = await _derivedStatsBox.get('derived_stats'); return raw == null ? DerivedAnalyticsDataModel() - : DerivedAnalyticsDataModel.fromJson( - Map.from(raw), - ); + : DerivedAnalyticsDataModel.fromJson(Map.from(raw)); } Future> getUses({ @@ -268,9 +261,7 @@ class AnalyticsDatabase with DatabaseFileStorage { for (final rawList in localValues) { if (rawList == null) continue; for (final raw in rawList) { - final use = OneConstructUse.fromJson( - Map.from(raw), - ); + final use = OneConstructUse.fromJson(Map.from(raw)); uses.add(use); } } @@ -283,11 +274,7 @@ class AnalyticsDatabase with DatabaseFileStorage { if (serverValues == null) return []; for (final entry in serverValues) { - uses.add( - OneConstructUse.fromJson( - Map.from(entry), - ), - ); + uses.add(OneConstructUse.fromJson(Map.from(entry))); } return uses; } @@ -309,9 +296,7 @@ class AnalyticsDatabase with DatabaseFileStorage { return [...serverKeys, ...localKeys]; } - Future getConstructUse( - List ids, - ) async { + Future getConstructUse(List ids) async { assert(ids.isNotEmpty); final ConstructUses construct = ConstructUses( @@ -332,16 +317,12 @@ class AnalyticsDatabase with DatabaseFileStorage { final serverRaw = await serverBox.get(key); if (serverRaw != null) { - server = ConstructUses.fromJson( - Map.from(serverRaw), - ); + server = ConstructUses.fromJson(Map.from(serverRaw)); } final localRaw = await localBox.get(key); if (localRaw != null) { - local = ConstructUses.fromJson( - Map.from(localRaw), - ); + local = ConstructUses.fromJson(Map.from(localRaw)); } if (server != null) construct.merge(server); @@ -370,9 +351,7 @@ class AnalyticsDatabase with DatabaseFileStorage { } /// Group uses by aggregate key - Map> _groupUses( - List uses, - ) { + Map> _groupUses(List uses) { final Map> grouped = {}; for (final u in uses) { final key = u.identifier.storageKey; @@ -438,10 +417,7 @@ class AnalyticsDatabase with DatabaseFileStorage { .map((e) => ConstructUses.fromJson(Map.from(e!))) .toList(); - final serverAgg = Map.fromIterables( - serverKeys, - serverConstructs, - ); + final serverAgg = Map.fromIterables(serverKeys, serverConstructs); if (localKeys.isEmpty) { combined = serverAgg; @@ -451,10 +427,7 @@ class AnalyticsDatabase with DatabaseFileStorage { .map((e) => ConstructUses.fromJson(Map.from(e!))) .toList(); - final localAgg = Map.fromIterables( - localKeys, - localConstructs, - ); + final localAgg = Map.fromIterables(localKeys, localConstructs); combined = Map.from(serverAgg); for (final entry in localAgg.entries) { @@ -472,19 +445,14 @@ class AnalyticsDatabase with DatabaseFileStorage { } stopwatch.stop(); - Logs().i( - "Combining aggregates took ${stopwatch.elapsedMilliseconds} ms", - ); + Logs().i("Combining aggregates took ${stopwatch.elapsedMilliseconds} ms"); return combined.values.toList(); } Future updateUserID(String userID) { return _transaction(() async { - await _lastEventTimestampBox.put( - 'user_id', - userID, - ); + await _lastEventTimestampBox.put('user_id', userID); }); } @@ -501,18 +469,12 @@ class AnalyticsDatabase with DatabaseFileStorage { return _transaction(() async { final stats = await getDerivedStats(); final updatedStats = stats.copyWith(offset: offset); - await _derivedStatsBox.put( - 'derived_stats', - updatedStats.toJson(), - ); + await _derivedStatsBox.put('derived_stats', updatedStats.toJson()); }); } Future updateDerivedStats(DerivedAnalyticsDataModel newStats) => - _derivedStatsBox.put( - 'derived_stats', - newStats.toJson(), - ); + _derivedStatsBox.put('derived_stats', newStats.toJson()); Future updateServerAnalytics( List events, @@ -600,9 +562,7 @@ class AnalyticsDatabase with DatabaseFileStorage { ); } - Future updateLocalAnalytics( - List uses, - ) async { + Future updateLocalAnalytics(List uses) async { if (uses.isEmpty) return; final stopwatch = Stopwatch()..start(); diff --git a/lib/pangea/analytics_data/analytics_database_builder.dart b/lib/pangea/analytics_data/analytics_database_builder.dart index 7f698aec8..bed8828d1 100644 --- a/lib/pangea/analytics_data/analytics_database_builder.dart +++ b/lib/pangea/analytics_data/analytics_database_builder.dart @@ -68,8 +68,9 @@ Future _constructDatabase(String name) async { // fix dlopen for old Android await applyWorkaroundToOpenSqlCipherOnOldAndroidVersions(); // import the SQLite / SQLCipher shared objects / dynamic libraries - final factory = - createDatabaseFactoryFfi(ffiInit: SQfLiteEncryptionHelper.ffiInit); + final factory = createDatabaseFactoryFfi( + ffiInit: SQfLiteEncryptionHelper.ffiInit, + ); // required for [getDatabasesPath] databaseFactory = factory; diff --git a/lib/pangea/analytics_data/analytics_sync_controller.dart b/lib/pangea/analytics_data/analytics_sync_controller.dart index f895c5657..6d51507a6 100644 --- a/lib/pangea/analytics_data/analytics_sync_controller.dart +++ b/lib/pangea/analytics_data/analytics_sync_controller.dart @@ -16,10 +16,7 @@ class AnalyticsSyncController { StreamSubscription? _subscription; - AnalyticsSyncController({ - required this.client, - required this.dataService, - }); + AnalyticsSyncController({required this.client, required this.dataService}); void start() { _subscription ??= client.onSync.stream.listen(_onSync); @@ -34,11 +31,12 @@ class AnalyticsSyncController { final analyticsRoom = _getAnalyticsRoom(); if (analyticsRoom == null) return; - final events = - update.rooms?.join?[analyticsRoom.id]?.timeline?.events?.where( - (e) => - e.type == PangeaEventTypes.construct && e.senderId == client.userID, - ); + final events = update.rooms?.join?[analyticsRoom.id]?.timeline?.events + ?.where( + (e) => + e.type == PangeaEventTypes.construct && + e.senderId == client.userID, + ); if (events == null || events.isEmpty) return; @@ -67,7 +65,8 @@ class AnalyticsSyncController { final roomUpdate = update.rooms?.join?[analyticsRoomId]; if (roomUpdate == null) return false; - final hasAnalyticsEvent = roomUpdate.timeline?.events?.any( + final hasAnalyticsEvent = + roomUpdate.timeline?.events?.any( (e) => e.type == PangeaEventTypes.construct && e.senderId == client.userID, diff --git a/lib/pangea/analytics_data/analytics_update_dispatcher.dart b/lib/pangea/analytics_data/analytics_update_dispatcher.dart index acf7052fc..a89586944 100644 --- a/lib/pangea/analytics_data/analytics_update_dispatcher.dart +++ b/lib/pangea/analytics_data/analytics_update_dispatcher.dart @@ -11,10 +11,7 @@ class LevelUpdate { final int prevLevel; final int newLevel; - LevelUpdate({ - required this.prevLevel, - required this.newLevel, - }); + LevelUpdate({required this.prevLevel, required this.newLevel}); } class AnalyticsUpdate { @@ -22,11 +19,7 @@ class AnalyticsUpdate { final ConstructIdentifier? blockedConstruct; final String? targetID; - AnalyticsUpdate( - this.addedConstructs, { - this.blockedConstruct, - this.targetID, - }); + AnalyticsUpdate(this.addedConstructs, {this.blockedConstruct, this.targetID}); } class ConstructLevelUpdate { @@ -63,8 +56,10 @@ class AnalyticsUpdateDispatcher { StreamController.broadcast(); final StreamController> - _lemmaInfoUpdateStream = StreamController< - MapEntry>.broadcast(); + _lemmaInfoUpdateStream = + StreamController< + MapEntry + >.broadcast(); AnalyticsUpdateDispatcher(this.dataService); @@ -77,23 +72,18 @@ class AnalyticsUpdateDispatcher { _lemmaInfoUpdateStream.close(); } - Stream lemmaUpdateStream( - ConstructIdentifier constructId, - ) => + Stream lemmaUpdateStream(ConstructIdentifier constructId) => _lemmaInfoUpdateStream.stream .where((update) => update.key == constructId) .map((update) => update.value); - void sendActivityAnalyticsUpdate( - String? activityAnalytics, - ) => + void sendActivityAnalyticsUpdate(String? activityAnalytics) => activityAnalyticsStream.add(activityAnalytics); void sendLemmaInfoUpdate( ConstructIdentifier constructId, UserSetLemmaInfo lemmaInfo, - ) => - _lemmaInfoUpdateStream.add(MapEntry(constructId, lemmaInfo)); + ) => _lemmaInfoUpdateStream.add(MapEntry(constructId, lemmaInfo)); Future sendConstructAnalyticsUpdate( AnalyticsUpdate analyticsUpdate, @@ -129,10 +119,7 @@ class AnalyticsUpdateDispatcher { void _onLevelUp(final int lowerLevel, final int upperLevel) { levelUpdateStream.add( - LevelUpdate( - prevLevel: lowerLevel, - newLevel: upperLevel, - ), + LevelUpdate(prevLevel: lowerLevel, newLevel: upperLevel), ); } @@ -150,10 +137,7 @@ class AnalyticsUpdateDispatcher { } void _onXPGained(int points, String? targetID) { - final update = AnalyticsStreamUpdate( - points: points, - targetID: targetID, - ); + final update = AnalyticsStreamUpdate(points: points, targetID: targetID); constructUpdateStream.add(update); } @@ -172,9 +156,7 @@ class AnalyticsUpdateDispatcher { } void _onBlockedConstruct(ConstructIdentifier constructId) { - final update = AnalyticsStreamUpdate( - blockedConstruct: constructId, - ); + final update = AnalyticsStreamUpdate(blockedConstruct: constructId); constructUpdateStream.add(update); } diff --git a/lib/pangea/analytics_data/analytics_update_events.dart b/lib/pangea/analytics_data/analytics_update_events.dart index 2e7a02ce6..a202baa06 100644 --- a/lib/pangea/analytics_data/analytics_update_events.dart +++ b/lib/pangea/analytics_data/analytics_update_events.dart @@ -18,11 +18,7 @@ class ConstructLevelUpEvent extends AnalyticsUpdateEvent { final ConstructIdentifier constructId; final ConstructLevelEnum level; final String? targetID; - ConstructLevelUpEvent( - this.constructId, - this.level, - this.targetID, - ); + ConstructLevelUpEvent(this.constructId, this.level, this.targetID); } class XPGainedEvent extends AnalyticsUpdateEvent { diff --git a/lib/pangea/analytics_data/analytics_update_service.dart b/lib/pangea/analytics_data/analytics_update_service.dart index e0cd2d66c..f133d199b 100644 --- a/lib/pangea/analytics_data/analytics_update_service.dart +++ b/lib/pangea/analytics_data/analytics_update_service.dart @@ -48,14 +48,13 @@ class AnalyticsUpdateService { } Future onUpdateLanguages(LanguageUpdate update) async { - await sendLocalAnalyticsToAnalyticsRoom( - l2Override: update.prevTargetLang, - ); + await sendLocalAnalyticsToAnalyticsRoom(l2Override: update.prevTargetLang); await dataService.reinitialize(); final data = await dataService.derivedData; - MatrixState.pangeaController.userController - .updateAnalyticsProfile(level: data.level); + MatrixState.pangeaController.userController.updateAnalyticsProfile( + level: data.level, + ); } Future addAnalytics( @@ -64,10 +63,7 @@ class AnalyticsUpdateService { bool forceUpdate = false, }) async { await dataService.updateDispatcher.sendConstructAnalyticsUpdate( - AnalyticsUpdate( - newConstructs, - targetID: targetID, - ), + AnalyticsUpdate(newConstructs, targetID: targetID), ); final localConstructCount = await dataService.getLocalConstructCount(); @@ -101,9 +97,7 @@ class AnalyticsUpdateService { e: err, m: "Failed to update analytics", s: s, - data: { - "l2Override": l2Override, - }, + data: {"l2Override": l2Override}, ); } finally { _updateCompleter?.complete(); @@ -145,10 +139,7 @@ class AnalyticsUpdateService { final current = analyticsRoom.analyticsSettings; final blockedConstructs = current.blockedConstructs; final updated = current.copyWith( - blockedConstructs: { - ...blockedConstructs, - constructId, - }, + blockedConstructs: {...blockedConstructs, constructId}, ); await analyticsRoom.setAnalyticsSettings(updated); @@ -175,11 +166,7 @@ class AnalyticsUpdateService { await analyticsRoom.setUserSetLemmaInfo(constructId, updated); } catch (err, s) { debugger(when: kDebugMode); - ErrorHandler.logError( - e: err, - data: userLemmaInfo.toJson(), - s: s, - ); + ErrorHandler.logError(e: err, data: userLemmaInfo.toJson(), s: s); } } } diff --git a/lib/pangea/analytics_data/analytics_updater_mixin.dart b/lib/pangea/analytics_data/analytics_updater_mixin.dart index d24628010..11b201e47 100644 --- a/lib/pangea/analytics_data/analytics_updater_mixin.dart +++ b/lib/pangea/analytics_data/analytics_updater_mixin.dart @@ -16,10 +16,11 @@ mixin AnalyticsUpdater on State { void initState() { super.initState(); final updater = Matrix.of(context).analyticsDataService.updateDispatcher; - _analyticsSubscription = - updater.constructUpdateStream.stream.listen(_onAnalyticsUpdate); - _constructLevelSubscription = - updater.constructLevelUpdateStream.stream.listen(_onConstructLevelUp); + _analyticsSubscription = updater.constructUpdateStream.stream.listen( + _onAnalyticsUpdate, + ); + _constructLevelSubscription = updater.constructLevelUpdateStream.stream + .listen(_onConstructLevelUp); } @override @@ -32,11 +33,9 @@ mixin AnalyticsUpdater on State { Future addAnalytics( List constructs, String? targetId, - ) => - Matrix.of(context).analyticsDataService.updateService.addAnalytics( - targetId, - constructs, - ); + ) => Matrix.of( + context, + ).analyticsDataService.updateService.addAnalytics(targetId, constructs); void _onAnalyticsUpdate(AnalyticsStreamUpdate update) { if (update.targetID != null) { diff --git a/lib/pangea/analytics_data/derived_analytics_data_model.dart b/lib/pangea/analytics_data/derived_analytics_data_model.dart index 384af243e..0d97a2736 100644 --- a/lib/pangea/analytics_data/derived_analytics_data_model.dart +++ b/lib/pangea/analytics_data/derived_analytics_data_model.dart @@ -7,10 +7,8 @@ class DerivedAnalyticsDataModel { final int _totalXP; final int offset; - DerivedAnalyticsDataModel({ - int totalXP = 0, - this.offset = 0, - }) : _totalXP = totalXP; + DerivedAnalyticsDataModel({int totalXP = 0, this.offset = 0}) + : _totalXP = totalXP; int get totalXP => _totalXP + offset; @@ -56,10 +54,7 @@ class DerivedAnalyticsDataModel { } else { ErrorHandler.logError( e: "Calculated level in Nan or Infinity", - data: { - "totalXP": totalXP, - "level": doubleScore, - }, + data: {"totalXP": totalXP, "level": doubleScore}, ); return 1; } @@ -72,9 +67,7 @@ class DerivedAnalyticsDataModel { xp += u.xp; } - return copyWith( - totalXP: xp, - ); + return copyWith(totalXP: xp); } DerivedAnalyticsDataModel merge(DerivedAnalyticsDataModel other) { @@ -84,10 +77,7 @@ class DerivedAnalyticsDataModel { ); } - DerivedAnalyticsDataModel copyWith({ - int? totalXP, - int? offset, - }) { + DerivedAnalyticsDataModel copyWith({int? totalXP, int? offset}) { return DerivedAnalyticsDataModel( totalXP: totalXP ?? this.totalXP, offset: offset ?? this.offset, @@ -95,14 +85,10 @@ class DerivedAnalyticsDataModel { } factory DerivedAnalyticsDataModel.fromJson(Map map) { - return DerivedAnalyticsDataModel( - totalXP: map['total_xp'] ?? 0, - ); + return DerivedAnalyticsDataModel(totalXP: map['total_xp'] ?? 0); } Map toJson() { - return { - 'total_xp': _totalXP, - }; + return {'total_xp': _totalXP}; } } diff --git a/lib/pangea/analytics_data/level_up_analytics_service.dart b/lib/pangea/analytics_data/level_up_analytics_service.dart index 532a5252c..9210bf802 100644 --- a/lib/pangea/analytics_data/level_up_analytics_service.dart +++ b/lib/pangea/analytics_data/level_up_analytics_service.dart @@ -44,10 +44,12 @@ class LevelUpAnalyticsService { final response = await ConstructRepo.generateConstructSummary(request); final summary = response.summary; - summary.levelVocabConstructs = - dataService.uniqueConstructsByType(ConstructTypeEnum.vocab); - summary.levelGrammarConstructs = - dataService.uniqueConstructsByType(ConstructTypeEnum.morph); + summary.levelVocabConstructs = dataService.uniqueConstructsByType( + ConstructTypeEnum.vocab, + ); + summary.levelGrammarConstructs = dataService.uniqueConstructsByType( + ConstructTypeEnum.morph, + ); return summary; } @@ -101,10 +103,7 @@ class LevelUpAnalyticsService { ErrorHandler.logError( e: e, s: s, - data: { - 'roomId': entry.key, - 'eventId': eventId, - }, + data: {'roomId': entry.key, 'eventId': eventId}, ); } } diff --git a/lib/pangea/analytics_details_popup/analytics_details_popup.dart b/lib/pangea/analytics_details_popup/analytics_details_popup.dart index 7bfa27c6a..962ba9e63 100644 --- a/lib/pangea/analytics_details_popup/analytics_details_popup.dart +++ b/lib/pangea/analytics_details_popup/analytics_details_popup.dart @@ -28,11 +28,7 @@ import 'package:fluffychat/pangea/token_info_feedback/token_info_feedback_reques import 'package:fluffychat/widgets/matrix.dart'; class ConstructAnalyticsView extends StatefulWidget { - const ConstructAnalyticsView({ - super.key, - required this.view, - this.construct, - }); + const ConstructAnalyticsView({super.key, required this.view, this.construct}); final ConstructTypeEnum view; final ConstructIdentifier? construct; @@ -82,10 +78,7 @@ class ConstructAnalyticsViewState extends State { } Future _setAnalyticsData() async { - final future = [ - _setMorphs(), - _setVocab(), - ]; + final future = [_setMorphs(), _setVocab()]; await Future.wait(future); } @@ -109,17 +102,16 @@ class ConstructAnalyticsViewState extends State { Future _setVocab() async { try { final analyticsService = Matrix.of(context).analyticsDataService; - final data = await analyticsService - .getAggregatedConstructs(ConstructTypeEnum.vocab); + final data = await analyticsService.getAggregatedConstructs( + ConstructTypeEnum.vocab, + ); vocab = data.values.toList(); - vocab!.sort( - (a, b) { - final normalizedA = removeDiacritics(a.lemma).toLowerCase(); - final normalizedB = removeDiacritics(b.lemma).toLowerCase(); - return normalizedA.compareTo(normalizedB); - }, - ); + vocab!.sort((a, b) { + final normalizedA = removeDiacritics(a.lemma).toLowerCase(); + final normalizedB = removeDiacritics(b.lemma).toLowerCase(); + return normalizedA.compareTo(normalizedB); + }); } finally { if (mounted) setState(() {}); } @@ -201,27 +193,26 @@ class ConstructAnalyticsViewState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ if (widget.construct == null) - LearningProgressIndicators( - selected: widget.view.indicator, - ), + LearningProgressIndicators(selected: widget.view.indicator), Expanded( child: widget.view == ConstructTypeEnum.morph ? widget.construct == null - ? MorphAnalyticsListView(controller: this) - : MorphDetailsView(constructId: widget.construct!) + ? MorphAnalyticsListView(controller: this) + : MorphDetailsView(constructId: widget.construct!) : widget.construct == null - ? VocabAnalyticsListView(controller: this) - : VocabDetailsView( - constructId: widget.construct!, - controller: this, - ), + ? VocabAnalyticsListView(controller: this) + : VocabDetailsView( + constructId: widget.construct!, + controller: this, + ), ), ], ), ), ), - floatingActionButton: - widget.construct == null ? _PracticeButton(view: widget.view) : null, + floatingActionButton: widget.construct == null + ? _PracticeButton(view: widget.view) + : null, ); } } @@ -233,10 +224,7 @@ class _PracticeButton extends StatelessWidget { void _showSnackbar(BuildContext context, String message) { ScaffoldMessenger.of(context).hideCurrentSnackBar(); ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(message), - behavior: SnackBarBehavior.floating, - ), + SnackBar(content: Text(message), behavior: SnackBarBehavior.floating), ); } @@ -245,14 +233,13 @@ class _PracticeButton extends StatelessWidget { final analyticsService = Matrix.of(context).analyticsDataService; if (analyticsService.isInitializing) { return FloatingActionButton.extended( - onPressed: () => _showSnackbar( - context, - L10n.of(context).loadingPleaseWait, - ), + onPressed: () => + _showSnackbar(context, L10n.of(context).loadingPleaseWait), label: Text(view.practiceButtonText(context)), backgroundColor: Theme.of(context).colorScheme.surface, - foregroundColor: - Theme.of(context).colorScheme.onSurface.withValues(alpha: 0.5), + foregroundColor: Theme.of( + context, + ).colorScheme.onSurface.withValues(alpha: 0.5), ); } @@ -262,22 +249,17 @@ class _PracticeButton extends StatelessWidget { return FloatingActionButton.extended( onPressed: enabled ? () => context.go("/rooms/analytics/${view.name}/practice") - : () => _showSnackbar( - context, - L10n.of(context).notEnoughToPractice, - ), - backgroundColor: - enabled ? null : Theme.of(context).colorScheme.surfaceContainer, + : () => _showSnackbar(context, L10n.of(context).notEnoughToPractice), + backgroundColor: enabled + ? null + : Theme.of(context).colorScheme.surfaceContainer, foregroundColor: enabled ? null : Theme.of(context).colorScheme.onSurface.withValues(alpha: 0.5), label: Row( mainAxisSize: MainAxisSize.min, children: [ - Icon( - enabled ? Symbols.fitness_center : Icons.lock_outline, - size: 18, - ), + Icon(enabled ? Symbols.fitness_center : Icons.lock_outline, size: 18), const SizedBox(width: 4), Text(view.practiceButtonText(context)), ], diff --git a/lib/pangea/analytics_details_popup/analytics_details_usage_content.dart b/lib/pangea/analytics_details_popup/analytics_details_usage_content.dart index dd258718d..284c6e391 100644 --- a/lib/pangea/analytics_details_popup/analytics_details_usage_content.dart +++ b/lib/pangea/analytics_details_popup/analytics_details_usage_content.dart @@ -8,10 +8,7 @@ import 'package:fluffychat/pangea/analytics_misc/learning_skills_enum.dart'; class AnalyticsDetailsUsageContent extends StatelessWidget { final ConstructUses construct; - const AnalyticsDetailsUsageContent({ - required this.construct, - super.key, - }); + const AnalyticsDetailsUsageContent({required this.construct, super.key}); @override Widget build(BuildContext context) { diff --git a/lib/pangea/analytics_details_popup/construct_xp_progress_bar.dart b/lib/pangea/analytics_details_popup/construct_xp_progress_bar.dart index 794cdbe5f..84c8bc369 100644 --- a/lib/pangea/analytics_details_popup/construct_xp_progress_bar.dart +++ b/lib/pangea/analytics_details_popup/construct_xp_progress_bar.dart @@ -14,10 +14,7 @@ import 'package:fluffychat/widgets/matrix.dart'; class ConstructXPProgressBar extends StatelessWidget { final ConstructIdentifier construct; - const ConstructXPProgressBar({ - required this.construct, - super.key, - }); + const ConstructXPProgressBar({required this.construct, super.key}); @override Widget build(BuildContext context) { @@ -56,8 +53,9 @@ class ConstructXPProgressBar extends StatelessWidget { height: 20.0, widthPercent: progress, barColor: AppConfig.goldLight, - backgroundColor: - Theme.of(context).colorScheme.secondaryContainer, + backgroundColor: Theme.of( + context, + ).colorScheme.secondaryContainer, ), ], ); diff --git a/lib/pangea/analytics_details_popup/lemma_usage_dots.dart b/lib/pangea/analytics_details_popup/lemma_usage_dots.dart index 7ccd9849f..3063a2d61 100644 --- a/lib/pangea/analytics_details_popup/lemma_usage_dots.dart +++ b/lib/pangea/analytics_details_popup/lemma_usage_dots.dart @@ -29,13 +29,11 @@ class LemmaUsageDots extends StatelessWidget { // If the use type matches the given category, save to list // Usage with positive XP is saved as true, else false if (category == use.useType.skillsEnumType) { - useList.add( - switch (use.xp) { - > 0 => AppConfig.success, - < 0 => Colors.red, - _ => Colors.grey[400]!, - }, - ); + useList.add(switch (use.xp) { + > 0 => AppConfig.success, + < 0 => Colors.red, + _ => Colors.grey[400]!, + }); } } return useList; @@ -49,10 +47,7 @@ class LemmaUsageDots extends StatelessWidget { Container( width: 15.0, height: 15.0, - decoration: BoxDecoration( - color: color, - shape: BoxShape.circle, - ), + decoration: BoxDecoration(color: color, shape: BoxShape.circle), ), ); } @@ -65,11 +60,7 @@ class LemmaUsageDots extends StatelessWidget { leading: Tooltip( triggerMode: TooltipTriggerMode.tap, message: tooltip, - child: Icon( - icon, - size: 24, - color: textColor.withValues(alpha: 0.7), - ), + child: Icon(icon, size: 24, color: textColor.withValues(alpha: 0.7)), ), title: dots.isEmpty ? Text( @@ -80,11 +71,7 @@ class LemmaUsageDots extends StatelessWidget { color: textColor.withAlpha(100), ), ) - : Wrap( - spacing: 3, - runSpacing: 5, - children: dots, - ), + : Wrap(spacing: 3, runSpacing: 5, children: dots), ); } } diff --git a/lib/pangea/analytics_details_popup/lemma_use_example_messages.dart b/lib/pangea/analytics_details_popup/lemma_use_example_messages.dart index cb59a93fb..6aa1b53bb 100644 --- a/lib/pangea/analytics_details_popup/lemma_use_example_messages.dart +++ b/lib/pangea/analytics_details_popup/lemma_use_example_messages.dart @@ -19,10 +19,7 @@ import 'package:fluffychat/widgets/matrix.dart'; class LemmaUseExampleMessages extends StatelessWidget { final ConstructUses construct; - const LemmaUseExampleMessages({ - super.key, - required this.construct, - }); + const LemmaUseExampleMessages({super.key, required this.construct}); Future> _getExampleMessages() async { final List examples = []; @@ -68,7 +65,8 @@ class LemmaUseExampleMessages extends StatelessWidget { final PangeaMessageEvent pangeaMessageEvent = PangeaMessageEvent( event: event, timeline: timeline!, - ownMessage: event.senderId == + ownMessage: + event.senderId == MatrixState.pangeaController.matrixState.client.userID, ); final tokens = pangeaMessageEvent.messageDisplayRepresentation?.tokens; @@ -119,7 +117,8 @@ class LemmaUseExampleMessages extends StatelessWidget { text: TextSpan( style: TextStyle( color: Theme.of(context).colorScheme.onPrimaryFixed, - fontSize: AppSettings.fontSizeFactor.value * + fontSize: + AppSettings.fontSizeFactor.value * AppConfig.messageFontSize, ), children: example.textSpans, @@ -133,9 +132,7 @@ class LemmaUseExampleMessages extends StatelessWidget { return const Column( children: [ SizedBox(height: 10), - CircularProgressIndicator.adaptive( - strokeWidth: 2, - ), + CircularProgressIndicator.adaptive(strokeWidth: 2), ], ); } @@ -183,34 +180,18 @@ class ExampleMessage { final gapSize = tokenIndex - globalTokenIndex; if (gapSize <= tokenWindowSize) { // if the gap is less than the window size, add all the gap tokens - tokenWindows.add( - TokenWindow( - globalTokenIndex, - tokenIndex, - false, - ), - ); + tokenWindows.add(TokenWindow(globalTokenIndex, tokenIndex, false)); } else { // otherwise, add the window size tokens preceding the bolded token tokenWindows.add( - TokenWindow( - tokenIndex - tokenWindowSize, - tokenIndex, - false, - ), + TokenWindow(tokenIndex - tokenWindowSize, tokenIndex, false), ); } } globalTokenIndex = tokenIndex; - tokenWindows.add( - TokenWindow( - tokenIndex, - tokenIndex + 1, - true, - ), - ); + tokenWindows.add(TokenWindow(tokenIndex, tokenIndex + 1, true)); globalTokenIndex = tokenIndex + 1; @@ -219,13 +200,7 @@ class ExampleMessage { // remaining tokens (up to the max window size) if (globalTokenIndex >= tokens.length) break; final endIndex = min(tokens.length, globalTokenIndex + tokenWindowSize); - tokenWindows.add( - TokenWindow( - globalTokenIndex, - endIndex, - false, - ), - ); + tokenWindows.add(TokenWindow(globalTokenIndex, endIndex, false)); break; } @@ -233,13 +208,7 @@ class ExampleMessage { final nextToken = _boldedTokens[i + 1]; final nextTokenIndex = tokens.indexOf(nextToken); final endIndex = min(nextTokenIndex, globalTokenIndex + tokenWindowSize); - tokenWindows.add( - TokenWindow( - globalTokenIndex, - endIndex, - false, - ), - ); + tokenWindows.add(TokenWindow(globalTokenIndex, endIndex, false)); globalTokenIndex = endIndex; } @@ -269,7 +238,8 @@ class ExampleMessage { ); tokenPointer = window.endTokenIndex; - characterPointer = tokens[window.endTokenIndex - 1].text.offset + + characterPointer = + tokens[window.endTokenIndex - 1].text.offset + tokens[window.endTokenIndex - 1].text.length; } diff --git a/lib/pangea/analytics_details_popup/morph_analytics_list_view.dart b/lib/pangea/analytics_details_popup/morph_analytics_list_view.dart index 9be8139e0..e2ccde7e7 100644 --- a/lib/pangea/analytics_details_popup/morph_analytics_list_view.dart +++ b/lib/pangea/analytics_details_popup/morph_analytics_list_view.dart @@ -21,10 +21,7 @@ import 'package:fluffychat/widgets/matrix.dart'; class MorphAnalyticsListView extends StatelessWidget { final ConstructAnalyticsViewState controller; - const MorphAnalyticsListView({ - required this.controller, - super.key, - }); + const MorphAnalyticsListView({required this.controller, super.key}); @override Widget build(BuildContext context) { @@ -37,9 +34,7 @@ class MorphAnalyticsListView extends StatelessWidget { padding: padding, child: Row( mainAxisAlignment: MainAxisAlignment.end, - children: [ - DownloadAnalyticsButton(), - ], + children: [DownloadAnalyticsButton()], ), ), Expanded( @@ -57,23 +52,20 @@ class MorphAnalyticsListView extends StatelessWidget { // Morph feature boxes SliverList( - delegate: SliverChildBuilderDelegate( - (context, index) { - final feature = controller.features[index]; - return feature.displayTags.isNotEmpty - ? Padding( - padding: const EdgeInsets.only(bottom: 16.0), - child: MorphFeatureBox( - morphFeature: feature.feature, - allTags: controller.morphs - .getDisplayTags(feature.feature) - .toSet(), - ), - ) - : const SizedBox.shrink(); - }, - childCount: controller.features.length, - ), + delegate: SliverChildBuilderDelegate((context, index) { + final feature = controller.features[index]; + return feature.displayTags.isNotEmpty + ? Padding( + padding: const EdgeInsets.only(bottom: 16.0), + child: MorphFeatureBox( + morphFeature: feature.feature, + allTags: controller.morphs + .getDisplayTags(feature.feature) + .toSet(), + ), + ) + : const SizedBox.shrink(); + }, childCount: controller.features.length), ), const SliverToBoxAdapter(child: SizedBox(height: 75.0)), ], @@ -140,31 +132,29 @@ class MorphFeatureBox extends StatelessWidget { alignment: WrapAlignment.center, spacing: 16.0, runSpacing: 16.0, - children: allTags.map( - (morphTag) { - final id = ConstructIdentifier( - lemma: morphTag, - type: ConstructTypeEnum.morph, - category: morphFeature, - ); + children: allTags.map((morphTag) { + final id = ConstructIdentifier( + lemma: morphTag, + type: ConstructTypeEnum.morph, + category: morphFeature, + ); - return FutureBuilder( - future: analyticsService.getConstructUse(id), - builder: (context, snapshot) => MorphTagChip( - morphFeature: morphFeature, - morphTag: morphTag, - constructAnalytics: snapshot.data, - onTap: () { - AnalyticsNavigationUtil.navigateToAnalytics( - context: context, - view: ProgressIndicatorEnum.morphsUsed, - construct: id, - ); - }, - ), - ); - }, - ).toList(), + return FutureBuilder( + future: analyticsService.getConstructUse(id), + builder: (context, snapshot) => MorphTagChip( + morphFeature: morphFeature, + morphTag: morphTag, + constructAnalytics: snapshot.data, + onTap: () { + AnalyticsNavigationUtil.navigateToAnalytics( + context: context, + view: ProgressIndicatorEnum.morphsUsed, + construct: id, + ); + }, + ), + ); + }).toList(), ), ), ], @@ -197,7 +187,7 @@ class MorphTagChip extends StatelessWidget { final theme = Theme.of(context); final unlocked = constructAnalytics != null && constructAnalytics!.numTotalUses > 0 || - Matrix.of(context).client.userID == Environment.supportUserId; + Matrix.of(context).client.userID == Environment.supportUserId; return Material( type: MaterialType.transparency, @@ -222,10 +212,7 @@ class MorphTagChip extends StatelessWidget { : null, color: unlocked ? null : theme.disabledColor, ), - padding: const EdgeInsets.symmetric( - vertical: 4.0, - horizontal: 8.0, - ), + padding: const EdgeInsets.symmetric(vertical: 4.0, horizontal: 8.0), child: Row( mainAxisSize: MainAxisSize.min, spacing: 8.0, @@ -245,10 +232,7 @@ class MorphTagChip extends StatelessWidget { morphTag: morphTag, ), ) - : const Icon( - Icons.lock, - color: Colors.white, - ), + : const Icon(Icons.lock, color: Colors.white), ), Flexible( child: Text( diff --git a/lib/pangea/analytics_details_popup/morph_details_view.dart b/lib/pangea/analytics_details_popup/morph_details_view.dart index ddfe948d4..bc2ca77b0 100644 --- a/lib/pangea/analytics_details_popup/morph_details_view.dart +++ b/lib/pangea/analytics_details_popup/morph_details_view.dart @@ -14,10 +14,7 @@ import 'package:fluffychat/widgets/matrix.dart'; class MorphDetailsView extends StatelessWidget { final ConstructIdentifier constructId; - const MorphDetailsView({ - required this.constructId, - super.key, - }); + const MorphDetailsView({required this.constructId, super.key}); MorphFeaturesEnum get _morphFeature => MorphFeaturesEnumExtension.fromString(constructId.category); @@ -26,8 +23,9 @@ class MorphDetailsView extends StatelessWidget { @override Widget build(BuildContext context) { return FutureBuilder( - future: - Matrix.of(context).analyticsDataService.getConstructUse(constructId), + future: Matrix.of( + context, + ).analyticsDataService.getConstructUse(constructId), builder: (context, snapshot) { final construct = snapshot.data; final level = construct?.lemmaCategory ?? ConstructLevelEnum.seeds; @@ -57,9 +55,7 @@ class MorphDetailsView extends StatelessWidget { ConstructXPProgressBar(construct: construct.id), Padding( padding: const EdgeInsets.all(20.0), - child: AnalyticsDetailsUsageContent( - construct: construct, - ), + child: AnalyticsDetailsUsageContent(construct: construct), ), ], ], diff --git a/lib/pangea/analytics_details_popup/morph_meaning_widget.dart b/lib/pangea/analytics_details_popup/morph_meaning_widget.dart index d9c619b32..78f55ef3e 100644 --- a/lib/pangea/analytics_details_popup/morph_meaning_widget.dart +++ b/lib/pangea/analytics_details_popup/morph_meaning_widget.dart @@ -62,11 +62,13 @@ class MorphMeaningWidgetState extends State { } MorphInfoRequest get _request => MorphInfoRequest( - userL1: MatrixState.pangeaController.userController.userL1?.langCode ?? - LanguageKeys.defaultLanguage, - userL2: MatrixState.pangeaController.userController.userL2?.langCode ?? - LanguageKeys.defaultLanguage, - ); + userL1: + MatrixState.pangeaController.userController.userL1?.langCode ?? + LanguageKeys.defaultLanguage, + userL2: + MatrixState.pangeaController.userController.userL2?.langCode ?? + LanguageKeys.defaultLanguage, + ); Future _loadMorphMeaning() async { if (mounted) { @@ -178,15 +180,7 @@ class MorphEditView extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ Text( - "${L10n.of(context).pangeaBotIsFallible} ${L10n.of(context).whatIsMeaning( - getGrammarCopy( - category: morphFeature.name, - lemma: morphTag, - context: context, - ) ?? - morphTag, - '', - )}", + "${L10n.of(context).pangeaBotIsFallible} ${L10n.of(context).whatIsMeaning(getGrammarCopy(category: morphFeature.name, lemma: morphTag, context: context) ?? morphTag, '')}", textAlign: TextAlign.center, style: const TextStyle(fontStyle: FontStyle.italic), ), @@ -218,8 +212,8 @@ class MorphEditView extends StatelessWidget { ElevatedButton( onPressed: () => controller.text != meaning && controller.text.isNotEmpty - ? editMorphMeaning(controller.text) - : null, + ? editMorphMeaning(controller.text) + : null, style: ElevatedButton.styleFrom( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10.0), diff --git a/lib/pangea/analytics_details_popup/vocab_analytics_details_view.dart b/lib/pangea/analytics_details_popup/vocab_analytics_details_view.dart index 79dda8441..9ae81c3da 100644 --- a/lib/pangea/analytics_details_popup/vocab_analytics_details_view.dart +++ b/lib/pangea/analytics_details_popup/vocab_analytics_details_view.dart @@ -41,10 +41,9 @@ class VocabDetailsView extends StatelessWidget { if (resp != OkCancelResult.ok) return; final res = await showFutureLoadingDialog( context: context, - future: () => Matrix.of(context) - .analyticsDataService - .updateService - .blockConstruct(constructId), + future: () => Matrix.of( + context, + ).analyticsDataService.updateService.blockConstruct(constructId), ); if (!res.isError) { @@ -63,8 +62,8 @@ class VocabDetailsView extends StatelessWidget { final Color textColor = (Theme.of(context).brightness != Brightness.light - ? level.color(context) - : level.darkColor(context)); + ? level.color(context) + : level.darkColor(context)); final forms = construct?.forms ?? []; final tokenText = PangeaTokenText.fromString(constructId.lemma); @@ -94,11 +93,13 @@ class VocabDetailsView extends StatelessWidget { MatrixState.pangeaController.userController.userL2Code!, construct: constructId, onClose: Navigator.of(context).pop, - onFlagTokenInfo: ( - LemmaInfoResponse lemmaInfo, - String phonetics, - ) => - controller.onFlagTokenInfo(token, lemmaInfo, phonetics), + onFlagTokenInfo: + (LemmaInfoResponse lemmaInfo, String phonetics) => + controller.onFlagTokenInfo( + token, + lemmaInfo, + phonetics, + ), reloadNotifier: controller.reloadNotifier, maxWidth: double.infinity, ), @@ -109,9 +110,7 @@ class VocabDetailsView extends StatelessWidget { children: [ Padding( padding: const EdgeInsets.symmetric(horizontal: 20.0), - child: ConstructXPProgressBar( - construct: constructId, - ), + child: ConstructXPProgressBar(construct: constructId), ), Column( children: [ @@ -126,9 +125,7 @@ class VocabDetailsView extends StatelessWidget { ), ), ), - AnalyticsDetailsUsageContent( - construct: construct, - ), + AnalyticsDetailsUsageContent(construct: construct), ListTile( leading: Icon( Icons.delete_outline, @@ -176,9 +173,9 @@ class _VocabForms extends StatelessWidget { children: [ Text( L10n.of(context).formSectionHeader, - style: Theme.of(context).textTheme.bodyLarge?.copyWith( - fontWeight: FontWeight.bold, - ), + style: Theme.of( + context, + ).textTheme.bodyLarge?.copyWith(fontWeight: FontWeight.bold), ), const SizedBox(width: 6.0), ...forms.mapIndexed( @@ -187,9 +184,9 @@ class _VocabForms extends StatelessWidget { children: [ WordTextWithAudioButton( text: form, - style: Theme.of(context).textTheme.bodyLarge?.copyWith( - color: textColor, - ), + style: Theme.of( + context, + ).textTheme.bodyLarge?.copyWith(color: textColor), uniqueID: "$form-$lemma-$i", langCode: MatrixState.pangeaController.userController.userL2Code!, diff --git a/lib/pangea/analytics_details_popup/vocab_analytics_list_tile.dart b/lib/pangea/analytics_details_popup/vocab_analytics_list_tile.dart index 91f81c172..0c7b2a2c7 100644 --- a/lib/pangea/analytics_details_popup/vocab_analytics_list_tile.dart +++ b/lib/pangea/analytics_details_popup/vocab_analytics_list_tile.dart @@ -49,22 +49,19 @@ class VocabAnalyticsListTile extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.center, children: [ StreamBuilder( - stream: analyticsService.updateDispatcher - .lemmaUpdateStream(constructId), + stream: analyticsService.updateDispatcher.lemmaUpdateStream( + constructId, + ), builder: (context, snapshot) { - final emoji = snapshot.data?.emojis?.firstOrNull ?? + final emoji = + snapshot.data?.emojis?.firstOrNull ?? constructId.userSetEmoji; return Container( alignment: Alignment.center, height: (maxWidth - padding * 2) * 0.6, child: emoji != null - ? Text( - emoji, - style: const TextStyle( - fontSize: 22, - ), - ) + ? Text(emoji, style: const TextStyle(fontSize: 22)) : Text( "-", style: TextStyle( @@ -83,10 +80,7 @@ class VocabAnalyticsListTile extends StatelessWidget { child: ShrinkableText( text: constructId.lemma, maxWidth: maxWidth - padding * 2, - style: TextStyle( - fontSize: 16, - color: textColor, - ), + style: TextStyle(fontSize: 16, color: textColor), ), ), ], diff --git a/lib/pangea/analytics_details_popup/vocab_analytics_list_view.dart b/lib/pangea/analytics_details_popup/vocab_analytics_list_view.dart index 541b3ff9c..9d392c51c 100644 --- a/lib/pangea/analytics_details_popup/vocab_analytics_list_view.dart +++ b/lib/pangea/analytics_details_popup/vocab_analytics_list_view.dart @@ -26,10 +26,7 @@ import 'package:fluffychat/widgets/matrix.dart'; class VocabAnalyticsListView extends StatelessWidget { final ConstructAnalyticsViewState controller; - const VocabAnalyticsListView({ - super.key, - required this.controller, - }); + const VocabAnalyticsListView({super.key, required this.controller}); List? get _filteredVocab => controller.vocab?.where(_vocabFilter).toList(); @@ -51,8 +48,9 @@ class VocabAnalyticsListView extends StatelessWidget { } final normalizedLemma = removeDiacritics(use.lemma).toLowerCase(); - final normalizedSearch = - removeDiacritics(controller.searchController.text).toLowerCase(); + final normalizedSearch = removeDiacritics( + controller.searchController.text, + ).toLowerCase(); return normalizedLemma.contains(normalizedSearch); } @@ -62,7 +60,8 @@ class VocabAnalyticsListView extends StatelessWidget { final vocab = controller.vocab; final List filters = ConstructLevelEnum.values.reversed .map((constructLevelCategory) { - final int count = vocab + final int count = + vocab ?.where((e) => e.lemmaCategory == constructLevelCategory) .length ?? 0; @@ -76,8 +75,8 @@ class VocabAnalyticsListView extends StatelessWidget { shape: BoxShape.circle, color: controller.selectedConstructLevel == constructLevelCategory - ? constructLevelCategory.color(context).withAlpha(50) - : null, + ? constructLevelCategory.color(context).withAlpha(50) + : null, ), padding: const EdgeInsets.all(8.0), child: Badge( @@ -101,8 +100,9 @@ class VocabAnalyticsListView extends StatelessWidget { filters.add(const DownloadAnalyticsButton()); } - final constructParam = - GoRouterState.of(context).pathParameters['construct']; + final constructParam = GoRouterState.of( + context, + ).pathParameters['construct']; ConstructIdentifier? selectedConstruct; if (constructParam != null) { @@ -126,10 +126,8 @@ class VocabAnalyticsListView extends StatelessWidget { alignment: Alignment.center, child: AnimatedSwitcher( duration: const Duration(milliseconds: 300), - transitionBuilder: (child, animation) => FadeTransition( - opacity: animation, - child: child, - ), + transitionBuilder: (child, animation) => + FadeTransition(opacity: animation, child: child), child: controller.isSearching ? Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -182,9 +180,7 @@ class VocabAnalyticsListView extends StatelessWidget { if (filteredVocab == null) const SliverFillRemaining( hasScrollBody: false, - child: Center( - child: CircularProgressIndicator.adaptive(), - ), + child: Center(child: CircularProgressIndicator.adaptive()), ) else filteredVocab.isEmpty @@ -203,38 +199,37 @@ class VocabAnalyticsListView extends StatelessWidget { : SliverGrid( gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent( - maxCrossAxisExtent: 100.0, - mainAxisExtent: 100.0, - crossAxisSpacing: 8.0, - mainAxisSpacing: 8.0, - ), - delegate: SliverChildBuilderDelegate( - (context, index) { - final vocabItem = filteredVocab[index]; - return VocabAnalyticsListTile( - onTap: () { - TtsController.tryToSpeak( - vocabItem.id.lemma, - langCode: MatrixState.pangeaController - .userController.userL2Code!, - ); - AnalyticsNavigationUtil.navigateToAnalytics( - context: context, - view: ProgressIndicatorEnum.wordsUsed, - construct: vocabItem.id, - ); - }, - constructId: vocabItem.id, - textColor: Theme.of(context).brightness == - Brightness.light - ? vocabItem.lemmaCategory.darkColor(context) - : vocabItem.lemmaCategory.color(context), - level: vocabItem.lemmaCategory, - selected: vocabItem.id == selectedConstruct, - ); - }, - childCount: filteredVocab.length, - ), + maxCrossAxisExtent: 100.0, + mainAxisExtent: 100.0, + crossAxisSpacing: 8.0, + mainAxisSpacing: 8.0, + ), + delegate: SliverChildBuilderDelegate((context, index) { + final vocabItem = filteredVocab[index]; + return VocabAnalyticsListTile( + onTap: () { + TtsController.tryToSpeak( + vocabItem.id.lemma, + langCode: MatrixState + .pangeaController + .userController + .userL2Code!, + ); + AnalyticsNavigationUtil.navigateToAnalytics( + context: context, + view: ProgressIndicatorEnum.wordsUsed, + construct: vocabItem.id, + ); + }, + constructId: vocabItem.id, + textColor: + Theme.of(context).brightness == Brightness.light + ? vocabItem.lemmaCategory.darkColor(context) + : vocabItem.lemmaCategory.color(context), + level: vocabItem.lemmaCategory, + selected: vocabItem.id == selectedConstruct, + ); + }, childCount: filteredVocab.length), ), const SliverToBoxAdapter(child: SizedBox(height: 75.0)), ], diff --git a/lib/pangea/analytics_downloads/analytics_dowload_dialog.dart b/lib/pangea/analytics_downloads/analytics_dowload_dialog.dart index da4a96c4b..5337a4abf 100644 --- a/lib/pangea/analytics_downloads/analytics_dowload_dialog.dart +++ b/lib/pangea/analytics_downloads/analytics_dowload_dialog.dart @@ -29,9 +29,7 @@ import 'package:fluffychat/pangea/morphs/morph_repo.dart'; import 'package:fluffychat/widgets/matrix.dart'; class AnalyticsDownloadDialog extends StatefulWidget { - const AnalyticsDownloadDialog({ - super.key, - }); + const AnalyticsDownloadDialog({super.key}); @override AnalyticsDownloadDialogState createState() => AnalyticsDownloadDialogState(); @@ -74,13 +72,7 @@ class AnalyticsDownloadDialogState extends State { vocabSummary = await _getVocabAnalytics(); morphSummary = await _getMorphAnalytics(); } catch (e, s) { - ErrorHandler.logError( - e: e, - s: s, - data: { - "downloadType": _downloadType, - }, - ); + ErrorHandler.logError(e: e, s: s, data: {"downloadType": _downloadType}); if (mounted) { setState(() { @@ -111,16 +103,8 @@ class AnalyticsDownloadDialogState extends State { "analytics_morph_${client.userID?.localpart}_${DateFormat('yyyy-MM-dd-hh:mm:ss').format(DateTime.now())}.csv"; final futures = [ - DownloadUtil.downloadFile( - vocabContent, - vocabFileName, - _downloadType, - ), - DownloadUtil.downloadFile( - morphContent, - morphFileName, - _downloadType, - ), + DownloadUtil.downloadFile(vocabContent, vocabFileName, _downloadType), + DownloadUtil.downloadFile(morphContent, morphFileName, _downloadType), ]; await Future.wait(futures); @@ -133,21 +117,11 @@ class AnalyticsDownloadDialogState extends State { final fileName = "analytics_${client.userID?.localpart}_${DateFormat('yyyy-MM-dd-hh:mm:ss').format(DateTime.now())}.xlsx"; - await DownloadUtil.downloadFile( - content, - fileName, - _downloadType, - ); + await DownloadUtil.downloadFile(content, fileName, _downloadType); } _downloaded = true; } catch (e, s) { - ErrorHandler.logError( - e: e, - s: s, - data: { - "downloadType": _downloadType, - }, - ); + ErrorHandler.logError(e: e, s: s, data: {"downloadType": _downloadType}); _error = L10n.of(context).errorDownloading; } finally { if (mounted) setState(() => _downloading = false); @@ -156,8 +130,9 @@ class AnalyticsDownloadDialogState extends State { Future> _getVocabAnalytics() async { final analyticsService = Matrix.of(context).analyticsDataService; - final aggregatedVocab = - await analyticsService.getAggregatedConstructs(ConstructTypeEnum.vocab); + final aggregatedVocab = await analyticsService.getAggregatedConstructs( + ConstructTypeEnum.vocab, + ); final uses = aggregatedVocab.values.toList(); final Map> lemmasToUses = {}; @@ -173,8 +148,9 @@ class AnalyticsDownloadDialogState extends State { final xp = uses.map((e) => e.points).reduce((a, total) => a + total); final exampleMessages = await _getExampleMessages(uses); - final allUses = - uses.map((u) => u.cappedUses).expand((element) => element); + final allUses = uses + .map((u) => u.cappedUses) + .expand((element) => element); int independantUseOccurrences = 0; int assistedUseOccurrences = 0; @@ -250,8 +226,9 @@ class AnalyticsDownloadDialogState extends State { ); final summary = AnalyticsSummaryModel( - morphFeature: MorphFeaturesEnumExtension.fromString(feature.feature) - .getDisplayCopy(context), + morphFeature: MorphFeaturesEnumExtension.fromString( + feature.feature, + ).getDisplayCopy(context), morphTag: tagCopy, xp: xp, forms: forms, @@ -270,8 +247,10 @@ class AnalyticsDownloadDialogState extends State { Future> _getExampleMessages( List constructUses, ) async { - final allUses = - constructUses.map((e) => e.cappedUses).expand((e) => e).toList(); + final allUses = constructUses + .map((e) => e.cappedUses) + .expand((e) => e) + .toList(); final List examples = []; for (final OneConstructUse use in allUses) { if (use.metadata.roomId == null) continue; @@ -331,16 +310,13 @@ class AnalyticsDownloadDialogState extends State { columnIndex: values.indexOf(key), ), ) - .value = TextCellValue(key.header(context)); + .value = TextCellValue( + key.header(context), + ); } final rows = entry.value - .map( - (summary) => _formatExcelRow( - summary, - entry.key, - ), - ) + .map((summary) => _formatExcelRow(summary, entry.key)) .toList(); for (int i = 0; i < rows.length; i++) { @@ -348,8 +324,11 @@ class AnalyticsDownloadDialogState extends State { for (int j = 0; j < row.length; j++) { final cell = row[j]; sheet - .cell(CellIndex.indexByColumnRow(rowIndex: i + 2, columnIndex: j)) - .value = cell; + .cell( + CellIndex.indexByColumnRow(rowIndex: i + 2, columnIndex: j), + ) + .value = + cell; } } } @@ -417,9 +396,7 @@ class AnalyticsDownloadDialogState extends State { Widget build(BuildContext context) { return Dialog( child: Container( - constraints: const BoxConstraints( - maxWidth: 400, - ), + constraints: const BoxConstraints(maxWidth: 400), padding: const EdgeInsets.symmetric(vertical: 20), child: Column( mainAxisSize: MainAxisSize.min, @@ -427,7 +404,8 @@ class AnalyticsDownloadDialogState extends State { Text( L10n.of(context).fileType, style: TextStyle( - fontSize: AppSettings.fontSizeFactor.value * + fontSize: + AppSettings.fontSizeFactor.value * AppConfig.messageFontSize, ), ), @@ -435,8 +413,9 @@ class AnalyticsDownloadDialogState extends State { padding: const EdgeInsets.all(8.0), child: SegmentedButton( selected: {_downloadType}, - onSelectionChanged: - _downloading ? null : (c) => _setDownloadType(c.first), + onSelectionChanged: _downloading + ? null + : (c) => _setDownloadType(c.first), segments: [ ButtonSegment( value: DownloadType.csv, @@ -492,9 +471,7 @@ class AnalyticsDownloadDialogState extends State { child: _error != null ? Padding( padding: const EdgeInsets.all(8.0), - child: ErrorIndicator( - message: _error!, - ), + child: ErrorIndicator(message: _error!), ) : const SizedBox(), ), diff --git a/lib/pangea/analytics_downloads/analytics_download_button.dart b/lib/pangea/analytics_downloads/analytics_download_button.dart index f78ec909e..8f1445a33 100644 --- a/lib/pangea/analytics_downloads/analytics_download_button.dart +++ b/lib/pangea/analytics_downloads/analytics_download_button.dart @@ -7,9 +7,7 @@ import 'package:fluffychat/l10n/l10n.dart'; import 'package:fluffychat/pangea/analytics_downloads/analytics_dowload_dialog.dart'; class DownloadAnalyticsButton extends StatelessWidget { - const DownloadAnalyticsButton({ - super.key, - }); + const DownloadAnalyticsButton({super.key}); @override Widget build(BuildContext context) { diff --git a/lib/pangea/analytics_downloads/analytics_summary_enum.dart b/lib/pangea/analytics_downloads/analytics_summary_enum.dart index 59d9dfcfd..ef7a1fb4a 100644 --- a/lib/pangea/analytics_downloads/analytics_summary_enum.dart +++ b/lib/pangea/analytics_downloads/analytics_summary_enum.dart @@ -37,21 +37,21 @@ enum AnalyticsSummaryEnum { const AnalyticsSummaryEnum(); static List get vocabValues => [ - lemma, - xp, - forms, - exampleMessages, - independentUseOccurrences, - assistedUseOccurrences, - ]; + lemma, + xp, + forms, + exampleMessages, + independentUseOccurrences, + assistedUseOccurrences, + ]; static List get morphValues => [ - morphFeature, - morphTag, - xp, - forms, - exampleMessages, - independentUseOccurrences, - assistedUseOccurrences, - ]; + morphFeature, + morphTag, + xp, + forms, + exampleMessages, + independentUseOccurrences, + assistedUseOccurrences, + ]; } diff --git a/lib/pangea/analytics_downloads/space_analytics_summary_model.dart b/lib/pangea/analytics_downloads/space_analytics_summary_model.dart index a176fff8d..bc3a05cd9 100644 --- a/lib/pangea/analytics_downloads/space_analytics_summary_model.dart +++ b/lib/pangea/analytics_downloads/space_analytics_summary_model.dart @@ -85,10 +85,7 @@ class SpaceAnalyticsSummaryModel { }); static SpaceAnalyticsSummaryModel emptyModel(String userID) { - return SpaceAnalyticsSummaryModel( - username: userID, - dataAvailable: false, - ); + return SpaceAnalyticsSummaryModel(username: userID, dataAvailable: false); } static SpaceAnalyticsSummaryModel fromEvents( @@ -189,8 +186,8 @@ class SpaceAnalyticsSummaryModel { } } - final totalXP = cleanedVocab.values - .fold(0, (sum, entry) => sum + entry.points) + + final totalXP = + cleanedVocab.values.fold(0, (sum, entry) => sum + entry.points) + cleanedMorph.values.fold(0, (sum, entry) => sum + entry.points); final level = DerivedAnalyticsDataModel.calculateLevelWithXp(totalXP); @@ -270,7 +267,8 @@ class SpaceAnalyticsSummaryModel { // if >= 80% correct original uses if (originalUsesCorrect.length + originalUsesIncorrect.length > 0) { - final percentCorrect = originalUsesCorrect.length / + final percentCorrect = + originalUsesCorrect.length / (originalUsesCorrect.length + originalUsesIncorrect.length); if (percentCorrect >= 0.8) { morphCorrectOriginal.add(entry.lemma); @@ -279,7 +277,8 @@ class SpaceAnalyticsSummaryModel { } if (systemUsesCorrect.length + systemUsesIncorrect.length > 0) { - final percentCorrectSystem = systemUsesCorrect.length / + final percentCorrectSystem = + systemUsesCorrect.length / (systemUsesCorrect.length + systemUsesIncorrect.length); if (percentCorrectSystem >= 0.8) { morphCorrectSystem.add(entry.lemma); diff --git a/lib/pangea/analytics_misc/analytics_navigation_util.dart b/lib/pangea/analytics_misc/analytics_navigation_util.dart index f6714618f..13a67fe3e 100644 --- a/lib/pangea/analytics_misc/analytics_navigation_util.dart +++ b/lib/pangea/analytics_misc/analytics_navigation_util.dart @@ -32,8 +32,10 @@ class AnalyticsNavigationUtil { } if (construct == null || - !{ProgressIndicatorEnum.wordsUsed, ProgressIndicatorEnum.morphsUsed} - .contains(view)) { + !{ + ProgressIndicatorEnum.wordsUsed, + ProgressIndicatorEnum.morphsUsed, + }.contains(view)) { context.go("/rooms/analytics/${view.route}"); return; } diff --git a/lib/pangea/analytics_misc/client_analytics_extension.dart b/lib/pangea/analytics_misc/client_analytics_extension.dart index ba2be21d1..4d171355c 100644 --- a/lib/pangea/analytics_misc/client_analytics_extension.dart +++ b/lib/pangea/analytics_misc/client_analytics_extension.dart @@ -45,15 +45,12 @@ extension AnalyticsClientExtension on Client { analyticsRoom.membership == Membership.invite) { debugger(when: kDebugMode); analyticsRoom.join().onError( - (error, stackTrace) => ErrorHandler.logError( - e: error, - s: stackTrace, - data: { - "langCode": lang!.langCodeShort, - "userIdParam": userIdParam, - }, - ), - ); + (error, stackTrace) => ErrorHandler.logError( + e: error, + s: stackTrace, + data: {"langCode": lang!.langCodeShort, "userIdParam": userIdParam}, + ), + ); return analyticsRoom; } return analyticsRoom; @@ -81,9 +78,7 @@ extension AnalyticsClientExtension on Client { initialState: [ StateEvent( type: EventTypes.RoomJoinRules, - content: { - ModelKey.joinRule: JoinRules.knock.name, - }, + content: {ModelKey.joinRule: JoinRules.knock.name}, ), ], ); @@ -97,11 +92,8 @@ extension AnalyticsClientExtension on Client { } /// Get all my analytics rooms - List get allMyAnalyticsRooms => rooms - .where( - (e) => e.isAnalyticsRoomOfUser(userID!), - ) - .toList(); + List get allMyAnalyticsRooms => + rooms.where((e) => e.isAnalyticsRoomOfUser(userID!)).toList(); /// Update the join rules of all analytics rooms to 'knock'. Future updateAnalyticsRoomJoinRules() async { @@ -123,9 +115,7 @@ extension AnalyticsClientExtension on Client { Future addAnalyticsRoomsToSpaces() async { if (userID == null || userID == BotName.byEnvironment) return; final spaces = rooms - .where( - (room) => room.isSpace && room.membership == Membership.join, - ) + .where((room) => room.isSpace && room.membership == Membership.join) .toList(); final Random random = Random(); diff --git a/lib/pangea/analytics_misc/construct_use_model.dart b/lib/pangea/analytics_misc/construct_use_model.dart index e3a3ddda5..cb298accf 100644 --- a/lib/pangea/analytics_misc/construct_use_model.dart +++ b/lib/pangea/analytics_misc/construct_use_model.dart @@ -21,18 +21,15 @@ class ConstructUses { required this.constructType, required this.lemma, required category, - }) : _category = category, - _uses = List.from(uses) { + }) : _category = category, + _uses = List.from(uses) { _sortUses(); } // Total points for all uses of this lemma int get points { return min( - _uses.fold( - 0, - (total, use) => total + use.xp, - ), + _uses.fold(0, (total, use) => total + use.xp), AnalyticsConstants.xpForFlower, ); } @@ -51,10 +48,10 @@ class ConstructUses { int get numTotalUses => _uses.length; ConstructIdentifier get id => ConstructIdentifier( - lemma: lemma, - type: constructType, - category: category, - ); + lemma: lemma, + type: constructType, + category: category, + ); /// Get the lemma category, based on points ConstructLevelEnum get lemmaCategory { @@ -80,10 +77,10 @@ class ConstructUses { } ConstructLevelEnum get constructLevel => switch (points) { - < AnalyticsConstants.xpForGreens => ConstructLevelEnum.seeds, - < AnalyticsConstants.xpForFlower => ConstructLevelEnum.greens, - _ => ConstructLevelEnum.flowers, - }; + < AnalyticsConstants.xpForGreens => ConstructLevelEnum.seeds, + < AnalyticsConstants.xpForFlower => ConstructLevelEnum.greens, + _ => ConstructLevelEnum.flowers, + }; List get forms => _uses.map((e) => e.form).whereType().toSet().toList(); diff --git a/lib/pangea/analytics_misc/constructs_model.dart b/lib/pangea/analytics_misc/constructs_model.dart index cb053585b..4ef803c23 100644 --- a/lib/pangea/analytics_misc/constructs_model.dart +++ b/lib/pangea/analytics_misc/constructs_model.dart @@ -17,9 +17,7 @@ import 'construct_type_enum.dart'; class ConstructAnalyticsModel { List uses; - ConstructAnalyticsModel({ - this.uses = const [], - }); + ConstructAnalyticsModel({this.uses = const []}); static const _usesKey = "uses"; @@ -37,13 +35,7 @@ class ConstructAnalyticsModel { try { uses.add(OneConstructUse.fromJson(useJson)); } catch (err, s) { - ErrorHandler.logError( - e: err, - s: s, - data: { - "useJson": useJson, - }, - ); + ErrorHandler.logError(e: err, s: s, data: {"useJson": useJson}); continue; } } @@ -52,21 +44,15 @@ class ConstructAnalyticsModel { debugger(when: kDebugMode); ErrorHandler.logError( m: "Analytics room with non-list uses", - data: { - "usesKey": _usesKey, - }, + data: {"usesKey": _usesKey}, ); } - return ConstructAnalyticsModel( - uses: uses, - ); + return ConstructAnalyticsModel(uses: uses); } Map toJson() { - return { - _usesKey: uses.map((use) => use.toJson()).toList(), - }; + return {_usesKey: uses.map((use) => use.toJson()).toList()}; } } @@ -139,17 +125,17 @@ class OneConstructUse { } Map toJson() => { - 'useType': useType.string, - 'chatId': metadata.roomId, - 'timeStamp': metadata.timeStamp.toIso8601String(), - 'form': form, - 'msgId': metadata.eventId, - 'lemma': lemma, - 'constructType': constructType.string, - 'categories': category, - 'id': id, - 'xp': xp, - }; + 'useType': useType.string, + 'chatId': metadata.roomId, + 'timeStamp': metadata.timeStamp.toIso8601String(), + 'form': form, + 'msgId': metadata.eventId, + 'lemma': lemma, + 'constructType': constructType.string, + 'categories': category, + 'id': id, + 'xp': xp, + }; OneConstructUse copyWith({ String? lemma, @@ -188,8 +174,8 @@ class OneConstructUse { final String? category = categoryEntry is String ? categoryEntry : categoryEntry is List && categoryEntry.isNotEmpty - ? categoryEntry.first - : null; + ? categoryEntry.first + : null; return category ?? "Other"; } @@ -231,10 +217,10 @@ class OneConstructUse { } ConstructIdentifier get identifier => ConstructIdentifier( - lemma: lemma, - type: constructType, - category: category, - ); + lemma: lemma, + type: constructType, + category: category, + ); } class ConstructUseMetaData { diff --git a/lib/pangea/analytics_misc/gain_points_animation.dart b/lib/pangea/analytics_misc/gain_points_animation.dart index 1580a73a8..fdad58fb8 100644 --- a/lib/pangea/analytics_misc/gain_points_animation.dart +++ b/lib/pangea/analytics_misc/gain_points_animation.dart @@ -51,43 +51,33 @@ class PointsGainedAnimationState extends State _progressAnimation = Tween( begin: 0.0, end: 3.0, - ).animate( - CurvedAnimation( - parent: _controller!, - curve: Curves.easeOut, - ), - ); + ).animate(CurvedAnimation(parent: _controller!, curve: Curves.easeOut)); _fadeAnimation = Tween( begin: 1.0, end: 0.0, - ).animate( - CurvedAnimation( - parent: _controller!, - curve: Curves.easeIn, - ), - ); + ).animate(CurvedAnimation(parent: _controller!, curve: Curves.easeIn)); initParticleTrajectories(); - _controller?.forward().then( - (_) { - if (!mounted) return; - MatrixState.pAnyState.closeOverlay("${widget.targetID}_points"); - }, - ); + _controller?.forward().then((_) { + if (!mounted) return; + MatrixState.pAnyState.closeOverlay("${widget.targetID}_points"); + }); } int get _points => widget.points.clamp(-25, 25); void initParticleTrajectories() { for (int i = 0; i < _points.abs(); i++) { - final angle = (i - _points.abs() / 2) / _points.abs() * (pi / 3) + + final angle = + (i - _points.abs() / 2) / _points.abs() * (pi / 3) + (_random.nextDouble() - 0.5) * pi / 6 + pi / 2; final speedMultiplier = 0.75 + _random.nextDouble() / 4; // Random speed multiplier. - final speed = _particleSpeed * + final speed = + _particleSpeed * speedMultiplier * (_points > 0 ? 2 : 1); // Exponential speed. _trajectories.add( @@ -127,9 +117,7 @@ class PointsGainedAnimationState extends State context, big: true, setColor: textColor == null, - existingStyle: TextStyle( - color: textColor, - ), + existingStyle: TextStyle(color: textColor), ), ); diff --git a/lib/pangea/analytics_misc/growth_animation.dart b/lib/pangea/analytics_misc/growth_animation.dart index 7cd42c4fa..263438507 100644 --- a/lib/pangea/analytics_misc/growth_animation.dart +++ b/lib/pangea/analytics_misc/growth_animation.dart @@ -57,14 +57,16 @@ class _GrowthAnimationState extends State _wiggleAmplitude = 4.0 + _random.nextDouble() * 4.0; _wiggleFrequency = 1.5 + _random.nextDouble() * 1.0; - _controller = AnimationController( - duration: const Duration(milliseconds: _durationMs), - vsync: this, - )..forward().then((_) { - if (mounted) { - MatrixState.pAnyState.closeOverlay(widget.targetID); - } - }); + _controller = + AnimationController( + duration: const Duration(milliseconds: _durationMs), + vsync: this, + ) + ..forward().then((_) { + if (mounted) { + MatrixState.pAnyState.closeOverlay(widget.targetID); + } + }); } @override @@ -85,7 +87,7 @@ class _GrowthAnimationState extends State final opacity = t < 0.5 ? t * 2 : (1.0 - t) * 2; final wiggle = sin(t * pi * _wiggleFrequency) * _wiggleAmplitude; return Transform.translate( - offset: Offset(_horizontalOffset! + wiggle, dy), + offset: Offset(_horizontalOffset + wiggle, dy), child: Opacity( opacity: opacity.clamp(0.0, 1.0), child: widget.level.icon(24), diff --git a/lib/pangea/analytics_misc/lemma_emoji_setter_mixin.dart b/lib/pangea/analytics_misc/lemma_emoji_setter_mixin.dart index 0719943e3..3ef9501e6 100644 --- a/lib/pangea/analytics_misc/lemma_emoji_setter_mixin.dart +++ b/lib/pangea/analytics_misc/lemma_emoji_setter_mixin.dart @@ -24,14 +24,14 @@ mixin LemmaEmojiSetter { } if (constructId.userSetEmoji == null) { - _getEmojiAnalytics( - constructId, - targetId: targetId, - ); + _getEmojiAnalytics(constructId, targetId: targetId); } await MatrixState - .pangeaController.matrixState.analyticsDataService.updateService + .pangeaController + .matrixState + .analyticsDataService + .updateService .setLemmaInfo(constructId, emoji: emoji); } @@ -67,8 +67,8 @@ mixin LemmaEmojiSetter { L10n.of(context).emojiSelectedSnackbar(constructId.lemma), textAlign: TextAlign.center, style: Theme.of(context).textTheme.bodyLarge?.copyWith( - color: Theme.of(context).colorScheme.surface, - ), + color: Theme.of(context).colorScheme.surface, + ), ), ), IconButton( @@ -107,9 +107,6 @@ mixin LemmaEmojiSetter { ]; MatrixState.pangeaController.matrixState.analyticsDataService.updateService - .addAnalytics( - targetId, - constructs, - ); + .addAnalytics(targetId, constructs); } } diff --git a/lib/pangea/analytics_misc/level_display_name.dart b/lib/pangea/analytics_misc/level_display_name.dart index e5903aa38..ae0371960 100644 --- a/lib/pangea/analytics_misc/level_display_name.dart +++ b/lib/pangea/analytics_misc/level_display_name.dart @@ -17,10 +17,7 @@ class LevelDisplayName extends StatelessWidget { @override Widget build(BuildContext context) { return Padding( - padding: const EdgeInsets.symmetric( - horizontal: 0, - vertical: 2.0, - ), + padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 2.0), child: FutureBuilder( future: MatrixState.pangeaController.userController .getPublicAnalyticsProfile(userId), @@ -47,7 +44,8 @@ class LevelDisplayName extends StatelessWidget { Text( snapshot.data!.baseLanguage!.langCodeShort .toUpperCase(), - style: textStyle ?? + style: + textStyle ?? TextStyle( fontWeight: FontWeight.bold, color: Theme.of(context).colorScheme.primary, @@ -63,7 +61,8 @@ class LevelDisplayName extends StatelessWidget { Text( snapshot.data!.targetLanguage!.langCodeShort .toUpperCase(), - style: textStyle ?? + style: + textStyle ?? TextStyle( fontWeight: FontWeight.bold, color: Theme.of(context).colorScheme.primary, @@ -71,14 +70,12 @@ class LevelDisplayName extends StatelessWidget { ), const SizedBox(width: 4.0), if (snapshot.data?.level != null) - Text( - "⭐", - style: textStyle, - ), + Text("⭐", style: textStyle), if (snapshot.data?.level != null) Text( "${snapshot.data!.level!}", - style: textStyle ?? + style: + textStyle ?? TextStyle( fontWeight: FontWeight.bold, color: Theme.of(context).colorScheme.primary, diff --git a/lib/pangea/analytics_misc/level_up/level_up_banner.dart b/lib/pangea/analytics_misc/level_up/level_up_banner.dart index 7f3c7e949..f026ad550 100644 --- a/lib/pangea/analytics_misc/level_up/level_up_banner.dart +++ b/lib/pangea/analytics_misc/level_up/level_up_banner.dart @@ -123,12 +123,7 @@ class LevelUpBannerState extends State _slideAnimation = Tween( begin: const Offset(0, -1), end: Offset.zero, - ).animate( - CurvedAnimation( - parent: _slideController, - curve: Curves.easeOut, - ), - ); + ).animate(CurvedAnimation(parent: _slideController, curve: Curves.easeOut)); _slideController.forward(); @@ -159,17 +154,16 @@ class LevelUpBannerState extends State await showDialog( context: context, - builder: (context) => LevelUpPopup( - constructSummaryCompleter: _constructSummaryCompleter, - ), + builder: (context) => + LevelUpPopup(constructSummaryCompleter: _constructSummaryCompleter), ); } Future _loadConstructSummary() async { try { final analyticsRoom = await Matrix.of(context).client.getMyAnalyticsRoom( - MatrixState.pangeaController.userController.userL2!, - ); + MatrixState.pangeaController.userController.userL2!, + ); final timestamp = analyticsRoom!.lastLevelUpTimestamp; final analyticsService = Matrix.of(context).analyticsDataService; @@ -192,15 +186,15 @@ class LevelUpBannerState extends State final style = isColumnMode ? Theme.of(context).textTheme.titleLarge?.copyWith( - color: AppConfig.gold, - fontWeight: FontWeight.bold, - letterSpacing: 0.5, - ) + color: AppConfig.gold, + fontWeight: FontWeight.bold, + letterSpacing: 0.5, + ) : Theme.of(context).textTheme.bodyLarge?.copyWith( - color: AppConfig.gold, - fontWeight: FontWeight.bold, - letterSpacing: 0.5, - ); + color: AppConfig.gold, + fontWeight: FontWeight.bold, + letterSpacing: 0.5, + ); return SafeArea( child: Material( @@ -280,12 +274,14 @@ class LevelUpBannerState extends State padding: const EdgeInsets.all(4.0), ), onPressed: () { - MatrixState.pAnyState - .closeOverlay("level_up_notification"); + MatrixState.pAnyState.closeOverlay( + "level_up_notification", + ); }, constraints: const BoxConstraints(), - color: - Theme.of(context).colorScheme.onSurface, + color: Theme.of( + context, + ).colorScheme.onSurface, ), ), ), diff --git a/lib/pangea/analytics_misc/level_up/level_up_manager.dart b/lib/pangea/analytics_misc/level_up/level_up_manager.dart index b358d7ad2..61f0b6b5d 100644 --- a/lib/pangea/analytics_misc/level_up/level_up_manager.dart +++ b/lib/pangea/analytics_misc/level_up/level_up_manager.dart @@ -40,8 +40,8 @@ class LevelUpManager { final LanguageModel? l2 = MatrixState.pangeaController.userController.userL2; - final Room? analyticsRoom = - MatrixState.pangeaController.matrixState.client.analyticsRoomLocal(l2!); + final Room? analyticsRoom = MatrixState.pangeaController.matrixState.client + .analyticsRoomLocal(l2!); if (analyticsRoom != null) { final lastSummary = analyticsRoom.levelUpSummary; diff --git a/lib/pangea/analytics_misc/level_up/level_up_popup.dart b/lib/pangea/analytics_misc/level_up/level_up_popup.dart index 839193c98..9e59e5bbb 100644 --- a/lib/pangea/analytics_misc/level_up/level_up_popup.dart +++ b/lib/pangea/analytics_misc/level_up/level_up_popup.dart @@ -26,10 +26,7 @@ import 'package:fluffychat/widgets/mxc_image.dart'; class LevelUpPopup extends StatefulWidget { final Completer constructSummaryCompleter; - const LevelUpPopup({ - required this.constructSummaryCompleter, - super.key, - }); + const LevelUpPopup({required this.constructSummaryCompleter, super.key}); @override State createState() => _LevelUpPopupState(); @@ -108,7 +105,7 @@ class _LevelUpPopupContentState extends State String language = MatrixState.pangeaController.userController.userL2Code?.toUpperCase() ?? - LanguageKeys.unknownLanguage; + LanguageKeys.unknownLanguage; ConstructSummary? _constructSummary; Object? _error; @@ -194,41 +191,41 @@ class _LevelUpPopupContentState extends State Widget build(BuildContext context) { final Animation vocabAnimation = IntTween(begin: _startVocab, end: _endVocab).animate( - CurvedAnimation( - parent: _controller, - curve: const Interval(0.0, 0.5, curve: Curves.easeInOutQuad), - ), - ); + CurvedAnimation( + parent: _controller, + curve: const Interval(0.0, 0.5, curve: Curves.easeInOutQuad), + ), + ); final Animation grammarAnimation = IntTween(begin: _startGrammar, end: _endGrammar).animate( - CurvedAnimation( - parent: _controller, - curve: const Interval(0.0, 0.5, curve: Curves.easeInOutQuad), - ), - ); + CurvedAnimation( + parent: _controller, + curve: const Interval(0.0, 0.5, curve: Curves.easeInOutQuad), + ), + ); - final Animation skillsOpacity = - Tween(begin: 0.0, end: 1.0).animate( - CurvedAnimation( - parent: _controller, - curve: const Interval(0.7, 1.0, curve: Curves.easeIn), - ), - ); + final Animation skillsOpacity = Tween(begin: 0.0, end: 1.0) + .animate( + CurvedAnimation( + parent: _controller, + curve: const Interval(0.7, 1.0, curve: Curves.easeIn), + ), + ); final Animation shrinkMultiplier = Tween(begin: 1.0, end: 0.3).animate( - CurvedAnimation( - parent: _controller, - curve: const Interval(0.7, 1.0, curve: Curves.easeInOut), - ), - ); + CurvedAnimation( + parent: _controller, + curve: const Interval(0.7, 1.0, curve: Curves.easeInOut), + ), + ); final colorScheme = Theme.of(context).colorScheme; final grammarVocabStyle = Theme.of(context).textTheme.titleLarge?.copyWith( - fontWeight: FontWeight.bold, - color: colorScheme.primary, - ); + fontWeight: FontWeight.bold, + color: colorScheme.primary, + ); final username = Matrix.of(context).client.userID?.split(':').first.substring(1) ?? ''; @@ -241,7 +238,7 @@ class _LevelUpPopupContentState extends State children: [ AnimatedBuilder( animation: _controller, - builder: (_, __) => Row( + builder: (_, _) => Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Padding( @@ -274,7 +271,7 @@ class _LevelUpPopupContentState extends State // Progress bar + Level AnimatedBuilder( animation: _controller, - builder: (_, __) => Row( + builder: (_, _) => Row( children: [ const Expanded( child: LevelPopupProgressBar( @@ -283,17 +280,12 @@ class _LevelUpPopupContentState extends State ), ), const SizedBox(width: 8), - Text( - "⭐", - style: Theme.of(context).textTheme.titleLarge, - ), + Text("⭐", style: Theme.of(context).textTheme.titleLarge), Padding( padding: const EdgeInsets.all(8.0), child: AnimatedFlipCounter( value: displayedLevel, - textStyle: Theme.of(context) - .textTheme - .headlineMedium + textStyle: Theme.of(context).textTheme.headlineMedium ?.copyWith( fontWeight: FontWeight.bold, color: AppConfig.goldLight, @@ -310,7 +302,7 @@ class _LevelUpPopupContentState extends State // Vocab and grammar row AnimatedBuilder( animation: _controller, - builder: (_, __) => Row( + builder: (_, _) => Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Column( @@ -392,7 +384,7 @@ class _LevelUpPopupContentState extends State // Skills section AnimatedBuilder( animation: skillsOpacity, - builder: (_, __) => Opacity( + builder: (_, _) => Opacity( opacity: skillsOpacity.value, child: Column( crossAxisAlignment: CrossAxisAlignment.center, @@ -472,10 +464,7 @@ class _LevelUpPopupContentState extends State // chunk into rows of up to 4 final rows = >[ for (var i = 0; i < visibleSkills.length; i += itemsPerRow) - visibleSkills.sublist( - i, - min(i + itemsPerRow, visibleSkills.length), - ), + visibleSkills.sublist(i, min(i + itemsPerRow, visibleSkills.length)), ]; return Column( diff --git a/lib/pangea/analytics_misc/message_analytics_feedback.dart b/lib/pangea/analytics_misc/message_analytics_feedback.dart index f9efe40ef..237b893be 100644 --- a/lib/pangea/analytics_misc/message_analytics_feedback.dart +++ b/lib/pangea/analytics_misc/message_analytics_feedback.dart @@ -93,25 +93,21 @@ class MessageAnalyticsFeedbackState extends State } void _startTickerAnimations() { - _vocabTickerAnimation = IntTween( - begin: 0, - end: widget.newVocabConstructs, - ).animate( - CurvedAnimation( - parent: _tickerController, - curve: Curves.easeOutCubic, - ), - ); + _vocabTickerAnimation = IntTween(begin: 0, end: widget.newVocabConstructs) + .animate( + CurvedAnimation( + parent: _tickerController, + curve: Curves.easeOutCubic, + ), + ); - _grammarTickerAnimation = IntTween( - begin: 0, - end: widget.newGrammarConstructs, - ).animate( - CurvedAnimation( - parent: _tickerController, - curve: Curves.easeOutCubic, - ), - ); + _grammarTickerAnimation = + IntTween(begin: 0, end: widget.newGrammarConstructs).animate( + CurvedAnimation( + parent: _tickerController, + curve: Curves.easeOutCubic, + ), + ); setState(() {}); _tickerController.forward(); @@ -136,9 +132,7 @@ class MessageAnalyticsFeedbackState extends State builder: (context, child) { return Container( decoration: BoxDecoration( - color: Theme.of(context) - .colorScheme - .surfaceContainer + color: Theme.of(context).colorScheme.surfaceContainer .withAlpha((_bubbleOpacityAnimation.value * 255).round()), borderRadius: const BorderRadius.only( topLeft: Radius.circular(16.0), @@ -240,28 +234,18 @@ class _AnimatedCounter extends StatelessWidget { final Animation? animation; final TextStyle? style; - const _AnimatedCounter({ - super.key, - required this.animation, - this.style, - }); + const _AnimatedCounter({super.key, required this.animation, this.style}); @override Widget build(BuildContext context) { if (animation == null) { - return Text( - "+ 0", - style: style, - ); + return Text("+ 0", style: style); } return AnimatedBuilder( animation: animation!, builder: (context, child) { - return Text( - "+ ${animation!.value}", - style: style, - ); + return Text("+ ${animation!.value}", style: style); }, ); } diff --git a/lib/pangea/analytics_misc/room_analytics_extension.dart b/lib/pangea/analytics_misc/room_analytics_extension.dart index 375bce4c0..de4fa816d 100644 --- a/lib/pangea/analytics_misc/room_analytics_extension.dart +++ b/lib/pangea/analytics_misc/room_analytics_extension.dart @@ -31,9 +31,7 @@ extension AnalyticsRoomExtension on Room { /// The [uses] parameter is a list of [OneConstructUse] objects representing the /// constructs to be sent. To prevent hitting the maximum event size, the events /// are chunked into smaller lists. Each chunk is sent as a separate event. - Future sendConstructsEvent( - List uses, - ) async { + Future sendConstructsEvent(List uses) async { // It's possible that the user has no info to send yet, but to prevent trying // to load the data over and over again, we'll sometimes send an empty event to // indicate that we have checked and there was no data. diff --git a/lib/pangea/analytics_misc/saved_analytics_extension.dart b/lib/pangea/analytics_misc/saved_analytics_extension.dart index 9e362baa8..f7457664a 100644 --- a/lib/pangea/analytics_misc/saved_analytics_extension.dart +++ b/lib/pangea/analytics_misc/saved_analytics_extension.dart @@ -34,12 +34,9 @@ extension SavedAnalyticsExtension on Room { ids.add(roomId); final syncFuture = client.waitForRoomInSync(id, join: true); - await client.setRoomStateWithKey( - id, - PangeaEventTypes.activityRoomIds, - "", - {ModelKey.roomIds: ids}, - ); + await client.setRoomStateWithKey(id, PangeaEventTypes.activityRoomIds, "", { + ModelKey.roomIds: ids, + }); final newLength = _activityRoomIds.length; if (newLength == prevLength) { await syncFuture; diff --git a/lib/pangea/analytics_misc/text_loading_shimmer.dart b/lib/pangea/analytics_misc/text_loading_shimmer.dart index 1b2232e6a..28050360d 100644 --- a/lib/pangea/analytics_misc/text_loading_shimmer.dart +++ b/lib/pangea/analytics_misc/text_loading_shimmer.dart @@ -9,11 +9,7 @@ class TextLoadingShimmer extends StatelessWidget { final double width; final double? height; - const TextLoadingShimmer({ - super.key, - this.width = 140.0, - this.height, - }); + const TextLoadingShimmer({super.key, this.width = 140.0, this.height}); @override Widget build(BuildContext context) { @@ -25,7 +21,8 @@ class TextLoadingShimmer extends StatelessWidget { borderRadius: BorderRadius.circular(4.0), color: Theme.of(context).colorScheme.primary, ), - height: height ?? + height: + height ?? (AppConfig.messageFontSize * AppSettings.fontSizeFactor.value), width: width, ), diff --git a/lib/pangea/analytics_page/activity_archive.dart b/lib/pangea/analytics_page/activity_archive.dart index c76bdff96..89cfc1c88 100644 --- a/lib/pangea/analytics_page/activity_archive.dart +++ b/lib/pangea/analytics_page/activity_archive.dart @@ -20,24 +20,22 @@ import '../../config/themes.dart'; import '../../widgets/avatar.dart'; class ActivityArchive extends StatelessWidget { - const ActivityArchive({ - super.key, - }); + const ActivityArchive({super.key}); @override Widget build(BuildContext context) { return StreamBuilder( - stream: Matrix.of(context) - .analyticsDataService - .updateDispatcher - .activityAnalyticsStream - .stream, + stream: Matrix.of( + context, + ).analyticsDataService.updateDispatcher.activityAnalyticsStream.stream, builder: (context, _) { - final Room? analyticsRoom = - Matrix.of(context).client.analyticsRoomLocal(); + final Room? analyticsRoom = Matrix.of( + context, + ).client.analyticsRoomLocal(); final archive = analyticsRoom?.archivedActivities ?? []; - final selectedRoomId = - GoRouterState.of(context).pathParameters['roomid']; + final selectedRoomId = GoRouterState.of( + context, + ).pathParameters['roomid']; return Scaffold( body: SafeArea( child: Padding( @@ -95,17 +93,12 @@ class AnalyticsActivityItem extends StatelessWidget { Widget build(BuildContext context) { final objective = room.activityPlan?.learningObjective ?? ''; final cefrLevel = room.activitySummary?.summary?.participants - .firstWhereOrNull( - (p) => p.participantId == room.client.userID, - ) + .firstWhereOrNull((p) => p.participantId == room.client.userID) ?.cefrLevel; final theme = Theme.of(context); return Padding( - padding: const EdgeInsets.symmetric( - horizontal: 8, - vertical: 1, - ), + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 1), child: Material( color: selected ? theme.colorScheme.secondaryContainer : null, borderRadius: BorderRadius.circular(AppConfig.borderRadius), diff --git a/lib/pangea/analytics_page/empty_analytics_page.dart b/lib/pangea/analytics_page/empty_analytics_page.dart index 852dfa679..ea5cadc40 100644 --- a/lib/pangea/analytics_page/empty_analytics_page.dart +++ b/lib/pangea/analytics_page/empty_analytics_page.dart @@ -19,9 +19,8 @@ class EmptyAnalyticsPage extends StatelessWidget { imageUrl: "${AppConfig.assetsBaseURL}/${AnalyticsPageConstants.dinoBotFileName}", errorWidget: (context, url, error) => const SizedBox(), - placeholder: (context, url) => const Center( - child: CircularProgressIndicator.adaptive(), - ), + placeholder: (context, url) => + const Center(child: CircularProgressIndicator.adaptive()), ), ), ), diff --git a/lib/pangea/analytics_practice/analytics_practice_page.dart b/lib/pangea/analytics_practice/analytics_practice_page.dart index 1bcc52d01..2c5467c05 100644 --- a/lib/pangea/analytics_practice/analytics_practice_page.dart +++ b/lib/pangea/analytics_practice/analytics_practice_page.dart @@ -32,10 +32,7 @@ class SelectedMorphChoice { final MorphFeaturesEnum feature; final String tag; - const SelectedMorphChoice({ - required this.feature, - required this.tag, - }); + const SelectedMorphChoice({required this.feature, required this.tag}); } class VocabPracticeChoice { @@ -54,10 +51,7 @@ class _PracticeQueueEntry { final MessageActivityRequest request; final Completer completer; - _PracticeQueueEntry({ - required this.request, - required this.completer, - }); + _PracticeQueueEntry({required this.request, required this.completer}); } class SessionLoader extends AsyncLoader { @@ -73,10 +67,7 @@ class AnalyticsPractice extends StatefulWidget { static bool bypassExitConfirmation = true; final ConstructTypeEnum type; - const AnalyticsPractice({ - super.key, - required this.type, - }); + const AnalyticsPractice({super.key, required this.type}); @override AnalyticsPracticeState createState() => AnalyticsPracticeState(); @@ -87,7 +78,7 @@ class AnalyticsPracticeState extends State late final SessionLoader _sessionLoader; final ValueNotifier> - activityState = ValueNotifier(const AsyncState.idle()); + activityState = ValueNotifier(const AsyncState.idle()); final Queue<_PracticeQueueEntry> _queue = Queue(); @@ -113,7 +104,10 @@ class AnalyticsPracticeState extends State _sessionLoader = SessionLoader(type: widget.type); _startSession(); _languageStreamSubscription = MatrixState - .pangeaController.userController.languageStream.stream + .pangeaController + .userController + .languageStream + .stream .listen((_) => _onLanguageUpdate()); } @@ -132,10 +126,10 @@ class AnalyticsPracticeState extends State MultipleChoicePracticeActivityModel? get _currentActivity => activityState.value is AsyncLoaded - ? (activityState.value - as AsyncLoaded) - .value - : null; + ? (activityState.value + as AsyncLoaded) + .value + : null; bool get _isComplete => _sessionLoader.value?.isComplete ?? false; @@ -249,7 +243,10 @@ class AnalyticsPracticeState extends State try { _clearState(); await _analyticsService - .updateDispatcher.constructUpdateStream.stream.first + .updateDispatcher + .constructUpdateStream + .stream + .first .timeout(const Duration(seconds: 10)); await reloadSession(); } catch (e) { @@ -381,22 +378,16 @@ class AnalyticsPracticeState extends State } AnalyticsPractice.bypassExitConfirmation = true; if (!mounted) return; - activityState.value = - AsyncState.error(L10n.of(context).oopsSomethingWentWrong); + activityState.value = AsyncState.error( + L10n.of(context).oopsSomethingWentWrong, + ); return; } - Future _fillActivityQueue( - List requests, - ) async { + Future _fillActivityQueue(List requests) async { for (final request in requests) { final completer = Completer(); - _queue.add( - _PracticeQueueEntry( - request: request, - completer: completer, - ), - ); + _queue.add(_PracticeQueueEntry(request: request, completer: completer)); try { final res = await _fetchActivity(request); if (!mounted) return; @@ -412,10 +403,7 @@ class AnalyticsPracticeState extends State Future _fetchActivity( MessageActivityRequest req, ) async { - final result = await PracticeRepo.getPracticeActivity( - req, - messageInfo: {}, - ); + final result = await PracticeRepo.getPracticeActivity(req, messageInfo: {}); if (result.isError || result.result is! MultipleChoicePracticeActivityModel) { @@ -469,10 +457,7 @@ class AnalyticsPracticeState extends State final use = OneConstructUse( useType: ConstructUseTypeEnum.ignPA, constructType: widget.type, - metadata: ConstructUseMetaData( - roomId: null, - timeStamp: DateTime.now(), - ), + metadata: ConstructUseMetaData(roomId: null, timeStamp: DateTime.now()), category: token.pos, lemma: token.lemma.text, form: token.lemma.text, @@ -486,9 +471,7 @@ class AnalyticsPracticeState extends State hintPressedNotifier.value = !hintPressedNotifier.value; } - Future onSelectChoice( - String choiceContent, - ) async { + Future onSelectChoice(String choiceContent) async { if (_currentActivity == null) return; final activity = _currentActivity!; @@ -513,8 +496,10 @@ class AnalyticsPracticeState extends State final use = activity.constructUse(choiceContent); _sessionLoader.value!.submitAnswer(use); - await _analyticsService.updateService - .addAnalytics(choiceTargetId(choiceContent), [use]); + await _analyticsService.updateService.addAnalytics( + choiceTargetId(choiceContent), + [use], + ); if (!activity.multipleChoiceContent.isCorrect(choiceContent)) return; diff --git a/lib/pangea/analytics_practice/analytics_practice_session_model.dart b/lib/pangea/analytics_practice/analytics_practice_session_model.dart index ebeccdce0..4291dfbb6 100644 --- a/lib/pangea/analytics_practice/analytics_practice_session_model.dart +++ b/lib/pangea/analytics_practice/analytics_practice_session_model.dart @@ -9,9 +9,7 @@ import 'package:fluffychat/pangea/practice_activities/practice_target.dart'; class MorphExampleInfo { final List exampleMessage; - const MorphExampleInfo({ - required this.exampleMessage, - }); + const MorphExampleInfo({required this.exampleMessage}); Map toJson() { final segments = >[]; @@ -25,9 +23,7 @@ class MorphExampleInfo { } } - return { - 'segments': segments, - }; + return {'segments': segments}; } factory MorphExampleInfo.fromJson(Map json) { @@ -62,10 +58,10 @@ class AnalyticsActivityTarget { }); Map toJson() => { - 'target': target.toJson(), - 'grammarErrorInfo': grammarErrorInfo?.toJson(), - 'morphExampleInfo': morphExampleInfo?.toJson(), - }; + 'target': target.toJson(), + 'grammarErrorInfo': grammarErrorInfo?.toJson(), + 'morphExampleInfo': morphExampleInfo?.toJson(), + }; factory AnalyticsActivityTarget.fromJson(Map json) => AnalyticsActivityTarget( @@ -96,19 +92,23 @@ class AnalyticsPracticeSessionModel { }) : state = state ?? const AnalyticsPracticeSessionState(); // Maximum activities to attempt (including skips) - int get _maxAttempts => (AnalyticsPracticeConstants.practiceGroupSize + - AnalyticsPracticeConstants.errorBufferSize) - .clamp(0, practiceTargets.length) - .toInt(); + int get _maxAttempts => + (AnalyticsPracticeConstants.practiceGroupSize + + AnalyticsPracticeConstants.errorBufferSize) + .clamp(0, practiceTargets.length) + .toInt(); - int get _completionGoal => AnalyticsPracticeConstants.practiceGroupSize - .clamp(0, practiceTargets.length); + int get _completionGoal => AnalyticsPracticeConstants.practiceGroupSize.clamp( + 0, + practiceTargets.length, + ); // Total attempted so far (completed + skipped) int get _totalAttempted => state.currentIndex + state.skippedActivities; bool get isComplete { - final complete = state.finished || + final complete = + state.finished || state.currentIndex >= _completionGoal || _totalAttempted >= _maxAttempts; return complete; @@ -116,8 +116,10 @@ class AnalyticsPracticeSessionModel { double get progress { final possibleCompletions = - (state.currentIndex + _maxAttempts - _totalAttempted) - .clamp(0, _completionGoal); + (state.currentIndex + _maxAttempts - _totalAttempted).clamp( + 0, + _completionGoal, + ); return possibleCompletions > 0 ? (state.currentIndex / possibleCompletions).clamp(0.0, 1.0) : 1.0; @@ -144,13 +146,11 @@ class AnalyticsPracticeSessionModel { void completeActivity() => state = state.copyWith(currentIndex: state.currentIndex + 1); - void incrementSkippedActivities() => state = state.copyWith( - skippedActivities: state.skippedActivities + 1, - ); + void incrementSkippedActivities() => + state = state.copyWith(skippedActivities: state.skippedActivities + 1); - void submitAnswer(OneConstructUse use) => state = state.copyWith( - completedUses: [...state.completedUses, use], - ); + void submitAnswer(OneConstructUse use) => + state = state.copyWith(completedUses: [...state.completedUses, use]); factory AnalyticsPracticeSessionModel.fromJson(Map json) { return AnalyticsPracticeSessionModel( @@ -161,9 +161,7 @@ class AnalyticsPracticeSessionModel { .toList(), userL1: json['userL1'] as String, userL2: json['userL2'] as String, - state: AnalyticsPracticeSessionState.fromJson( - json, - ), + state: AnalyticsPracticeSessionState.fromJson(json), ); } @@ -221,22 +219,22 @@ class AnalyticsPracticeSessionState { completedUses.where((use) => use.xp > 0).map(_bonusUse).toList(); List get allBonusUses => [ - if (_giveAccuracyBonus) ..._bonusUses, - if (_giveTimeBonus) ..._bonusUses, - ]; + if (_giveAccuracyBonus) ..._bonusUses, + if (_giveTimeBonus) ..._bonusUses, + ]; OneConstructUse _bonusUse(OneConstructUse originalUse) => OneConstructUse( - useType: ConstructUseTypeEnum.bonus, - constructType: originalUse.constructType, - metadata: ConstructUseMetaData( - roomId: originalUse.metadata.roomId, - timeStamp: DateTime.now(), - ), - category: originalUse.category, - lemma: originalUse.lemma, - form: originalUse.form, - xp: ConstructUseTypeEnum.bonus.pointValue, - ); + useType: ConstructUseTypeEnum.bonus, + constructType: originalUse.constructType, + metadata: ConstructUseMetaData( + roomId: originalUse.metadata.roomId, + timeStamp: DateTime.now(), + ), + category: originalUse.category, + lemma: originalUse.lemma, + form: originalUse.form, + xp: ConstructUseTypeEnum.bonus.pointValue, + ); AnalyticsPracticeSessionState copyWith({ List? completedUses, @@ -266,7 +264,8 @@ class AnalyticsPracticeSessionState { factory AnalyticsPracticeSessionState.fromJson(Map json) { return AnalyticsPracticeSessionState( - completedUses: (json['completedUses'] as List?) + completedUses: + (json['completedUses'] as List?) ?.map((e) => OneConstructUse.fromJson(e)) .whereType() .toList() ?? diff --git a/lib/pangea/analytics_practice/analytics_practice_session_repo.dart b/lib/pangea/analytics_practice/analytics_practice_session_repo.dart index 5e82d6b6d..e575542c3 100644 --- a/lib/pangea/analytics_practice/analytics_practice_session_repo.dart +++ b/lib/pangea/analytics_practice/analytics_practice_session_repo.dart @@ -64,7 +64,8 @@ class AnalyticsPracticeSessionRepo { (AnalyticsPracticeConstants.practiceGroupSize + AnalyticsPracticeConstants.errorBufferSize)) { final morphs = await _fetchMorphs(); - final remainingCount = (AnalyticsPracticeConstants.practiceGroupSize + + final remainingCount = + (AnalyticsPracticeConstants.practiceGroupSize + AnalyticsPracticeConstants.errorBufferSize) - targets.length; final morphEntries = morphs.take(remainingCount); @@ -103,7 +104,9 @@ class AnalyticsPracticeSessionRepo { static Future> _fetchVocab() async { final constructs = await MatrixState - .pangeaController.matrixState.analyticsDataService + .pangeaController + .matrixState + .analyticsDataService .getAggregatedConstructs(ConstructTypeEnum.vocab) .then((map) => map.values.toList()); @@ -134,14 +137,18 @@ class AnalyticsPracticeSessionRepo { static Future> _fetchMorphs() async { final constructs = await MatrixState - .pangeaController.matrixState.analyticsDataService + .pangeaController + .matrixState + .analyticsDataService .getAggregatedConstructs(ConstructTypeEnum.morph) .then((map) => map.values.toList()); final morphInfoRequest = MorphInfoRequest( - userL1: MatrixState.pangeaController.userController.userL1?.langCode ?? + userL1: + MatrixState.pangeaController.userController.userL1?.langCode ?? LanguageKeys.defaultLanguage, - userL2: MatrixState.pangeaController.userController.userL2?.langCode ?? + userL2: + MatrixState.pangeaController.userController.userL2?.langCode ?? LanguageKeys.defaultLanguage, ); @@ -218,11 +225,7 @@ class AnalyticsPracticeSessionRepo { seenForms.add(form); final token = PangeaToken( - lemma: Lemma( - text: form, - saveVocab: true, - form: form, - ), + lemma: Lemma(text: form, saveVocab: true, form: form), text: PangeaTokenText.fromString(form), pos: 'other', morph: {feature: use.lemma}, @@ -244,7 +247,9 @@ class AnalyticsPracticeSessionRepo { static Future> _fetchErrors() async { // Fetch all recent uses in one call (not filtering blocked constructs) final allRecentUses = await MatrixState - .pangeaController.matrixState.analyticsDataService + .pangeaController + .matrixState + .analyticsDataService .getUses(count: 200, filterCapped: false); // Filter for grammar error uses @@ -341,9 +346,7 @@ class AnalyticsPracticeSessionRepo { .where( (token) => token.lemma.saveVocab && - choices.any( - (choice) => choice.contains(token.text.content), - ), + choices.any((choice) => choice.contains(token.text.content)), ) .toList(); @@ -359,8 +362,9 @@ class AnalyticsPracticeSessionRepo { category: firstToken.pos, ); - final hasRecentPractice = - recentlyPracticedConstructs.contains(tokenIdentifier); + final hasRecentPractice = recentlyPracticedConstructs.contains( + tokenIdentifier, + ); if (hasRecentPractice) continue; diff --git a/lib/pangea/analytics_practice/analytics_practice_view.dart b/lib/pangea/analytics_practice/analytics_practice_view.dart index a38c7525f..8b24d488a 100644 --- a/lib/pangea/analytics_practice/analytics_practice_view.dart +++ b/lib/pangea/analytics_practice/analytics_practice_view.dart @@ -49,7 +49,7 @@ class AnalyticsPracticeView extends StatelessWidget { Expanded( child: ValueListenableBuilder( valueListenable: controller.progressNotifier, - builder: (context, progress, __) { + builder: (context, progress, _) { return AnimatedProgressBar( height: 20.0, widthPercent: progress, @@ -61,7 +61,7 @@ class AnalyticsPracticeView extends StatelessWidget { //keep track of state to update timer ValueListenableBuilder( valueListenable: controller.sessionState, - builder: (context, state, __) { + builder: (context, state, _) { if (state is AsyncLoaded) { return PracticeTimerWidget( key: ValueKey(state.value.startedAt), @@ -77,20 +77,16 @@ class AnalyticsPracticeView extends StatelessWidget { ), ), body: Padding( - padding: const EdgeInsets.symmetric( - horizontal: 8.0, - ), + padding: const EdgeInsets.symmetric(horizontal: 8.0), child: MaxWidthBody( withScrolling: false, showBorder: false, child: ValueListenableBuilder( valueListenable: controller.sessionState, - builder: (context, state, __) { + builder: (context, state, _) { return switch (state) { AsyncError(:final error) => - ErrorIndicator( - message: error.toLocalizedString(context), - ), + ErrorIndicator(message: error.toLocalizedString(context)), AsyncLoaded(:final value) => value.isComplete ? CompletedActivitySessionView(state.value, controller) @@ -108,9 +104,7 @@ class AnalyticsPracticeView extends StatelessWidget { class _AnalyticsActivityView extends StatelessWidget { final AnalyticsPracticeState controller; - const _AnalyticsActivityView( - this.controller, - ); + const _AnalyticsActivityView(this.controller); @override Widget build(BuildContext context) { @@ -125,15 +119,13 @@ class _AnalyticsActivityView extends StatelessWidget { //per-activity instructions, add switch statement once there are more types const InstructionsInlineTooltip( instructionsEnum: InstructionsEnum.selectMeaning, - padding: EdgeInsets.symmetric( - vertical: 8.0, - ), + padding: EdgeInsets.symmetric(vertical: 8.0), ), SizedBox( height: 75.0, child: ValueListenableBuilder( valueListenable: controller.activityTarget, - builder: (context, target, __) => target != null + builder: (context, target, _) => target != null ? Column( children: [ Text( @@ -148,7 +140,9 @@ class _AnalyticsActivityView extends StatelessWidget { text: target.target.tokens.first.vocabConstructID.lemma, textLanguage: MatrixState - .pangeaController.userController.userL2!, + .pangeaController + .userController + .userL2!, style: const TextStyle(fontSize: 14.0), ), ], @@ -157,9 +151,7 @@ class _AnalyticsActivityView extends StatelessWidget { ), ), const SizedBox(height: 16.0), - Center( - child: _AnalyticsPracticeCenterContent(controller: controller), - ), + Center(child: _AnalyticsPracticeCenterContent(controller: controller)), const SizedBox(height: 16.0), _ActivityChoicesWidget(controller), const SizedBox(height: 16.0), @@ -172,70 +164,64 @@ class _AnalyticsActivityView extends StatelessWidget { class _AnalyticsPracticeCenterContent extends StatelessWidget { final AnalyticsPracticeState controller; - const _AnalyticsPracticeCenterContent({ - required this.controller, - }); + const _AnalyticsPracticeCenterContent({required this.controller}); @override Widget build(BuildContext context) { return ValueListenableBuilder( valueListenable: controller.activityTarget, - builder: (context, target, __) => switch (target?.target.activityType) { + builder: (context, target, _) => switch (target?.target.activityType) { null => const SizedBox(), ActivityTypeEnum.grammarError => SizedBox( - height: 160.0, - child: SingleChildScrollView( - child: ValueListenableBuilder( - valueListenable: controller.activityState, - builder: (context, state, __) => switch (state) { - AsyncLoaded( - value: final GrammarErrorPracticeActivityModel activity - ) => - Column( - mainAxisSize: MainAxisSize.min, - children: [ - _ErrorBlankWidget( - key: ValueKey( - '${activity.eventID}_${activity.errorOffset}_${activity.errorLength}', - ), - activity: activity, + height: 160.0, + child: SingleChildScrollView( + child: ValueListenableBuilder( + valueListenable: controller.activityState, + builder: (context, state, _) => switch (state) { + AsyncLoaded( + value: final GrammarErrorPracticeActivityModel activity, + ) => + Column( + mainAxisSize: MainAxisSize.min, + children: [ + _ErrorBlankWidget( + key: ValueKey( + '${activity.eventID}_${activity.errorOffset}_${activity.errorLength}', ), - const SizedBox(height: 12), - ], - ), - _ => const SizedBox(), + activity: activity, + ), + const SizedBox(height: 12), + ], + ), + _ => const SizedBox(), + }, + ), + ), + ), + ActivityTypeEnum.grammarCategory => Center( + child: Column( + children: [ + _CorrectAnswerHint(controller: controller), + _ExampleMessageWidget(controller.getExampleMessage(target!)), + const SizedBox(height: 12), + ValueListenableBuilder( + valueListenable: controller.hintPressedNotifier, + builder: (context, hintPressed, _) { + return HintButton( + depressed: hintPressed, + onPressed: controller.onHintPressed, + ); }, ), - ), - ), - ActivityTypeEnum.grammarCategory => Center( - child: Column( - children: [ - _CorrectAnswerHint(controller: controller), - _ExampleMessageWidget( - controller.getExampleMessage(target!), - ), - const SizedBox(height: 12), - ValueListenableBuilder( - valueListenable: controller.hintPressedNotifier, - builder: (context, hintPressed, __) { - return HintButton( - depressed: hintPressed, - onPressed: controller.onHintPressed, - ); - }, - ), - ], - ), + ], ), + ), _ => SizedBox( - height: 100.0, - child: Center( - child: _ExampleMessageWidget( - controller.getExampleMessage(target!), - ), - ), + height: 100.0, + child: Center( + child: _ExampleMessageWidget(controller.getExampleMessage(target!)), ), + ), }, ); } @@ -256,10 +242,7 @@ class _ExampleMessageWidget extends StatelessWidget { } return Container( - padding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 8, - ), + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), decoration: BoxDecoration( color: Color.alphaBlend( Colors.white.withAlpha(180), @@ -271,7 +254,8 @@ class _ExampleMessageWidget extends StatelessWidget { text: TextSpan( style: TextStyle( color: Theme.of(context).colorScheme.onPrimaryFixed, - fontSize: AppSettings.fontSizeFactor.value * + fontSize: + AppSettings.fontSizeFactor.value * AppConfig.messageFontSize, ), children: snapshot.data!, @@ -286,22 +270,20 @@ class _ExampleMessageWidget extends StatelessWidget { class _CorrectAnswerHint extends StatelessWidget { final AnalyticsPracticeState controller; - const _CorrectAnswerHint({ - required this.controller, - }); + const _CorrectAnswerHint({required this.controller}); @override Widget build(BuildContext context) { return ValueListenableBuilder( valueListenable: controller.hintPressedNotifier, - builder: (context, hintPressed, __) { + builder: (context, hintPressed, _) { if (!hintPressed) { return const SizedBox.shrink(); } return ValueListenableBuilder( valueListenable: controller.activityState, - builder: (context, state, __) { + builder: (context, state, _) { if (state is! AsyncLoaded) { return const SizedBox.shrink(); } @@ -331,9 +313,7 @@ class _CorrectAnswerHint extends StatelessWidget { class _WrongAnswerFeedback extends StatelessWidget { final AnalyticsPracticeState controller; - const _WrongAnswerFeedback({ - required this.controller, - }); + const _WrongAnswerFeedback({required this.controller}); @override Widget build(BuildContext context) { @@ -353,8 +333,9 @@ class _WrongAnswerFeedback extends StatelessWidget { } final activity = activityState.value; - final isWrongAnswer = - !activity.multipleChoiceContent.isCorrect(selectedChoice.tag); + final isWrongAnswer = !activity.multipleChoiceContent.isCorrect( + selectedChoice.tag, + ); if (!isWrongAnswer) { return const SizedBox.shrink(); @@ -376,10 +357,7 @@ class _WrongAnswerFeedback extends StatelessWidget { class _ErrorBlankWidget extends StatefulWidget { final GrammarErrorPracticeActivityModel activity; - const _ErrorBlankWidget({ - super.key, - required this.activity, - }); + const _ErrorBlankWidget({super.key, required this.activity}); @override State<_ErrorBlankWidget> createState() => _ErrorBlankWidgetState(); @@ -422,8 +400,10 @@ class _ErrorBlankWidgetState extends State<_ErrorBlankWidget> { trimmedBefore = true; } - final before = - chars.skip(beforeStart).take(errorOffset - beforeStart).toString(); + final before = chars + .skip(beforeStart) + .take(errorOffset - beforeStart) + .toString(); // ---------- AFTER ---------- int afterEnd = totalLength; @@ -449,10 +429,7 @@ class _ErrorBlankWidgetState extends State<_ErrorBlankWidget> { return Column( children: [ Container( - padding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 8, - ), + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), decoration: BoxDecoration( color: Color.alphaBlend( Colors.white.withAlpha(180), @@ -466,7 +443,8 @@ class _ErrorBlankWidgetState extends State<_ErrorBlankWidget> { text: TextSpan( style: TextStyle( color: Theme.of(context).colorScheme.onPrimaryFixed, - fontSize: AppSettings.fontSizeFactor.value * + fontSize: + AppSettings.fontSizeFactor.value * AppConfig.messageFontSize, ), children: [ @@ -493,7 +471,8 @@ class _ErrorBlankWidgetState extends State<_ErrorBlankWidget> { translation, style: TextStyle( color: Theme.of(context).colorScheme.onPrimaryFixed, - fontSize: AppSettings.fontSizeFactor.value * + fontSize: + AppSettings.fontSizeFactor.value * AppConfig.messageFontSize, fontStyle: FontStyle.italic, ), @@ -542,10 +521,7 @@ class HintButton extends StatelessWidget { shape: BoxShape.circle, ), ), - const Icon( - Icons.lightbulb_outline, - size: 20, - ), + const Icon(Icons.lightbulb_outline, size: 20), ], ), ); @@ -555,23 +531,21 @@ class HintButton extends StatelessWidget { class _ActivityChoicesWidget extends StatelessWidget { final AnalyticsPracticeState controller; - const _ActivityChoicesWidget( - this.controller, - ); + const _ActivityChoicesWidget(this.controller); @override Widget build(BuildContext context) { return ValueListenableBuilder( valueListenable: controller.activityState, - builder: (context, state, __) { + builder: (context, state, _) { return switch (state) { AsyncLoading() => const Center( - child: SizedBox( - width: 24, - height: 24, - child: CircularProgressIndicator.adaptive(), - ), + child: SizedBox( + width: 24, + height: 24, + child: CircularProgressIndicator.adaptive(), ), + ), AsyncError(:final error) => Column( mainAxisAlignment: MainAxisAlignment.center, @@ -589,7 +563,7 @@ class _ActivityChoicesWidget extends StatelessWidget { AsyncLoaded(:final value) => ValueListenableBuilder( valueListenable: controller.enableChoicesNotifier, - builder: (context, enabled, __) { + builder: (context, enabled, _) { final choices = controller.filteredChoices(value); return Column( spacing: 8.0, @@ -600,9 +574,8 @@ class _ActivityChoicesWidget extends StatelessWidget { activity: value, targetId: controller.choiceTargetId(choice.choiceId), choiceId: choice.choiceId, - onPressed: () => controller.onSelectChoice( - choice.choiceId, - ), + onPressed: () => + controller.onSelectChoice(choice.choiceId), cardHeight: 60.0, choiceText: choice.choiceText, choiceEmoji: choice.choiceEmoji, @@ -614,11 +587,9 @@ class _ActivityChoicesWidget extends StatelessWidget { }, ), _ => Container( - constraints: const BoxConstraints(maxHeight: 400.0), - child: const Center( - child: CircularProgressIndicator.adaptive(), - ), - ), + constraints: const BoxConstraints(maxHeight: 400.0), + child: const Center(child: CircularProgressIndicator.adaptive()), + ), }; }, ); diff --git a/lib/pangea/analytics_practice/choice_cards/grammar_choice_card.dart b/lib/pangea/analytics_practice/choice_cards/grammar_choice_card.dart index 230944160..60a38c82e 100644 --- a/lib/pangea/analytics_practice/choice_cards/grammar_choice_card.dart +++ b/lib/pangea/analytics_practice/choice_cards/grammar_choice_card.dart @@ -34,13 +34,10 @@ class GrammarChoiceCard extends StatelessWidget { Widget build(BuildContext context) { final baseTextSize = (Theme.of(context).textTheme.titleMedium?.fontSize ?? 16) * - (height / 72.0).clamp(1.0, 1.4); + (height / 72.0).clamp(1.0, 1.4); final emojiSize = baseTextSize * 1.5; - final copy = getGrammarCopy( - category: feature.name, - lemma: tag, - context: context, - ) ?? + final copy = + getGrammarCopy(category: feature.name, lemma: tag, context: context) ?? tag; return GameChoiceCard( @@ -69,9 +66,7 @@ class GrammarChoiceCard extends StatelessWidget { copy, overflow: TextOverflow.ellipsis, textAlign: TextAlign.left, - style: TextStyle( - fontSize: baseTextSize, - ), + style: TextStyle(fontSize: baseTextSize), ), ), ], diff --git a/lib/pangea/analytics_practice/choice_cards/meaning_choice_card.dart b/lib/pangea/analytics_practice/choice_cards/meaning_choice_card.dart index f51394054..1dbe54c93 100644 --- a/lib/pangea/analytics_practice/choice_cards/meaning_choice_card.dart +++ b/lib/pangea/analytics_practice/choice_cards/meaning_choice_card.dart @@ -30,7 +30,7 @@ class MeaningChoiceCard extends StatelessWidget { Widget build(BuildContext context) { final baseTextSize = (Theme.of(context).textTheme.titleMedium?.fontSize ?? 16) * - (height / 72.0).clamp(1.0, 1.4); + (height / 72.0).clamp(1.0, 1.4); final emojiSize = baseTextSize * 1.2; return GameChoiceCard( @@ -48,10 +48,7 @@ class MeaningChoiceCard extends StatelessWidget { width: height * .7, height: height, child: Center( - child: Text( - emoji!, - style: TextStyle(fontSize: emojiSize), - ), + child: Text(emoji!, style: TextStyle(fontSize: emojiSize)), ), ), Expanded( @@ -60,9 +57,7 @@ class MeaningChoiceCard extends StatelessWidget { overflow: TextOverflow.ellipsis, maxLines: 2, textAlign: TextAlign.left, - style: TextStyle( - fontSize: baseTextSize, - ), + style: TextStyle(fontSize: baseTextSize), ), ), ], @@ -75,10 +70,7 @@ class MeaningChoiceCard extends StatelessWidget { width: height * .7, height: height, child: Center( - child: Text( - emoji!, - style: TextStyle(fontSize: emojiSize), - ), + child: Text(emoji!, style: TextStyle(fontSize: emojiSize)), ), ), Expanded( @@ -87,9 +79,7 @@ class MeaningChoiceCard extends StatelessWidget { overflow: TextOverflow.ellipsis, maxLines: 2, textAlign: TextAlign.left, - style: TextStyle( - fontSize: baseTextSize, - ), + style: TextStyle(fontSize: baseTextSize), ), ), ], diff --git a/lib/pangea/analytics_practice/completed_activity_session_view.dart b/lib/pangea/analytics_practice/completed_activity_session_view.dart index d9aefee22..7cac8c218 100644 --- a/lib/pangea/analytics_practice/completed_activity_session_view.dart +++ b/lib/pangea/analytics_practice/completed_activity_session_view.dart @@ -48,9 +48,9 @@ class CompletedActivitySessionView extends StatelessWidget { children: [ Text( L10n.of(context).congratulationsYouveCompletedPractice, - style: Theme.of(context).textTheme.titleMedium?.copyWith( - fontWeight: FontWeight.bold, - ), + style: Theme.of( + context, + ).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold), textAlign: TextAlign.center, ), Expanded( @@ -87,20 +87,20 @@ class CompletedActivitySessionView extends StatelessWidget { widthPercent: snapshot.hasData ? snapshot.data!.levelProgress : 0.0, - backgroundColor: Theme.of(context) - .colorScheme - .surfaceContainerHighest, + backgroundColor: Theme.of( + context, + ).colorScheme.surfaceContainerHighest, duration: const Duration(milliseconds: 500), ), ), ), Text( "+ ${session.state.allXPGained} XP", - style: - Theme.of(context).textTheme.titleLarge?.copyWith( - color: AppConfig.goldLight, - fontWeight: FontWeight.bold, - ), + style: Theme.of(context).textTheme.titleLarge + ?.copyWith( + color: AppConfig.goldLight, + fontWeight: FontWeight.bold, + ), ), ], ), @@ -115,14 +115,14 @@ class CompletedActivitySessionView extends StatelessWidget { markerWidth: 20.0, markerColor: AppConfig.success, backgroundColor: !accuracyAchievement - ? Theme.of(context) - .colorScheme - .surfaceContainerHighest + ? Theme.of( + context, + ).colorScheme.surfaceContainerHighest : Color.alphaBlend( AppConfig.goldLight.withValues(alpha: 0.3), - Theme.of(context) - .colorScheme - .surfaceContainerHighest, + Theme.of( + context, + ).colorScheme.surfaceContainerHighest, ), ), ), @@ -132,9 +132,7 @@ class CompletedActivitySessionView extends StatelessWidget { "${L10n.of(context).time}: ${_formatTime(elapsedSeconds)}", isAchievement: timeAchievement, achievementText: "+ ${session.state.timeBonusXP} XP", - child: TimeStarsWidget( - elapsedSeconds: elapsedSeconds, - ), + child: TimeStarsWidget(elapsedSeconds: elapsedSeconds), ), Column( children: [ @@ -149,11 +147,7 @@ class CompletedActivitySessionView extends StatelessWidget { onPressed: () => controller.reloadSession(), child: Row( mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - L10n.of(context).anotherRound, - ), - ], + children: [Text(L10n.of(context).anotherRound)], ), ), const SizedBox(height: 16), @@ -169,11 +163,7 @@ class CompletedActivitySessionView extends StatelessWidget { }, child: Row( mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - L10n.of(context).quit, - ), - ], + children: [Text(L10n.of(context).quit)], ), ), ], @@ -196,10 +186,7 @@ class CompletedActivitySessionView extends StatelessWidget { class TimeStarsWidget extends StatelessWidget { final int elapsedSeconds; - const TimeStarsWidget({ - required this.elapsedSeconds, - super.key, - }); + const TimeStarsWidget({required this.elapsedSeconds, super.key}); int get starCount { const timeForBonus = AnalyticsPracticeConstants.timeForBonus; diff --git a/lib/pangea/analytics_practice/grammar_error_practice_generator.dart b/lib/pangea/analytics_practice/grammar_error_practice_generator.dart index 9284a3c9f..762f8005a 100644 --- a/lib/pangea/analytics_practice/grammar_error_practice_generator.dart +++ b/lib/pangea/analytics_practice/grammar_error_practice_generator.dart @@ -5,9 +5,7 @@ import 'package:fluffychat/pangea/practice_activities/multiple_choice_activity_m import 'package:fluffychat/pangea/practice_activities/practice_activity_model.dart'; class GrammarErrorPracticeGenerator { - static Future get( - MessageActivityRequest req, - ) async { + static Future get(MessageActivityRequest req) async { assert( req.grammarErrorInfo != null, 'Grammar error info must be provided for grammar error practice', diff --git a/lib/pangea/analytics_practice/morph_category_activity_generator.dart b/lib/pangea/analytics_practice/morph_category_activity_generator.dart index 78ef8ba78..1d24967e6 100644 --- a/lib/pangea/analytics_practice/morph_category_activity_generator.dart +++ b/lib/pangea/analytics_practice/morph_category_activity_generator.dart @@ -9,9 +9,7 @@ import 'package:fluffychat/pangea/practice_activities/practice_activity_model.da import 'package:fluffychat/widgets/matrix.dart'; class MorphCategoryActivityGenerator { - static Future get( - MessageActivityRequest req, - ) async { + static Future get(MessageActivityRequest req) async { if (req.target.morphFeature == null) { throw ArgumentError( "MorphCategoryActivityGenerator requires a targetMorphFeature", @@ -21,9 +19,7 @@ class MorphCategoryActivityGenerator { final feature = req.target.morphFeature!; final morphTag = req.target.tokens.first.getMorphTag(feature); if (morphTag == null) { - throw ArgumentError( - "Token does not have the specified morph feature", - ); + throw ArgumentError("Token does not have the specified morph feature"); } MorphFeaturesAndTags morphs = defaultMorphMapping; diff --git a/lib/pangea/analytics_practice/percent_marker_bar.dart b/lib/pangea/analytics_practice/percent_marker_bar.dart index 2bc8b63a0..469b7fa4b 100644 --- a/lib/pangea/analytics_practice/percent_marker_bar.dart +++ b/lib/pangea/analytics_practice/percent_marker_bar.dart @@ -31,8 +31,10 @@ class PercentMarkerBar extends StatelessWidget { final targetPosition = totalWidth * widthPercent.clamp(0.0, 1.0); // Calculate the start position, clamping to keep marker within bounds - final markerStart = - (targetPosition - halfMarker).clamp(0.0, totalWidth - markerWidth); + final markerStart = (targetPosition - halfMarker).clamp( + 0.0, + totalWidth - markerWidth, + ); return Stack( alignment: Alignment.centerLeft, @@ -45,7 +47,8 @@ class PercentMarkerBar extends StatelessWidget { width: constraints.maxWidth, decoration: BoxDecoration( borderRadius: BorderRadius.circular(height / 2), - color: backgroundColor ?? + color: + backgroundColor ?? Theme.of(context).colorScheme.secondaryContainer, ), ), diff --git a/lib/pangea/analytics_practice/practice_timer_widget.dart b/lib/pangea/analytics_practice/practice_timer_widget.dart index 005efe0cc..41c8a669e 100644 --- a/lib/pangea/analytics_practice/practice_timer_widget.dart +++ b/lib/pangea/analytics_practice/practice_timer_widget.dart @@ -84,9 +84,9 @@ class PracticeTimerWidgetState extends State { const SizedBox(width: 4.0), Text( _formatTime(_getCurrentSeconds()), - style: Theme.of(context).textTheme.titleMedium?.copyWith( - fontWeight: FontWeight.bold, - ), + style: Theme.of( + context, + ).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold), ), ], ); diff --git a/lib/pangea/analytics_practice/stat_card.dart b/lib/pangea/analytics_practice/stat_card.dart index 2c1f5d570..88f3430fe 100644 --- a/lib/pangea/analytics_practice/stat_card.dart +++ b/lib/pangea/analytics_practice/stat_card.dart @@ -35,17 +35,13 @@ class StatCard extends StatelessWidget { if (!isColumnMode) { titleStyle = theme.textTheme.bodyMedium; } - titleStyle = titleStyle?.copyWith( - fontWeight: FontWeight.bold, - ); + titleStyle = titleStyle?.copyWith(fontWeight: FontWeight.bold); TextStyle? achievementStyle = theme.textTheme.titleSmall; if (!isColumnMode) { achievementStyle = theme.textTheme.bodySmall; } - achievementStyle = achievementStyle?.copyWith( - fontWeight: FontWeight.bold, - ); + achievementStyle = achievementStyle?.copyWith(fontWeight: FontWeight.bold); return Container( decoration: BoxDecoration( @@ -59,20 +55,12 @@ class StatCard extends StatelessWidget { children: [ Row( children: [ - Icon( - icon, - ), + Icon(icon), const SizedBox(width: 8), - Text( - text, - style: titleStyle, - ), + Text(text, style: titleStyle), if (isAchievement) ...[ const Spacer(), - Text( - achievementText, - style: achievementStyle, - ), + Text(achievementText, style: achievementStyle), ], ], ), diff --git a/lib/pangea/analytics_practice/vocab_audio_activity_generator.dart b/lib/pangea/analytics_practice/vocab_audio_activity_generator.dart index 7b2954f51..6605db90e 100644 --- a/lib/pangea/analytics_practice/vocab_audio_activity_generator.dart +++ b/lib/pangea/analytics_practice/vocab_audio_activity_generator.dart @@ -4,12 +4,11 @@ import 'package:fluffychat/pangea/practice_activities/multiple_choice_activity_m import 'package:fluffychat/pangea/practice_activities/practice_activity_model.dart'; class VocabAudioActivityGenerator { - static Future get( - MessageActivityRequest req, - ) async { + static Future get(MessageActivityRequest req) async { final token = req.target.tokens.first; - final choices = - await LemmaActivityGenerator.lemmaActivityDistractors(token); + final choices = await LemmaActivityGenerator.lemmaActivityDistractors( + token, + ); final choicesList = choices.map((c) => c.lemma).toList(); choicesList.shuffle(); diff --git a/lib/pangea/analytics_practice/vocab_meaning_activity_generator.dart b/lib/pangea/analytics_practice/vocab_meaning_activity_generator.dart index 7acc77b0d..14757ddf0 100644 --- a/lib/pangea/analytics_practice/vocab_meaning_activity_generator.dart +++ b/lib/pangea/analytics_practice/vocab_meaning_activity_generator.dart @@ -4,12 +4,11 @@ import 'package:fluffychat/pangea/practice_activities/multiple_choice_activity_m import 'package:fluffychat/pangea/practice_activities/practice_activity_model.dart'; class VocabMeaningActivityGenerator { - static Future get( - MessageActivityRequest req, - ) async { + static Future get(MessageActivityRequest req) async { final token = req.target.tokens.first; - final choices = - await LemmaActivityGenerator.lemmaActivityDistractors(token); + final choices = await LemmaActivityGenerator.lemmaActivityDistractors( + token, + ); if (!choices.contains(token.vocabConstructID)) { choices.add(token.vocabConstructID); diff --git a/lib/pangea/analytics_settings/analytics_settings_extension.dart b/lib/pangea/analytics_settings/analytics_settings_extension.dart index 7e7316ea9..63afccf49 100644 --- a/lib/pangea/analytics_settings/analytics_settings_extension.dart +++ b/lib/pangea/analytics_settings/analytics_settings_extension.dart @@ -16,9 +16,7 @@ extension AnalyticsSettingsRoomExtension on Room { Set get blockedConstructs => analyticsSettings.blockedConstructs; - Future setAnalyticsSettings( - AnalyticsSettingsModel settings, - ) async { + Future setAnalyticsSettings(AnalyticsSettingsModel settings) async { await client.setRoomStateWithKey( id, PangeaEventTypes.analyticsSettings, diff --git a/lib/pangea/analytics_settings/analytics_settings_model.dart b/lib/pangea/analytics_settings/analytics_settings_model.dart index 149964747..1566fabf5 100644 --- a/lib/pangea/analytics_settings/analytics_settings_model.dart +++ b/lib/pangea/analytics_settings/analytics_settings_model.dart @@ -3,9 +3,7 @@ import 'package:fluffychat/pangea/constructs/construct_identifier.dart'; class AnalyticsSettingsModel { final Set blockedConstructs; - const AnalyticsSettingsModel({ - required this.blockedConstructs, - }); + const AnalyticsSettingsModel({required this.blockedConstructs}); AnalyticsSettingsModel copyWith({ Set? blockedConstructs, @@ -23,9 +21,7 @@ class AnalyticsSettingsModel { blockedConstructs.add(ConstructIdentifier.fromJson(lemma)); } } - return AnalyticsSettingsModel( - blockedConstructs: blockedConstructs, - ); + return AnalyticsSettingsModel(blockedConstructs: blockedConstructs); } Map toJson() { diff --git a/lib/pangea/analytics_summary/animated_progress_bar.dart b/lib/pangea/analytics_summary/animated_progress_bar.dart index eece5bf6d..354edd373 100644 --- a/lib/pangea/analytics_summary/animated_progress_bar.dart +++ b/lib/pangea/analytics_summary/animated_progress_bar.dart @@ -38,7 +38,8 @@ class AnimatedProgressBar extends StatelessWidget { borderRadius: const BorderRadius.all( Radius.circular(AppConfig.borderRadius), ), - color: backgroundColor ?? + color: + backgroundColor ?? Theme.of(context).colorScheme.secondaryContainer, ), ), diff --git a/lib/pangea/analytics_summary/learning_progress_bar.dart b/lib/pangea/analytics_summary/learning_progress_bar.dart index 2292c2b94..b841b9484 100644 --- a/lib/pangea/analytics_summary/learning_progress_bar.dart +++ b/lib/pangea/analytics_summary/learning_progress_bar.dart @@ -21,9 +21,7 @@ class LearningProgressBar extends StatelessWidget { return Container( alignment: Alignment.center, height: height, - child: const LinearProgressIndicator( - color: AppConfig.goldLight, - ), + child: const LinearProgressIndicator(color: AppConfig.goldLight), ); } diff --git a/lib/pangea/analytics_summary/learning_progress_indicator_button.dart b/lib/pangea/analytics_summary/learning_progress_indicator_button.dart index 1e4632e0b..999f95453 100644 --- a/lib/pangea/analytics_summary/learning_progress_indicator_button.dart +++ b/lib/pangea/analytics_summary/learning_progress_indicator_button.dart @@ -29,10 +29,9 @@ class HoverButton extends StatelessWidget { child: Container( decoration: BoxDecoration( color: hovered || selected - ? Theme.of(context) - .colorScheme - .primary - .withAlpha((hoverOpacity * 255).round()) + ? Theme.of(context).colorScheme.primary.withAlpha( + (hoverOpacity * 255).round(), + ) : Colors.transparent, borderRadius: borderRadius ?? BorderRadius.circular(36.0), ), diff --git a/lib/pangea/analytics_summary/learning_progress_indicators.dart b/lib/pangea/analytics_summary/learning_progress_indicators.dart index 7147d4540..c3e91e20e 100644 --- a/lib/pangea/analytics_summary/learning_progress_indicators.dart +++ b/lib/pangea/analytics_summary/learning_progress_indicators.dart @@ -82,13 +82,13 @@ class LearningProgressIndicators extends StatelessWidget { builder: (context, _) { final archivedActivitiesCount = analyticsRoom?.archivedActivitiesCount ?? - 0; + 0; return HoverButton( - selected: selected == + selected: + selected == ProgressIndicatorEnum.activities, onPressed: () { - AnalyticsNavigationUtil - .navigateToAnalytics( + AnalyticsNavigationUtil.navigateToAnalytics( context: context, view: ProgressIndicatorEnum.activities, ); @@ -107,9 +107,9 @@ class LearningProgressIndicators extends StatelessWidget { Icon( size: 18, Icons.radar, - color: Theme.of(context) - .colorScheme - .primary, + color: Theme.of( + context, + ).colorScheme.primary, weight: 1000, ), const SizedBox(width: 6.0), @@ -141,9 +141,9 @@ class LearningProgressIndicators extends StatelessWidget { .titleLarge ?.copyWith( fontWeight: FontWeight.bold, - color: Theme.of(context) - .colorScheme - .primary, + color: Theme.of( + context, + ).colorScheme.primary, ), textScaler: TextScaler.noScaling, ), @@ -157,9 +157,9 @@ class LearningProgressIndicators extends StatelessWidget { .titleLarge ?.copyWith( fontWeight: FontWeight.bold, - color: Theme.of(context) - .colorScheme - .primary, + color: Theme.of( + context, + ).colorScheme.primary, ), textScaler: TextScaler.noScaling, ), @@ -173,12 +173,11 @@ class LearningProgressIndicators extends StatelessWidget { builder: (context, hovered) { return Container( decoration: BoxDecoration( - color: (hovered && canSelect) || + color: + (hovered && canSelect) || (selected == ProgressIndicatorEnum.level) - ? Theme.of(context) - .colorScheme - .primary - .withAlpha((0.2 * 255).round()) + ? Theme.of(context).colorScheme.primary + .withAlpha((0.2 * 255).round()) : Colors.transparent, borderRadius: BorderRadius.circular(36.0), ), @@ -193,8 +192,7 @@ class LearningProgressIndicators extends StatelessWidget { child: GestureDetector( onTap: canSelect ? () { - AnalyticsNavigationUtil - .navigateToAnalytics( + AnalyticsNavigationUtil.navigateToAnalytics( context: context, view: ProgressIndicatorEnum.level, ); @@ -225,9 +223,9 @@ class LearningProgressIndicators extends StatelessWidget { .titleLarge ?.copyWith( fontWeight: FontWeight.bold, - color: Theme.of(context) - .colorScheme - .primary, + color: Theme.of( + context, + ).colorScheme.primary, ), ), ], diff --git a/lib/pangea/analytics_summary/level_analytics_details_content.dart b/lib/pangea/analytics_summary/level_analytics_details_content.dart index 61c316ff9..69ca9389b 100644 --- a/lib/pangea/analytics_summary/level_analytics_details_content.dart +++ b/lib/pangea/analytics_summary/level_analytics_details_content.dart @@ -13,9 +13,7 @@ import 'package:fluffychat/pangea/morphs/get_grammar_copy.dart'; import 'package:fluffychat/widgets/matrix.dart'; class LevelAnalyticsDetailsContent extends StatelessWidget { - const LevelAnalyticsDetailsContent({ - super.key, - }); + const LevelAnalyticsDetailsContent({super.key}); @override Widget build(BuildContext context) { @@ -96,7 +94,8 @@ class LevelAnalyticsDetailsContent extends StatelessWidget { final use = uses[index]; String lemmaCopy = use.lemma; if (use.constructType == ConstructTypeEnum.morph) { - lemmaCopy = getGrammarCopy( + lemmaCopy = + getGrammarCopy( category: use.category, lemma: use.lemma, context: context, @@ -141,8 +140,9 @@ class LevelAnalyticsDetailsContent extends StatelessWidget { fontWeight: FontWeight.w900, fontSize: 14, height: 1, - color: - use.pointValueColor(context), + color: use.pointValueColor( + context, + ), ), ), ], diff --git a/lib/pangea/analytics_summary/progress_indicator.dart b/lib/pangea/analytics_summary/progress_indicator.dart index c690a3cbf..7a54b5955 100644 --- a/lib/pangea/analytics_summary/progress_indicator.dart +++ b/lib/pangea/analytics_summary/progress_indicator.dart @@ -32,15 +32,11 @@ class ProgressIndicatorBadge extends StatelessWidget { ), const SizedBox(width: 6.0), !loading - ? AnimatedFloatingNumber( - number: points, - ) + ? AnimatedFloatingNumber(number: points) : const SizedBox( height: 8, width: 8, - child: CircularProgressIndicator.adaptive( - strokeWidth: 2, - ), + child: CircularProgressIndicator.adaptive(strokeWidth: 2), ), ], ), @@ -52,10 +48,7 @@ class ProgressIndicatorBadge extends StatelessWidget { class AnimatedFloatingNumber extends StatefulWidget { final int number; - const AnimatedFloatingNumber({ - super.key, - required this.number, - }); + const AnimatedFloatingNumber({super.key, required this.number}); @override State createState() => AnimatedFloatingNumberState(); @@ -119,10 +112,7 @@ class AnimatedFloatingNumberState extends State position: _offsetAnim, child: FadeTransition( opacity: ReverseAnimation(_fadeAnim), - child: Text( - "$_floatingNumber", - style: indicatorStyle, - ), + child: Text("$_floatingNumber", style: indicatorStyle), ), ), Text( diff --git a/lib/pangea/authentication/p_login.dart b/lib/pangea/authentication/p_login.dart index b805ce72c..318431e4d 100644 --- a/lib/pangea/authentication/p_login.dart +++ b/lib/pangea/authentication/p_login.dart @@ -20,10 +20,7 @@ void pLoginAction({ await showFutureLoadingDialog( context: context, - future: () => _loginFuture( - controller: controller, - context: context, - ), + future: () => _loginFuture(controller: controller, context: context), onError: (e, s) { controller.setLoadingSignIn(false); return e is MatrixException @@ -65,14 +62,13 @@ Future _loginFuture({ final redirect = client.onLoginStateChanged.stream .where((state) => state == LoginState.loggedIn) .first - .then( - (_) { - final route = FluffyChatApp.router.state.fullPath; - if (route == null || !route.contains("/rooms")) { - context.go("/rooms"); - } - }, - ).timeout(const Duration(seconds: 30)); + .then((_) { + final route = FluffyChatApp.router.state.fullPath; + if (route == null || !route.contains("/rooms")) { + context.go("/rooms"); + } + }) + .timeout(const Duration(seconds: 30)); final loginRes = await client.login( LoginType.mLoginPassword, diff --git a/lib/pangea/authentication/p_logout.dart b/lib/pangea/authentication/p_logout.dart index fdc2a25a8..b7b197e0d 100644 --- a/lib/pangea/authentication/p_logout.dart +++ b/lib/pangea/authentication/p_logout.dart @@ -31,22 +31,20 @@ void pLogoutAction( final client = Matrix.of(context).client; // before wiping out locally cached construct data, save it to the server - await Matrix.of(context) - .analyticsDataService - .updateService - .sendLocalAnalyticsToAnalyticsRoom(); + await Matrix.of( + context, + ).analyticsDataService.updateService.sendLocalAnalyticsToAnalyticsRoom(); final redirect = client.onLoginStateChanged.stream .where((state) => state != LoginState.loggedIn) .first - .then( - (_) { - final route = FluffyChatApp.router.state.fullPath; - if (route == null || !route.contains("/home")) { - context.go("/home"); - } - }, - ).timeout(const Duration(seconds: 30)); + .then((_) { + final route = FluffyChatApp.router.state.fullPath; + if (route == null || !route.contains("/home")) { + context.go("/home"); + } + }) + .timeout(const Duration(seconds: 30)); await showFutureLoadingDialog( context: context, diff --git a/lib/pangea/bot/utils/bot_name.dart b/lib/pangea/bot/utils/bot_name.dart index 2596766cc..c53260c2e 100644 --- a/lib/pangea/bot/utils/bot_name.dart +++ b/lib/pangea/bot/utils/bot_name.dart @@ -4,7 +4,7 @@ class BotName { static String get byEnvironment => Environment.botName != null ? Environment.botName! : Environment.isStagingEnvironment - ? "@bot:staging.pangea.chat" - : "@bot:pangea.chat"; + ? "@bot:staging.pangea.chat" + : "@bot:pangea.chat"; static String get localBot => "@matrix-bot-test:staging.pangea.chat"; } diff --git a/lib/pangea/bot/utils/bot_room_extension.dart b/lib/pangea/bot/utils/bot_room_extension.dart index 830ca6a84..6a21e2cdc 100644 --- a/lib/pangea/bot/utils/bot_room_extension.dart +++ b/lib/pangea/bot/utils/bot_room_extension.dart @@ -47,11 +47,7 @@ extension BotRoomExtension on Room { ErrorHandler.logError( e: e, s: s, - data: { - 'roomId': id, - 'options': options.toJson(), - 'attempt': attempt, - }, + data: {'roomId': id, 'options': options.toJson(), 'attempt': attempt}, ); if (attempt == maxRetries) { diff --git a/lib/pangea/bot/utils/bot_style.dart b/lib/pangea/bot/utils/bot_style.dart index 8c344887a..95edf22eb 100644 --- a/lib/pangea/bot/utils/bot_style.dart +++ b/lib/pangea/bot/utils/bot_style.dart @@ -16,7 +16,8 @@ class BotStyle { try { final TextStyle botStyle = TextStyle( fontWeight: bold ? FontWeight.w700 : null, - fontSize: AppConfig.messageFontSize * + fontSize: + AppConfig.messageFontSize * AppSettings.fontSizeFactor.value * (big == true ? 1.2 : 1), fontStyle: italics ? FontStyle.italic : null, @@ -27,11 +28,7 @@ class BotStyle { return existingStyle?.merge(botStyle) ?? botStyle; } catch (err, stack) { - ErrorHandler.logError( - m: "error getting styles", - s: stack, - data: {}, - ); + ErrorHandler.logError(m: "error getting styles", s: stack, data: {}); return existingStyle ?? const TextStyle(); } } diff --git a/lib/pangea/bot/widgets/bot_chat_settings_dialog.dart b/lib/pangea/bot/widgets/bot_chat_settings_dialog.dart index ea1a19f63..5293b9981 100644 --- a/lib/pangea/bot/widgets/bot_chat_settings_dialog.dart +++ b/lib/pangea/bot/widgets/bot_chat_settings_dialog.dart @@ -19,10 +19,7 @@ import 'package:fluffychat/widgets/matrix.dart'; class BotChatSettingsDialog extends StatefulWidget { final Room room; - const BotChatSettingsDialog({ - required this.room, - super.key, - }); + const BotChatSettingsDialog({required this.room, super.key}); @override BotChatSettingsDialogState createState() => BotChatSettingsDialogState(); @@ -58,17 +55,14 @@ class BotChatSettingsDialogState extends State { await MatrixState.pangeaController.userController .updateProfile(update, waitForDataInSync: true) .timeout(const Duration(seconds: 15)); - await Matrix.of(context).client.updateBotOptions( - _userProfile.userSettings, - ); + await Matrix.of( + context, + ).client.updateBotOptions(_userProfile.userSettings); } catch (e, s) { ErrorHandler.logError( e: e, s: s, - data: { - 'roomId': widget.room.id, - 'model': _userProfile.toJson(), - }, + data: {'roomId': widget.room.id, 'model': _userProfile.toJson()}, ); } } @@ -159,7 +153,8 @@ class BotChatSettingsDialogState extends State { onChanged: _setVoice, value: _selectedVoice, language: _selectedLang, - enabled: !widget.room.isActivitySession || + enabled: + !widget.room.isActivitySession || (_selectedLang != null && _selectedLang == MatrixState.pangeaController.userController.userL2), diff --git a/lib/pangea/bot/widgets/bot_face_svg.dart b/lib/pangea/bot/widgets/bot_face_svg.dart index cdd46316f..d4b0af347 100644 --- a/lib/pangea/bot/widgets/bot_face_svg.dart +++ b/lib/pangea/bot/widgets/bot_face_svg.dart @@ -91,12 +91,15 @@ class BotFaceState extends State { Future _loadRiveFile() async { if (!widget.useRive) return; - final riveFile = - await RiveFile.asset('assets/pangea/bot_faces/pangea_bot.riv'); + final riveFile = await RiveFile.asset( + 'assets/pangea/bot_faces/pangea_bot.riv', + ); final artboard = riveFile.mainArtboard; - _controller = - StateMachineController.fromArtboard(artboard, 'BotIconStateMachine'); + _controller = StateMachineController.fromArtboard( + artboard, + 'BotIconStateMachine', + ); if (_controller != null) { artboard.addController(_controller!); @@ -119,10 +122,7 @@ class BotFaceState extends State { width: widget.width, height: widget.width, child: _artboard != null - ? Rive( - artboard: _artboard!, - fit: BoxFit.cover, - ) + ? Rive(artboard: _artboard!, fit: BoxFit.cover) : CachedNetworkImage( imageUrl: svgURL, placeholder: (context, url) => const CircularProgressIndicator(), diff --git a/lib/pangea/bot/widgets/bot_settings_language_icon.dart b/lib/pangea/bot/widgets/bot_settings_language_icon.dart index 837bba59f..c8735315e 100644 --- a/lib/pangea/bot/widgets/bot_settings_language_icon.dart +++ b/lib/pangea/bot/widgets/bot_settings_language_icon.dart @@ -10,10 +10,7 @@ import 'package:fluffychat/widgets/member_actions_popup_menu_button.dart'; class BotSettingsLanguageIcon extends StatelessWidget { final User user; - const BotSettingsLanguageIcon({ - super.key, - required this.user, - }); + const BotSettingsLanguageIcon({super.key, required this.user}); @override Widget build(BuildContext context) { @@ -31,10 +28,10 @@ class BotSettingsLanguageIcon extends StatelessWidget { borderRadius: BorderRadius.circular(32.0), onTap: room.isRoomAdmin ? () => showMemberActionsPopupMenu( - context: context, - user: user, - room: room, - ) + context: context, + user: user, + room: room, + ) : null, child: Container( decoration: BoxDecoration( diff --git a/lib/pangea/chat/constants/default_power_level.dart b/lib/pangea/chat/constants/default_power_level.dart index 1e84aca80..30f1c1f4f 100644 --- a/lib/pangea/chat/constants/default_power_level.dart +++ b/lib/pangea/chat/constants/default_power_level.dart @@ -4,88 +4,75 @@ import 'package:fluffychat/pangea/events/constants/pangea_event_types.dart'; class RoomDefaults { static StateEvent defaultPowerLevels(String userID) => StateEvent( - type: EventTypes.RoomPowerLevels, - stateKey: '', - content: { - "ban": 50, - "kick": 50, - "invite": 50, - "redact": 50, - "events": { - PangeaEventTypes.activityPlan: 0, - PangeaEventTypes.activityRole: 0, - PangeaEventTypes.activitySummary: 0, - "m.room.power_levels": 100, - "m.room.pinned_events": 50, - }, - "events_default": 0, - "state_default": 50, - "users": { - userID: 100, - }, - "users_default": 0, - "notifications": { - "room": 50, - }, - }, - ); + type: EventTypes.RoomPowerLevels, + stateKey: '', + content: { + "ban": 50, + "kick": 50, + "invite": 50, + "redact": 50, + "events": { + PangeaEventTypes.activityPlan: 0, + PangeaEventTypes.activityRole: 0, + PangeaEventTypes.activitySummary: 0, + "m.room.power_levels": 100, + "m.room.pinned_events": 50, + }, + "events_default": 0, + "state_default": 50, + "users": {userID: 100}, + "users_default": 0, + "notifications": {"room": 50}, + }, + ); static StateEvent restrictedPowerLevels(String userID) => StateEvent( - type: EventTypes.RoomPowerLevels, - stateKey: '', - content: { - "ban": 50, - "kick": 50, - "invite": 50, - "redact": 50, - "events": { - PangeaEventTypes.activityPlan: 50, - PangeaEventTypes.activityRole: 0, - PangeaEventTypes.activitySummary: 0, - "m.room.power_levels": 100, - "m.room.pinned_events": 50, - }, - "events_default": 50, - "state_default": 50, - "users": { - userID: 100, - }, - "users_default": 0, - "notifications": { - "room": 50, - }, - }, - ); + type: EventTypes.RoomPowerLevels, + stateKey: '', + content: { + "ban": 50, + "kick": 50, + "invite": 50, + "redact": 50, + "events": { + PangeaEventTypes.activityPlan: 50, + PangeaEventTypes.activityRole: 0, + PangeaEventTypes.activitySummary: 0, + "m.room.power_levels": 100, + "m.room.pinned_events": 50, + }, + "events_default": 50, + "state_default": 50, + "users": {userID: 100}, + "users_default": 0, + "notifications": {"room": 50}, + }, + ); static StateEvent defaultSpacePowerLevels( String userID, { int spaceChild = 50, - }) => - StateEvent( - type: EventTypes.RoomPowerLevels, - stateKey: '', - content: { - "ban": 50, - "kick": 50, - "invite": 50, - "redact": 50, - "events": { - PangeaEventTypes.courseUser: 0, - "m.room.power_levels": 100, - "m.room.join_rules": 100, - "m.space.child": spaceChild, - }, - "events_default": 0, - "state_default": 50, - "users": { - userID: 100, - }, - "users_default": 0, - "notifications": { - "room": 50, - }, - }, - ); + }) => StateEvent( + type: EventTypes.RoomPowerLevels, + stateKey: '', + content: { + "ban": 50, + "kick": 50, + "invite": 50, + "redact": 50, + "events": { + PangeaEventTypes.courseUser: 0, + "m.room.power_levels": 100, + "m.room.join_rules": 100, + "m.space.child": spaceChild, + }, + "events_default": 0, + "state_default": 50, + "users": {userID: 100}, + "users_default": 0, + "notifications": {"room": 50}, + }, + ); static Visibility spaceChildVisibility = Visibility.private; } diff --git a/lib/pangea/chat/utils/unlocked_morphs_snackbar.dart b/lib/pangea/chat/utils/unlocked_morphs_snackbar.dart index a88c25f34..653fb8b81 100644 --- a/lib/pangea/chat/utils/unlocked_morphs_snackbar.dart +++ b/lib/pangea/chat/utils/unlocked_morphs_snackbar.dart @@ -59,10 +59,7 @@ class ConstructNotificationUtil { final bool result = OverlayUtil.showOverlay( overlayKey: "${construct.string}_snackbar", context: context, - child: ConstructNotificationOverlay( - construct: construct, - copy: copy, - ), + child: ConstructNotificationOverlay(construct: construct, copy: copy), transformTargetId: "", position: OverlayPositionEnum.top, backDropToDismiss: false, @@ -103,7 +100,8 @@ class ConstructNotificationOverlay extends StatefulWidget { } class ConstructNotificationOverlayState - extends State with TickerProviderStateMixin { + extends State + with TickerProviderStateMixin { AnimationController? _controller; Animation? _animation; @@ -115,10 +113,7 @@ class ConstructNotificationOverlayState vsync: this, ); - _animation = CurvedAnimation( - parent: _controller!, - curve: Curves.easeInOut, - ); + _animation = CurvedAnimation(parent: _controller!, curve: Curves.easeInOut); _controller!.forward().then((_) { OverlayUtil.showOverlay( @@ -247,8 +242,8 @@ class ConstructNotificationOverlayState : const Size(22.0, 22.0), morphFeature: MorphFeaturesEnumExtension.fromString( - widget.construct.category, - ), + widget.construct.category, + ), morphTag: widget.construct.lemma, ), ], @@ -271,9 +266,7 @@ class ConstructNotificationOverlayState ), ), onPressed: _showDetails, - child: Text( - L10n.of(context).details, - ), + child: Text(L10n.of(context).details), ) : SizedBox( width: 32.0, @@ -284,8 +277,9 @@ class ConstructNotificationOverlayState Icons.info_outline, ), style: IconButton.styleFrom( - padding: - const EdgeInsets.all(4.0), + padding: const EdgeInsets.all( + 4.0, + ), ), onPressed: _showDetails, constraints: const BoxConstraints(), @@ -300,9 +294,7 @@ class ConstructNotificationOverlayState child: Tooltip( message: L10n.of(context).close, child: IconButton( - icon: const Icon( - Icons.close, - ), + icon: const Icon(Icons.close), style: IconButton.styleFrom( padding: const EdgeInsets.all(4.0), ), diff --git a/lib/pangea/chat/widgets/chat_floating_action_button.dart b/lib/pangea/chat/widgets/chat_floating_action_button.dart index 88122aa3c..b29f5ee59 100644 --- a/lib/pangea/chat/widgets/chat_floating_action_button.dart +++ b/lib/pangea/chat/widgets/chat_floating_action_button.dart @@ -5,10 +5,7 @@ import 'package:fluffychat/pangea/choreographer/choreographer_has_error_button.d class ChatFloatingActionButton extends StatelessWidget { final ChatController controller; - const ChatFloatingActionButton({ - super.key, - required this.controller, - }); + const ChatFloatingActionButton({super.key, required this.controller}); @override Widget build(BuildContext context) { @@ -17,14 +14,12 @@ class ChatFloatingActionButton extends StatelessWidget { } return ListenableBuilder( - listenable: Listenable.merge( - [ - controller.choreographer.errorService, - controller.choreographer.itController.open, - controller.scrollController, - controller.scrollableNotifier, - ], - ), + listenable: Listenable.merge([ + controller.choreographer.errorService, + controller.choreographer.itController.open, + controller.scrollController, + controller.scrollableNotifier, + ]), builder: (context, _) { if (controller.scrollController.hasClients && controller.scrollController.position.pixels > 0) { diff --git a/lib/pangea/chat/widgets/chat_input_bar.dart b/lib/pangea/chat/widgets/chat_input_bar.dart index 599c25abb..1938ffbd7 100644 --- a/lib/pangea/chat/widgets/chat_input_bar.dart +++ b/lib/pangea/chat/widgets/chat_input_bar.dart @@ -29,7 +29,7 @@ class ChatInputBar extends StatelessWidget { children: [ ValueListenableBuilder( valueListenable: controller.choreographer.itController.open, - builder: (context, open, __) { + builder: (context, open, _) { return open ? Container( constraints: const BoxConstraints( @@ -69,9 +69,7 @@ class ChatInputBar extends StatelessWidget { child: Material( clipBehavior: Clip.hardEdge, color: theme.colorScheme.surfaceContainerHigh, - borderRadius: const BorderRadius.all( - Radius.circular(24), - ), + borderRadius: const BorderRadius.all(Radius.circular(24)), child: controller.room.isAbandonedDMRoom == true ? _AbandonedDMContent(controller: controller) : Column( @@ -79,9 +77,7 @@ class ChatInputBar extends StatelessWidget { children: [ ITBar(choreographer: controller.choreographer), ReplyDisplay(controller), - PangeaChatInputRow( - controller: controller, - ), + PangeaChatInputRow(controller: controller), ChatEmojiPicker(controller), ], ), @@ -95,9 +91,7 @@ class ChatInputBar extends StatelessWidget { class _AbandonedDMContent extends StatelessWidget { final ChatController controller; - const _AbandonedDMContent({ - required this.controller, - }); + const _AbandonedDMContent({required this.controller}); @override Widget build(BuildContext context) { @@ -106,32 +100,18 @@ class _AbandonedDMContent extends StatelessWidget { children: [ TextButton.icon( style: TextButton.styleFrom( - padding: const EdgeInsets.all( - 16, - ), + padding: const EdgeInsets.all(16), foregroundColor: Theme.of(context).colorScheme.error, ), - icon: const Icon( - Icons.archive_outlined, - ), + icon: const Icon(Icons.archive_outlined), onPressed: controller.leaveChat, - label: Text( - L10n.of(context).leave, - ), + label: Text(L10n.of(context).leave), ), TextButton.icon( - style: TextButton.styleFrom( - padding: const EdgeInsets.all( - 16, - ), - ), - icon: const Icon( - Icons.forum_outlined, - ), + style: TextButton.styleFrom(padding: const EdgeInsets.all(16)), + icon: const Icon(Icons.forum_outlined), onPressed: controller.recreateChat, - label: Text( - L10n.of(context).reopenChat, - ), + label: Text(L10n.of(context).reopenChat), ), ], ); diff --git a/lib/pangea/chat/widgets/chat_input_bar_header.dart b/lib/pangea/chat/widgets/chat_input_bar_header.dart index cc3408790..762be951f 100644 --- a/lib/pangea/chat/widgets/chat_input_bar_header.dart +++ b/lib/pangea/chat/widgets/chat_input_bar_header.dart @@ -21,21 +21,13 @@ class ChatInputBarHeader extends StatelessWidget { } return Container( - margin: EdgeInsets.only( - bottom: 10, - left: padding, - right: padding, - ), + margin: EdgeInsets.only(bottom: 10, left: padding, right: padding), constraints: const BoxConstraints( maxWidth: FluffyThemes.columnWidth * 2.4, ), child: Row( mainAxisAlignment: MainAxisAlignment.end, - children: [ - ChatFloatingActionButton( - controller: controller, - ), - ], + children: [ChatFloatingActionButton(controller: controller)], ), ); } diff --git a/lib/pangea/chat/widgets/icon_rain.dart b/lib/pangea/chat/widgets/icon_rain.dart index b6dd09aff..18890b992 100644 --- a/lib/pangea/chat/widgets/icon_rain.dart +++ b/lib/pangea/chat/widgets/icon_rain.dart @@ -215,13 +215,11 @@ class _AnimatedFallingIconState extends State<_AnimatedFallingIcon> @override void initState() { super.initState(); - _controller = AnimationController( - duration: widget.duration, - vsync: this, - ); - _animation = Tween(begin: -40, end: widget.maxHeight + 40).animate( - CurvedAnimation(parent: _controller, curve: Curves.easeIn), - ); + _controller = AnimationController(duration: widget.duration, vsync: this); + _animation = Tween( + begin: -40, + end: widget.maxHeight + 40, + ).animate(CurvedAnimation(parent: _controller, curve: Curves.easeIn)); _controller.forward().then((_) => widget.onComplete()); } @@ -237,7 +235,8 @@ class _AnimatedFallingIconState extends State<_AnimatedFallingIcon> animation: _animation, builder: (context, child) { final progress = _controller.value; - final sway = widget.swayAmplitude * + final sway = + widget.swayAmplitude * sin( 2 * pi * widget.swayFrequency * progress + widget.startX * 2 * pi, ); diff --git a/lib/pangea/chat/widgets/pangea_chat_input_row.dart b/lib/pangea/chat/widgets/pangea_chat_input_row.dart index 04d3a20ce..63787a4d3 100644 --- a/lib/pangea/chat/widgets/pangea_chat_input_row.dart +++ b/lib/pangea/chat/widgets/pangea_chat_input_row.dart @@ -22,10 +22,7 @@ import 'package:fluffychat/widgets/matrix.dart'; class PangeaChatInputRow extends StatelessWidget { final ChatController controller; - const PangeaChatInputRow({ - required this.controller, - super.key, - }); + const PangeaChatInputRow({required this.controller, super.key}); LanguageModel? get activel1 => controller.pangeaController.userController.userL1; @@ -46,9 +43,7 @@ class PangeaChatInputRow extends StatelessWidget { .link, child: Container( decoration: const BoxDecoration( - borderRadius: BorderRadius.all( - Radius.circular(8.0), - ), + borderRadius: BorderRadius.all(Radius.circular(8.0)), ), child: RecordingViewModel( builder: (context, recordingViewModel) { @@ -68,15 +63,19 @@ class PangeaChatInputRow extends StatelessWidget { const SizedBox(width: 4), ValueListenableBuilder( valueListenable: controller.sendController, - builder: (context, text, __) { + builder: (context, text, _) { final isBotDM = controller.room.isBotDM; return AnimatedContainer( duration: FluffyThemes.animationDuration, curve: FluffyThemes.animationCurve, height: height, - width: text.text.isEmpty && + width: + text.text.isEmpty && !controller - .choreographer.itController.open.value + .choreographer + .itController + .open + .value ? height : 0, alignment: Alignment.center, @@ -88,105 +87,125 @@ class PangeaChatInputRow extends StatelessWidget { onSelected: controller.onAddPopupMenuButtonSelected, itemBuilder: (BuildContext context) => >[ - PopupMenuItem( - value: AddPopupMenuActions.poll, - child: ListTile( - leading: CircleAvatar( - backgroundColor: - theme.colorScheme.onPrimaryContainer, - foregroundColor: - theme.colorScheme.primaryContainer, - child: const Icon(Icons.poll_outlined), - ), - title: Text(L10n.of(context).startPoll), - contentPadding: const EdgeInsets.all(0), - ), - ), - if (!isBotDM) - PopupMenuItem( - value: AddPopupMenuActions.file, - child: ListTile( - leading: const CircleAvatar( - backgroundColor: Colors.green, - foregroundColor: Colors.white, - child: Icon(Icons.attachment_outlined), - ), - title: Text(L10n.of(context).sendFile), - contentPadding: const EdgeInsets.all(0), - ), - ), - PopupMenuItem( - value: AddPopupMenuActions.image, - child: ListTile( - leading: const CircleAvatar( - backgroundColor: Colors.blue, - foregroundColor: Colors.white, - child: Icon(Icons.image_outlined), - ), - title: Text(L10n.of(context).sendImage), - contentPadding: const EdgeInsets.all(0), - ), - ), - if (!isBotDM) - PopupMenuItem( - value: AddPopupMenuActions.image, - child: ListTile( - leading: CircleAvatar( - backgroundColor: - theme.colorScheme.onPrimaryContainer, - foregroundColor: - theme.colorScheme.primaryContainer, - child: const Icon(Icons.photo_outlined), - ), - title: Text(L10n.of(context).sendImage), - contentPadding: const EdgeInsets.all(0), - ), - ), - if (PlatformInfos.isMobile) - PopupMenuItem( - value: AddPopupMenuActions.photoCamera, - child: ListTile( - leading: const CircleAvatar( - backgroundColor: Colors.purple, - foregroundColor: Colors.white, - child: Icon(Icons.camera_alt_outlined), - ), - title: Text(L10n.of(context).openCamera), - contentPadding: const EdgeInsets.all(0), - ), - ), - if (!isBotDM) - if (PlatformInfos.isMobile) - PopupMenuItem( - value: AddPopupMenuActions.videoCamera, + PopupMenuItem( + value: AddPopupMenuActions.poll, child: ListTile( - leading: const CircleAvatar( - backgroundColor: Colors.red, - foregroundColor: Colors.white, - child: Icon(Icons.videocam_outlined), - ), - title: Text( - L10n.of(context).openVideoCamera, + leading: CircleAvatar( + backgroundColor: theme + .colorScheme + .onPrimaryContainer, + foregroundColor: + theme.colorScheme.primaryContainer, + child: const Icon(Icons.poll_outlined), ), + title: Text(L10n.of(context).startPoll), contentPadding: const EdgeInsets.all(0), ), ), - if (!isBotDM) - if (PlatformInfos.isMobile) + if (!isBotDM) + PopupMenuItem( + value: AddPopupMenuActions.file, + child: ListTile( + leading: const CircleAvatar( + backgroundColor: Colors.green, + foregroundColor: Colors.white, + child: Icon( + Icons.attachment_outlined, + ), + ), + title: Text(L10n.of(context).sendFile), + contentPadding: const EdgeInsets.all(0), + ), + ), PopupMenuItem( - value: AddPopupMenuActions.location, + value: AddPopupMenuActions.image, child: ListTile( leading: const CircleAvatar( - backgroundColor: Colors.brown, + backgroundColor: Colors.blue, foregroundColor: Colors.white, - child: Icon(Icons.gps_fixed_outlined), + child: Icon(Icons.image_outlined), ), - title: - Text(L10n.of(context).shareLocation), + title: Text(L10n.of(context).sendImage), contentPadding: const EdgeInsets.all(0), ), ), - ], + if (!isBotDM) + PopupMenuItem( + value: AddPopupMenuActions.image, + child: ListTile( + leading: CircleAvatar( + backgroundColor: theme + .colorScheme + .onPrimaryContainer, + foregroundColor: theme + .colorScheme + .primaryContainer, + child: const Icon( + Icons.photo_outlined, + ), + ), + title: Text(L10n.of(context).sendImage), + contentPadding: const EdgeInsets.all(0), + ), + ), + if (PlatformInfos.isMobile) + PopupMenuItem( + value: AddPopupMenuActions.photoCamera, + child: ListTile( + leading: const CircleAvatar( + backgroundColor: Colors.purple, + foregroundColor: Colors.white, + child: Icon( + Icons.camera_alt_outlined, + ), + ), + title: Text( + L10n.of(context).openCamera, + ), + contentPadding: const EdgeInsets.all(0), + ), + ), + if (!isBotDM) + if (PlatformInfos.isMobile) + PopupMenuItem( + value: AddPopupMenuActions.videoCamera, + child: ListTile( + leading: const CircleAvatar( + backgroundColor: Colors.red, + foregroundColor: Colors.white, + child: Icon( + Icons.videocam_outlined, + ), + ), + title: Text( + L10n.of(context).openVideoCamera, + ), + contentPadding: const EdgeInsets.all( + 0, + ), + ), + ), + if (!isBotDM) + if (PlatformInfos.isMobile) + PopupMenuItem( + value: AddPopupMenuActions.location, + child: ListTile( + leading: const CircleAvatar( + backgroundColor: Colors.brown, + foregroundColor: Colors.white, + child: Icon( + Icons.gps_fixed_outlined, + ), + ), + title: Text( + L10n.of(context).shareLocation, + ), + contentPadding: const EdgeInsets.all( + 0, + ), + ), + ), + ], ), ); }, @@ -199,19 +218,21 @@ class PangeaChatInputRow extends StatelessWidget { child: IconButton( tooltip: L10n.of(context).emojis, icon: PageTransitionSwitcher( - transitionBuilder: ( - Widget child, - Animation primaryAnimation, - Animation secondaryAnimation, - ) { - return SharedAxisTransition( - animation: primaryAnimation, - secondaryAnimation: secondaryAnimation, - transitionType: SharedAxisTransitionType.scaled, - fillColor: Colors.transparent, - child: child, - ); - }, + transitionBuilder: + ( + Widget child, + Animation primaryAnimation, + Animation secondaryAnimation, + ) { + return SharedAxisTransition( + animation: primaryAnimation, + secondaryAnimation: secondaryAnimation, + transitionType: + SharedAxisTransitionType.scaled, + fillColor: Colors.transparent, + child: child, + ); + }, child: Icon( controller.showEmojiPicker ? Icons.keyboard @@ -233,9 +254,9 @@ class PangeaChatInputRow extends StatelessWidget { keyboardType: TextInputType.multiline, textInputAction: AppSettings.sendOnEnter.value == true && - PlatformInfos.isMobile - ? TextInputAction.send - : null, + PlatformInfos.isMobile + ? TextInputAction.send + : null, onSubmitted: (_) => controller.onInputBarSubmitted(), onSubmitImage: controller.sendImageFromClipBoard, focusNode: controller.inputFocus, @@ -256,17 +277,21 @@ class PangeaChatInputRow extends StatelessWidget { onChanged: controller.onInputBarChanged, choreographer: controller.choreographer, showNextMatch: controller.showNextMatch, - suggestionEmojis: getDefaultEmojiLocale( - AppSettings.emojiSuggestionLocale.value.isNotEmpty - ? Locale( - AppSettings.emojiSuggestionLocale.value, - ) - : Localizations.localeOf(context), - ).fold( - [], - (emojis, category) => - emojis..addAll(category.emoji), - ), + suggestionEmojis: + getDefaultEmojiLocale( + AppSettings + .emojiSuggestionLocale + .value + .isNotEmpty + ? Locale( + AppSettings.emojiSuggestionLocale.value, + ) + : Localizations.localeOf(context), + ).fold( + [], + (emojis, category) => + emojis..addAll(category.emoji), + ), ), ), ), @@ -281,26 +306,31 @@ class PangeaChatInputRow extends StatelessWidget { ), ValueListenableBuilder( valueListenable: controller.sendController, - builder: (context, text, __) { + builder: (context, text, _) { return Container( height: height, width: height, alignment: Alignment.center, - child: PlatformInfos.platformCanRecord && + child: + PlatformInfos.platformCanRecord && text.text.isEmpty && !controller - .choreographer.itController.open.value + .choreographer + .itController + .open + .value ? IconButton( tooltip: L10n.of(context).voiceMessage, onPressed: () => ScaffoldMessenger.of(context) .showSnackBar( - SnackBar( - content: Text( - L10n.of(context) - .longPressToRecordVoiceMessage, + SnackBar( + content: Text( + L10n.of( + context, + ).longPressToRecordVoiceMessage, + ), + ), ), - ), - ), onLongPress: () => recordingViewModel .startRecording(controller.room), style: IconButton.styleFrom( @@ -309,9 +339,7 @@ class PangeaChatInputRow extends StatelessWidget { ), icon: const Icon(Icons.mic_none_outlined), ) - : ChoreographerSendButton( - controller: controller, - ), + : ChoreographerSendButton(controller: controller), ); }, ), diff --git a/lib/pangea/chat_list/utils/app_version_util.dart b/lib/pangea/chat_list/utils/app_version_util.dart index cdd6242ce..a94d37a56 100644 --- a/lib/pangea/chat_list/utils/app_version_util.dart +++ b/lib/pangea/chat_list/utils/app_version_util.dart @@ -25,9 +25,7 @@ import 'package:fluffychat/widgets/matrix.dart'; class AppVersionUtil { static final GetStorage _versionBox = GetStorage("version_storage"); - static Future _getAppVersion( - String accessToken, - ) async { + static Future _getAppVersion(String accessToken) async { final packageInfo = await PackageInfo.fromPlatform(); final currentVersion = packageInfo.version; final currentBuildNumber = packageInfo.buildNumber; @@ -110,9 +108,11 @@ class AppVersionUtil { // If a part of the current version is greater than the // remote version, then the current version is newer than // the remote version. - for (int i = 0; - i < min(currentVersionParts.length, remoteVersionParts.length); - i++) { + for ( + int i = 0; + i < min(currentVersionParts.length, remoteVersionParts.length); + i++ + ) { if (currentVersionParts[i] < remoteVersionParts[i]) { isOlderCurrentVersion = true; isDifferentVersion = true; diff --git a/lib/pangea/chat_list/utils/chat_list_handle_space_tap.dart b/lib/pangea/chat_list/utils/chat_list_handle_space_tap.dart index aad62e677..980380c0f 100644 --- a/lib/pangea/chat_list/utils/chat_list_handle_space_tap.dart +++ b/lib/pangea/chat_list/utils/chat_list_handle_space_tap.dart @@ -33,10 +33,12 @@ Future showInviteDialog(Room room, BuildContext context) async { constraints: const BoxConstraints(maxWidth: 256, maxHeight: 256), child: Text( room.isSpace - ? L10n.of(context) - .invitedToSpace(room.name, room.creatorId ?? "???") - : L10n.of(context) - .invitedToChat(room.name, room.creatorId ?? "???"), + ? L10n.of( + context, + ).invitedToSpace(room.name, room.creatorId ?? "???") + : L10n.of( + context, + ).invitedToChat(room.name, room.creatorId ?? "???"), textAlign: TextAlign.center, ), ), @@ -87,10 +89,7 @@ Future showInviteDialog(Room room, BuildContext context) async { } // ignore: curly_braces_in_flow_control_structures -void chatListHandleSpaceTap( - BuildContext context, - Room space, -) { +void chatListHandleSpaceTap(BuildContext context, Room space) { void setActiveSpaceAndCloseChat() { context.go("/rooms/spaces/${space.id}/details"); } @@ -114,9 +113,8 @@ void chatListHandleSpaceTap( //else confirm you want to join //can we tell whether space or chat? final rooms = Matrix.of(context).client.rooms.where( - (element) => - element.isSpace && element.membership == Membership.join, - ); + (element) => element.isSpace && element.membership == Membership.join, + ); final justInputtedCode = SpaceCodeRepo.recentCode; if (rooms.any((s) => s.spaceChildren.any((c) => c.roomId == space.id))) { autoJoin(space); diff --git a/lib/pangea/chat_list/utils/get_chat_list_item_subtitle.dart b/lib/pangea/chat_list/utils/get_chat_list_item_subtitle.dart index c4440ac5a..4b1264f05 100644 --- a/lib/pangea/chat_list/utils/get_chat_list_item_subtitle.dart +++ b/lib/pangea/chat_list/utils/get_chat_list_item_subtitle.dart @@ -30,9 +30,7 @@ class ChatListItemSubtitle extends StatelessWidget { event.isRichMessage); } - Future _getPangeaMessageEvent( - final Event event, - ) async { + Future _getPangeaMessageEvent(final Event event) async { final Timeline timeline = event.room.timeline != null ? event.room.timeline! : await event.room.getTimeline(); @@ -81,7 +79,8 @@ class ChatListItemSubtitle extends StatelessWidget { hideEdit: true, plaintextBody: true, removeMarkdown: true, - withSenderNamePrefix: !event.room.isDirectChat || + withSenderNamePrefix: + !event.room.isDirectChat || event.room.directChatMatrixID != event.room.lastEvent?.senderId, ), builder: (context, snapshot) { diff --git a/lib/pangea/chat_list/widgets/chat_list_view_body_wrapper.dart b/lib/pangea/chat_list/widgets/chat_list_view_body_wrapper.dart index a721c5921..25e57ea8b 100644 --- a/lib/pangea/chat_list/widgets/chat_list_view_body_wrapper.dart +++ b/lib/pangea/chat_list/widgets/chat_list_view_body_wrapper.dart @@ -11,10 +11,7 @@ import 'package:fluffychat/widgets/matrix.dart'; class ChatListViewBodyWrapper extends StatefulWidget { final ChatListController controller; - const ChatListViewBodyWrapper({ - required this.controller, - super.key, - }); + const ChatListViewBodyWrapper({required this.controller, super.key}); @override State createState() => diff --git a/lib/pangea/chat_list/widgets/pangea_chat_list_header.dart b/lib/pangea/chat_list/widgets/pangea_chat_list_header.dart index a951ef459..2cdc1ed46 100644 --- a/lib/pangea/chat_list/widgets/pangea_chat_list_header.dart +++ b/lib/pangea/chat_list/widgets/pangea_chat_list_header.dart @@ -23,62 +23,59 @@ class PangeaChatListHeader extends StatelessWidget final theme = Theme.of(context); return SliverList( - delegate: SliverChildListDelegate( - [ - Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - children: [ - const LearningProgressIndicators(), - AnimatedSize( - duration: FluffyThemes.animationDuration, - child: showSearch - ? TextField( - controller: controller.searchController, - focusNode: controller.searchFocusNode, - textInputAction: TextInputAction.search, - onChanged: (text) => controller.onSearchEnter( - text, - globalSearch: globalSearch, + delegate: SliverChildListDelegate([ + Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + children: [ + const LearningProgressIndicators(), + AnimatedSize( + duration: FluffyThemes.animationDuration, + child: showSearch + ? TextField( + controller: controller.searchController, + focusNode: controller.searchFocusNode, + textInputAction: TextInputAction.search, + onChanged: (text) => controller.onSearchEnter( + text, + globalSearch: globalSearch, + ), + decoration: InputDecoration( + filled: true, + fillColor: theme.colorScheme.secondaryContainer, + border: OutlineInputBorder( + borderSide: BorderSide.none, + borderRadius: BorderRadius.circular(99), ), - decoration: InputDecoration( - filled: true, - fillColor: theme.colorScheme.secondaryContainer, - border: OutlineInputBorder( - borderSide: BorderSide.none, - borderRadius: BorderRadius.circular(99), - ), - contentPadding: EdgeInsets.zero, - hintText: L10n.of(context).search, - hintStyle: TextStyle( - color: theme.colorScheme.onPrimaryContainer, - fontWeight: FontWeight.normal, - ), - floatingLabelBehavior: FloatingLabelBehavior.never, - prefixIcon: controller.isSearchMode - ? IconButton( - tooltip: L10n.of(context).cancel, - icon: const Icon(Icons.close_outlined), - onPressed: controller.cancelSearch, + contentPadding: EdgeInsets.zero, + hintText: L10n.of(context).search, + hintStyle: TextStyle( + color: theme.colorScheme.onPrimaryContainer, + fontWeight: FontWeight.normal, + ), + floatingLabelBehavior: FloatingLabelBehavior.never, + prefixIcon: controller.isSearchMode + ? IconButton( + tooltip: L10n.of(context).cancel, + icon: const Icon(Icons.close_outlined), + onPressed: controller.cancelSearch, + color: theme.colorScheme.onPrimaryContainer, + ) + : IconButton( + onPressed: controller.startSearch, + icon: Icon( + Icons.search_outlined, color: theme.colorScheme.onPrimaryContainer, - ) - : IconButton( - onPressed: controller.startSearch, - icon: Icon( - Icons.search_outlined, - color: - theme.colorScheme.onPrimaryContainer, - ), ), - ), - ) - : const SizedBox.shrink(), - ), - ], - ), + ), + ), + ) + : const SizedBox.shrink(), + ), + ], ), - ], - ), + ), + ]), ); } diff --git a/lib/pangea/chat_list/widgets/public_room_bottom_sheet.dart b/lib/pangea/chat_list/widgets/public_room_bottom_sheet.dart index 715918012..b7bb3fb28 100644 --- a/lib/pangea/chat_list/widgets/public_room_bottom_sheet.dart +++ b/lib/pangea/chat_list/widgets/public_room_bottom_sheet.dart @@ -35,8 +35,9 @@ class PublicRoomBottomSheet extends StatefulWidget { PublishedRoomsChunk? chunk, List? via, }) async { - final room = MatrixState.pangeaController.matrixState.client - .getRoomById(chunk!.roomId); + final room = MatrixState.pangeaController.matrixState.client.getRoomById( + chunk!.roomId, + ); if (room != null && room.membership == Membership.join) { context.go("/rooms/spaces/${room.id}/details"); @@ -129,10 +130,8 @@ class PublicRoomBottomSheetState extends State { await showFutureLoadingDialog( context: context, - future: () async => client.knockRoom( - roomAlias ?? chunk!.roomId, - via: via, - ), + future: () async => + client.knockRoom(roomAlias ?? chunk!.roomId, via: via), onSuccess: () => L10n.of(context).knockSpaceSuccess, delay: false, ); @@ -144,11 +143,9 @@ class PublicRoomBottomSheetState extends State { final chunk = this.chunk; if (chunk != null) return chunk; final query = await Matrix.of(outerContext).client.queryPublicRooms( - server: roomAlias!.domain, - filter: PublicRoomQueryFilter( - genericSearchTerm: roomAlias, - ), - ); + server: roomAlias!.domain, + filter: PublicRoomQueryFilter(genericSearchTerm: roomAlias), + ); if (!query.chunk.any(testRoom)) { throw (L10n.of(outerContext).noRoomsFound); } @@ -227,10 +224,12 @@ class PublicRoomBottomSheetState extends State { child: Text( chunk?.topic ?? (chunk?.roomType != 'm.space' - ? L10n.of(context) - .noChatDescriptionYet - : L10n.of(context) - .noSpaceDescriptionYet), + ? L10n.of( + context, + ).noChatDescriptionYet + : L10n.of( + context, + ).noSpaceDescriptionYet), softWrap: true, textAlign: TextAlign.start, maxLines: null, @@ -265,12 +264,13 @@ class PublicRoomBottomSheetState extends State { enabledBorder: InputBorder.none, errorBorder: InputBorder.none, disabledBorder: InputBorder.none, - hintText: - L10n.of(context).enterSpaceCode, + hintText: L10n.of( + context, + ).enterSpaceCode, contentPadding: const EdgeInsets.symmetric( - horizontal: 16.0, - ), + horizontal: 16.0, + ), hintStyle: TextStyle( color: Theme.of(context).hintColor, ), @@ -281,9 +281,9 @@ class PublicRoomBottomSheetState extends State { decoration: BoxDecoration( border: Border( left: BorderSide( - color: Theme.of(context) - .colorScheme - .outline, + color: Theme.of( + context, + ).colorScheme.outline, ), ), ), @@ -311,10 +311,7 @@ class PublicRoomBottomSheetState extends State { spacing: 8.0, mainAxisAlignment: MainAxisAlignment.center, children: [ - const Icon( - Symbols.door_open, - size: 20.0, - ), + const Icon(Symbols.door_open, size: 20.0), Text(L10n.of(context).askToJoin), ], ), diff --git a/lib/pangea/chat_settings/models/bot_options_model.dart b/lib/pangea/chat_settings/models/bot_options_model.dart index 1c9af5912..7592cc9e7 100644 --- a/lib/pangea/chat_settings/models/bot_options_model.dart +++ b/lib/pangea/chat_settings/models/bot_options_model.dart @@ -84,10 +84,8 @@ class BotOptionsModel { languageLevel: json[ModelKey.languageLevel] is int ? LanguageLevelTypeEnum.fromInt(json[ModelKey.languageLevel]) : json[ModelKey.languageLevel] is String - ? LanguageLevelTypeEnum.fromString( - json[ModelKey.languageLevel], - ) - : LanguageLevelTypeEnum.a1, + ? LanguageLevelTypeEnum.fromString(json[ModelKey.languageLevel]) + : LanguageLevelTypeEnum.a1, safetyModeration: json[ModelKey.safetyModeration] ?? true, mode: json[ModelKey.mode] ?? BotMode.discussion, targetLanguage: json[ModelKey.targetLanguage], @@ -150,11 +148,7 @@ class BotOptionsModel { return data; } catch (e, s) { debugger(when: kDebugMode); - ErrorHandler.logError( - e: e, - s: s, - data: data, - ); + ErrorHandler.logError(e: e, s: s, data: data); return data; } } @@ -185,7 +179,8 @@ class BotOptionsModel { mode: mode ?? this.mode, discussionTopic: discussionTopic ?? this.discussionTopic, discussionKeywords: discussionKeywords ?? this.discussionKeywords, - discussionTriggerReactionEnabled: discussionTriggerReactionEnabled ?? + discussionTriggerReactionEnabled: + discussionTriggerReactionEnabled ?? this.discussionTriggerReactionEnabled, discussionTriggerReactionKey: discussionTriggerReactionKey ?? this.discussionTriggerReactionKey, @@ -196,7 +191,7 @@ class BotOptionsModel { customTriggerReactionKey ?? this.customTriggerReactionKey, textAdventureGameMasterInstructions: textAdventureGameMasterInstructions ?? - this.textAdventureGameMasterInstructions, + this.textAdventureGameMasterInstructions, targetLanguage: targetLanguage ?? this.targetLanguage, targetVoice: targetVoice ?? this.targetVoice, userGenders: userGenders ?? this.userGenders, diff --git a/lib/pangea/chat_settings/pages/chat_details_button_row.dart b/lib/pangea/chat_settings/pages/chat_details_button_row.dart index 731032817..25fe876d5 100644 --- a/lib/pangea/chat_settings/pages/chat_details_button_row.dart +++ b/lib/pangea/chat_settings/pages/chat_details_button_row.dart @@ -37,10 +37,7 @@ class ChatDetailsButtonRowState extends State { @override void initState() { super.initState(); - notificationChangeSub ??= Matrix.of(context) - .client - .onSync - .stream + notificationChangeSub ??= Matrix.of(context).client.onSync.stream .where( (syncUpdate) => syncUpdate.accountData?.any( @@ -48,9 +45,7 @@ class ChatDetailsButtonRowState extends State { ) ?? false, ) - .listen( - (u) => setState(() {}), - ); + .listen((u) => setState(() {})); } @override @@ -71,11 +66,10 @@ class ChatDetailsButtonRowState extends State { title: l10n.permissions, icon: const Icon(Icons.edit_attributes_outlined, size: 30.0), onPressed: () { - NavigationUtil.goToSpaceRoute( - room.id, - ['details', 'permissions'], - context, - ); + NavigationUtil.goToSpaceRoute(room.id, [ + 'details', + 'permissions', + ], context); }, enabled: room.isRoomAdmin, visible: !room.isDirectChat, @@ -112,9 +106,7 @@ class ChatDetailsButtonRowState extends State { room.id, ['details', 'invite'], context, - queryParams: { - 'filter': filter, - }, + queryParams: {'filter': filter}, ); }, enabled: room.canInvite, @@ -190,11 +182,9 @@ class ChatDetailsButtonRowState extends State { @override Widget build(BuildContext context) { - final buttons = _buttons(context) - .where( - (button) => button.visible, - ) - .toList(); + final buttons = _buttons( + context, + ).where((button) => button.visible).toList(); return Padding( padding: const EdgeInsets.symmetric(vertical: 16.0), @@ -205,10 +195,12 @@ class ChatDetailsButtonRowState extends State { final mini = fullButtonCapacity < 4; - final List mainViewButtons = - buttons.where((button) => button.showInMainView).toList(); - final List otherButtons = - buttons.where((button) => !button.showInMainView).toList(); + final List mainViewButtons = buttons + .where((button) => button.showInMainView) + .toList(); + final List otherButtons = buttons + .where((button) => !button.showInMainView) + .toList(); return Row( spacing: FluffyThemes.isColumnMode(context) ? 12.0 : 0.0, diff --git a/lib/pangea/chat_settings/pages/chat_details_content.dart b/lib/pangea/chat_settings/pages/chat_details_content.dart index b97eb0cfb..c71edb338 100644 --- a/lib/pangea/chat_settings/pages/chat_details_content.dart +++ b/lib/pangea/chat_settings/pages/chat_details_content.dart @@ -58,18 +58,14 @@ class ChatDetailsContent extends StatelessWidget { ), ), if (!room.isDirectChat && - room.canChangeStateEvent( - EventTypes.RoomAvatar, - )) + room.canChangeStateEvent(EventTypes.RoomAvatar)) Positioned( bottom: 0, right: 0, child: FloatingActionButton.small( onPressed: controller.setAvatarAction, heroTag: null, - child: const Icon( - Icons.camera_alt_outlined, - ), + child: const Icon(Icons.camera_alt_outlined), ), ), ], @@ -83,23 +79,22 @@ class ChatDetailsContent extends StatelessWidget { TextButton.icon( onPressed: room.isDirectChat ? null - : () => room.canChangeStateEvent( - EventTypes.RoomName, - ) - ? controller.setDisplaynameAction() - : FluffyShare.share( - displayname, - context, - copyOnly: true, - ), + : () => + room.canChangeStateEvent( + EventTypes.RoomName, + ) + ? controller.setDisplaynameAction() + : FluffyShare.share( + displayname, + context, + copyOnly: true, + ), icon: Icon( room.isDirectChat ? Icons.chat_bubble_outline - : room.canChangeStateEvent( - EventTypes.RoomName, - ) - ? Icons.edit_outlined - : Icons.copy_outlined, + : room.canChangeStateEvent(EventTypes.RoomName) + ? Icons.edit_outlined + : Icons.copy_outlined, size: 16, ), style: TextButton.styleFrom( @@ -120,17 +115,12 @@ class ChatDetailsContent extends StatelessWidget { onPressed: room.isDirectChat || !room.canInvite ? null : () => NavigationUtil.goToSpaceRoute( - controller.roomId, - ['details', 'invite'], - context, - queryParams: { - 'filter': 'participants', - }, - ), - icon: const Icon( - Icons.group_outlined, - size: 14, - ), + controller.roomId, + ['details', 'invite'], + context, + queryParams: {'filter': 'participants'}, + ), + icon: const Icon(Icons.group_outlined, size: 14), style: TextButton.styleFrom( foregroundColor: theme.colorScheme.secondary, disabledForegroundColor: @@ -171,8 +161,8 @@ class ChatDetailsContent extends StatelessWidget { child: SelectableLinkify( text: room.topic.isEmpty ? room.isSpace - ? L10n.of(context).noSpaceDescriptionYet - : L10n.of(context).noChatDescriptionYet + ? L10n.of(context).noSpaceDescriptionYet + : L10n.of(context).noChatDescriptionYet : room.topic, options: const LinkifyOptions(humanize: false), linkStyle: const TextStyle( @@ -195,10 +185,7 @@ class ChatDetailsContent extends StatelessWidget { ), Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: ChatDetailsButtonRow( - controller: controller, - room: room, - ), + child: ChatDetailsButtonRow(controller: controller, room: room), ), ], ); @@ -210,9 +197,7 @@ class ChatDetailsContent extends StatelessWidget { children: [ const InstructionsInlineTooltip( instructionsEnum: InstructionsEnum.chatParticipantTooltip, - padding: EdgeInsets.only( - bottom: 16.0, - ), + padding: EdgeInsets.only(bottom: 16.0), ), RoomParticipantsSection(room: room), ], diff --git a/lib/pangea/chat_settings/pages/edit_course.dart b/lib/pangea/chat_settings/pages/edit_course.dart index c8a024ba1..e68ad995a 100644 --- a/lib/pangea/chat_settings/pages/edit_course.dart +++ b/lib/pangea/chat_settings/pages/edit_course.dart @@ -171,18 +171,16 @@ class EditCourseController extends State { title: Text(L10n.of(context).editing), ), body: StreamBuilder( - stream: Matrix.of(context).client.onRoomState.stream.where( - (u) => u.roomId == widget.roomId, - ), + stream: Matrix.of( + context, + ).client.onRoomState.stream.where((u) => u.roomId == widget.roomId), builder: (context, snapshot) { return SafeArea( child: Container( alignment: Alignment.topCenter, padding: const EdgeInsets.all(16.0), child: ConstrainedBox( - constraints: const BoxConstraints( - maxWidth: 600, - ), + constraints: const BoxConstraints(maxWidth: 600), child: _room == null || !_room!.isSpace ? Center(child: Text(L10n.of(context).noRoomsFound)) : Column( @@ -212,8 +210,8 @@ class EditCourseController extends State { name: _room?.name, borderRadius: BorderRadius.circular( - 0.0, - ), + 0.0, + ), size: 200.0, ), ), @@ -234,8 +232,9 @@ class EditCourseController extends State { controller: _titleController, decoration: InputDecoration( border: OutlineInputBorder( - borderRadius: - BorderRadius.circular(4.0), + borderRadius: BorderRadius.circular( + 4.0, + ), ), hintText: L10n.of(context).courseTitle, ), @@ -244,8 +243,9 @@ class EditCourseController extends State { controller: _descController, decoration: InputDecoration( border: OutlineInputBorder( - borderRadius: - BorderRadius.circular(4.0), + borderRadius: BorderRadius.circular( + 4.0, + ), ), hintText: L10n.of(context).courseDesc, ), diff --git a/lib/pangea/chat_settings/pages/pangea_chat_access_settings.dart b/lib/pangea/chat_settings/pages/pangea_chat_access_settings.dart index 8cf55cb3a..e5e000812 100644 --- a/lib/pangea/chat_settings/pages/pangea_chat_access_settings.dart +++ b/lib/pangea/chat_settings/pages/pangea_chat_access_settings.dart @@ -29,14 +29,13 @@ class PangeaChatAccessSettingsPageView extends StatelessWidget { body: MaxWidthBody( showBorder: false, child: StreamBuilder( - stream: room.client.onRoomState.stream - .where((update) => update.roomId == controller.room.id), + stream: room.client.onRoomState.stream.where( + (update) => update.roomId == controller.room.id, + ), builder: (context, snapshot) { return Container( width: 400.0, - padding: const EdgeInsets.symmetric( - horizontal: 16.0, - ), + padding: const EdgeInsets.symmetric(horizontal: 16.0), child: FutureBuilder( future: room.client.getRoomVisibilityOnDirectory(room.id), builder: (context, snapshot) { @@ -111,11 +110,7 @@ class ChatAccessTitle extends StatelessWidget { final IconData icon; final String title; - const ChatAccessTitle({ - super.key, - required this.icon, - required this.title, - }); + const ChatAccessTitle({super.key, required this.icon, required this.title}); @override Widget build(BuildContext context) { @@ -124,10 +119,7 @@ class ChatAccessTitle extends StatelessWidget { return Row( mainAxisSize: MainAxisSize.min, children: [ - Icon( - icon, - size: isColumnMode ? 32.0 : 24.0, - ), + Icon(icon, size: isColumnMode ? 32.0 : 24.0), SizedBox(width: isColumnMode ? 32.0 : 16.0), Text( title, @@ -206,8 +198,8 @@ class ChatAccessTile extends StatelessWidget { description != null ? Text(description!) : descriptionWidget != null - ? descriptionWidget! - : const SizedBox.shrink(), + ? descriptionWidget! + : const SizedBox.shrink(), ], ), ), diff --git a/lib/pangea/chat_settings/pages/pangea_invitation_selection.dart b/lib/pangea/chat_settings/pages/pangea_invitation_selection.dart index bdf7e050c..6588362bd 100644 --- a/lib/pangea/chat_settings/pages/pangea_invitation_selection.dart +++ b/lib/pangea/chat_settings/pages/pangea_invitation_selection.dart @@ -91,13 +91,15 @@ class PangeaInvitationSelectionController void initState() { super.initState(); - _room?.requestParticipants( - [Membership.join, Membership.invite, Membership.knock], - false, - true, - ).then((_) { - if (mounted) setState(() {}); - }); + _room + ?.requestParticipants( + [Membership.join, Membership.invite, Membership.knock], + false, + true, + ) + .then((_) { + if (mounted) setState(() {}); + }); if (widget.initialFilter != null && availableFilters.contains(widget.initialFilter)) { @@ -167,14 +169,11 @@ class PangeaInvitationSelectionController (f) => switch (f) { InvitationFilter.space => spaceParent != null, InvitationFilter.contacts => true, - InvitationFilter.invited => participants?.any( - (u) => u.membership == Membership.invite, - ) ?? - false, - InvitationFilter.knocking => participants?.any( - (u) => u.membership == Membership.knock, - ) ?? - false, + InvitationFilter.invited => + participants?.any((u) => u.membership == Membership.invite) ?? + false, + InvitationFilter.knocking => + participants?.any((u) => u.membership == Membership.knock) ?? false, InvitationFilter.public => true, InvitationFilter.participants => true, }, @@ -186,21 +185,21 @@ class PangeaInvitationSelectionController } List get _membershipOrder => [ - Membership.join, - Membership.invite, - Membership.knock, - Membership.leave, - Membership.ban, - ]; + Membership.join, + Membership.invite, + Membership.knock, + Membership.leave, + Membership.ban, + ]; String? membershipCopy(Membership? membership) => switch (membership) { - Membership.ban => L10n.of(context).banned, - Membership.invite => L10n.of(context).invited, - Membership.join => null, - Membership.knock => L10n.of(context).knocking, - Membership.leave => L10n.of(context).leftTheChat, - null => null, - }; + Membership.ban => L10n.of(context).banned, + Membership.invite => L10n.of(context).invited, + Membership.join => null, + Membership.knock => L10n.of(context).knocking, + Membership.leave => L10n.of(context).leftTheChat, + null => null, + }; int _sortUsers(User a, User b) { // sort yourself to the top @@ -256,17 +255,15 @@ class PangeaInvitationSelectionController case InvitationFilter.contacts: contacts = getContacts(context); case InvitationFilter.invited: - contacts = participants - ?.where( - (u) => u.membership == Membership.invite, - ) + contacts = + participants + ?.where((u) => u.membership == Membership.invite) .toList() ?? []; case InvitationFilter.knocking: - contacts = participants - ?.where( - (u) => u.membership == Membership.knock, - ) + contacts = + participants + ?.where((u) => u.membership == Membership.knock) .toList() ?? []; default: @@ -323,11 +320,7 @@ class PangeaInvitationSelectionController await _room!.addJoinCode(); if (mounted) setState(() {}); } catch (e, s) { - ErrorHandler.logError( - e: e, - s: s, - data: {'roomId': _room!.id}, - ); + ErrorHandler.logError(e: e, s: s, data: {'roomId': _room!.id}); } } @@ -343,9 +336,9 @@ class PangeaInvitationSelectionController try { response = await matrix.client.searchUser(text, limit: 100); } catch (e) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text((e).toLocalizedString(context))), - ); + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text((e).toLocalizedString(context)))); return; } finally { setState(() => loading = false); @@ -367,8 +360,7 @@ class PangeaInvitationSelectionController ); } - final participants = this - .participants + final participants = this.participants ?.where( (user) => [Membership.join, Membership.invite].contains(user.membership), @@ -457,9 +449,9 @@ class PangeaInvitationSelectionController ), ); } else { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text(result.error.toString())), - ); + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text(result.error.toString()))); } }); } diff --git a/lib/pangea/chat_settings/pages/pangea_invitation_selection_view.dart b/lib/pangea/chat_settings/pages/pangea_invitation_selection_view.dart index 0b050a1ed..ca55851db 100644 --- a/lib/pangea/chat_settings/pages/pangea_invitation_selection_view.dart +++ b/lib/pangea/chat_settings/pages/pangea_invitation_selection_view.dart @@ -31,13 +31,12 @@ class PangeaInvitationSelectionView extends StatelessWidget { @override Widget build(BuildContext context) { - final room = - Matrix.of(context).client.getRoomById(controller.widget.roomId); + final room = Matrix.of( + context, + ).client.getRoomById(controller.widget.roomId); if (room == null) { return Scaffold( - appBar: AppBar( - title: Text(L10n.of(context).oopsSomethingWentWrong), - ), + appBar: AppBar(title: Text(L10n.of(context).oopsSomethingWentWrong)), body: Center( child: Text(L10n.of(context).youAreNoLongerParticipatingInThisChat), ), @@ -50,19 +49,13 @@ class PangeaInvitationSelectionView extends StatelessWidget { final doneButton = ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: theme.colorScheme.primaryContainer, - padding: const EdgeInsets.symmetric( - horizontal: 20, - vertical: 16, - ), + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 16), ), child: Row( spacing: 12.0, mainAxisAlignment: MainAxisAlignment.center, children: [ - Icon( - Icons.check, - color: theme.colorScheme.onPrimaryContainer, - ), + Icon(Icons.check, color: theme.colorScheme.onPrimaryContainer), Text( L10n.of(context).done, style: TextStyle( @@ -154,32 +147,34 @@ class PangeaInvitationSelectionView extends StatelessWidget { .where((update) => update.roomId == room.id) .rateLimit(const Duration(seconds: 1)), builder: (context, snapshot) { - final participants = - room.getParticipants().map((user) => user.id).toSet(); + final participants = room + .getParticipants() + .map((user) => user.id) + .toSet(); return controller.filter == InvitationFilter.public ? 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, + ? Padding( + padding: const EdgeInsets.all(24.0), + child: Text( + room.isSpace + ? L10n.of(context).publicInviteDescSpace + : L10n.of(context).publicInviteDescChat, ), - onTap: () => controller.inviteAction( - controller.foundProfiles[i].userId, - ), - controller: controller, - ), - ) + ) + : 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) { @@ -206,7 +201,9 @@ class PangeaInvitationSelectionView extends StatelessWidget { ), subtitle: Text( L10n.of(context).countParticipants( - controller.spaceParent!.summary + controller + .spaceParent! + .summary .mJoinedMemberCount ?? 1, ), @@ -237,10 +234,9 @@ class PangeaInvitationSelectionView extends StatelessWidget { "${AppConfig.assetsBaseURL}/${RoomSettingsConstants.referFriendAsset}", errorWidget: (context, url, error) => const SizedBox(), - placeholder: (context, url) => - const Center( - child: CircularProgressIndicator - .adaptive(), + placeholder: (context, url) => const Center( + child: + CircularProgressIndicator.adaptive(), ), ), ), @@ -250,15 +246,15 @@ class PangeaInvitationSelectionView extends StatelessWidget { user: contacts[i], profile: Profile( avatarUrl: contacts[i].avatarUrl, - displayName: contacts[i].displayName ?? + displayName: + contacts[i].displayName ?? contacts[i].id.localpart ?? L10n.of(context).user, userId: contacts[i].id, ), isMember: participants.contains(contacts[i].id), - onTap: () => controller.inviteAction( - contacts[i].id, - ), + onTap: () => + controller.inviteAction(contacts[i].id), controller: controller, ); }, @@ -314,41 +310,36 @@ class PangeaInvitationSelectionView extends StatelessWidget { "$initialUrl/#/join_with_link?${SpaceConstants.classCode}=${room.classCode}"; } - await Clipboard.setData( - ClipboardData(text: toCopy), - ); - ScaffoldMessenger.of( - context, - ).showSnackBar( + await Clipboard.setData(ClipboardData(text: toCopy)); + ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: Text( - L10n.of(context).copiedToClipboard, - ), + content: Text(L10n.of(context).copiedToClipboard), ), ); }, itemBuilder: (BuildContext context) => >[ - PopupMenuItem( - value: 0, - child: ListTile( - leading: const Icon(Icons.share_outlined), - title: Text(L10n.of(context).shareSpaceLink), - contentPadding: const EdgeInsets.all(0), - ), - ), - PopupMenuItem( - value: 1, - child: ListTile( - leading: const Icon(Icons.share_outlined), - title: Text( - L10n.of(context) - .shareInviteCode(room.classCode!), + PopupMenuItem( + value: 0, + child: ListTile( + leading: const Icon(Icons.share_outlined), + title: Text(L10n.of(context).shareSpaceLink), + contentPadding: const EdgeInsets.all(0), + ), ), - contentPadding: const EdgeInsets.all(0), - ), - ), - ], + PopupMenuItem( + value: 1, + child: ListTile( + leading: const Icon(Icons.share_outlined), + title: Text( + L10n.of( + context, + ).shareInviteCode(room.classCode!), + ), + contentPadding: const EdgeInsets.all(0), + ), + ), + ], ), ), room.classCode != null @@ -392,26 +383,21 @@ class _InviteContactListTile extends StatelessWidget { final String? permissionBatch = participant == null ? null : participant.powerLevel >= 100 - ? L10n.of(context).admin - : participant.powerLevel >= 50 - ? L10n.of(context).moderator - : null; + ? L10n.of(context).admin + : participant.powerLevel >= 50 + ? L10n.of(context).moderator + : null; return ListTile( onTap: participant != null - ? () => showMemberActionsPopupMenu( - context: context, - user: participant, - ) + ? () => + showMemberActionsPopupMenu(context: context, user: participant) : null, leading: Avatar( mxContent: profile.avatarUrl, name: profile.displayName, presenceUserId: profile.userId, - onTap: () => UserDialog.show( - context: context, - profile: profile, - ), + onTap: () => UserDialog.show(context: context, profile: profile), ), title: Text( profile.displayName ?? profile.userId.localpart ?? l10n.user, @@ -425,9 +411,7 @@ class _InviteContactListTile extends StatelessWidget { const SizedBox(height: 2.0), Text( profile.userId, - style: const TextStyle( - fontSize: 12.0, - ), + style: const TextStyle(fontSize: 12.0), maxLines: 1, overflow: TextOverflow.ellipsis, ), @@ -450,34 +434,29 @@ class _InviteContactListTile extends StatelessWidget { ), ) : permissionBatch != null - ? Container( - margin: const EdgeInsets.only(right: 12.0), - padding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 6, - ), - decoration: BoxDecoration( - color: participant!.powerLevel >= 100 - ? theme.colorScheme.tertiary - : theme.colorScheme.tertiaryContainer, - borderRadius: BorderRadius.circular( - AppConfig.borderRadius, - ), - ), - child: Text( - permissionBatch, - style: theme.textTheme.labelSmall?.copyWith( - color: participant.powerLevel >= 100 - ? theme.colorScheme.onTertiary - : theme.colorScheme.onTertiaryContainer, - ), - ), - ) - : TextButton.icon( - onPressed: isMember ? null : onTap, - label: Text(isMember ? l10n.participant : l10n.invite), - icon: Icon(isMember ? Icons.check : Icons.add), + ? Container( + margin: const EdgeInsets.only(right: 12.0), + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), + decoration: BoxDecoration( + color: participant!.powerLevel >= 100 + ? theme.colorScheme.tertiary + : theme.colorScheme.tertiaryContainer, + borderRadius: BorderRadius.circular(AppConfig.borderRadius), + ), + child: Text( + permissionBatch, + style: theme.textTheme.labelSmall?.copyWith( + color: participant.powerLevel >= 100 + ? theme.colorScheme.onTertiary + : theme.colorScheme.onTertiaryContainer, ), + ), + ) + : TextButton.icon( + onPressed: isMember ? null : onTap, + label: Text(isMember ? l10n.participant : l10n.invite), + icon: Icon(isMember ? Icons.check : Icons.add), + ), ); } } diff --git a/lib/pangea/chat_settings/pages/pangea_room_details.dart b/lib/pangea/chat_settings/pages/pangea_room_details.dart index c0573ed5c..8631c7b85 100644 --- a/lib/pangea/chat_settings/pages/pangea_room_details.dart +++ b/lib/pangea/chat_settings/pages/pangea_room_details.dart @@ -19,9 +19,7 @@ class PangeaRoomDetailsView extends StatelessWidget { final room = Matrix.of(context).client.getRoomById(controller.roomId!); if (room == null || room.membership == Membership.leave) { return Scaffold( - appBar: AppBar( - title: Text(L10n.of(context).oopsSomethingWentWrong), - ), + appBar: AppBar(title: Text(L10n.of(context).oopsSomethingWentWrong)), body: Center( child: Text(L10n.of(context).youAreNoLongerParticipatingInThisChat), ), @@ -29,15 +27,17 @@ class PangeaRoomDetailsView extends StatelessWidget { } return StreamBuilder( - stream: room.client.onRoomState.stream - .where((update) => update.roomId == room.id), + stream: room.client.onRoomState.stream.where( + (update) => update.roomId == room.id, + ), builder: (context, snapshot) { return SafeArea( child: Scaffold( appBar: room.isSpace ? null : AppBar( - leading: controller.widget.embeddedCloseButton ?? + leading: + controller.widget.embeddedCloseButton ?? const Center(child: BackButton()), ), body: Padding( diff --git a/lib/pangea/chat_settings/pages/room_details_buttons.dart b/lib/pangea/chat_settings/pages/room_details_buttons.dart index c47f64734..e3138cb16 100644 --- a/lib/pangea/chat_settings/pages/room_details_buttons.dart +++ b/lib/pangea/chat_settings/pages/room_details_buttons.dart @@ -71,10 +71,9 @@ class RoomDetailsButton extends StatelessWidget { height: height, decoration: BoxDecoration( color: hovered || selected - ? Theme.of(context) - .colorScheme - .primaryContainer - .withAlpha(200) + ? Theme.of( + context, + ).colorScheme.primaryContainer.withAlpha(200) : Colors.transparent, borderRadius: BorderRadius.circular(8), ), diff --git a/lib/pangea/chat_settings/pages/room_participants_widget.dart b/lib/pangea/chat_settings/pages/room_participants_widget.dart index ba6484e8b..59600aae4 100644 --- a/lib/pangea/chat_settings/pages/room_participants_widget.dart +++ b/lib/pangea/chat_settings/pages/room_participants_widget.dart @@ -16,10 +16,7 @@ import 'package:fluffychat/widgets/member_actions_popup_menu_button.dart'; class RoomParticipantsSection extends StatelessWidget { final Room room; - const RoomParticipantsSection({ - required this.room, - super.key, - }); + const RoomParticipantsSection({required this.room, super.key}); final double _width = 100.0; @@ -69,20 +66,18 @@ class RoomParticipantsSection extends StatelessWidget { ? MouseRegion( cursor: SystemMouseCursors.click, child: GestureDetector( - onTap: () => NavigationUtil.goToSpaceRoute( - room.id, - ['details', 'invite'], - context, - ), + onTap: () => NavigationUtil.goToSpaceRoute(room.id, [ + 'details', + 'invite', + ], context), child: HoverBuilder( builder: (context, hovered) { return Container( decoration: BoxDecoration( color: hovered - ? Theme.of(context) - .colorScheme - .primary - .withAlpha(50) + ? Theme.of( + context, + ).colorScheme.primary.withAlpha(50) : Colors.transparent, borderRadius: BorderRadius.circular(8), ), @@ -116,8 +111,8 @@ class RoomParticipantsSection extends StatelessWidget { final permissionBatch = user.powerLevel >= 100 ? L10n.of(context).admin : user.powerLevel >= 50 - ? L10n.of(context).moderator - : ''; + ? L10n.of(context).moderator + : ''; final membershipBatch = switch (user.membership) { Membership.ban => null, @@ -165,10 +160,7 @@ class RoomParticipantsSection extends StatelessWidget { ), ) else - SizedBox( - height: _width, - width: _width, - ), + SizedBox(height: _width, width: _width), Builder( builder: (context) { return MouseRegion( @@ -235,31 +227,29 @@ class RoomParticipantsSection extends StatelessWidget { ), ) : permissionBatch.isNotEmpty - ? Container( - padding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 4, - ), - decoration: BoxDecoration( - color: user.powerLevel >= 100 - ? theme.colorScheme.tertiary - : theme.colorScheme.tertiaryContainer, - borderRadius: BorderRadius.circular( - AppConfig.borderRadius, - ), - ), - child: Text( - permissionBatch, - style: - theme.textTheme.labelSmall?.copyWith( - color: user.powerLevel >= 100 - ? theme.colorScheme.onTertiary - : theme.colorScheme - .onTertiaryContainer, - ), - ), - ) - : null, + ? Container( + padding: const EdgeInsets.symmetric( + horizontal: 12, + vertical: 4, + ), + decoration: BoxDecoration( + color: user.powerLevel >= 100 + ? theme.colorScheme.tertiary + : theme.colorScheme.tertiaryContainer, + borderRadius: BorderRadius.circular( + AppConfig.borderRadius, + ), + ), + child: Text( + permissionBatch, + style: theme.textTheme.labelSmall?.copyWith( + color: user.powerLevel >= 100 + ? theme.colorScheme.onTertiary + : theme.colorScheme.onTertiaryContainer, + ), + ), + ) + : null, ), ], ), diff --git a/lib/pangea/chat_settings/pages/space_details_button_row.dart b/lib/pangea/chat_settings/pages/space_details_button_row.dart index 2ca0c62b8..2d404b176 100644 --- a/lib/pangea/chat_settings/pages/space_details_button_row.dart +++ b/lib/pangea/chat_settings/pages/space_details_button_row.dart @@ -38,10 +38,7 @@ class SpaceDetailsButtonRowState extends State { @override void initState() { super.initState(); - notificationChangeSub ??= Matrix.of(context) - .client - .onSync - .stream + notificationChangeSub ??= Matrix.of(context).client.onSync.stream .where( (syncUpdate) => syncUpdate.accountData?.any( @@ -49,9 +46,7 @@ class SpaceDetailsButtonRowState extends State { ) ?? false, ) - .listen( - (u) => setState(() {}), - ); + .listen((u) => setState(() {})); } @override @@ -67,11 +62,7 @@ class SpaceDetailsButtonRowState extends State { @override Widget build(BuildContext context) { - final buttons = widget.buttons - .where( - (button) => button.visible, - ) - .toList(); + final buttons = widget.buttons.where((button) => button.visible).toList(); return LayoutBuilder( builder: (context, constraints) { @@ -80,10 +71,12 @@ class SpaceDetailsButtonRowState extends State { final mini = fullButtonCapacity < 4; - final List mainViewButtons = - buttons.where((button) => button.showInMainView).toList(); - final List otherButtons = - buttons.where((button) => !button.showInMainView).toList(); + final List mainViewButtons = buttons + .where((button) => button.showInMainView) + .toList(); + final List otherButtons = buttons + .where((button) => !button.showInMainView) + .toList(); return Row( spacing: FluffyThemes.isColumnMode(context) ? 12.0 : 0.0, diff --git a/lib/pangea/chat_settings/pages/space_details_content.dart b/lib/pangea/chat_settings/pages/space_details_content.dart index b57233edd..65976c4da 100644 --- a/lib/pangea/chat_settings/pages/space_details_content.dart +++ b/lib/pangea/chat_settings/pages/space_details_content.dart @@ -38,9 +38,7 @@ enum SpaceSettingsTabs { more; static SpaceSettingsTabs? fromString(String value) { - return SpaceSettingsTabs.values.firstWhereOrNull( - (e) => e.name == value, - ); + return SpaceSettingsTabs.values.firstWhereOrNull((e) => e.name == value); } } @@ -48,11 +46,7 @@ class SpaceDetailsContent extends StatelessWidget { final ChatDetailsController controller; final Room room; - const SpaceDetailsContent( - this.controller, - this.room, { - super.key, - }); + const SpaceDetailsContent(this.controller, this.room, {super.key}); SpaceSettingsTabs tab(BuildContext context) { final defaultTab = FluffyThemes.isColumnMode(context) @@ -111,9 +105,7 @@ class SpaceDetailsContent extends StatelessWidget { if (room.getParticipants([Membership.knock]).isEmpty) { filter = room.pangeaSpaceParents.isNotEmpty ? 'space' : 'contacts'; } - context.go( - '/rooms/spaces/${room.id}/details/invite?filter=$filter', - ); + context.go('/rooms/spaces/${room.id}/details/invite?filter=$filter'); }, enabled: room.canInvite, showInMainView: false, @@ -216,10 +208,8 @@ class SpaceDetailsContent extends StatelessWidget { description: l10n.createGroupChatDesc, icon: const Icon(Symbols.chat_add_on, size: 30.0), onPressed: controller.addGroupChat, - enabled: room.isRoomAdmin && - room.canChangeStateEvent( - EventTypes.SpaceChild, - ), + enabled: + room.isRoomAdmin && room.canChangeStateEvent(EventTypes.SpaceChild), showInMainView: false, ), ButtonDetails( @@ -250,10 +240,7 @@ class SpaceDetailsContent extends StatelessWidget { ButtonDetails( title: l10n.delete, description: l10n.deleteDesc, - icon: const Icon( - Icons.delete_outline, - size: 30.0, - ), + icon: const Icon(Icons.delete_outline, size: 30.0), onPressed: () => DeleteSpaceDialog.show(room, context), enabled: room.isRoomAdmin, showInMainView: false, @@ -351,9 +338,7 @@ class SpaceDetailsContent extends StatelessWidget { ); case SpaceSettingsTabs.course: return SingleChildScrollView( - child: CourseSettings( - controller: controller, - ), + child: CourseSettings(controller: controller), ); case SpaceSettingsTabs.participants: return SingleChildScrollView( @@ -374,16 +359,12 @@ class SpaceDetailsContent extends StatelessWidget { ); case SpaceSettingsTabs.analytics: return SingleChildScrollView( - child: Center( - child: SpaceAnalytics(roomId: room.id), - ), + child: Center(child: SpaceAnalytics(roomId: room.id)), ); case SpaceSettingsTabs.more: - final buttons = _buttons(context) - .where( - (b) => !b.showInMainView && b.visible, - ) - .toList(); + final buttons = _buttons( + context, + ).where((b) => !b.showInMainView && b.visible).toList(); return SingleChildScrollView( child: Column( diff --git a/lib/pangea/chat_settings/utils/bot_client_extension.dart b/lib/pangea/chat_settings/utils/bot_client_extension.dart index c1ad861b7..307dc1400 100644 --- a/lib/pangea/chat_settings/utils/bot_client_extension.dart +++ b/lib/pangea/chat_settings/utils/bot_client_extension.dart @@ -19,35 +19,37 @@ extension BotClientExtension on Client { // All 2-member rooms with the bot List get _targetBotChats => rooms.where((r) { - return - // bot settings exist - r.botOptions != null && - // there is no activity plan - r.activityPlan == null && - // it's just the bot and one other user in the room - r.summary.mJoinedMemberCount == 2 && - r.getParticipants().any((u) => u.id == BotName.byEnvironment); - }).toList(); + return + // bot settings exist + r.botOptions != null && + // there is no activity plan + r.activityPlan == null && + // it's just the bot and one other user in the room + r.summary.mJoinedMemberCount == 2 && + r.getParticipants().any((u) => u.id == BotName.byEnvironment); + }).toList(); Future startChatWithBot() => startDirectChat( - BotName.byEnvironment, - preset: CreateRoomPreset.trustedPrivateChat, - initialState: [ - StateEvent( - content: BotOptionsModel( - mode: BotMode.directChat, - targetLanguage: - MatrixState.pangeaController.userController.userL2?.langCode, - languageLevel: MatrixState.pangeaController.userController.profile - .userSettings.cefrLevel, - ).toJson(), - type: PangeaEventTypes.botOptions, - ), - RoomDefaults.defaultPowerLevels( - userID!, - ), - ], - ); + BotName.byEnvironment, + preset: CreateRoomPreset.trustedPrivateChat, + initialState: [ + StateEvent( + content: BotOptionsModel( + mode: BotMode.directChat, + targetLanguage: + MatrixState.pangeaController.userController.userL2?.langCode, + languageLevel: MatrixState + .pangeaController + .userController + .profile + .userSettings + .cefrLevel, + ).toJson(), + type: PangeaEventTypes.botOptions, + ), + RoomDefaults.defaultPowerLevels(userID!), + ], + ); Future updateBotOptions(UserSettings userSettings) async { final targetBotRooms = [..._targetBotChats]; @@ -69,8 +71,9 @@ extension BotClientExtension on Client { continue; } - final updatedGenders = - Map.from(botOptions.userGenders); + final updatedGenders = Map.from( + botOptions.userGenders, + ); if (updatedGenders[userID] != gender) { updatedGenders[userID!] = gender; diff --git a/lib/pangea/chat_settings/utils/delete_room.dart b/lib/pangea/chat_settings/utils/delete_room.dart index 26511f420..7cd772dfc 100644 --- a/lib/pangea/chat_settings/utils/delete_room.dart +++ b/lib/pangea/chat_settings/utils/delete_room.dart @@ -11,17 +11,11 @@ extension on Api { // Response 200 OK format: { message: "Deleted" }. // Requester must be member of the room and have the highest power level of the room to perform this request. Future delete(String roomId) async { - final requestUri = Uri( - path: '_synapse/client/pangea/v1/delete_room', - ); + final requestUri = Uri(path: '_synapse/client/pangea/v1/delete_room'); final request = Request('POST', baseUri!.resolveUri(requestUri)); request.headers['content-type'] = 'application/json'; request.headers['authorization'] = 'Bearer ${bearerToken!}'; - request.bodyBytes = utf8.encode( - jsonEncode({ - 'room_id': roomId, - }), - ); + request.bodyBytes = utf8.encode(jsonEncode({'room_id': roomId})); final response = await httpClient.send(request); if (response.statusCode != 200) { throw Exception('http error response'); @@ -51,9 +45,7 @@ extension DeleteRoom on Room { } return rooms - .where( - (r) => r.roomType != PangeaRoomTypes.analytics && r.roomId != id, - ) + .where((r) => r.roomType != PangeaRoomTypes.analytics && r.roomId != id) .toList(); } } diff --git a/lib/pangea/chat_settings/utils/room_summary_extension.dart b/lib/pangea/chat_settings/utils/room_summary_extension.dart index 4315a11a7..37ff4e6c8 100644 --- a/lib/pangea/chat_settings/utils/room_summary_extension.dart +++ b/lib/pangea/chat_settings/utils/room_summary_extension.dart @@ -16,9 +16,7 @@ extension RoomSummaryExtension on Api { Future getRoomSummaries(List roomIds) async { final requestUri = Uri( path: '/_synapse/client/unstable/org.pangea/room_preview', - queryParameters: { - 'rooms': roomIds.join(","), - }, + queryParameters: {'rooms': roomIds.join(",")}, ); final request = Request('GET', baseUri!.resolveUri(requestUri)); request.headers['content-type'] = 'application/json'; @@ -147,8 +145,9 @@ class RoomSummaryResponse { json[EventTypes.RoomJoinRules]?['default']?['content']?['join_rule']; JoinRules? joinRule; if (joinRulesString != null && joinRulesString is String) { - joinRule = JoinRules.values - .singleWhereOrNull((element) => element.text == joinRulesString); + joinRule = JoinRules.values.singleWhereOrNull( + (element) => element.text == joinRulesString, + ); } final displayName = diff --git a/lib/pangea/chat_settings/widgets/chat_context_menu_action.dart b/lib/pangea/chat_settings/widgets/chat_context_menu_action.dart index acf7b5ff9..387de07aa 100644 --- a/lib/pangea/chat_settings/widgets/chat_context_menu_action.dart +++ b/lib/pangea/chat_settings/widgets/chat_context_menu_action.dart @@ -84,9 +84,7 @@ void chatContextMenuAction( ), const SizedBox(width: 12), Expanded( - child: Text( - l10n.goToCourse(space.getLocalizedDisplayname()), - ), + child: Text(l10n.goToCourse(space.getLocalizedDisplayname())), ), ], ), @@ -123,9 +121,7 @@ void chatContextMenuAction( : Icons.mark_as_unread_outlined, ), const SizedBox(width: 12), - Text( - room.markedUnread ? l10n.markAsRead : l10n.markAsUnread, - ), + Text(room.markedUnread ? l10n.markAsRead : l10n.markAsUnread), ], ), ), @@ -139,9 +135,7 @@ void chatContextMenuAction( room.isFavourite ? Icons.push_pin : Icons.push_pin_outlined, ), const SizedBox(width: 12), - Text( - room.isFavourite ? l10n.unpin : l10n.pin, - ), + Text(room.isFavourite ? l10n.unpin : l10n.pin), ], ), ), @@ -152,13 +146,9 @@ void chatContextMenuAction( child: Row( mainAxisSize: MainAxisSize.min, children: [ - const Icon( - Icons.stop_circle_outlined, - ), + const Icon(Icons.stop_circle_outlined), const SizedBox(width: 12), - Text( - l10n.endActivity, - ), + Text(l10n.endActivity), ], ), ), @@ -175,9 +165,7 @@ void chatContextMenuAction( const SizedBox(width: 12), Text( room.membership == Membership.invite ? l10n.delete : l10n.leave, - style: TextStyle( - color: theme.colorScheme.onErrorContainer, - ), + style: TextStyle(color: theme.colorScheme.onErrorContainer), ), ], ), @@ -195,9 +183,7 @@ void chatContextMenuAction( const SizedBox(width: 12), Text( l10n.delete, - style: TextStyle( - color: theme.colorScheme.onErrorContainer, - ), + style: TextStyle(color: theme.colorScheme.onErrorContainer), ), ], ), diff --git a/lib/pangea/chat_settings/widgets/delete_space_dialog.dart b/lib/pangea/chat_settings/widgets/delete_space_dialog.dart index c755faacb..0d3937f8d 100644 --- a/lib/pangea/chat_settings/widgets/delete_space_dialog.dart +++ b/lib/pangea/chat_settings/widgets/delete_space_dialog.dart @@ -14,15 +14,9 @@ import 'package:fluffychat/widgets/future_loading_dialog.dart'; class DeleteSpaceDialog extends StatefulWidget { final Room space; - const DeleteSpaceDialog({ - super.key, - required this.space, - }); + const DeleteSpaceDialog({super.key, required this.space}); - static Future show( - Room room, - BuildContext context, - ) async { + static Future show(Room room, BuildContext context) async { final resp = await showDialog?>( context: context, builder: (_) => DeleteSpaceDialog(space: room), @@ -93,13 +87,7 @@ class DeleteSpaceDialogState extends State { _rooms = await widget.space.getSpaceChildrenToDelete(); } catch (e, s) { _roomLoadError = L10n.of(context).errorLoadingSpaceChildren; - ErrorHandler.logError( - e: e, - s: s, - data: { - "roomID": widget.space.id, - }, - ); + ErrorHandler.logError(e: e, s: s, data: {"roomID": widget.space.id}); } finally { setState(() { _loadingRooms = false; @@ -107,10 +95,7 @@ class DeleteSpaceDialogState extends State { } } - void _onRoomSelected( - bool? selected, - SpaceRoomsChunk$2 room, - ) { + void _onRoomSelected(bool? selected, SpaceRoomsChunk$2 room) { if (selected == null || (selected && _roomsToDelete.contains(room)) || (!selected && !_roomsToDelete.contains(room))) { @@ -147,16 +132,11 @@ class DeleteSpaceDialogState extends State { Widget build(BuildContext context) { return Dialog( shape: RoundedRectangleBorder( - side: BorderSide( - color: Theme.of(context).colorScheme.error, - ), + side: BorderSide(color: Theme.of(context).colorScheme.error), borderRadius: BorderRadius.circular(32.0), ), child: Container( - constraints: const BoxConstraints( - maxWidth: 400, - maxHeight: 600, - ), + constraints: const BoxConstraints(maxWidth: 400, maxHeight: 600), padding: const EdgeInsets.symmetric(vertical: 20), child: Column( mainAxisSize: MainAxisSize.min, @@ -164,8 +144,8 @@ class DeleteSpaceDialogState extends State { Text( L10n.of(context).areYouSure, style: Theme.of(context).textTheme.titleLarge?.copyWith( - color: Theme.of(context).colorScheme.error, - ), + color: Theme.of(context).colorScheme.error, + ), ), Padding( padding: const EdgeInsets.symmetric( @@ -210,7 +190,8 @@ class DeleteSpaceDialogState extends State { children: [ if (_selectableRooms.length > 1) CheckboxListTile( - value: _roomsToDelete.length == + value: + _roomsToDelete.length == _selectableRooms.length, onChanged: (_) => _toggleSelectAll(), title: Text( @@ -226,13 +207,16 @@ class DeleteSpaceDialogState extends State { itemBuilder: (context, index) { final chunk = _rooms[index]; - final room = widget.space.client - .getRoomById(chunk.roomId); - final isMember = room != null && + final room = widget.space.client.getRoomById( + chunk.roomId, + ); + final isMember = + room != null && room.membership == Membership.join && room.isRoomAdmin; - final displayname = chunk.name ?? + final displayname = + chunk.name ?? chunk.canonicalAlias ?? L10n.of(context).emptyChat; @@ -243,7 +227,7 @@ class DeleteSpaceDialogState extends State { value: _roomsToDelete.contains(chunk), onChanged: isMember ? (value) => - _onRoomSelected(value, chunk) + _onRoomSelected(value, chunk) : null, title: Text(displayname), controlAffinity: diff --git a/lib/pangea/chat_settings/widgets/language_level_dropdown.dart b/lib/pangea/chat_settings/widgets/language_level_dropdown.dart index cf0b5d11d..9f0cbdb87 100644 --- a/lib/pangea/chat_settings/widgets/language_level_dropdown.dart +++ b/lib/pangea/chat_settings/widgets/language_level_dropdown.dart @@ -23,9 +23,7 @@ class LanguageLevelDropdown extends StatelessWidget { alignedDropdown: true, child: DropdownButtonFormField( itemHeight: null, - decoration: InputDecoration( - labelText: l10n.cefrLevelLabel, - ), + decoration: InputDecoration(labelText: l10n.cefrLevelLabel), selectedItemBuilder: (context) => LanguageLevelTypeEnum.values .map((levelOption) => Text(levelOption.title(context))) .toList(), @@ -38,8 +36,9 @@ class LanguageLevelDropdown extends StatelessWidget { } : null, initialValue: initialLevel, - items: LanguageLevelTypeEnum.values - .map((LanguageLevelTypeEnum levelOption) { + items: LanguageLevelTypeEnum.values.map(( + LanguageLevelTypeEnum levelOption, + ) { return DropdownMenuItem( value: levelOption, child: Padding( diff --git a/lib/pangea/chat_settings/widgets/room_capacity_button.dart b/lib/pangea/chat_settings/widgets/room_capacity_button.dart index 7397325ac..161b90946 100644 --- a/lib/pangea/chat_settings/widgets/room_capacity_button.dart +++ b/lib/pangea/chat_settings/widgets/room_capacity_button.dart @@ -12,11 +12,7 @@ class RoomCapacityButton extends StatefulWidget { final Room room; final ChatDetailsController? controller; - const RoomCapacityButton({ - super.key, - required this.room, - this.controller, - }); + const RoomCapacityButton({super.key, required this.room, this.controller}); @override RoomCapacityButtonState createState() => RoomCapacityButtonState(); @@ -90,9 +86,7 @@ class RoomCapacityButtonState extends State { ); if (success.error == null) { ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(L10n.of(context).chatCapacityHasBeenChanged), - ), + SnackBar(content: Text(L10n.of(context).chatCapacityHasBeenChanged)), ); setState(() {}); } diff --git a/lib/pangea/choreographer/assistance_state_enum.dart b/lib/pangea/choreographer/assistance_state_enum.dart index 3af392469..1a4f95539 100644 --- a/lib/pangea/choreographer/assistance_state_enum.dart +++ b/lib/pangea/choreographer/assistance_state_enum.dart @@ -46,17 +46,18 @@ enum AssistanceStateEnum { } bool get allowsFeedback => switch (this) { - AssistanceStateEnum.notFetched => true, - _ => false, - }; + AssistanceStateEnum.notFetched => true, + _ => false, + }; Color backgroundColor(BuildContext context) => switch (this) { - AssistanceStateEnum.noSub || - AssistanceStateEnum.noMessage || - AssistanceStateEnum.fetched || - AssistanceStateEnum.complete || - AssistanceStateEnum.error => - Theme.of(context).colorScheme.surfaceContainerHighest, - _ => Theme.of(context).colorScheme.primaryContainer, - }; + AssistanceStateEnum.noSub || + AssistanceStateEnum.noMessage || + AssistanceStateEnum.fetched || + AssistanceStateEnum.complete || + AssistanceStateEnum.error => Theme.of( + context, + ).colorScheme.surfaceContainerHighest, + _ => Theme.of(context).colorScheme.primaryContainer, + }; } diff --git a/lib/pangea/choreographer/choreo_edit_model.dart b/lib/pangea/choreographer/choreo_edit_model.dart index 6669dffa9..6ce869120 100644 --- a/lib/pangea/choreographer/choreo_edit_model.dart +++ b/lib/pangea/choreographer/choreo_edit_model.dart @@ -9,11 +9,7 @@ class ChoreoEditModel { final String insert; /// Normal constructor created from preexisting ChoreoEdit values - const ChoreoEditModel({ - this.offset = 0, - this.length = 0, - this.insert = "", - }); + const ChoreoEditModel({this.offset = 0, this.length = 0, this.insert = ""}); /// Constructor that determines and saves /// edits differentiating originalText and editedText @@ -30,11 +26,7 @@ class ChoreoEditModel { final length = _lastDifference(originalText, editedText, offset) + 1 - offset; final insert = _insertion(originalText, editedText, offset, length); - return ChoreoEditModel( - offset: offset, - length: length, - insert: insert, - ); + return ChoreoEditModel(offset: offset, length: length, insert: insert); } factory ChoreoEditModel.fromJson(Map json) { diff --git a/lib/pangea/choreographer/choreo_record_model.dart b/lib/pangea/choreographer/choreo_record_model.dart index 502977e06..cc02fd108 100644 --- a/lib/pangea/choreographer/choreo_record_model.dart +++ b/lib/pangea/choreographer/choreo_record_model.dart @@ -96,11 +96,7 @@ class ChoreoRecordModel { length = textBefore.length - offset; } - textAfter = textBefore.replaceRange( - offset, - offset + length, - insert, - ); + textAfter = textBefore.replaceRange(offset, offset + length, insert); final edits = ChoreoEditModel.fromText( originalText: currentEdit, @@ -143,23 +139,24 @@ class ChoreoRecordModel { Map toJson() { final data = {}; data[_stepsKey] = jsonEncode(choreoSteps.map((e) => e.toJson()).toList()); - data[_openMatchesKey] = - jsonEncode(openMatches.map((e) => e.toJson()).toList()); + data[_openMatchesKey] = jsonEncode( + openMatches.map((e) => e.toJson()).toList(), + ); data[_originalTextKey] = originalText; return data; } bool get includedIT => choreoSteps.any((step) { - return step.acceptedOrIgnoredMatch?.status == - PangeaMatchStatusEnum.accepted && - (step.acceptedOrIgnoredMatch?.isOutOfTargetMatch ?? false); - }); + return step.acceptedOrIgnoredMatch?.status == + PangeaMatchStatusEnum.accepted && + (step.acceptedOrIgnoredMatch?.isOutOfTargetMatch ?? false); + }); bool get includedIGC => choreoSteps.any((step) { - return step.acceptedOrIgnoredMatch?.status == - PangeaMatchStatusEnum.accepted && - (step.acceptedOrIgnoredMatch?.isGrammarMatch ?? false); - }); + return step.acceptedOrIgnoredMatch?.status == + PangeaMatchStatusEnum.accepted && + (step.acceptedOrIgnoredMatch?.isGrammarMatch ?? false); + }); bool endedWithIT(String sent) { return includedIT && stepText() == sent; diff --git a/lib/pangea/choreographer/choreographer.dart b/lib/pangea/choreographer/choreographer.dart index 0b198eeff..10b20b9bb 100644 --- a/lib/pangea/choreographer/choreographer.dart +++ b/lib/pangea/choreographer/choreographer.dart @@ -57,9 +57,7 @@ class Choreographer extends ChangeNotifier { StreamSubscription? _acceptedContinuanceSub; StreamSubscription? _updatedMatchSub; - Choreographer( - this.inputFocus, - ) { + Choreographer(this.inputFocus) { _initialize(); } @@ -70,10 +68,10 @@ class Choreographer extends ChangeNotifier { String get currentText => textController.text; ChoreoRecordModel get _record => _choreoRecord ??= ChoreoRecordModel( - originalText: textController.text, - choreoSteps: [], - openMatches: [], - ); + originalText: textController.text, + choreoSteps: [], + openMatches: [], + ); bool _backoffRequest(DateTime? error, int backoffSeconds) { if (error == null) return false; @@ -106,22 +104,29 @@ class Choreographer extends ChangeNotifier { ); _languageSub ??= MatrixState - .pangeaController.userController.languageStream.stream + .pangeaController + .userController + .languageStream + .stream .listen((update) { - clear(); - }); + clear(); + }); _settingsUpdateSub ??= MatrixState - .pangeaController.userController.settingsUpdateStream.stream + .pangeaController + .userController + .settingsUpdateStream + .stream .listen((_) { - notifyListeners(); - }); + notifyListeners(); + }); _acceptedContinuanceSub ??= itController.acceptedContinuanceStream.stream .listen(_onAcceptContinuance); - _updatedMatchSub ??= - igcController.matchUpdateStream.stream.listen(_onUpdateMatch); + _updatedMatchSub ??= igcController.matchUpdateStream.stream.listen( + _onUpdateMatch, + ); } void clear() { @@ -239,9 +244,7 @@ class Choreographer extends ChangeNotifier { textController.editType = EditTypeEnum.keyboard; } - Future requestWritingAssistance({ - bool manual = false, - }) async { + Future requestWritingAssistance({bool manual = false}) async { if (assistanceState != AssistanceStateEnum.notFetched) return; final SubscriptionStatus canSendStatus = MatrixState.pangeaController.subscriptionController.subscriptionStatus; @@ -261,10 +264,7 @@ class Choreographer extends ChangeNotifier { _resetDebounceTimer(); _startLoading(); - await igcController.getIGCTextData( - textController.text, - [], - ); + await igcController.getIGCTextData(textController.text, []); // init choreo record to record the original text before any matches are applied _choreoRecord ??= ChoreoRecordModel( @@ -277,15 +277,13 @@ class Choreographer extends ChangeNotifier { await igcController.acceptNormalizationMatches(); } else { // trigger a re-render of the text field to show IGC matches - textController.setSystemText( - textController.text, - EditTypeEnum.igc, - ); + textController.setSystemText(textController.text, EditTypeEnum.igc); } _stopLoading(); - if (!igcController.openMatches - .any((match) => match.updatedMatch.isITStart)) { + if (!igcController.openMatches.any( + (match) => match.updatedMatch.isITStart, + )) { igcController.fetchAllSpanDetails().catchError((e) => clearMatches(e)); } } @@ -299,19 +297,20 @@ class Choreographer extends ChangeNotifier { if (l1LangCode != null && l2LangCode != null && !_backoffRequest(_lastTokensError, _tokenErrorBackoff)) { - final res = await TokensRepo.get( - MatrixState.pangeaController.userController.accessToken, - TokensRequestModel( - fullText: message, - senderL1: l1LangCode, - senderL2: l2LangCode, - ), - ).timeout( - const Duration(seconds: 10), - onTimeout: () { - return Result.error("Token request timed out"); - }, - ); + final res = + await TokensRepo.get( + MatrixState.pangeaController.userController.accessToken, + TokensRequestModel( + fullText: message, + senderL1: l1LangCode, + senderL2: l2LangCode, + ), + ).timeout( + const Duration(seconds: 10), + onTimeout: () { + return Result.error("Token request timed out"); + }, + ); if (res.isError) { _lastTokensError = DateTime.now(); @@ -362,10 +361,7 @@ class Choreographer extends ChangeNotifier { igcController.clear(); itMatch.setStatus(PangeaMatchStatusEnum.accepted); - _record.addRecord( - "", - match: itMatch.updatedMatch, - ); + _record.addRecord("", match: itMatch.updatedMatch); _setChoreoMode(ChoreoModeEnum.it); textController.setSystemText("", EditTypeEnum.it); @@ -411,19 +407,13 @@ class Choreographer extends ChangeNotifier { } void _onUpdateMatch(PangeaMatchState match) { - textController.setSystemText( - igcController.currentText!, - EditTypeEnum.igc, - ); + textController.setSystemText(igcController.currentText!, EditTypeEnum.igc); switch (match.updatedMatch.status) { case PangeaMatchStatusEnum.accepted: case PangeaMatchStatusEnum.automatic: case PangeaMatchStatusEnum.ignored: - _record.addRecord( - textController.text, - match: match.updatedMatch, - ); + _record.addRecord(textController.text, match: match.updatedMatch); case PangeaMatchStatusEnum.undo: _record.choreoSteps.removeWhere( (step) => diff --git a/lib/pangea/choreographer/choreographer_send_button.dart b/lib/pangea/choreographer/choreographer_send_button.dart index b367ee482..69a6c6a15 100644 --- a/lib/pangea/choreographer/choreographer_send_button.dart +++ b/lib/pangea/choreographer/choreographer_send_button.dart @@ -6,10 +6,7 @@ import 'package:fluffychat/pangea/choreographer/choreographer_state_extension.da class ChoreographerSendButton extends StatelessWidget { final ChatController controller; - const ChoreographerSendButton({ - super.key, - required this.controller, - }); + const ChoreographerSendButton({super.key, required this.controller}); Future _onPressed(BuildContext context) async { controller.choreographer.onClickSend(); @@ -20,14 +17,15 @@ class ChoreographerSendButton extends StatelessWidget { Widget build(BuildContext context) { return ValueListenableBuilder( valueListenable: controller.choreographer.isFetching, - builder: (context, fetching, __) { + builder: (context, fetching, _) { return Container( height: 56, alignment: Alignment.center, child: IconButton( icon: const Icon(Icons.send_outlined), - color: controller.choreographer.assistanceState - .sendButtonColor(context), + color: controller.choreographer.assistanceState.sendButtonColor( + context, + ), onPressed: fetching ? null : () => _onPressed(context), tooltip: L10n.of(context).send, ), diff --git a/lib/pangea/choreographer/igc/autocorrect_popup.dart b/lib/pangea/choreographer/igc/autocorrect_popup.dart index dc49d053a..e4f4e332f 100644 --- a/lib/pangea/choreographer/igc/autocorrect_popup.dart +++ b/lib/pangea/choreographer/igc/autocorrect_popup.dart @@ -25,10 +25,7 @@ class AutocorrectPopup extends StatelessWidget { spacing: 8.0, children: [ Text(originalText), - InkWell( - onTap: onUndo, - child: const Icon(Icons.replay, size: 12), - ), + InkWell(onTap: onUndo, child: const Icon(Icons.replay, size: 12)), ], ), ), diff --git a/lib/pangea/choreographer/igc/autocorrect_span.dart b/lib/pangea/choreographer/igc/autocorrect_span.dart index 5517172d1..02607f997 100644 --- a/lib/pangea/choreographer/igc/autocorrect_span.dart +++ b/lib/pangea/choreographer/igc/autocorrect_span.dart @@ -13,33 +13,33 @@ class AutocorrectSpan extends WidgetSpan { required VoidCallback onUndo, required TextStyle style, }) : super( - alignment: PlaceholderAlignment.middle, - child: CompositedTransformTarget( - link: MatrixState.pAnyState.layerLinkAndKey(transformTargetId).link, - child: Builder( - builder: (context) { - return RichText( - key: MatrixState.pAnyState - .layerLinkAndKey(transformTargetId) - .key, - text: TextSpan( - text: currentText, - style: style, - recognizer: TapGestureRecognizer() - ..onTap = () { - OverlayUtil.showOverlay( - context: context, - child: AutocorrectPopup( - originalText: originalText, - onUndo: onUndo, - ), - transformTargetId: transformTargetId, - ); - }, - ), - ); - }, - ), - ), - ); + alignment: PlaceholderAlignment.middle, + child: CompositedTransformTarget( + link: MatrixState.pAnyState.layerLinkAndKey(transformTargetId).link, + child: Builder( + builder: (context) { + return RichText( + key: MatrixState.pAnyState + .layerLinkAndKey(transformTargetId) + .key, + text: TextSpan( + text: currentText, + style: style, + recognizer: TapGestureRecognizer() + ..onTap = () { + OverlayUtil.showOverlay( + context: context, + child: AutocorrectPopup( + originalText: originalText, + onUndo: onUndo, + ), + transformTargetId: transformTargetId, + ); + }, + ), + ); + }, + ), + ), + ); } diff --git a/lib/pangea/choreographer/igc/igc_controller.dart b/lib/pangea/choreographer/igc/igc_controller.dart index 9b78cb439..6cf2e8f1e 100644 --- a/lib/pangea/choreographer/igc/igc_controller.dart +++ b/lib/pangea/choreographer/igc/igc_controller.dart @@ -33,12 +33,12 @@ class IgcController { String? get currentText => _currentText; List get openMatches => _openMatches; - List get recentAutomaticCorrections => - _closedMatches.reversed - .takeWhile( - (m) => m.updatedMatch.status == PangeaMatchStatusEnum.automatic, - ) - .toList(); + List get recentAutomaticCorrections => _closedMatches + .reversed + .takeWhile( + (m) => m.updatedMatch.status == PangeaMatchStatusEnum.automatic, + ) + .toList(); List get openAutomaticMatches => _openMatches .where((match) => match.updatedMatch.match.isNormalizationError()) @@ -46,8 +46,9 @@ class IgcController { PangeaMatchState? get currentlyOpenMatch { final RegExp pattern = RegExp(r'span_card_overlay_.+'); - final String? matchingKey = - MatrixState.pAnyState.getMatchingOverlayKeys(pattern).firstOrNull; + final String? matchingKey = MatrixState.pAnyState + .getMatchingOverlayKeys(pattern) + .firstOrNull; if (matchingKey == null) return null; final parts = matchingKey.split('_'); @@ -66,24 +67,23 @@ class IgcController { IGCRequestModel _igcRequest( String text, List prevMessages, - ) => - IGCRequestModel( - fullText: text, - userId: MatrixState.pangeaController.userController.client.userID!, - userL1: MatrixState.pangeaController.userController.userL1Code!, - userL2: MatrixState.pangeaController.userController.userL2Code!, - enableIGC: true, - enableIT: true, - prevMessages: prevMessages, - ); + ) => IGCRequestModel( + fullText: text, + userId: MatrixState.pangeaController.userController.client.userID!, + userL1: MatrixState.pangeaController.userController.userL1Code!, + userL2: MatrixState.pangeaController.userController.userL2Code!, + enableIGC: true, + enableIT: true, + prevMessages: prevMessages, + ); SpanDetailsRequest _spanDetailsRequest(SpanData span) => SpanDetailsRequest( - userL1: MatrixState.pangeaController.userController.userL1Code!, - userL2: MatrixState.pangeaController.userController.userL2Code!, - enableIGC: true, - enableIT: true, - span: span, - ); + userL1: MatrixState.pangeaController.userController.userL1Code!, + userL2: MatrixState.pangeaController.userController.userL2Code!, + enableIGC: true, + enableIT: true, + span: span, + ); void dispose() { matchUpdateStream.close(); @@ -125,10 +125,7 @@ class IgcController { _openMatches.add(matchState); } - void updateMatch( - PangeaMatchState match, - PangeaMatchStatusEnum status, - ) { + void updateMatch(PangeaMatchState match, PangeaMatchStatusEnum status) { PangeaMatchState updated; switch (status) { case PangeaMatchStatusEnum.accepted: @@ -151,9 +148,8 @@ class IgcController { ) { final PangeaMatchState openMatch = _openMatches.firstWhere( (m) => m.originalMatch == matchState.originalMatch, - orElse: () => throw StateError( - 'No open match found while updating match.', - ), + orElse: () => + throw StateError('No open match found while updating match.'), ); matchState.setStatus(status); @@ -165,9 +161,7 @@ class IgcController { case PangeaMatchStatusEnum.automatic: final choice = matchState.updatedMatch.match.selectedChoice; if (choice == null) { - throw ArgumentError( - 'acceptMatch called with a null selectedChoice.', - ); + throw ArgumentError('acceptMatch called with a null selectedChoice.'); } _applyReplacement( matchState.updatedMatch.match.offset, @@ -191,9 +185,8 @@ class IgcController { ) { final closedMatch = _closedMatches.firstWhere( (m) => m.originalMatch == matchState.originalMatch, - orElse: () => throw StateError( - 'No closed match found while updating match.', - ), + orElse: () => + throw StateError('No closed match found while updating match.'), ); matchState.setStatus(status); @@ -201,9 +194,7 @@ class IgcController { final selectedValue = matchState.updatedMatch.match.selectedChoice?.value; if (selectedValue == null) { - throw StateError( - 'Cannot update match without a selectedChoice value.', - ); + throw StateError('Cannot update match without a selectedChoice value.'); } final replacement = matchState.originalMatch.match.fullText.characters @@ -257,11 +248,7 @@ class IgcController { } }); } catch (e, s) { - ErrorHandler.logError( - e: e, - s: s, - data: {"currentText": currentText}, - ); + ErrorHandler.logError(e: e, s: s, data: {"currentText": currentText}); if (!completer.isCompleted) completer.complete(); } @@ -271,11 +258,7 @@ class IgcController { /// Applies a text replacement to [_currentText] and adjusts match offsets. /// /// Called internally when a correction is accepted or undone. - void _applyReplacement( - int offset, - int length, - String replacement, - ) { + void _applyReplacement(int offset, int length, String replacement) { if (_currentText == null) { throw StateError('_applyReplacement called with null _currentText'); } @@ -306,17 +289,16 @@ class IgcController { if (_isFetching) return; _isFetching = true; - final res = await IgcRepo.get( - MatrixState.pangeaController.userController.accessToken, - _igcRequest(text, prevMessages), - ).timeout( - (const Duration(seconds: 10)), - onTimeout: () { - return Result.error( - TimeoutException('IGC request timed out'), + final res = + await IgcRepo.get( + MatrixState.pangeaController.userController.accessToken, + _igcRequest(text, prevMessages), + ).timeout( + (const Duration(seconds: 10)), + onTimeout: () { + return Result.error(TimeoutException('IGC request timed out')); + }, ); - }, - ); if (res.isError) { onError(res.asError!); @@ -353,17 +335,18 @@ class IgcController { return; } - final response = await SpanDataRepo.get( - MatrixState.pangeaController.userController.accessToken, - request: _spanDetailsRequest(span), - ).timeout( - (const Duration(seconds: 10)), - onTimeout: () { - return Result.error( - TimeoutException('Span details request timed out'), + final response = + await SpanDataRepo.get( + MatrixState.pangeaController.userController.accessToken, + request: _spanDetailsRequest(span), + ).timeout( + (const Duration(seconds: 10)), + onTimeout: () { + return Result.error( + TimeoutException('Span details request timed out'), + ); + }, ); - }, - ); if (response.isError) throw response.error!; setSpanData(match, response.result!); diff --git a/lib/pangea/choreographer/igc/igc_repo.dart b/lib/pangea/choreographer/igc/igc_repo.dart index 3ffbc5d07..85e29c7fb 100644 --- a/lib/pangea/choreographer/igc/igc_repo.dart +++ b/lib/pangea/choreographer/igc/igc_repo.dart @@ -17,10 +17,7 @@ class _IgcCacheItem { final Future data; final DateTime timestamp; - const _IgcCacheItem({ - required this.data, - required this.timestamp, - }); + const _IgcCacheItem({required this.data, required this.timestamp}); } class _IgnoredMatchCacheItem { @@ -41,10 +38,7 @@ class _IgnoredMatchCacheItem { @override int get hashCode => spanText.hashCode; - _IgnoredMatchCacheItem({ - required this.match, - required this.timestamp, - }); + _IgnoredMatchCacheItem({required this.match, required this.timestamp}); } class IgcRepo { @@ -61,10 +55,7 @@ class IgcRepo { return _getResult(igcRequest, cached); } - final future = _fetch( - accessToken, - igcRequest: igcRequest, - ); + final future = _fetch(accessToken, igcRequest: igcRequest); _setCached(igcRequest, future); return _getResult(igcRequest, future); } @@ -88,8 +79,9 @@ class IgcRepo { ); } - final Map json = - jsonDecode(utf8.decode(res.bodyBytes).toString()); + final Map json = jsonDecode( + utf8.decode(res.bodyBytes).toString(), + ); return IGCResponseModel.fromJson(json); } @@ -103,23 +95,17 @@ class IgcRepo { return Result.value(res); } catch (e, s) { _igcCache.remove(request.hashCode.toString()); - ErrorHandler.logError( - e: e, - s: s, - data: request.toJson(), - ); + ErrorHandler.logError(e: e, s: s, data: request.toJson()); return Result.error(e); } } - static Future? _getCached( - IGCRequestModel request, - ) { + static Future? _getCached(IGCRequestModel request) { final cacheKeys = [..._igcCache.keys]; for (final key in cacheKeys) { - if (_igcCache[key]! - .timestamp - .isBefore(DateTime.now().subtract(_cacheDuration))) { + if (_igcCache[key]!.timestamp.isBefore( + DateTime.now().subtract(_cacheDuration), + )) { _igcCache.remove(key); } } @@ -130,11 +116,10 @@ class IgcRepo { static void _setCached( IGCRequestModel request, Future response, - ) => - _igcCache[request.hashCode.toString()] = _IgcCacheItem( - data: response, - timestamp: DateTime.now(), - ); + ) => _igcCache[request.hashCode.toString()] = _IgcCacheItem( + data: response, + timestamp: DateTime.now(), + ); static void ignore(PangeaMatch match) { _setCachedIgnoredSpan(match); @@ -145,9 +130,7 @@ class IgcRepo { return cached != null; } - static PangeaMatch? _getCachedIgnoredSpan( - PangeaMatch match, - ) { + static PangeaMatch? _getCachedIgnoredSpan(PangeaMatch match) { final cacheKeys = [..._ignoredMatchCache.keys]; for (final key in cacheKeys) { final entry = _ignoredMatchCache[key]!; @@ -163,9 +146,7 @@ class IgcRepo { return _ignoredMatchCache[cacheEntry.hashCode.toString()]?.match; } - static void _setCachedIgnoredSpan( - PangeaMatch match, - ) { + static void _setCachedIgnoredSpan(PangeaMatch match) { final cacheEntry = _IgnoredMatchCacheItem( match: match, timestamp: DateTime.now(), diff --git a/lib/pangea/choreographer/igc/igc_request_model.dart b/lib/pangea/choreographer/igc/igc_request_model.dart index cbe6a41eb..bda0edac7 100644 --- a/lib/pangea/choreographer/igc/igc_request_model.dart +++ b/lib/pangea/choreographer/igc/igc_request_model.dart @@ -22,15 +22,16 @@ class IGCRequestModel { }); Map toJson() => { - ModelKey.fullText: fullText, - ModelKey.userL1: userL1, - ModelKey.userL2: userL2, - ModelKey.enableIT: enableIT, - ModelKey.enableIGC: enableIGC, - ModelKey.userId: userId, - ModelKey.prevMessages: - jsonEncode(prevMessages.map((x) => x.toJson()).toList()), - }; + ModelKey.fullText: fullText, + ModelKey.userL1: userL1, + ModelKey.userL2: userL2, + ModelKey.enableIT: enableIT, + ModelKey.enableIGC: enableIGC, + ModelKey.userId: userId, + ModelKey.prevMessages: jsonEncode( + prevMessages.map((x) => x.toJson()).toList(), + ), + }; @override bool operator ==(Object other) { @@ -47,14 +48,8 @@ class IGCRequestModel { } @override - int get hashCode => Object.hash( - fullText.trim(), - userL1, - userL2, - enableIT, - enableIGC, - userId, - ); + int get hashCode => + Object.hash(fullText.trim(), userL1, userL2, enableIT, enableIGC, userId); } /// Previous text/audio message sent in chat @@ -80,10 +75,10 @@ class PreviousMessage { ); Map toJson() => { - ModelKey.prevContent: content, - ModelKey.prevSender: sender, - ModelKey.prevTimestamp: timestamp.toIso8601String(), - }; + ModelKey.prevContent: content, + ModelKey.prevSender: sender, + ModelKey.prevTimestamp: timestamp.toIso8601String(), + }; @override bool operator ==(Object other) { @@ -98,10 +93,6 @@ class PreviousMessage { @override int get hashCode { - return Object.hash( - content, - sender, - timestamp, - ); + return Object.hash(content, sender, timestamp); } } diff --git a/lib/pangea/choreographer/igc/igc_response_model.dart b/lib/pangea/choreographer/igc/igc_response_model.dart index aed6b4bcd..23ad87086 100644 --- a/lib/pangea/choreographer/igc/igc_response_model.dart +++ b/lib/pangea/choreographer/igc/igc_response_model.dart @@ -24,13 +24,11 @@ class IGCResponseModel { return IGCResponseModel( matches: json["matches"] != null ? (json["matches"] as Iterable) - .map( - (e) { + .map((e) { return PangeaMatch.fromJson(e as Map); - }, - ) - .toList() - .cast() + }) + .toList() + .cast() : [], originalInput: json["original_input"], fullTextCorrection: json["full_text_correction"], @@ -42,12 +40,12 @@ class IGCResponseModel { } Map toJson() => { - "original_input": originalInput, - "full_text_correction": fullTextCorrection, - "matches": matches.map((e) => e.toJson()).toList(), - ModelKey.userL1: userL1, - ModelKey.userL2: userL2, - ModelKey.enableIT: enableIT, - ModelKey.enableIGC: enableIGC, - }; + "original_input": originalInput, + "full_text_correction": fullTextCorrection, + "matches": matches.map((e) => e.toJson()).toList(), + ModelKey.userL1: userL1, + ModelKey.userL2: userL2, + ModelKey.enableIT: enableIT, + ModelKey.enableIGC: enableIGC, + }; } diff --git a/lib/pangea/choreographer/igc/pangea_match_model.dart b/lib/pangea/choreographer/igc/pangea_match_model.dart index a2db081f8..b7230553d 100644 --- a/lib/pangea/choreographer/igc/pangea_match_model.dart +++ b/lib/pangea/choreographer/igc/pangea_match_model.dart @@ -7,10 +7,7 @@ class PangeaMatch { final SpanData match; final PangeaMatchStatusEnum status; - const PangeaMatch({ - required this.match, - required this.status, - }); + const PangeaMatch({required this.match, required this.status}); factory PangeaMatch.fromJson(Map json) { return PangeaMatch( @@ -22,17 +19,19 @@ class PangeaMatch { } Map toJson() => { - _matchKey: match.toJson(), - _statusKey: status.name, - }; + _matchKey: match.toJson(), + _statusKey: status.name, + }; static const _matchKey = "match"; static const _statusKey = "status"; bool get isITStart => match.rule?.id == MatchRuleIdModel.interactiveTranslation || - [SpanDataTypeEnum.itStart, SpanDataTypeEnum.itStart.name] - .contains(match.type.typeName); + [ + SpanDataTypeEnum.itStart, + SpanDataTypeEnum.itStart.name, + ].contains(match.type.typeName); bool get _needsTranslation => match.rule?.id != null ? [ diff --git a/lib/pangea/choreographer/igc/pangea_match_state_model.dart b/lib/pangea/choreographer/igc/pangea_match_state_model.dart index 7fb0fcc7d..3418c1a79 100644 --- a/lib/pangea/choreographer/igc/pangea_match_state_model.dart +++ b/lib/pangea/choreographer/igc/pangea_match_state_model.dart @@ -11,16 +11,13 @@ class PangeaMatchState { required PangeaMatch original, required SpanData match, required PangeaMatchStatusEnum status, - }) : _original = original, - _match = match, - _status = status; + }) : _original = original, + _match = match, + _status = status; PangeaMatch get originalMatch => _original; - PangeaMatch get updatedMatch => PangeaMatch( - match: _match, - status: _status, - ); + PangeaMatch get updatedMatch => PangeaMatch(match: _match, status: _status); void setStatus(PangeaMatchStatusEnum status) { _status = status; @@ -44,9 +41,7 @@ class PangeaMatchState { throw Exception('No choices available to select best choice from.'); } selectChoice( - updatedMatch.match.choices!.indexWhere( - (c) => c.isBestCorrection, - ), + updatedMatch.match.choices!.indexWhere((c) => c.isBestCorrection), ); } diff --git a/lib/pangea/choreographer/igc/span_card.dart b/lib/pangea/choreographer/igc/span_card.dart index a69225650..dc8774437 100644 --- a/lib/pangea/choreographer/igc/span_card.dart +++ b/lib/pangea/choreographer/igc/span_card.dart @@ -126,19 +126,14 @@ class SpanCardState extends State { void _updateMatch(PangeaMatchStatusEnum status) { try { - widget.choreographer.igcController.updateMatch( - widget.match, - status, - ); + widget.choreographer.igcController.updateMatch(widget.match, status); widget.showNextMatch(); } catch (e, s) { ErrorHandler.logError( e: e, s: s, level: SentryLevel.warning, - data: { - "match": widget.match.toJson(), - }, + data: {"match": widget.match.toJson()}, ); widget.choreographer.clearMatches(e); return; @@ -180,7 +175,9 @@ class SpanCardState extends State { widget.match.updatedMatch.match.selectedChoiceIndex, id: widget.match.hashCode.toString(), langCode: MatrixState - .pangeaController.userController.userL2Code!, + .pangeaController + .userController + .userL2Code!, ), const SizedBox(), _SpanCardFeedback( @@ -223,28 +220,32 @@ class _SpanCardFeedback extends StatelessWidget { children: [ ValueListenableBuilder( valueListenable: feedbackState, - builder: (context, state, __) { + builder: (context, state, _) { return switch (state) { - AsyncIdle() => hasSelectedChoice - ? IconButton( - onPressed: fetchFeedback, - icon: const Icon(Icons.lightbulb_outline, size: 24), - ) - : Text( - L10n.of(context).correctionDefaultPrompt, - style: BotStyle.text(context).copyWith( - fontStyle: FontStyle.italic, + AsyncIdle() => + hasSelectedChoice + ? IconButton( + onPressed: fetchFeedback, + icon: const Icon(Icons.lightbulb_outline, size: 24), + ) + : Text( + L10n.of(context).correctionDefaultPrompt, + style: BotStyle.text( + context, + ).copyWith(fontStyle: FontStyle.italic), ), - ), AsyncLoading() => const SizedBox( - width: 24, - height: 24, - child: CircularProgressIndicator(), - ), - AsyncError(:final error) => - ErrorIndicator(message: error.toString()), - AsyncLoaded(:final value) => - Text(value, style: BotStyle.text(context)), + width: 24, + height: 24, + child: CircularProgressIndicator(), + ), + AsyncError(:final error) => ErrorIndicator( + message: error.toString(), + ), + AsyncLoaded(:final value) => Text( + value, + style: BotStyle.text(context), + ), }; }, ), @@ -267,9 +268,7 @@ class _SpanCardButtons extends StatelessWidget { @override Widget build(BuildContext context) { return Container( - decoration: BoxDecoration( - color: Theme.of(context).cardColor, - ), + decoration: BoxDecoration(color: Theme.of(context).cardColor), padding: const EdgeInsets.only(top: 12.0), child: Row( spacing: 10.0, @@ -279,13 +278,12 @@ class _SpanCardButtons extends StatelessWidget { opacity: 0.8, child: TextButton( style: TextButton.styleFrom( - backgroundColor: - Theme.of(context).colorScheme.primary.withAlpha(25), + backgroundColor: Theme.of( + context, + ).colorScheme.primary.withAlpha(25), ), onPressed: onIgnore, - child: Center( - child: Text(L10n.of(context).ignoreInThisText), - ), + child: Center(child: Text(L10n.of(context).ignoreInThisText)), ), ), ), @@ -295,9 +293,10 @@ class _SpanCardButtons extends StatelessWidget { child: TextButton( onPressed: selectedChoice != null ? onAccept : null, style: TextButton.styleFrom( - backgroundColor: (selectedChoice?.color ?? - Theme.of(context).colorScheme.primary) - .withAlpha(50), + backgroundColor: + (selectedChoice?.color ?? + Theme.of(context).colorScheme.primary) + .withAlpha(50), side: selectedChoice != null ? BorderSide( color: selectedChoice!.color, diff --git a/lib/pangea/choreographer/igc/span_choice_type_enum.dart b/lib/pangea/choreographer/igc/span_choice_type_enum.dart index af8dccb32..829e120c3 100644 --- a/lib/pangea/choreographer/igc/span_choice_type_enum.dart +++ b/lib/pangea/choreographer/igc/span_choice_type_enum.dart @@ -2,11 +2,7 @@ import 'package:flutter/material.dart'; import 'package:fluffychat/l10n/l10n.dart'; -enum SpanChoiceTypeEnum { - bestCorrection, - distractor, - bestAnswer, -} +enum SpanChoiceTypeEnum { bestCorrection, distractor, bestAnswer } extension SpanChoiceExt on SpanChoiceTypeEnum { String get name { diff --git a/lib/pangea/choreographer/igc/span_data_model.dart b/lib/pangea/choreographer/igc/span_data_model.dart index ac65a1347..99fcda558 100644 --- a/lib/pangea/choreographer/igc/span_data_model.dart +++ b/lib/pangea/choreographer/igc/span_data_model.dart @@ -102,9 +102,7 @@ class SpanData { offset >= this.offset && offset <= this.offset + length; SpanChoice? get bestChoice { - return choices?.firstWhereOrNull( - (choice) => choice.isBestCorrection, - ); + return choices?.firstWhereOrNull((choice) => choice.isBestCorrection); } int get selectedChoiceIndex { @@ -137,9 +135,7 @@ class SpanData { bool isNormalizationError() { final correctChoice = choices - ?.firstWhereOrNull( - (c) => c.isBestCorrection, - ) + ?.firstWhereOrNull((c) => c.isBestCorrection) ?.value; final l2Code = @@ -225,22 +221,20 @@ class SpanChoice { value: json['value'] as String, type: json['type'] != null ? SpanChoiceTypeEnum.values.firstWhereOrNull( - (element) => element.name == json['type'], - ) ?? - SpanChoiceTypeEnum.bestCorrection + (element) => element.name == json['type'], + ) ?? + SpanChoiceTypeEnum.bestCorrection : SpanChoiceTypeEnum.bestCorrection, feedback: json['feedback'], selected: json['selected'] ?? false, - timestamp: - json['timestamp'] != null ? DateTime.parse(json['timestamp']) : null, + timestamp: json['timestamp'] != null + ? DateTime.parse(json['timestamp']) + : null, ); } Map toJson() { - final Map data = { - 'value': value, - 'type': type.name, - }; + final Map data = {'value': value, 'type': type.name}; if (selected) { data['selected'] = selected; @@ -294,17 +288,12 @@ class SpanChoice { class Rule { final String id; - const Rule({ - required this.id, - }); + const Rule({required this.id}); - factory Rule.fromJson(Map json) => Rule( - id: json['id'] as String, - ); + factory Rule.fromJson(Map json) => + Rule(id: json['id'] as String); - Map toJson() => { - 'id': id, - }; + Map toJson() => {'id': id}; @override bool operator ==(Object other) { @@ -322,25 +311,22 @@ class Rule { class SpanDataType { final SpanDataTypeEnum typeName; - const SpanDataType({ - required this.typeName, - }); + const SpanDataType({required this.typeName}); factory SpanDataType.fromJson(Map json) { final String? type = json['typeName'] ?? json['type'] ?? json['type_name'] as String?; return SpanDataType( typeName: type != null - ? SpanDataTypeEnum.values - .firstWhereOrNull((element) => element.name == type) ?? - SpanDataTypeEnum.correction + ? SpanDataTypeEnum.values.firstWhereOrNull( + (element) => element.name == type, + ) ?? + SpanDataTypeEnum.correction : SpanDataTypeEnum.correction, ); } - Map toJson() => { - 'type_name': typeName.name, - }; + Map toJson() => {'type_name': typeName.name}; @override bool operator ==(Object other) { diff --git a/lib/pangea/choreographer/igc/span_data_repo.dart b/lib/pangea/choreographer/igc/span_data_repo.dart index 7c07825bc..c19a9aafe 100644 --- a/lib/pangea/choreographer/igc/span_data_repo.dart +++ b/lib/pangea/choreographer/igc/span_data_repo.dart @@ -15,10 +15,7 @@ class _SpanDetailsCacheItem { final Future data; final DateTime timestamp; - const _SpanDetailsCacheItem({ - required this.data, - required this.timestamp, - }); + const _SpanDetailsCacheItem({required this.data, required this.timestamp}); } class SpanDataRepo { @@ -34,10 +31,7 @@ class SpanDataRepo { return _getResult(request, cached); } - final future = _fetch( - accessToken, - request: request, - ); + final future = _fetch(accessToken, request: request); _setCached(request, future); return _getResult(request, future); } @@ -75,18 +69,12 @@ class SpanDataRepo { return Result.value(res); } catch (e, s) { _cache.remove(request.hashCode.toString()); - ErrorHandler.logError( - e: e, - s: s, - data: request.toJson(), - ); + ErrorHandler.logError(e: e, s: s, data: request.toJson()); return Result.error(e); } } - static Future? _getCached( - SpanDetailsRequest request, - ) { + static Future? _getCached(SpanDetailsRequest request) { final cacheKeys = [..._cache.keys]; for (final key in cacheKeys) { if (DateTime.now().difference(_cache[key]!.timestamp) >= _cacheDuration) { diff --git a/lib/pangea/choreographer/igc/span_data_request.dart b/lib/pangea/choreographer/igc/span_data_request.dart index 50fd6441b..88b80f139 100644 --- a/lib/pangea/choreographer/igc/span_data_request.dart +++ b/lib/pangea/choreographer/igc/span_data_request.dart @@ -17,12 +17,12 @@ class SpanDetailsRequest { }); Map toJson() => { - ModelKey.userL1: userL1, - ModelKey.userL2: userL2, - ModelKey.enableIT: enableIT, - ModelKey.enableIGC: enableIGC, - 'span': span.toJson(), - }; + ModelKey.userL1: userL1, + ModelKey.userL2: userL2, + ModelKey.enableIT: enableIT, + ModelKey.enableIGC: enableIGC, + 'span': span.toJson(), + }; @override bool operator ==(Object other) { diff --git a/lib/pangea/choreographer/igc/span_data_type_enum.dart b/lib/pangea/choreographer/igc/span_data_type_enum.dart index d3cfa4b87..567ae2658 100644 --- a/lib/pangea/choreographer/igc/span_data_type_enum.dart +++ b/lib/pangea/choreographer/igc/span_data_type_enum.dart @@ -3,12 +3,7 @@ import 'package:flutter/material.dart'; import 'package:fluffychat/l10n/l10n.dart'; import 'package:fluffychat/widgets/matrix.dart'; -enum SpanDataTypeEnum { - definition, - practice, - correction, - itStart, -} +enum SpanDataTypeEnum { definition, practice, correction, itStart } extension SpanDataTypeEnumExt on SpanDataTypeEnum { String get name { @@ -34,8 +29,9 @@ extension SpanDataTypeEnumExt on SpanDataTypeEnum { return L10n.of(context).correctionDefaultPrompt; case SpanDataTypeEnum.itStart: return L10n.of(context).needsItMessage( - MatrixState.pangeaController.userController.userL2 - ?.getDisplayName(context) ?? + MatrixState.pangeaController.userController.userL2?.getDisplayName( + context, + ) ?? L10n.of(context).targetLanguage, ); } diff --git a/lib/pangea/choreographer/igc/start_igc_button.dart b/lib/pangea/choreographer/igc/start_igc_button.dart index 34db5f2d3..1340e899d 100644 --- a/lib/pangea/choreographer/igc/start_igc_button.dart +++ b/lib/pangea/choreographer/igc/start_igc_button.dart @@ -41,26 +41,25 @@ class _StartIGCButtonState extends State @override void initState() { super.initState(); - _spinController = AnimationController( - vsync: this, - duration: const Duration(milliseconds: 300), - )..addStatusListener((status) { - if (status == AnimationStatus.completed) { - if (_shouldStop) { - _spinController?.stop(); - _spinController?.value = 0; - } else { - _spinController?.forward(from: 0); + _spinController = + AnimationController( + vsync: this, + duration: const Duration(milliseconds: 300), + )..addStatusListener((status) { + if (status == AnimationStatus.completed) { + if (_shouldStop) { + _spinController?.stop(); + _spinController?.value = 0; + } else { + _spinController?.forward(from: 0); + } } - } - }); + }); - _rotation = Tween(begin: 0.0, end: 1.0).animate( - CurvedAnimation( - parent: _spinController!, - curve: Curves.linear, - ), - ); + _rotation = Tween( + begin: 0.0, + end: 1.0, + ).animate(CurvedAnimation(parent: _spinController!, curve: Curves.linear)); _colorController = AnimationController( vsync: this, @@ -137,10 +136,10 @@ class _StartIGCButtonState extends State onTap: enableFeedback ? widget.onPressed : null, onLongPress: enableFeedback ? () => showDialog( - context: context, - builder: (c) => const SettingsLearning(), - barrierDismissible: false, - ) + context: context, + builder: (c) => const SettingsLearning(), + barrierDismissible: false, + ) : null, child: Stack( alignment: Alignment.center, @@ -175,11 +174,7 @@ class _StartIGCButtonState extends State color: _backgroundColor.value, ), ), - Icon( - size: 16, - Icons.check, - color: _iconColor.value, - ), + Icon(size: 16, Icons.check, color: _iconColor.value), ], ), ), diff --git a/lib/pangea/choreographer/igc/text_normalization_util.dart b/lib/pangea/choreographer/igc/text_normalization_util.dart index 08364c3e7..b08a491c7 100644 --- a/lib/pangea/choreographer/igc/text_normalization_util.dart +++ b/lib/pangea/choreographer/igc/text_normalization_util.dart @@ -29,11 +29,7 @@ String normalizeString(String input, String languageCode) { // Step 5: Normalize whitespace (collapse multiple spaces, trim) return normalized.replaceAll(RegExp(r'\s+'), '').trim(); } catch (e, s) { - ErrorHandler.logError( - e: e, - s: s, - data: {'input': input}, - ); + ErrorHandler.logError(e: e, s: s, data: {'input': input}); return input; } } diff --git a/lib/pangea/choreographer/it/completed_it_step_model.dart b/lib/pangea/choreographer/it/completed_it_step_model.dart index e1af2afff..5eafc6f05 100644 --- a/lib/pangea/choreographer/it/completed_it_step_model.dart +++ b/lib/pangea/choreographer/it/completed_it_step_model.dart @@ -7,10 +7,7 @@ class CompletedITStepModel { final List continuances; final int chosen; - const CompletedITStepModel( - this.continuances, { - required this.chosen, - }); + const CompletedITStepModel(this.continuances, {required this.chosen}); Map toJson() { final Map data = {}; @@ -24,10 +21,7 @@ class CompletedITStepModel { for (final Map continuance in json['continuances']) { continuances.add(ContinuanceModel.fromJson(continuance)); } - return CompletedITStepModel( - continuances, - chosen: json['chosen'], - ); + return CompletedITStepModel(continuances, chosen: json['chosen']); } ContinuanceModel? get chosenContinuance { diff --git a/lib/pangea/choreographer/it/contextual_definition_repo.dart b/lib/pangea/choreographer/it/contextual_definition_repo.dart index 8d6a5a616..3050d28b2 100644 --- a/lib/pangea/choreographer/it/contextual_definition_repo.dart +++ b/lib/pangea/choreographer/it/contextual_definition_repo.dart @@ -23,11 +23,7 @@ class ContextualDefinitionRepo { return Result.value(await cached); } catch (e, s) { _cache.remove(request.hashCode.toString()); - ErrorHandler.logError( - e: e, - s: s, - data: request.toJson(), - ); + ErrorHandler.logError(e: e, s: s, data: request.toJson()); return Result.error(e); } } @@ -59,20 +55,13 @@ class ContextualDefinitionRepo { final ContextualDefinitionResponseModel response = ContextualDefinitionResponseModel.fromJson( - jsonDecode( - utf8.decode(res.bodyBytes).toString(), - ), - ); + jsonDecode(utf8.decode(res.bodyBytes).toString()), + ); if (response.text.isEmpty) { ErrorHandler.logError( - e: Exception( - "empty text in contextual definition response", - ), - data: { - "request": request.toJson(), - "accessToken": accessToken, - }, + e: Exception("empty text in contextual definition response"), + data: {"request": request.toJson(), "accessToken": accessToken}, ); } @@ -88,23 +77,16 @@ class ContextualDefinitionRepo { return Result.value(res); } catch (e, s) { _cache.remove(request.hashCode.toString()); - ErrorHandler.logError( - e: e, - s: s, - data: request.toJson(), - ); + ErrorHandler.logError(e: e, s: s, data: request.toJson()); return Result.error(e); } } - static Future? _getCached( - ContextualDefinitionRequestModel request, - ) => + static Future? _getCached(ContextualDefinitionRequestModel request) => _cache[request.hashCode.toString()]; static void _setCached( ContextualDefinitionRequestModel request, Future response, - ) => - _cache[request.hashCode.toString()] = response; + ) => _cache[request.hashCode.toString()] = response; } diff --git a/lib/pangea/choreographer/it/contextual_definition_request_model.dart b/lib/pangea/choreographer/it/contextual_definition_request_model.dart index 71376d9e7..a160d5ec3 100644 --- a/lib/pangea/choreographer/it/contextual_definition_request_model.dart +++ b/lib/pangea/choreographer/it/contextual_definition_request_model.dart @@ -16,12 +16,12 @@ class ContextualDefinitionRequestModel { }); Map toJson() => { - ModelKey.fullText: fullText, - ModelKey.word: word, - ModelKey.lang: feedbackLang, - ModelKey.fullTextLang: fullTextLang, - ModelKey.wordLang: wordLang, - }; + ModelKey.fullText: fullText, + ModelKey.word: word, + ModelKey.lang: feedbackLang, + ModelKey.fullTextLang: fullTextLang, + ModelKey.wordLang: wordLang, + }; @override bool operator ==(Object other) => diff --git a/lib/pangea/choreographer/it/contextual_definition_response_model.dart b/lib/pangea/choreographer/it/contextual_definition_response_model.dart index 7b3cd613a..fb6e2a032 100644 --- a/lib/pangea/choreographer/it/contextual_definition_response_model.dart +++ b/lib/pangea/choreographer/it/contextual_definition_response_model.dart @@ -5,6 +5,5 @@ class ContextualDefinitionResponseModel { factory ContextualDefinitionResponseModel.fromJson( Map json, - ) => - ContextualDefinitionResponseModel(text: json["response"]); + ) => ContextualDefinitionResponseModel(text: json["response"]); } diff --git a/lib/pangea/choreographer/it/gold_route_tracker_model.dart b/lib/pangea/choreographer/it/gold_route_tracker_model.dart index dfb2d61c3..47a7a9be4 100644 --- a/lib/pangea/choreographer/it/gold_route_tracker_model.dart +++ b/lib/pangea/choreographer/it/gold_route_tracker_model.dart @@ -5,7 +5,7 @@ class GoldRouteTrackerModel { final List continuances; const GoldRouteTrackerModel(this.continuances, String originalText) - : _originalText = originalText; + : _originalText = originalText; ContinuanceModel? currentContinuance({ required String currentText, diff --git a/lib/pangea/choreographer/it/it_bar.dart b/lib/pangea/choreographer/it/it_bar.dart index fc856954b..d9d1915bf 100644 --- a/lib/pangea/choreographer/it/it_bar.dart +++ b/lib/pangea/choreographer/it/it_bar.dart @@ -21,10 +21,7 @@ import '../../common/widgets/choice_array.dart'; class ITBar extends StatefulWidget { final Choreographer choreographer; - const ITBar({ - super.key, - required this.choreographer, - }); + const ITBar({super.key, required this.choreographer}); @override ITBarState createState() => ITBarState(); @@ -128,9 +125,7 @@ class ITBarState extends State with SingleTickerProviderStateMixin { e: e, s: s, level: SentryLevel.warning, - data: { - "index": index, - }, + data: {"index": index}, ); widget.choreographer.itController.closeIT(); return; @@ -158,9 +153,7 @@ class ITBarState extends State with SingleTickerProviderStateMixin { e: e, s: s, level: SentryLevel.warning, - data: { - "index": index, - }, + data: {"index": index}, ); widget.choreographer.itController.closeIT(); } @@ -229,22 +222,20 @@ class ITBarState extends State with SingleTickerProviderStateMixin { IconButton( onPressed: widget.choreographer.itController.closeIT, - icon: const Icon( - Icons.close, - size: 20, - ), + icon: const Icon(Icons.close, size: 20), ), ], ) : ValueListenableBuilder( valueListenable: widget.choreographer.itController.currentITStep, - builder: (context, step, __) { + builder: (context, step, _) { return step == null ? CircularProgressIndicator( strokeWidth: 2.0, - color: - Theme.of(context).colorScheme.primary, + color: Theme.of( + context, + ).colorScheme.primary, ) : _ITChoices( continuances: step.continuances, @@ -287,7 +278,7 @@ class _ITBarHeader extends StatelessWidget { Widget build(BuildContext context) { return ValueListenableBuilder( valueListenable: editing, - builder: (context, isEditing, __) { + builder: (context, isEditing, _) { return Column( mainAxisSize: MainAxisSize.min, children: [ @@ -326,16 +317,15 @@ class _ITBarHeader extends StatelessWidget { padding: const EdgeInsets.only(left: 8.0, right: 8.0), child: ValueListenableBuilder( valueListenable: progress, - builder: (context, value, __) => AnimatedProgressBar( + builder: (context, value, _) => AnimatedProgressBar( height: 20.0, widthPercent: value, - backgroundColor: Theme.of(context) - .colorScheme - .surfaceContainerHighest, - barColor: Theme.of(context) - .colorScheme - .primary - .withAlpha(180), + backgroundColor: Theme.of( + context, + ).colorScheme.surfaceContainerHighest, + barColor: Theme.of( + context, + ).colorScheme.primary.withAlpha(180), ), ), ), @@ -366,7 +356,7 @@ class _ITBarHeader extends StatelessWidget { ? const SizedBox(height: 24.0) : ValueListenableBuilder( valueListenable: sourceText, - builder: (context, text, __) { + builder: (context, text, _) { return Container( padding: const EdgeInsets.only(top: 8.0), constraints: const BoxConstraints(minHeight: 24.0), diff --git a/lib/pangea/choreographer/it/it_controller.dart b/lib/pangea/choreographer/it/it_controller.dart index 34efef30d..d8f51dc50 100644 --- a/lib/pangea/choreographer/it/it_controller.dart +++ b/lib/pangea/choreographer/it/it_controller.dart @@ -147,7 +147,8 @@ class ITController { chosen: chosenIndex, ), ); - final progress = (_goldRouteTracker!.continuances.indexWhere( + final progress = + (_goldRouteTracker!.continuances.indexWhere( (c) => c.text == _currentITStep.value!.continuances[chosenIndex].text, diff --git a/lib/pangea/choreographer/it/it_feedback_card.dart b/lib/pangea/choreographer/it/it_feedback_card.dart index 39ffbba8d..75df42b79 100644 --- a/lib/pangea/choreographer/it/it_feedback_card.dart +++ b/lib/pangea/choreographer/it/it_feedback_card.dart @@ -16,10 +16,7 @@ import '../../common/widgets/card_error_widget.dart'; class ITFeedbackCard extends StatelessWidget { final FullTextTranslationRequestModel req; - const ITFeedbackCard( - this.req, { - super.key, - }); + const ITFeedbackCard(this.req, {super.key}); Future> _getFeedback() { return FullTextTranslationRepo.get( @@ -47,25 +44,11 @@ class ITFeedbackCard extends StatelessWidget { spacing: 10, alignment: WrapAlignment.center, children: [ - Text( - req.text, - style: BotStyle.text(context), - ), - Text( - "≈", - style: BotStyle.text(context), - ), + Text(req.text, style: BotStyle.text(context)), + Text("≈", style: BotStyle.text(context)), snapshot.hasData - ? Text( - snapshot.data!.result!, - style: BotStyle.text(context), - ) - : TextLoadingShimmer( - width: min( - 140, - 10.0 * req.text.length, - ), - ), + ? Text(snapshot.data!.result!, style: BotStyle.text(context)) + : TextLoadingShimmer(width: min(140, 10.0 * req.text.length)), ], ), ); diff --git a/lib/pangea/choreographer/it/it_repo.dart b/lib/pangea/choreographer/it/it_repo.dart index 7c36b33dc..04ccb5c77 100644 --- a/lib/pangea/choreographer/it/it_repo.dart +++ b/lib/pangea/choreographer/it/it_repo.dart @@ -15,19 +15,14 @@ class _ITCacheItem { final Future response; final DateTime timestamp; - const _ITCacheItem({ - required this.response, - required this.timestamp, - }); + const _ITCacheItem({required this.response, required this.timestamp}); } class ITRepo { static final Map _cache = {}; static const Duration _cacheDuration = Duration(minutes: 10); - static Future> get( - ITRequestModel request, - ) { + static Future> get(ITRequestModel request) { final cached = _getCached(request); if (cached != null) { return _getResult(request, cached); @@ -38,15 +33,15 @@ class ITRepo { return _getResult(request, future); } - static Future _fetch( - ITRequestModel request, - ) async { + static Future _fetch(ITRequestModel request) async { final Requests req = Requests( choreoApiKey: Environment.choreoApiKey, accessToken: MatrixState.pangeaController.userController.accessToken, ); - final Response res = - await req.post(url: PApiUrls.firstStep, body: request.toJson()); + final Response res = await req.post( + url: PApiUrls.firstStep, + body: request.toJson(), + ); if (res.statusCode != 200) { throw Exception('Failed to load interactive translation'); @@ -65,18 +60,12 @@ class ITRepo { return Result.value(res); } catch (e, s) { _cache.remove(request.hashCode.toString()); - ErrorHandler.logError( - e: e, - s: s, - data: request.toJson(), - ); + ErrorHandler.logError(e: e, s: s, data: request.toJson()); return Result.error(e); } } - static Future? _getCached( - ITRequestModel request, - ) { + static Future? _getCached(ITRequestModel request) { final cacheKeys = [..._cache.keys]; for (final key in cacheKeys) { if (DateTime.now().difference(_cache[key]!.timestamp) >= _cacheDuration) { diff --git a/lib/pangea/choreographer/it/it_request_model.dart b/lib/pangea/choreographer/it/it_request_model.dart index ac598be33..5e70a65b4 100644 --- a/lib/pangea/choreographer/it/it_request_model.dart +++ b/lib/pangea/choreographer/it/it_request_model.dart @@ -22,28 +22,28 @@ class ITRequestModel { }); factory ITRequestModel.fromJson(Map json) => ITRequestModel( - text: json[ModelKey.text], - customInput: json['custom_input'], - sourceLangCode: json[ModelKey.srcLang], - targetLangCode: json[ModelKey.tgtLang], - goldTranslation: json[ModelKey.goldTranslation], - goldContinuances: json['gold_continuances'] != null - ? (json['gold_continuances']) - .map((e) => ContinuanceModel.fromJson(e)) - .toList() - : null, - ); + text: json[ModelKey.text], + customInput: json['custom_input'], + sourceLangCode: json[ModelKey.srcLang], + targetLangCode: json[ModelKey.tgtLang], + goldTranslation: json[ModelKey.goldTranslation], + goldContinuances: json['gold_continuances'] != null + ? (json['gold_continuances']) + .map((e) => ContinuanceModel.fromJson(e)) + .toList() + : null, + ); Map toJson() => { - ModelKey.text: text, - 'custom_input': customInput, - ModelKey.srcLang: sourceLangCode, - ModelKey.tgtLang: targetLangCode, - ModelKey.goldTranslation: goldTranslation, - 'gold_continuances': goldContinuances != null - ? List.from(goldContinuances!.map((e) => e.toJson())) - : null, - }; + ModelKey.text: text, + 'custom_input': customInput, + ModelKey.srcLang: sourceLangCode, + ModelKey.tgtLang: targetLangCode, + ModelKey.goldTranslation: goldTranslation, + 'gold_continuances': goldContinuances != null + ? List.from(goldContinuances!.map((e) => e.toJson())) + : null, + }; @override bool operator ==(Object other) { diff --git a/lib/pangea/choreographer/it/it_shimmer.dart b/lib/pangea/choreographer/it/it_shimmer.dart index 33ab1ba28..06912b0ed 100644 --- a/lib/pangea/choreographer/it/it_shimmer.dart +++ b/lib/pangea/choreographer/it/it_shimmer.dart @@ -28,10 +28,7 @@ class ItShimmer extends StatelessWidget { onPressed: null, child: const Text( " ", // 10 spaces - style: TextStyle( - color: Colors.transparent, - fontSize: 16, - ), + style: TextStyle(color: Colors.transparent, fontSize: 16), ), ), ); diff --git a/lib/pangea/choreographer/it/it_step_model.dart b/lib/pangea/choreographer/it/it_step_model.dart index e3e72200a..34f98b42c 100644 --- a/lib/pangea/choreographer/it/it_step_model.dart +++ b/lib/pangea/choreographer/it/it_step_model.dart @@ -33,14 +33,14 @@ class ITStepModel { ...responseModel.continuances .where((c) => c.text.toLowerCase() != goldCont.text.toLowerCase()) .map((e) { - //we only want one green choice and for that to be our gold - if (e.level == ChoreoConstants.levelThresholdForGreen) { - return e.copyWith( - level: ChoreoConstants.levelThresholdForYellow, - ); - } - return e; - }), + //we only want one green choice and for that to be our gold + if (e.level == ChoreoConstants.levelThresholdForGreen) { + return e.copyWith( + level: ChoreoConstants.levelThresholdForYellow, + ); + } + return e; + }), goldCont, ]; continuances.shuffle(); @@ -49,16 +49,10 @@ class ITStepModel { } } - return ITStepModel( - continuances: continuances, - isFinal: isFinal, - ); + return ITStepModel(continuances: continuances, isFinal: isFinal); } - ITStepModel copyWith({ - List? continuances, - bool? isFinal, - }) { + ITStepModel copyWith({List? continuances, bool? isFinal}) { return ITStepModel( continuances: continuances ?? this.continuances, isFinal: isFinal ?? this.isFinal, diff --git a/lib/pangea/choreographer/it/word_data_card.dart b/lib/pangea/choreographer/it/word_data_card.dart index ae8c1ab57..a4359c657 100644 --- a/lib/pangea/choreographer/it/word_data_card.dart +++ b/lib/pangea/choreographer/it/word_data_card.dart @@ -29,7 +29,8 @@ class WordDataCard extends StatelessWidget { word: word, fullTextLang: langCode, wordLang: langCode, - feedbackLang: MatrixState.pangeaController.userController.userL1Code ?? + feedbackLang: + MatrixState.pangeaController.userController.userL1Code ?? LanguageKeys.defaultLanguage, ); diff --git a/lib/pangea/choreographer/text_editing/edit_type_enum.dart b/lib/pangea/choreographer/text_editing/edit_type_enum.dart index 8ef9eaedc..c3b6a7d1e 100644 --- a/lib/pangea/choreographer/text_editing/edit_type_enum.dart +++ b/lib/pangea/choreographer/text_editing/edit_type_enum.dart @@ -1,7 +1 @@ -enum EditTypeEnum { - igc, - it, - itDismissed, - keyboard, - other, -} +enum EditTypeEnum { igc, it, itDismissed, keyboard, other } diff --git a/lib/pangea/choreographer/text_editing/pangea_text_controller.dart b/lib/pangea/choreographer/text_editing/pangea_text_controller.dart index 26691b94c..ad26b08f7 100644 --- a/lib/pangea/choreographer/text_editing/pangea_text_controller.dart +++ b/lib/pangea/choreographer/text_editing/pangea_text_controller.dart @@ -19,19 +19,17 @@ class PangeaTextController extends TextEditingController { EditTypeEnum editType = EditTypeEnum.keyboard; String _currentText = ''; - PangeaTextController({ - required this.choreographer, - }) { + PangeaTextController({required this.choreographer}) { addListener(_onTextChanged); } bool get exceededMaxLength => text.length >= ChoreoConstants.maxLength; TextStyle _underlineStyle(Color color) => TextStyle( - decoration: TextDecoration.underline, - decorationColor: color, - decorationThickness: 5, - ); + decoration: TextDecoration.underline, + decorationColor: color, + decorationThickness: 5, + ); Color _underlineColor(PangeaMatch match) { if (match.status == PangeaMatchStatusEnum.automatic) { @@ -92,9 +90,7 @@ class PangeaTextController extends TextEditingController { e: e, s: s, level: SentryLevel.warning, - data: { - "match": match.toJson(), - }, + data: {"match": match.toJson()}, ); MatrixState.pAnyState.closeOverlay(); choreographer.clearMatches(e); @@ -133,16 +129,13 @@ class PangeaTextController extends TextEditingController { } TextSpan _buildPaywallSpan(TextStyle? style) => TextSpan( - text: text, - style: style?.merge( - _underlineStyle(const Color.fromARGB(187, 132, 96, 224)), - ), - ); + text: text, + style: style?.merge( + _underlineStyle(const Color.fromARGB(187, 132, 96, 224)), + ), + ); - InlineSpan _buildMatchSpan( - PangeaMatchState match, - TextStyle style, - ) { + InlineSpan _buildMatchSpan(PangeaMatchState match, TextStyle style) { final span = choreographer.igcController.currentText!.characters .getRange( match.updatedMatch.match.offset, @@ -167,25 +160,22 @@ class PangeaTextController extends TextEditingController { style: style, ); } else { - return TextSpan( - text: span, - style: style, - ); + return TextSpan(text: span, style: style); } } /// Returns a list of [TextSpan]s used to display the text in the input field /// with the appropriate styling for each error match. - List _buildTokenSpan({ - TextStyle? defaultStyle, - }) { - final textSpanMatches = [ - ...choreographer.igcController.openMatches, - ...choreographer.igcController.recentAutomaticCorrections, - ]..sort( - (a, b) => - a.updatedMatch.match.offset.compareTo(b.updatedMatch.match.offset), - ); + List _buildTokenSpan({TextStyle? defaultStyle}) { + final textSpanMatches = + [ + ...choreographer.igcController.openMatches, + ...choreographer.igcController.recentAutomaticCorrections, + ]..sort( + (a, b) => a.updatedMatch.match.offset.compareTo( + b.updatedMatch.match.offset, + ), + ); final currentText = choreographer.igcController.currentText!; final spans = []; diff --git a/lib/pangea/common/config/environment.dart b/lib/pangea/common/config/environment.dart index 53388f2dc..dc5ae9cc7 100644 --- a/lib/pangea/common/config/environment.dart +++ b/lib/pangea/common/config/environment.dart @@ -32,16 +32,22 @@ class Environment { appConfigOverride?.synapseURL ?? dotenv.env['SYNAPSE_URL']; if (homeServerFromSynapseURL != null) { if (homeServerFromSynapseURL.startsWith("http://")) { - homeServerFromSynapseURL = - homeServerFromSynapseURL.replaceFirst("http://", ""); + homeServerFromSynapseURL = homeServerFromSynapseURL.replaceFirst( + "http://", + "", + ); } if (homeServerFromSynapseURL.startsWith("https://")) { - homeServerFromSynapseURL = - homeServerFromSynapseURL.replaceFirst("https://", ""); + homeServerFromSynapseURL = homeServerFromSynapseURL.replaceFirst( + "https://", + "", + ); } if (homeServerFromSynapseURL.startsWith("matrix.")) { - homeServerFromSynapseURL = - homeServerFromSynapseURL.replaceFirst("matrix.", ""); + homeServerFromSynapseURL = homeServerFromSynapseURL.replaceFirst( + "matrix.", + "", + ); } } return appConfigOverride?.homeServer ?? @@ -65,7 +71,8 @@ class Environment { } static String get cmsApi { - final envEntry = dotenv.env['CMS_API'] ?? + final envEntry = + dotenv.env['CMS_API'] ?? appConfigOverride?.choreoApi ?? dotenv.env['CHOREO_API']; if (envEntry == null) { @@ -152,11 +159,7 @@ class Environment { final override = AppConfigOverride.fromJson(entry); overrides.add(override); } catch (e, s) { - ErrorHandler.logError( - e: e, - s: s, - data: entry, - ); + ErrorHandler.logError(e: e, s: s, data: entry); continue; } } @@ -169,11 +172,7 @@ class Environment { try { return AppConfigOverride.fromJson(entry); } catch (e) { - ErrorHandler.logError( - e: e, - s: StackTrace.current, - data: entry, - ); + ErrorHandler.logError(e: e, s: StackTrace.current, data: entry); return null; } } diff --git a/lib/pangea/common/controllers/pangea_controller.dart b/lib/pangea/common/controllers/pangea_controller.dart index 0d5fbcdac..677348ce8 100644 --- a/lib/pangea/common/controllers/pangea_controller.dart +++ b/lib/pangea/common/controllers/pangea_controller.dart @@ -102,20 +102,16 @@ class PangeaController { } Sentry.configureScope( - (scope) => scope.setUser( - SentryUser( - id: userID, - name: userID, - ), - ), + (scope) => scope.setUser(SentryUser(id: userID, name: userID)), ); GoogleAnalytics.analyticsUserUpdate(userID); } void _registerSubscriptions() { _languageSubscription?.cancel(); - _languageSubscription = - userController.languageStream.stream.listen(_onLanguageUpdate); + _languageSubscription = userController.languageStream.stream.listen( + _onLanguageUpdate, + ); _settingsSubscription?.cancel(); _settingsSubscription = userController.settingsUpdateStream.stream.listen( diff --git a/lib/pangea/common/network/requests.dart b/lib/pangea/common/network/requests.dart index f10b620a4..e68ff4bad 100644 --- a/lib/pangea/common/network/requests.dart +++ b/lib/pangea/common/network/requests.dart @@ -13,19 +13,26 @@ class Requests { late String? accessToken; late String? choreoApiKey; - Requests({ - this.accessToken, - this.choreoApiKey, - }); + Requests({this.accessToken, this.choreoApiKey}); Future post({ required String url, required Map body, }) async { body[ModelKey.cefrLevel] = MatrixState - .pangeaController.userController.profile.userSettings.cefrLevel.string; + .pangeaController + .userController + .profile + .userSettings + .cefrLevel + .string; body[ModelKey.userGender] = MatrixState - .pangeaController.userController.profile.userSettings.gender.string; + .pangeaController + .userController + .profile + .userSettings + .gender + .string; dynamic encoded; encoded = jsonEncode(body); @@ -41,17 +48,16 @@ class Requests { } Future get({required String url}) async { - final http.Response response = - await http.get(Uri.parse(url), headers: _headers); + final http.Response response = await http.get( + Uri.parse(url), + headers: _headers, + ); handleError(response); return response; } - void addBreadcrumb( - http.Response response, { - Map? body, - }) { + void addBreadcrumb(http.Response response, {Map? body}) { debugPrint("Error - code: ${response.statusCode}"); debugPrint("api: ${response.request?.url}"); debugPrint("request body: $body"); @@ -62,15 +68,10 @@ class Requests { statusCode: response.statusCode, ), ); - Sentry.addBreadcrumb( - Breadcrumb(data: {"body": body}), - ); + Sentry.addBreadcrumb(Breadcrumb(data: {"body": body})); } - void handleError( - http.Response response, { - Map? body, - }) { + void handleError(http.Response response, {Map? body}) { if (response.statusCode == 401) { final responseBody = jsonDecode(utf8.decode(response.bodyBytes)); if (responseBody['detail'] == 'No active subscription found') { diff --git a/lib/pangea/common/utils/any_state_holder.dart b/lib/pangea/common/utils/any_state_holder.dart index a2f8d4c61..2e2d69980 100644 --- a/lib/pangea/common/utils/any_state_holder.dart +++ b/lib/pangea/common/utils/any_state_holder.dart @@ -32,8 +32,9 @@ class PangeaAnyState { Sentry.addBreadcrumb(Breadcrumb(data: _layerLinkAndKeys)); throw Exception("layerLinkAndKey with null for $transformTargetId"); } else { - _layerLinkAndKeys[transformTargetId] = - LayerLinkAndKey(transformTargetId); + _layerLinkAndKeys[transformTargetId] = LayerLinkAndKey( + transformTargetId, + ); } } @@ -66,10 +67,7 @@ class PangeaAnyState { ), ); - Overlay.of( - context, - rootOverlay: rootOverlay, - ).insert(entry); + Overlay.of(context, rootOverlay: rootOverlay).insert(entry); return true; } @@ -77,31 +75,20 @@ class PangeaAnyState { void closeOverlay([String? overlayKey]) { final entry = overlayKey != null ? entries.firstWhereOrNull((element) => element.key == overlayKey) - : entries.lastWhereOrNull( - (element) => element.canPop, - ); + : entries.lastWhereOrNull((element) => element.canPop); if (entry != null) { try { entry.entry.remove(); entry.entry.dispose(); } catch (err, s) { - ErrorHandler.logError( - e: err, - s: s, - data: { - "overlay": entry, - }, - ); + ErrorHandler.logError(e: err, s: s, data: {"overlay": entry}); } entries.remove(entry); } } - void closeAllOverlays({ - RegExp? filter, - force = false, - }) { + void closeAllOverlays({RegExp? filter, force = false}) { List shouldRemove = List.from(entries); if (!force) { shouldRemove = shouldRemove.where((element) => element.canPop).toList(); @@ -120,13 +107,7 @@ class PangeaAnyState { shouldRemove[i].entry.remove(); shouldRemove[i].entry.dispose(); } catch (err, s) { - ErrorHandler.logError( - e: err, - s: s, - data: { - "overlay": shouldRemove[i], - }, - ); + ErrorHandler.logError(e: err, s: s, data: {"overlay": shouldRemove[i]}); } entries.remove(shouldRemove[i]); @@ -134,8 +115,9 @@ class PangeaAnyState { } RenderBox? getRenderBox(String key) { - final box = layerLinkAndKey(key).key.currentContext?.findRenderObject() - as RenderBox?; + final box = + layerLinkAndKey(key).key.currentContext?.findRenderObject() + as RenderBox?; return box?.hasSize == true ? box : null; } @@ -166,10 +148,10 @@ class LayerLinkAndKey { } Map toJson() => { - "key": key.toString(), - "link": link.toString(), - "transformTargetId": transformTargetId, - }; + "key": key.toString(), + "link": link.toString(), + "transformTargetId": transformTargetId, + }; @override operator ==(Object other) => diff --git a/lib/pangea/common/utils/async_state.dart b/lib/pangea/common/utils/async_state.dart index 908f9e021..725c9b06b 100644 --- a/lib/pangea/common/utils/async_state.dart +++ b/lib/pangea/common/utils/async_state.dart @@ -101,11 +101,7 @@ abstract class AsyncLoader { } if (e is! HttpException) { - ErrorHandler.logError( - e: e, - s: s, - data: {}, - ); + ErrorHandler.logError(e: e, s: s, data: {}); } } } diff --git a/lib/pangea/common/utils/error_handler.dart b/lib/pangea/common/utils/error_handler.dart index 520b01ee1..9018ff5f2 100644 --- a/lib/pangea/common/utils/error_handler.dart +++ b/lib/pangea/common/utils/error_handler.dart @@ -13,7 +13,7 @@ import 'package:fluffychat/utils/platform_infos.dart'; class PangeaWarningError implements Exception { final String message; PangeaWarningError(String message) - : message = "Pangea Warning Error: $message"; + : message = "Pangea Warning Error: $message"; @override String toString() => message; @@ -23,18 +23,16 @@ class ErrorHandler { ErrorHandler(); static Future initialize() async { - await SentryFlutter.init( - (options) { - options.dsn = Environment.sentryDsn; - options.tracesSampleRate = 0.1; - options.debug = kDebugMode; - options.environment = kDebugMode - ? "debug" - : Environment.isStagingEnvironment - ? "staging" - : "productionC"; - }, - ); + await SentryFlutter.init((options) { + options.dsn = Environment.sentryDsn; + options.tracesSampleRate = 0.1; + options.debug = kDebugMode; + options.environment = kDebugMode + ? "debug" + : Environment.isStagingEnvironment + ? "staging" + : "productionC"; + }); // Error handling FlutterError.onError = (FlutterErrorDetails details) async { @@ -47,11 +45,7 @@ class ErrorHandler { }; PlatformDispatcher.instance.onError = (exception, stack) { - logError( - e: exception, - s: stack, - data: {}, - ); + logError(e: exception, s: stack, data: {}); return true; }; } @@ -91,12 +85,7 @@ class ErrorCopy { late String body; int? errorCode; - ErrorCopy( - this.context, { - this.error, - String? title, - String? body, - }) { + ErrorCopy(this.context, {this.error, String? title, String? body}) { if (title != null) this.title = title; if (body != null) this.body = body; if (title == null || body == null) setCopy(); @@ -157,11 +146,7 @@ class ErrorCopy { body = l10n.errorPleaseRefresh; } } catch (e, s) { - ErrorHandler.logError( - e: s, - s: s, - data: {}, - ); + ErrorHandler.logError(e: s, s: s, data: {}); _setDefaults(); } } diff --git a/lib/pangea/common/utils/firebase_analytics.dart b/lib/pangea/common/utils/firebase_analytics.dart index 4bad82dca..8d8fc59c0 100644 --- a/lib/pangea/common/utils/firebase_analytics.dart +++ b/lib/pangea/common/utils/firebase_analytics.dart @@ -46,10 +46,7 @@ class GoogleAnalytics { } static void updateUserSubscriptionStatus(bool subscribed) { - analytics?.setUserProperty( - name: 'subscribed', - value: "$subscribed", - ); + analytics?.setUserProperty(name: 'subscribed', value: "$subscribed"); } static void logEvent(String name, {parameters}) { @@ -103,10 +100,7 @@ class GoogleAnalytics { static void sendMessage(String chatRoomId, String classCode) { logEvent( 'sent_message', - parameters: { - "chat_id": chatRoomId, - 'group_id': classCode, - }, + parameters: {"chat_id": chatRoomId, 'group_id': classCode}, ); } @@ -135,7 +129,7 @@ class GoogleAnalytics { 'price': details.price, 'item_category': "subscription", 'quantity': 1, - } + }, ], }, ); diff --git a/lib/pangea/common/utils/overlay.dart b/lib/pangea/common/utils/overlay.dart index f0f1f2ec9..16e4e88f9 100644 --- a/lib/pangea/common/utils/overlay.dart +++ b/lib/pangea/common/utils/overlay.dart @@ -21,11 +21,7 @@ import '../../../config/themes.dart'; import '../../../widgets/matrix.dart'; import 'error_handler.dart'; -enum OverlayPositionEnum { - transform, - centered, - top, -} +enum OverlayPositionEnum { transform, centered, top } class OverlayUtil { static bool showOverlay({ @@ -72,15 +68,18 @@ class OverlayUtil { ), ), Positioned( - top: (position == OverlayPositionEnum.centered || + top: + (position == OverlayPositionEnum.centered || position == OverlayPositionEnum.top) ? 0 : null, - right: (position == OverlayPositionEnum.centered || + right: + (position == OverlayPositionEnum.centered || position == OverlayPositionEnum.top) ? 0 : null, - left: (position == OverlayPositionEnum.centered || + left: + (position == OverlayPositionEnum.centered || position == OverlayPositionEnum.top) ? 0 : null, @@ -111,11 +110,7 @@ class OverlayUtil { ); } catch (err, stack) { debugger(when: kDebugMode); - ErrorHandler.logError( - e: err, - s: stack, - data: {}, - ); + ErrorHandler.logError(e: err, s: stack, data: {}); return false; } } @@ -138,8 +133,8 @@ class OverlayUtil { Alignment? followerAnchor, }) { try { - final LayerLinkAndKey layerLinkAndKey = - MatrixState.pAnyState.layerLinkAndKey(transformTargetId); + final LayerLinkAndKey layerLinkAndKey = MatrixState.pAnyState + .layerLinkAndKey(transformTargetId); if (layerLinkAndKey.key.currentContext == null) { debugPrint("layerLinkAndKey.key.currentContext is null"); return; @@ -151,20 +146,23 @@ class OverlayUtil { bool hasTopOverflow = false; if (targetRenderBox != null && targetRenderBox.hasSize) { - final Offset transformTargetOffset = - (targetRenderBox).localToGlobal(Offset.zero); + final Offset transformTargetOffset = (targetRenderBox).localToGlobal( + Offset.zero, + ); final Size transformTargetSize = targetRenderBox.size; final columnWidth = FluffyThemes.isColumnMode(context) ? FluffyThemes.columnWidth + FluffyThemes.navRailWidth : 0; - final horizontalMidpoint = (transformTargetOffset.dx - columnWidth) + + final horizontalMidpoint = + (transformTargetOffset.dx - columnWidth) + (transformTargetSize.width / 2); final halfMaxWidth = maxWidth / 2; final hasLeftOverflow = (horizontalMidpoint - halfMaxWidth) < 10; - final hasRightOverflow = (horizontalMidpoint + halfMaxWidth) > + final hasRightOverflow = + (horizontalMidpoint + halfMaxWidth) > (MediaQuery.widthOf(context) - columnWidth - 10); hasTopOverflow = maxHeight + kToolbarHeight > transformTargetOffset.dy; @@ -174,7 +172,8 @@ class OverlayUtil { if (hasLeftOverflow) { xOffset = (horizontalMidpoint - halfMaxWidth - 10) * -1; } else if (hasRightOverflow) { - xOffset = (MediaQuery.of(context).size.width - columnWidth) - + xOffset = + (MediaQuery.of(context).size.width - columnWidth) - (horizontalMidpoint + halfMaxWidth + 10); } offset = Offset(xOffset, 0); @@ -204,20 +203,18 @@ class OverlayUtil { closePrevOverlay: closePrevOverlay, offset: offset, overlayKey: overlayKey, - targetAnchor: targetAnchor ?? + targetAnchor: + targetAnchor ?? (hasTopOverflow ? Alignment.bottomCenter : Alignment.topCenter), - followerAnchor: followerAnchor ?? + followerAnchor: + followerAnchor ?? (hasTopOverflow ? Alignment.topCenter : Alignment.bottomCenter), onDismiss: onDismiss, ignorePointer: ignorePointer, ); } catch (err, stack) { debugger(when: kDebugMode); - ErrorHandler.logError( - e: err, - s: stack, - data: {}, - ); + ErrorHandler.logError(e: err, s: stack, data: {}); } } @@ -288,9 +285,7 @@ class OverlayUtil { closePrevOverlay: false, canPop: false, overlayKey: "star_rain_level_up", - child: const StarRainWidget( - overlayKey: "star_rain_level_up", - ), + child: const StarRainWidget(overlayKey: "star_rain_level_up"), ); } @@ -304,10 +299,7 @@ class OverlayUtil { followerAnchor: Alignment.bottomCenter, targetAnchor: Alignment.bottomCenter, context: context, - child: PointsGainedAnimation( - points: points, - targetID: targetId, - ), + child: PointsGainedAnimation(points: points, targetID: targetId), transformTargetId: targetId, closePrevOverlay: false, backDropToDismiss: false, @@ -328,10 +320,7 @@ class OverlayUtil { followerAnchor: Alignment.topCenter, targetAnchor: Alignment.topCenter, context: context, - child: GrowthAnimation( - targetID: overlayKey, - level: level, - ), + child: GrowthAnimation(targetID: overlayKey, level: level), transformTargetId: targetId, closePrevOverlay: false, backDropToDismiss: false, diff --git a/lib/pangea/common/utils/p_vguard.dart b/lib/pangea/common/utils/p_vguard.dart index c977618c1..afecbb9d4 100644 --- a/lib/pangea/common/utils/p_vguard.dart +++ b/lib/pangea/common/utils/p_vguard.dart @@ -20,8 +20,9 @@ class PAuthGaurd { return Matrix.of(context).client.isLogged() ? '/rooms' : null; } - final isLogged = - Matrix.of(context).widget.clients.any((client) => client.isLogged()); + final isLogged = Matrix.of( + context, + ).widget.clients.any((client) => client.isLogged()); if (!isLogged) return null; // If user hasn't set their L2, @@ -39,8 +40,9 @@ class PAuthGaurd { return Matrix.of(context).client.isLogged() ? null : '/home'; } - final isLogged = - Matrix.of(context).widget.clients.any((client) => client.isLogged()); + final isLogged = Matrix.of( + context, + ).widget.clients.any((client) => client.isLogged()); if (!isLogged) { return '/home'; } @@ -60,9 +62,9 @@ class PAuthGaurd { return Matrix.of(context).client.isLogged() ? null : '/home'; } - final isLogged = Matrix.of(context).widget.clients.any( - (client) => client.isLogged(), - ); + final isLogged = Matrix.of( + context, + ).widget.clients.any((client) => client.isLogged()); if (!isLogged) { return '/home'; } diff --git a/lib/pangea/common/widgets/anchored_overlay_widget.dart b/lib/pangea/common/widgets/anchored_overlay_widget.dart index 60fd2dc9a..e20ef580d 100644 --- a/lib/pangea/common/widgets/anchored_overlay_widget.dart +++ b/lib/pangea/common/widgets/anchored_overlay_widget.dart @@ -54,10 +54,11 @@ class _AnchoredOverlayWidgetState extends State { @override Widget build(BuildContext context) { - final leftPosition = (widget.anchorRect.left + - (widget.anchorRect.width / 2) - - (overlayWidth / 2)) - .clamp(8.0, MediaQuery.sizeOf(context).width - overlayWidth - 8.0); + final leftPosition = + (widget.anchorRect.left + + (widget.anchorRect.width / 2) - + (overlayWidth / 2)) + .clamp(8.0, MediaQuery.sizeOf(context).width - overlayWidth - 8.0); return AnimatedOpacity( opacity: _visible ? 1.0 : 0.0, @@ -91,10 +92,7 @@ class _AnchoredOverlayWidgetState extends State { child: Material( color: Colors.transparent, elevation: 4, - child: SizedBox( - width: overlayWidth, - child: widget.child, - ), + child: SizedBox(width: overlayWidth, child: widget.child), ), ), ], diff --git a/lib/pangea/common/widgets/card_error_widget.dart b/lib/pangea/common/widgets/card_error_widget.dart index 43f7c107a..88df1caf3 100644 --- a/lib/pangea/common/widgets/card_error_widget.dart +++ b/lib/pangea/common/widgets/card_error_widget.dart @@ -6,10 +6,7 @@ import 'package:fluffychat/pangea/bot/widgets/bot_face_svg.dart'; class CardErrorWidget extends StatelessWidget { final String error; - const CardErrorWidget( - this.error, { - super.key, - }); + const CardErrorWidget(this.error, {super.key}); @override Widget build(BuildContext context) { @@ -28,10 +25,7 @@ class CardErrorWidget extends StatelessWidget { spacing: 12.0, mainAxisSize: MainAxisSize.min, children: [ - const BotFace( - width: 50.0, - expression: BotExpression.addled, - ), + const BotFace(width: 50.0, expression: BotExpression.addled), Flexible( child: Text( error, diff --git a/lib/pangea/common/widgets/card_header.dart b/lib/pangea/common/widgets/card_header.dart index 3999c0a40..b9ab8974b 100644 --- a/lib/pangea/common/widgets/card_header.dart +++ b/lib/pangea/common/widgets/card_header.dart @@ -5,10 +5,7 @@ import 'package:fluffychat/widgets/matrix.dart'; import '../../bot/widgets/bot_face_svg.dart'; class CardHeader extends StatelessWidget { - const CardHeader( - this.text, { - super.key, - }); + const CardHeader(this.text, {super.key}); final String text; @@ -21,10 +18,7 @@ class CardHeader extends StatelessWidget { child: Row( spacing: 12.0, children: [ - const BotFace( - width: 50.0, - expression: BotExpression.addled, - ), + const BotFace(width: 50.0, expression: BotExpression.addled), Expanded( child: Text( text, diff --git a/lib/pangea/common/widgets/choice_animation.dart b/lib/pangea/common/widgets/choice_animation.dart index 616a74ede..eafd2a5b0 100644 --- a/lib/pangea/common/widgets/choice_animation.dart +++ b/lib/pangea/common/widgets/choice_animation.dart @@ -82,25 +82,19 @@ class ChoiceAnimationWidgetState extends State return widget.isCorrect == null ? widget.child : widget.isCorrect == true - ? AnimatedBuilder( - animation: _animation, - builder: (context, child) { - return Transform.scale( - scale: _animation.value, - child: child, - ); - }, - child: widget.child, - ) - : AnimatedBuilder( - animation: _animation, - builder: (context, child) { - return Transform.rotate( - angle: _animation.value, - child: child, - ); - }, - child: widget.child, - ); + ? AnimatedBuilder( + animation: _animation, + builder: (context, child) { + return Transform.scale(scale: _animation.value, child: child); + }, + child: widget.child, + ) + : AnimatedBuilder( + animation: _animation, + builder: (context, child) { + return Transform.rotate(angle: _animation.value, child: child); + }, + child: widget.child, + ); } } diff --git a/lib/pangea/common/widgets/choice_array.dart b/lib/pangea/common/widgets/choice_array.dart index d0c109259..660b87e5a 100644 --- a/lib/pangea/common/widgets/choice_array.dart +++ b/lib/pangea/common/widgets/choice_array.dart @@ -76,11 +76,7 @@ class ChoicesArray extends StatelessWidget { } class Choice { - Choice({ - this.color, - required this.text, - this.isGold = false, - }); + Choice({this.color, required this.text, this.isGold = false}); final Color? color; final String text; @@ -142,11 +138,9 @@ class ChoiceItem extends StatelessWidget { ), child: TextButton( style: TextButton.styleFrom( - padding: const EdgeInsets.symmetric( - horizontal: 8, - vertical: 4, - ), - backgroundColor: entry.value.color?.withAlpha(50) ?? + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), + backgroundColor: + entry.value.color?.withAlpha(50) ?? theme.colorScheme.primary.withAlpha(10), textStyle: BotStyle.text(context), shape: RoundedRectangleBorder( @@ -161,9 +155,7 @@ class ChoiceItem extends StatelessWidget { getDisplayCopy != null ? getDisplayCopy!(entry.value.text) : entry.value.text, - style: BotStyle.text(context).copyWith( - fontSize: fontSize, - ), + style: BotStyle.text(context).copyWith(fontSize: fontSize), textAlign: TextAlign.center, ), ), diff --git a/lib/pangea/common/widgets/content_loading_indicator.dart b/lib/pangea/common/widgets/content_loading_indicator.dart index 15655d9ee..3c7047cf9 100644 --- a/lib/pangea/common/widgets/content_loading_indicator.dart +++ b/lib/pangea/common/widgets/content_loading_indicator.dart @@ -3,10 +3,7 @@ import 'package:flutter/material.dart'; import 'package:fluffychat/config/app_config.dart'; class ContentLoadingIndicator extends StatelessWidget { - const ContentLoadingIndicator({ - super.key, - this.height, - }); + const ContentLoadingIndicator({super.key, this.height}); final double? height; diff --git a/lib/pangea/common/widgets/customized_svg.dart b/lib/pangea/common/widgets/customized_svg.dart index ad8c3dc89..b70f75c59 100644 --- a/lib/pangea/common/widgets/customized_svg.dart +++ b/lib/pangea/common/widgets/customized_svg.dart @@ -108,16 +108,10 @@ class _CustomizedSvgState extends State { final response = await http.get(Uri.parse(widget.svgUrl)); if (response.statusCode != 200) { final e = Exception('Failed to load SVG: ${response.statusCode}'); - ErrorHandler.logError( - e: e, - data: { - "svgUrl": widget.svgUrl, - }, - ); - await _svgStorage.write( - widget.svgUrl, - {'timestamp': DateTime.now().millisecondsSinceEpoch}, - ); + ErrorHandler.logError(e: e, data: {"svgUrl": widget.svgUrl}); + await _svgStorage.write(widget.svgUrl, { + 'timestamp': DateTime.now().millisecondsSinceEpoch, + }); throw e; } @@ -144,8 +138,9 @@ class _CustomizedSvgState extends State { cachedSvgEntry is Map && cachedSvgEntry['svg'] is String && cachedSvgEntry['timestamp'] is int && - DateTime.fromMillisecondsSinceEpoch(cachedSvgEntry['timestamp']) - .isAfter(DateTime.now().subtract(const Duration(days: 1)))) { + DateTime.fromMillisecondsSinceEpoch( + cachedSvgEntry['timestamp'], + ).isAfter(DateTime.now().subtract(const Duration(days: 1)))) { return _modifySVG(cachedSvgEntry['svg'] as String); } return null; @@ -158,15 +153,10 @@ class _CustomizedSvgState extends State { return SizedBox( width: widget.width, height: widget.height, - child: const Center( - child: CircularProgressIndicator(), - ), + child: const Center(child: CircularProgressIndicator()), ); } else { - return SizedBox( - width: widget.width, - height: widget.height, - ); + return SizedBox(width: widget.width, height: widget.height); } } else if (_hasError || _svgContent == null) { return widget.errorIcon; diff --git a/lib/pangea/common/widgets/dropdown_text_button.dart b/lib/pangea/common/widgets/dropdown_text_button.dart index ce3f5e6f4..abab1cd43 100644 --- a/lib/pangea/common/widgets/dropdown_text_button.dart +++ b/lib/pangea/common/widgets/dropdown_text_button.dart @@ -14,23 +14,12 @@ class DropdownTextButton extends StatelessWidget { Widget build(BuildContext context) { return Container( color: isSelected - ? Theme.of(context) - .colorScheme - .primary - .withAlpha(20) // Highlight selected + ? Theme.of(context).colorScheme.primary.withAlpha( + 20, + ) // Highlight selected : Colors.transparent, - padding: const EdgeInsets.symmetric( - vertical: 12, - horizontal: 12, - ), - child: Row( - children: [ - Text( - text, - overflow: TextOverflow.clip, - ), - ], - ), + padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 12), + child: Row(children: [Text(text, overflow: TextOverflow.clip)]), ); } } @@ -38,21 +27,13 @@ class DropdownTextButton extends StatelessWidget { class CustomDropdownTextButton extends StatelessWidget { final String text; - const CustomDropdownTextButton({ - required this.text, - super.key, - }); + const CustomDropdownTextButton({required this.text, super.key}); @override Widget build(BuildContext context) { return Row( children: [ - Expanded( - child: Text( - text, - overflow: TextOverflow.clip, - ), - ), + Expanded(child: Text(text, overflow: TextOverflow.clip)), Icon( Icons.arrow_drop_down, color: Theme.of(context).colorScheme.onSurfaceVariant, diff --git a/lib/pangea/common/widgets/error_indicator.dart b/lib/pangea/common/widgets/error_indicator.dart index 8e9f30397..fa74eb2c5 100644 --- a/lib/pangea/common/widgets/error_indicator.dart +++ b/lib/pangea/common/widgets/error_indicator.dart @@ -26,20 +26,13 @@ class ErrorIndicator extends StatelessWidget { ), const SizedBox(width: 8), Flexible( - child: Text( - message, - style: style, - textAlign: TextAlign.center, - ), + child: Text(message, style: style, textAlign: TextAlign.center), ), ], ); if (onTap != null) { - return TextButton( - onPressed: onTap, - child: content, - ); + return TextButton(onPressed: onTap, child: content); } return content; diff --git a/lib/pangea/common/widgets/feedback_dialog.dart b/lib/pangea/common/widgets/feedback_dialog.dart index 3ec11dee5..84bbe9a67 100644 --- a/lib/pangea/common/widgets/feedback_dialog.dart +++ b/lib/pangea/common/widgets/feedback_dialog.dart @@ -40,21 +40,13 @@ class _FeedbackDialogState extends State { mainAxisSize: MainAxisSize.min, children: [ const Center( - child: BotFace( - width: 50.0, - expression: BotExpression.addled, - ), - ), - Text( - L10n.of(context).feedbackDialogDesc, - textAlign: TextAlign.center, + child: BotFace(width: 50.0, expression: BotExpression.addled), ), + Text(L10n.of(context).feedbackDialogDesc, textAlign: TextAlign.center), if (widget.extraContent != null) widget.extraContent!, TextFormField( controller: _feedbackController, - decoration: InputDecoration( - hintText: L10n.of(context).feedbackHint, - ), + decoration: InputDecoration(hintText: L10n.of(context).feedbackHint), keyboardType: TextInputType.multiline, onFieldSubmitted: _feedbackController.text.isNotEmpty ? (value) => widget.onSubmit(value) @@ -74,9 +66,7 @@ class _FeedbackDialogState extends State { ), child: Container( width: 325.0, - constraints: const BoxConstraints( - maxHeight: 600.0, - ), + constraints: const BoxConstraints(maxHeight: 600.0), padding: const EdgeInsets.all(12.0), child: Column( spacing: 20.0, @@ -91,9 +81,7 @@ class _FeedbackDialogState extends State { ), Expanded( child: Container( - constraints: const BoxConstraints( - minHeight: 40.0, - ), + constraints: const BoxConstraints(minHeight: 40.0), alignment: Alignment.center, child: Text( widget.title, @@ -108,9 +96,7 @@ class _FeedbackDialogState extends State { const SizedBox( width: 40.0, height: 40.0, - child: Center( - child: Icon(Icons.flag_outlined), - ), + child: Center(child: Icon(Icons.flag_outlined)), ), ], ), @@ -122,13 +108,12 @@ class _FeedbackDialogState extends State { builder: (context, value, _) { final isNotEmpty = value.text.isNotEmpty; return ElevatedButton( - onPressed: - isNotEmpty ? () => widget.onSubmit(value.text) : null, + onPressed: isNotEmpty + ? () => widget.onSubmit(value.text) + : null, child: Row( mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text(L10n.of(context).feedbackButton), - ], + children: [Text(L10n.of(context).feedbackButton)], ), ); }, diff --git a/lib/pangea/common/widgets/feedback_response_dialog.dart b/lib/pangea/common/widgets/feedback_response_dialog.dart index e411116d1..986ad0903 100644 --- a/lib/pangea/common/widgets/feedback_response_dialog.dart +++ b/lib/pangea/common/widgets/feedback_response_dialog.dart @@ -49,34 +49,21 @@ class FeedbackResponseDialog extends StatelessWidget { const SizedBox( width: 40.0, height: 40.0, - child: Center( - child: Icon(Icons.flag_outlined), - ), + child: Center(child: Icon(Icons.flag_outlined)), ), ], ), ), Padding( - padding: const EdgeInsets.symmetric( - horizontal: 20.0, - ), + padding: const EdgeInsets.symmetric(horizontal: 20.0), child: Column( spacing: 20.0, mainAxisSize: MainAxisSize.min, children: [ - const BotFace( - width: 60.0, - expression: BotExpression.idle, - ), - Text( - feedback, - textAlign: TextAlign.center, - ), + const BotFace(width: 60.0, expression: BotExpression.idle), + Text(feedback, textAlign: TextAlign.center), if (description != null) - Text( - description!, - textAlign: TextAlign.center, - ), + Text(description!, textAlign: TextAlign.center), const SizedBox.shrink(), ], ), diff --git a/lib/pangea/common/widgets/full_width_dialog.dart b/lib/pangea/common/widgets/full_width_dialog.dart index 62c177098..e3fb69d65 100644 --- a/lib/pangea/common/widgets/full_width_dialog.dart +++ b/lib/pangea/common/widgets/full_width_dialog.dart @@ -25,17 +25,15 @@ class FullWidthDialog extends StatelessWidget { duration: FluffyThemes.animationDuration, child: ConstrainedBox( constraints: isColumnMode - ? BoxConstraints( - maxWidth: maxWidth, - maxHeight: maxHeight, - ) + ? BoxConstraints(maxWidth: maxWidth, maxHeight: maxHeight) : BoxConstraints( maxWidth: MediaQuery.widthOf(context), maxHeight: MediaQuery.heightOf(context), ), child: ClipRRect( - borderRadius: - isColumnMode ? BorderRadius.circular(20.0) : BorderRadius.zero, + borderRadius: isColumnMode + ? BorderRadius.circular(20.0) + : BorderRadius.zero, child: dialogContent, ), ), @@ -44,14 +42,8 @@ class FullWidthDialog extends StatelessWidget { return BackdropFilter( filter: ImageFilter.blur(sigmaX: 2.5, sigmaY: 2.5), child: isColumnMode - ? Dialog( - backgroundColor: backgroundColor, - child: content, - ) - : Dialog.fullscreen( - backgroundColor: backgroundColor, - child: content, - ), + ? Dialog(backgroundColor: backgroundColor, child: content) + : Dialog.fullscreen(backgroundColor: backgroundColor, child: content), ); } } diff --git a/lib/pangea/common/widgets/overlay_container.dart b/lib/pangea/common/widgets/overlay_container.dart index fa09779be..65949595f 100644 --- a/lib/pangea/common/widgets/overlay_container.dart +++ b/lib/pangea/common/widgets/overlay_container.dart @@ -35,9 +35,7 @@ class OverlayContainer extends StatelessWidget { width: 2, color: borderColor ?? Theme.of(context).colorScheme.primary, ), - borderRadius: const BorderRadius.all( - Radius.circular(25), - ), + borderRadius: const BorderRadius.all(Radius.circular(25)), ), constraints: BoxConstraints( maxWidth: maxWidth, diff --git a/lib/pangea/common/widgets/pressable_button.dart b/lib/pangea/common/widgets/pressable_button.dart index 04fc8ffd7..9b69fb4a2 100644 --- a/lib/pangea/common/widgets/pressable_button.dart +++ b/lib/pangea/common/widgets/pressable_button.dart @@ -12,7 +12,7 @@ class PressableButton extends StatefulWidget { final bool depressed; final Color color; final Widget Function(BuildContext context, bool depressed, Color shadowColor) - builder; + builder; final void Function()? onPressed; final Stream? triggerAnimation; @@ -59,8 +59,10 @@ class PressableButtonState extends State duration: const Duration(milliseconds: 100), vsync: this, ); - _tweenAnimation = - Tween(begin: 0, end: widget.buttonHeight).animate(_controller); + _tweenAnimation = Tween( + begin: 0, + end: widget.buttonHeight, + ).animate(_controller); if (!_depressed) { _triggerAnimationSubscription = widget.triggerAnimation?.listen((_) { @@ -139,9 +141,7 @@ class PressableButtonState extends State @override Widget build(BuildContext context) { final shadowColor = Color.alphaBlend( - Colors.black.withAlpha( - (255 * widget.colorFactor).round(), - ), + Colors.black.withAlpha((255 * widget.colorFactor).round()), widget.color, ); diff --git a/lib/pangea/common/widgets/share_room_button.dart b/lib/pangea/common/widgets/share_room_button.dart index b698ef703..c3a390cf9 100644 --- a/lib/pangea/common/widgets/share_room_button.dart +++ b/lib/pangea/common/widgets/share_room_button.dart @@ -13,10 +13,7 @@ import 'package:fluffychat/pangea/spaces/space_constants.dart'; class ShareRoomButton extends StatelessWidget { final Room room; - const ShareRoomButton({ - super.key, - required this.room, - }); + const ShareRoomButton({super.key, required this.room}); @override Widget build(BuildContext context) { @@ -32,21 +29,16 @@ class ShareRoomButton extends StatelessWidget { final spaceCode = room.classCode!; String toCopy = spaceCode; if (value == 0) { - final String initialUrl = - kIsWeb ? html.window.origin! : Environment.frontendURL; + final String initialUrl = kIsWeb + ? html.window.origin! + : Environment.frontendURL; toCopy = "$initialUrl/#/join_with_link?${SpaceConstants.classCode}=${room.classCode}"; } await Clipboard.setData(ClipboardData(text: toCopy)); - ScaffoldMessenger.of( - context, - ).showSnackBar( - SnackBar( - content: Text( - L10n.of(context).copiedToClipboard, - ), - ), + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text(L10n.of(context).copiedToClipboard)), ); }, itemBuilder: (BuildContext context) => >[ @@ -60,9 +52,7 @@ class ShareRoomButton extends StatelessWidget { PopupMenuItem( value: 1, child: ListTile( - title: Text( - L10n.of(context).shareInviteCode(room.classCode!), - ), + title: Text(L10n.of(context).shareInviteCode(room.classCode!)), contentPadding: const EdgeInsets.all(0), ), ), diff --git a/lib/pangea/common/widgets/shrinkable_text.dart b/lib/pangea/common/widgets/shrinkable_text.dart index 8a3177ed2..a62b3cbb1 100644 --- a/lib/pangea/common/widgets/shrinkable_text.dart +++ b/lib/pangea/common/widgets/shrinkable_text.dart @@ -24,10 +24,7 @@ class ShrinkableText extends StatelessWidget { child: FittedBox( fit: BoxFit.scaleDown, alignment: Alignment.centerLeft, - child: Text( - text, - style: style, - ), + child: Text(text, style: style), ), ); }, diff --git a/lib/pangea/common/widgets/transparent_backdrop.dart b/lib/pangea/common/widgets/transparent_backdrop.dart index 7103d1e0e..adcedde88 100644 --- a/lib/pangea/common/widgets/transparent_backdrop.dart +++ b/lib/pangea/common/widgets/transparent_backdrop.dart @@ -28,19 +28,12 @@ class TransparentBackdrop extends StatelessWidget { backgroundColor?.withAlpha((0.8 * 255).round()) ?? Colors.transparent; return TweenAnimationBuilder( - tween: Tween( - begin: animateBackground ? 0.0 : 1.0, - end: 1.0, - ), + tween: Tween(begin: animateBackground ? 0.0 : 1.0, end: 1.0), duration: animateBackground ? backgroundAnimationDuration : Duration.zero, builder: (context, t, child) { return Material( borderOnForeground: false, - color: Color.lerp( - Colors.transparent, - targetColor, - t, - ), + color: Color.lerp(Colors.transparent, targetColor, t), clipBehavior: Clip.antiAlias, child: InkWell( hoverColor: Colors.transparent, diff --git a/lib/pangea/common/widgets/tutorial_overlay_message.dart b/lib/pangea/common/widgets/tutorial_overlay_message.dart index aed582a2c..dbc5c1c53 100644 --- a/lib/pangea/common/widgets/tutorial_overlay_message.dart +++ b/lib/pangea/common/widgets/tutorial_overlay_message.dart @@ -5,10 +5,7 @@ import 'package:fluffychat/config/app_config.dart'; class TutorialOverlayMessage extends StatelessWidget { final String message; - const TutorialOverlayMessage( - this.message, { - super.key, - }); + const TutorialOverlayMessage(this.message, {super.key}); @override Widget build(BuildContext context) { @@ -36,8 +33,8 @@ class TutorialOverlayMessage extends StatelessWidget { child: Text( message, style: Theme.of(context).textTheme.titleMedium?.copyWith( - color: Theme.of(context).colorScheme.onSurface, - ), + color: Theme.of(context).colorScheme.onSurface, + ), textAlign: TextAlign.center, ), ), diff --git a/lib/pangea/common/widgets/url_image_widget.dart b/lib/pangea/common/widgets/url_image_widget.dart index 30bff2b9b..6236b42da 100644 --- a/lib/pangea/common/widgets/url_image_widget.dart +++ b/lib/pangea/common/widgets/url_image_widget.dart @@ -54,15 +54,13 @@ class ImageByUrl extends StatelessWidget { height: width, fit: BoxFit.cover, imageUrl: imageUrl.toString(), - placeholder: ( - context, - url, - ) => - Shimmer.fromColors( - baseColor: - Theme.of(context).colorScheme.primary.withAlpha(20), - highlightColor: - Theme.of(context).colorScheme.primary.withAlpha(50), + placeholder: (context, url) => Shimmer.fromColors( + baseColor: Theme.of( + context, + ).colorScheme.primary.withAlpha(20), + highlightColor: Theme.of( + context, + ).colorScheme.primary.withAlpha(50), child: Container( width: width, height: width, @@ -71,11 +69,7 @@ class ImageByUrl extends StatelessWidget { ), ), ), - errorWidget: ( - context, - url, - error, - ) => + errorWidget: (context, url, error) => replacement ?? const SizedBox(), httpHeaders: headers, imageRenderMethodForWeb: ImageRenderMethodForWeb.HttpGet, diff --git a/lib/pangea/common/widgets/word_audio_button.dart b/lib/pangea/common/widgets/word_audio_button.dart index 385290e38..0adba8318 100644 --- a/lib/pangea/common/widgets/word_audio_button.dart +++ b/lib/pangea/common/widgets/word_audio_button.dart @@ -43,10 +43,10 @@ class WordAudioButtonState extends State { @override void initState() { super.initState(); - _loadingChoreoSubscription = - TtsController.loadingChoreoStream.stream.listen((val) { - if (mounted) setState(() => _isLoading = val); - }); + _loadingChoreoSubscription = TtsController.loadingChoreoStream.stream + .listen((val) { + if (mounted) setState(() => _isLoading = val); + }); } @override @@ -77,12 +77,14 @@ class WordAudioButtonState extends State { .key, opacity: widget.isSelected || _isPlaying ? 1 : widget.baseOpacity, child: Tooltip( - message: - _isPlaying ? L10n.of(context).stop : L10n.of(context).playAudio, + message: _isPlaying + ? L10n.of(context).stop + : L10n.of(context).playAudio, child: MouseRegion( cursor: SystemMouseCursors.click, child: GestureDetector( - onTap: widget.callbackOverride ?? + onTap: + widget.callbackOverride ?? () async { if (_isPlaying) { await TtsController.stop(); @@ -111,9 +113,7 @@ class WordAudioButtonState extends State { ? const SizedBox( width: 16, height: 16, - child: CircularProgressIndicator( - strokeWidth: 3, - ), + child: CircularProgressIndicator(strokeWidth: 3), ) : Icon( _isPlaying ? Icons.pause_outlined : Icons.volume_up, diff --git a/lib/pangea/constructs/construct_form.dart b/lib/pangea/constructs/construct_form.dart index 50f62d47d..05f37d167 100644 --- a/lib/pangea/constructs/construct_form.dart +++ b/lib/pangea/constructs/construct_form.dart @@ -7,10 +7,7 @@ class ConstructForm { /// The constructIdenfifier final ConstructIdentifier cId; - ConstructForm({ - required this.form, - required this.cId, - }); + ConstructForm({required this.form, required this.cId}); @override bool operator ==(Object other) { @@ -30,9 +27,6 @@ class ConstructForm { } Map toJson() { - return { - 'form': form, - 'cId': cId.toJson(), - }; + return {'form': form, 'cId': cId.toJson()}; } } diff --git a/lib/pangea/constructs/construct_identifier.dart b/lib/pangea/constructs/construct_identifier.dart index 63943c074..e0c240621 100644 --- a/lib/pangea/constructs/construct_identifier.dart +++ b/lib/pangea/constructs/construct_identifier.dart @@ -39,11 +39,7 @@ class ConstructIdentifier { debugger(when: kDebugMode); ErrorHandler.logError( e: Exception("Morph feature not found"), - data: { - "category": category, - "lemma": lemma, - "type": type, - }, + data: {"category": category, "lemma": lemma, "type": type}, ); } } @@ -88,11 +84,7 @@ class ConstructIdentifier { } Map toJson() { - return { - 'lemma': lemma, - 'type': type.string, - 'cat': category, - }; + return {'lemma': lemma, 'type': type.string, 'cat': category}; } // override operator == and hashCode @@ -132,11 +124,7 @@ class ConstructIdentifier { if (type == null) return null; - return ConstructIdentifier( - lemma: lemma, - type: type, - category: category, - ); + return ConstructIdentifier(lemma: lemma, type: type, category: category); } bool get isContentWord => @@ -147,10 +135,10 @@ class ConstructIdentifier { partOfSpeech: category, lemmaLang: MatrixState.pangeaController.userController.userL2?.langCodeShort ?? - LanguageKeys.defaultLanguage, + LanguageKeys.defaultLanguage, userL1: MatrixState.pangeaController.userController.userL1?.langCodeShort ?? - LanguageKeys.defaultLanguage, + LanguageKeys.defaultLanguage, lemma: lemma, messageInfo: messageInfo, ); @@ -158,11 +146,10 @@ class ConstructIdentifier { /// [lemmmaLang] if not set, assumed to be userL2 Future> getLemmaInfo( Map messageInfo, - ) => - LemmaInfoRepo.get( - MatrixState.pangeaController.userController.accessToken, - lemmaInfoRequest(messageInfo), - ); + ) => LemmaInfoRepo.get( + MatrixState.pangeaController.userController.accessToken, + lemmaInfoRequest(messageInfo), + ); String? get userSetEmoji => _userLemmaInfo.emojis?.firstOrNull; @@ -182,26 +169,17 @@ class ConstructIdentifier { final typeName = parts[1]; final category = parts[2]; - final type = ConstructTypeEnum.values.firstWhereOrNull( - (e) => e.name == typeName, - ) ?? + final type = + ConstructTypeEnum.values.firstWhereOrNull((e) => e.name == typeName) ?? ConstructTypeEnum.vocab; - return ConstructIdentifier( - lemma: lemma, - type: type, - category: category, - ); + return ConstructIdentifier(lemma: lemma, type: type, category: category); } PangeaToken get asToken => PangeaToken( - lemma: Lemma( - text: lemma, - saveVocab: true, - form: lemma, - ), - pos: category, - text: PangeaTokenText.fromString(lemma), - morph: {}, - ); + lemma: Lemma(text: lemma, saveVocab: true, form: lemma), + pos: category, + text: PangeaTokenText.fromString(lemma), + morph: {}, + ); } diff --git a/lib/pangea/constructs/construct_level_enum.dart b/lib/pangea/constructs/construct_level_enum.dart index 1fc003cf2..6e973c3df 100644 --- a/lib/pangea/constructs/construct_level_enum.dart +++ b/lib/pangea/constructs/construct_level_enum.dart @@ -4,21 +4,13 @@ import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/pangea/analytics_misc/analytics_constants.dart'; import 'package:fluffychat/pangea/common/widgets/customized_svg.dart'; -enum ConstructLevelEnum { - flowers, - greens, - seeds, -} +enum ConstructLevelEnum { flowers, greens, seeds } extension ConstructLevelEnumExt on ConstructLevelEnum { Color color(BuildContext context) { switch (this) { case ConstructLevelEnum.flowers: - return Color.lerp( - AppConfig.primaryColor, - Colors.white, - 0.6, - ) ?? + return Color.lerp(AppConfig.primaryColor, Colors.white, 0.6) ?? AppConfig.primaryColor; case ConstructLevelEnum.greens: return Color.lerp(AppConfig.success, Colors.white, 0.6) ?? @@ -31,11 +23,7 @@ extension ConstructLevelEnumExt on ConstructLevelEnum { Color darkColor(BuildContext context) { switch (this) { case ConstructLevelEnum.flowers: - return Color.lerp( - AppConfig.primaryColor, - Colors.white, - 0.3, - ) ?? + return Color.lerp(AppConfig.primaryColor, Colors.white, 0.3) ?? AppConfig.primaryColor; case ConstructLevelEnum.greens: return Color.lerp(AppConfig.success, Colors.black, 0.3) ?? @@ -90,15 +78,10 @@ extension ConstructLevelEnumExt on ConstructLevelEnum { } Widget icon([double? size]) => CustomizedSvg( - svgUrl: _svgURL, - colorReplacements: const {}, - errorIcon: Text( - emoji, - style: TextStyle( - fontSize: size ?? 24, - ), - ), - width: size, - height: size, - ); + svgUrl: _svgURL, + colorReplacements: const {}, + errorIcon: Text(emoji, style: TextStyle(fontSize: size ?? 24)), + width: size, + height: size, + ); } diff --git a/lib/pangea/constructs/construct_repo.dart b/lib/pangea/constructs/construct_repo.dart index 8fe3bb917..bedafc4a9 100644 --- a/lib/pangea/constructs/construct_repo.dart +++ b/lib/pangea/constructs/construct_repo.dart @@ -97,14 +97,10 @@ class ConstructSummaryRequest { class ConstructSummaryResponse { final ConstructSummary summary; - ConstructSummaryResponse({ - required this.summary, - }); + ConstructSummaryResponse({required this.summary}); Map toJson() { - return { - 'summary': summary.toJson(), - }; + return {'summary': summary.toJson()}; } factory ConstructSummaryResponse.fromJson(Map json) { @@ -122,8 +118,10 @@ class ConstructRepo { choreoApiKey: Environment.choreoApiKey, accessToken: MatrixState.pangeaController.userController.accessToken, ); - final Response res = - await req.post(url: PApiUrls.constructSummary, body: request.toJson()); + final Response res = await req.post( + url: PApiUrls.constructSummary, + body: request.toJson(), + ); final decodedBody = jsonDecode(utf8.decode(res.bodyBytes)); final response = ConstructSummaryResponse.fromJson(decodedBody); return response; diff --git a/lib/pangea/course_chats/activity_template_chat_list_item.dart b/lib/pangea/course_chats/activity_template_chat_list_item.dart index 6396be97f..c589a5d82 100644 --- a/lib/pangea/course_chats/activity_template_chat_list_item.dart +++ b/lib/pangea/course_chats/activity_template_chat_list_item.dart @@ -26,10 +26,7 @@ class ActivityTemplateChatListItem extends StatelessWidget { Widget build(BuildContext context) { final activity = sessions.first.activity; return Padding( - padding: const EdgeInsets.symmetric( - horizontal: 8, - vertical: 1, - ), + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 1), child: Column( spacing: 10.0, mainAxisSize: MainAxisSize.min, @@ -43,9 +40,7 @@ class ActivityTemplateChatListItem extends StatelessWidget { leading: ImageByUrl( imageUrl: activity.imageURL, width: Avatar.defaultSize, - borderRadius: BorderRadius.circular( - AppConfig.borderRadius / 2, - ), + borderRadius: BorderRadius.circular(AppConfig.borderRadius / 2), replacement: Avatar( name: activity.title, borderRadius: BorderRadius.circular( @@ -66,53 +61,44 @@ class ActivityTemplateChatListItem extends StatelessWidget { ), ), ), - ...sessions.map( - (e) { - return Padding( - padding: const EdgeInsets.only( - top: 4.0, - bottom: 4.0, - right: 4.0, - left: 14.0, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: OpenRolesIndicator( - roles: e.activity.roles.values.toList(), - assignedRoles: e.assignedRoles, - space: space, + ...sessions.map((e) { + return Padding( + padding: const EdgeInsets.only( + top: 4.0, + bottom: 4.0, + right: 4.0, + left: 14.0, + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: OpenRolesIndicator( + roles: e.activity.roles.values.toList(), + assignedRoles: e.assignedRoles, + space: space, + ), + ), + ConstrainedBox( + constraints: const BoxConstraints(maxHeight: 24.0), + child: ElevatedButton( + onPressed: () => showFutureLoadingDialog( + context: context, + future: () => joinActivity(e), + ), + style: ElevatedButton.styleFrom( + padding: const EdgeInsets.only(left: 8.0, right: 8.0), + ), + child: Text( + L10n.of(context).join, + style: const TextStyle(fontSize: 12), ), ), - ConstrainedBox( - constraints: const BoxConstraints( - maxHeight: 24.0, - ), - child: ElevatedButton( - onPressed: () => showFutureLoadingDialog( - context: context, - future: () => joinActivity(e), - ), - style: ElevatedButton.styleFrom( - padding: const EdgeInsets.only( - left: 8.0, - right: 8.0, - ), - ), - child: Text( - L10n.of(context).join, - style: const TextStyle( - fontSize: 12, - ), - ), - ), - ), - ], - ), - ); - }, - ), + ), + ], + ), + ); + }), ], ), ); diff --git a/lib/pangea/course_chats/course_chats_page.dart b/lib/pangea/course_chats/course_chats_page.dart index 379155bd1..f3f7c6142 100644 --- a/lib/pangea/course_chats/course_chats_page.dart +++ b/lib/pangea/course_chats/course_chats_page.dart @@ -57,9 +57,7 @@ class CourseChatsController extends State @override void initState() { - loadHierarchy(reload: true).then( - (_) => _joinDefaultChats(), - ); + loadHierarchy(reload: true).then((_) => _joinDefaultChats()); // Listen for changes to the activeSpace's hierarchy, // and reload the hierarchy when they come through @@ -99,9 +97,7 @@ class CourseChatsController extends State room?.spaceChildren.map((c) => c.roomId).whereType().toSet() ?? {}; - List get joinedRooms => Matrix.of(context) - .client - .rooms + List get joinedRooms => Matrix.of(context).client.rooms .where((room) => childrenIds.contains(room.id)) .where((room) => !room.isHiddenRoom) .toList(); @@ -181,27 +177,30 @@ class CourseChatsController extends State if (chunk.canonicalAlias == null) continue; final alias = chunk.canonicalAlias!; - final isDefaultChat = (alias.localpart ?? '') - .startsWith(SpaceConstants.announcementsChatAlias) || - (alias.localpart ?? '') - .startsWith(SpaceConstants.introductionChatAlias); + final isDefaultChat = + (alias.localpart ?? '').startsWith( + SpaceConstants.announcementsChatAlias, + ) || + (alias.localpart ?? '').startsWith( + SpaceConstants.introductionChatAlias, + ); if (!isDefaultChat) continue; joinFutures.add( - widget.client.joinRoom(alias).then((_) { - discoveredChildren?.remove(chunk); - }).catchError((e, s) { - ErrorHandler.logError( - e: e, - s: s, - data: { - 'alias': alias, - 'spaceId': widget.roomId, - }, - ); - return null; - }), + widget.client + .joinRoom(alias) + .then((_) { + discoveredChildren?.remove(chunk); + }) + .catchError((e, s) { + ErrorHandler.logError( + e: e, + s: s, + data: {'alias': alias, 'spaceId': widget.roomId}, + ); + return null; + }), ); } @@ -271,8 +270,8 @@ class CourseChatsController extends State List? currentHierarchy = discoveredChildren == null || reload - ? null - : List.from(discoveredChildren!); + ? null + : List.from(discoveredChildren!); String? currentNextBatch = reload ? null : _nextBatch; // Makes repeated calls to the server until 10 new visible rooms have @@ -308,10 +307,7 @@ class CourseChatsController extends State // if rooms have earlier been loaded for this space, add those // previously loaded rooms to the front of the response list - response.rooms.insertAll( - 0, - currentHierarchy ?? [], - ); + response.rooms.insertAll(0, currentHierarchy ?? []); // finally, set the response to the last response for this space // and set the current next batch token @@ -351,13 +347,13 @@ class CourseChatsController extends State inviteEvent == null ? L10n.of(context).inviteForMe : inviteEvent.content.tryGet('reason') ?? - L10n.of(context).youInvitedBy( - room - .unsafeGetUserFromMemoryOrFallback( - inviteEvent.senderId, - ) - .calcDisplayname(i18n: matrixLocals), - ), + L10n.of(context).youInvitedBy( + room + .unsafeGetUserFromMemoryOrFallback( + inviteEvent.senderId, + ) + .calcDisplayname(i18n: matrixLocals), + ), textAlign: TextAlign.center, ), ), @@ -399,10 +395,7 @@ class CourseChatsController extends State return; case InviteAction.block: final userId = inviteEvent?.senderId; - context.go( - '/rooms/settings/security/ignorelist', - extra: userId, - ); + context.go('/rooms/settings/security/ignorelist', extra: userId); return; } if (!mounted) return; @@ -423,9 +416,7 @@ class CourseChatsController extends State if (room.membership == Membership.ban) { ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(L10n.of(context).youHaveBeenBannedFromThisChat), - ), + SnackBar(content: Text(L10n.of(context).youHaveBeenBannedFromThisChat)), ); return; } @@ -449,9 +440,7 @@ class CourseChatsController extends State context: context, chunk: item, via: space?.spaceChildren - .firstWhereOrNull( - (child) => child.roomId == item.roomId, - ) + .firstWhereOrNull((child) => child.roomId == item.roomId) ?.via, ); if (mounted && roomId != null) { @@ -483,9 +472,7 @@ class CourseChatsController extends State via: widget.client .getRoomById(widget.roomId) ?.spaceChildren - .firstWhereOrNull( - (child) => child.roomId == roomId, - ) + .firstWhereOrNull((child) => child.roomId == roomId) ?.via, ); @@ -501,17 +488,15 @@ class CourseChatsController extends State context.go("/rooms/spaces/${widget.roomId}/$roomId"); } - bool _includeSpaceChild( - Room space, - SpaceRoomsChunk$2 hierarchyMember, - ) { + bool _includeSpaceChild(Room space, SpaceRoomsChunk$2 hierarchyMember) { if (!mounted) return false; final bool isAnalyticsRoom = hierarchyMember.roomType == PangeaRoomTypes.analytics; - final bool isMember = [Membership.join, Membership.invite].contains( - widget.client.getRoomById(hierarchyMember.roomId)?.membership, - ); + final bool isMember = [ + Membership.join, + Membership.invite, + ].contains(widget.client.getRoomById(hierarchyMember.roomId)?.membership); final bool isSuggested = space.spaceChildSuggestionStatus[hierarchyMember.roomId] ?? true; @@ -558,27 +543,22 @@ class CourseChatsController extends State } final joinedRooms = joinUpdate?.entries - .where( - (e) => childrenIds.contains(e.key), - ) + .where((e) => childrenIds.contains(e.key)) .map((e) => e.value.timeline?.events) .whereType>(); final invitedRooms = inviteUpdate?.entries - .where( - (e) => childrenIds.contains(e.key), - ) + .where((e) => childrenIds.contains(e.key)) .map((e) => e.value.inviteState) .whereType>(); final leftRooms = leaveUpdate?.entries - .where( - (e) => childrenIds.contains(e.key), - ) + .where((e) => childrenIds.contains(e.key)) .map((e) => e.value.timeline?.events) .whereType>(); - final bool hasJoinedRoom = joinedRooms?.any( + final bool hasJoinedRoom = + joinedRooms?.any( (events) => events.any( (e) => e.senderId == widget.client.userID && @@ -587,7 +567,8 @@ class CourseChatsController extends State ) ?? false; - final bool hasLeftRoom = leftRooms?.any( + final bool hasLeftRoom = + leftRooms?.any( (events) => events.any( (e) => e.senderId == widget.client.userID && @@ -604,21 +585,16 @@ class CourseChatsController extends State final leaveTimeline = leaveUpdate?[widget.roomId]?.timeline?.events; if (joinTimeline == null && leaveTimeline == null) return false; - final bool hasJoinUpdate = joinTimeline?.any( - (event) => event.type == EventTypes.SpaceChild, - ) ?? + final bool hasJoinUpdate = + joinTimeline?.any((event) => event.type == EventTypes.SpaceChild) ?? false; - final bool hasLeaveUpdate = leaveTimeline?.any( - (event) => event.type == EventTypes.SpaceChild, - ) ?? + final bool hasLeaveUpdate = + leaveTimeline?.any((event) => event.type == EventTypes.SpaceChild) ?? false; return hasJoinUpdate || hasLeaveUpdate; } - int _sortSpaceChildren( - SpaceRoomsChunk$2 a, - SpaceRoomsChunk$2 b, - ) { + int _sortSpaceChildren(SpaceRoomsChunk$2 a, SpaceRoomsChunk$2 b) { final bool aIsSpace = a.roomType == 'm.space'; final bool bIsSpace = b.roomType == 'm.space'; @@ -635,9 +611,7 @@ class CourseChatsController extends State return !room!.dismissedDefaultChat(type) && !room!.hasDefaultChat(type); } - Future dismissDefaultChatCreation( - CourseDefaultChatsEnum type, - ) async { + Future dismissDefaultChatCreation(CourseDefaultChatsEnum type) async { if (room == null) { throw Exception("Room is null"); } @@ -651,9 +625,7 @@ class CourseChatsController extends State await room!.setCourseChatsSettings(settings); } - Future createDefaultChat( - CourseDefaultChatsEnum type, - ) async { + Future createDefaultChat(CourseDefaultChatsEnum type) async { if (room == null) { throw Exception("Room is null"); } diff --git a/lib/pangea/course_chats/course_chats_settings_model.dart b/lib/pangea/course_chats/course_chats_settings_model.dart index a05af31c6..fa05467a9 100644 --- a/lib/pangea/course_chats/course_chats_settings_model.dart +++ b/lib/pangea/course_chats/course_chats_settings_model.dart @@ -8,9 +8,9 @@ class CourseChatsSettingsModel { }); Map toJson() => { - 'dismissed_intro_chat': dismissedIntroChat, - 'dismissed_announcements_chat': dismissedAnnouncementsChat, - }; + 'dismissed_intro_chat': dismissedIntroChat, + 'dismissed_announcements_chat': dismissedAnnouncementsChat, + }; factory CourseChatsSettingsModel.fromJson(Map json) { return CourseChatsSettingsModel( @@ -22,10 +22,9 @@ class CourseChatsSettingsModel { CourseChatsSettingsModel copyWith({ bool? dismissedIntroChat, bool? dismissedAnnouncementsChat, - }) => - CourseChatsSettingsModel( - dismissedIntroChat: dismissedIntroChat ?? this.dismissedIntroChat, - dismissedAnnouncementsChat: - dismissedAnnouncementsChat ?? this.dismissedAnnouncementsChat, - ); + }) => CourseChatsSettingsModel( + dismissedIntroChat: dismissedIntroChat ?? this.dismissedIntroChat, + dismissedAnnouncementsChat: + dismissedAnnouncementsChat ?? this.dismissedAnnouncementsChat, + ); } diff --git a/lib/pangea/course_chats/course_chats_view.dart b/lib/pangea/course_chats/course_chats_view.dart index ce4b41310..136c69a62 100644 --- a/lib/pangea/course_chats/course_chats_view.dart +++ b/lib/pangea/course_chats/course_chats_view.dart @@ -22,21 +22,13 @@ import 'package:fluffychat/widgets/future_loading_dialog.dart'; class CourseChatsView extends StatelessWidget { final CourseChatsController controller; - const CourseChatsView( - this.controller, { - super.key, - }); + const CourseChatsView(this.controller, {super.key}); @override Widget build(BuildContext context) { final room = controller.room; if (room == null) { - return const Center( - child: Icon( - Icons.search_outlined, - size: 80, - ), - ); + return const Center(child: Icon(Icons.search_outlined, size: 80)); } return StreamBuilder( @@ -48,21 +40,20 @@ class CourseChatsView extends StatelessWidget { final joinedSessions = controller.joinedActivities(); final discoveredGroupChats = controller.discoveredGroupChats; - final discoveredSessions = - controller.discoveredActivities().entries.toList(); + final discoveredSessions = controller + .discoveredActivities() + .entries + .toList(); final isColumnMode = FluffyThemes.isColumnMode(context); return Padding( padding: isColumnMode - ? const EdgeInsets.only( - top: 12.0, - left: 8.0, - right: 8.0, - ) + ? const EdgeInsets.only(top: 12.0, left: 8.0, right: 8.0) : const EdgeInsets.all(0.0), child: ListView.builder( shrinkWrap: true, - itemCount: joinedChats.length + + itemCount: + joinedChats.length + joinedSessions.length + discoveredGroupChats.length + discoveredSessions.length + @@ -81,10 +72,7 @@ class CourseChatsView extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ LearningProgressIndicators(), - Icon( - Icons.chat_bubble_outline, - size: 30.0, - ), + Icon(Icons.chat_bubble_outline, size: 30.0), SizedBox(height: 12.0), ], ), @@ -167,10 +155,7 @@ class CourseChatsView extends StatelessWidget { return joinedSessions.isEmpty ? const SizedBox() : Padding( - padding: const EdgeInsets.only( - top: 20.0, - bottom: 4.0, - ), + padding: const EdgeInsets.only(top: 20.0, bottom: 4.0), child: Text( L10n.of(context).myActivities, style: const TextStyle(fontSize: 12.0), @@ -204,10 +189,7 @@ class CourseChatsView extends StatelessWidget { return discoveredSessions.isEmpty ? const SizedBox() : Padding( - padding: const EdgeInsets.only( - top: 20.0, - bottom: 4.0, - ), + padding: const EdgeInsets.only(top: 20.0, bottom: 4.0), child: Text( L10n.of(context).openToJoin, style: const TextStyle(fontSize: 12.0), @@ -239,8 +221,9 @@ class CourseChatsView extends StatelessWidget { vertical: 2.0, ), child: TextButton( - onPressed: - controller.isLoading ? null : controller.loadHierarchy, + onPressed: controller.isLoading + ? null + : controller.loadHierarchy, child: controller.isLoading ? LinearProgressIndicator( borderRadius: BorderRadius.circular( diff --git a/lib/pangea/course_chats/course_default_chats_enum.dart b/lib/pangea/course_chats/course_default_chats_enum.dart index e9e335fbd..a0de4f5fc 100644 --- a/lib/pangea/course_chats/course_default_chats_enum.dart +++ b/lib/pangea/course_chats/course_default_chats_enum.dart @@ -7,31 +7,33 @@ enum CourseDefaultChatsEnum { announcements; String get alias => switch (this) { - CourseDefaultChatsEnum.introductions => - SpaceConstants.introductionChatAlias, - CourseDefaultChatsEnum.announcements => - SpaceConstants.announcementsChatAlias, - }; + CourseDefaultChatsEnum.introductions => + SpaceConstants.introductionChatAlias, + CourseDefaultChatsEnum.announcements => + SpaceConstants.announcementsChatAlias, + }; String title(L10n l10n) => switch (this) { - CourseDefaultChatsEnum.introductions => l10n.introductions, - CourseDefaultChatsEnum.announcements => l10n.announcements, - }; + CourseDefaultChatsEnum.introductions => l10n.introductions, + CourseDefaultChatsEnum.announcements => l10n.announcements, + }; String creationTitle(L10n l10n) => switch (this) { - CourseDefaultChatsEnum.introductions => l10n.introChatTitle, - CourseDefaultChatsEnum.announcements => l10n.announcementsChatTitle, - }; + CourseDefaultChatsEnum.introductions => l10n.introChatTitle, + CourseDefaultChatsEnum.announcements => l10n.announcementsChatTitle, + }; String creationDesc(L10n l10n) => switch (this) { - CourseDefaultChatsEnum.introductions => l10n.introChatDesc, - CourseDefaultChatsEnum.announcements => l10n.announcementsChatDesc, - }; + CourseDefaultChatsEnum.introductions => l10n.introChatDesc, + CourseDefaultChatsEnum.announcements => l10n.announcementsChatDesc, + }; dynamic powerLevels(String userID) => switch (this) { - CourseDefaultChatsEnum.introductions => - RoomDefaults.defaultPowerLevels(userID), - CourseDefaultChatsEnum.announcements => - RoomDefaults.restrictedPowerLevels(userID), - }; + CourseDefaultChatsEnum.introductions => RoomDefaults.defaultPowerLevels( + userID, + ), + CourseDefaultChatsEnum.announcements => RoomDefaults.restrictedPowerLevels( + userID, + ), + }; } diff --git a/lib/pangea/course_chats/open_roles_indicator.dart b/lib/pangea/course_chats/open_roles_indicator.dart index e90e7095b..4739903f0 100644 --- a/lib/pangea/course_chats/open_roles_indicator.dart +++ b/lib/pangea/course_chats/open_roles_indicator.dart @@ -37,21 +37,25 @@ class OpenRolesIndicator extends StatelessWidget { spacing: spacing ?? 2.0, children: [ ...roles.map((role) { - final assigned = - assignedRoles.firstWhereOrNull((r) => r.id == role.id); + final assigned = assignedRoles.firstWhereOrNull( + (r) => r.id == role.id, + ); final user = assigned != null - ? roomParticipants - .firstWhereOrNull((p) => p.id == assigned.userId) ?? - spaceParticipants - .firstWhereOrNull((p) => p.id == assigned.userId) + ? roomParticipants.firstWhereOrNull( + (p) => p.id == assigned.userId, + ) ?? + spaceParticipants.firstWhereOrNull( + (p) => p.id == assigned.userId, + ) : null; if (assigned != null) { return Builder( builder: (context) => Avatar( mxContent: user?.avatarUrl, - name: user?.calcDisplayname() ?? + name: + user?.calcDisplayname() ?? assigned.userId.localpart ?? assigned.userId, size: size ?? 16, diff --git a/lib/pangea/course_chats/unjoined_chat_list_item.dart b/lib/pangea/course_chats/unjoined_chat_list_item.dart index 0d2372812..3ddeec3bb 100644 --- a/lib/pangea/course_chats/unjoined_chat_list_item.dart +++ b/lib/pangea/course_chats/unjoined_chat_list_item.dart @@ -21,10 +21,7 @@ class UnjoinedChatListItem extends StatelessWidget { final displayname = chunk.name ?? chunk.canonicalAlias ?? L10n.of(context).emptyChat; return Padding( - padding: const EdgeInsets.symmetric( - horizontal: 8, - vertical: 1, - ), + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 1), child: Material( borderRadius: BorderRadius.circular(AppConfig.borderRadius), clipBehavior: Clip.hardEdge, @@ -35,14 +32,11 @@ class UnjoinedChatListItem extends StatelessWidget { leading: Avatar( mxContent: chunk.avatarUrl, name: displayname, - userId: Matrix.of(context) - .client - .getRoomById(chunk.roomId) - ?.directChatMatrixID, + userId: Matrix.of( + context, + ).client.getRoomById(chunk.roomId)?.directChatMatrixID, borderRadius: chunk.roomType == 'm.space' - ? BorderRadius.circular( - AppConfig.borderRadius / 2, - ) + ? BorderRadius.circular(AppConfig.borderRadius / 2) : null, ), title: Row( @@ -62,17 +56,12 @@ class UnjoinedChatListItem extends StatelessWidget { ), ), const SizedBox(width: 4), - const Icon( - Icons.people_outlined, - size: 14, - ), + const Icon(Icons.people_outlined, size: 14), ], ), subtitle: Text( chunk.topic ?? - L10n.of(context).countParticipants( - chunk.numJoinedMembers, - ), + L10n.of(context).countParticipants(chunk.numJoinedMembers), maxLines: 1, overflow: TextOverflow.ellipsis, ), diff --git a/lib/pangea/course_creation/course_info_chip_widget.dart b/lib/pangea/course_creation/course_info_chip_widget.dart index 51daf3d2b..991dc64b9 100644 --- a/lib/pangea/course_creation/course_info_chip_widget.dart +++ b/lib/pangea/course_creation/course_info_chip_widget.dart @@ -28,16 +28,8 @@ class CourseInfoChip extends StatelessWidget { spacing: 4.0, mainAxisSize: MainAxisSize.min, children: [ - Icon( - icon, - size: iconSize, - ), - Text( - text, - style: TextStyle( - fontSize: fontSize, - ), - ), + Icon(icon, size: iconSize), + Text(text, style: TextStyle(fontSize: fontSize)), ], ), ); diff --git a/lib/pangea/course_creation/course_invite_page.dart b/lib/pangea/course_creation/course_invite_page.dart index 2af4659e8..1f50e8e67 100644 --- a/lib/pangea/course_creation/course_invite_page.dart +++ b/lib/pangea/course_creation/course_invite_page.dart @@ -54,12 +54,12 @@ class CourseInvitePageController extends State final spaceId = await widget.courseCreationCompleter!.future; final room = Matrix.of(context).client.getRoomById(spaceId); if (room == null || room.coursePlan == null) { - await Matrix.of(context).client.onRoomState.stream.firstWhere((event) { - return event.roomId == spaceId && - event.state.type == PangeaEventTypes.coursePlan; - }).timeout( - const Duration(seconds: 10), - ); + await Matrix.of(context).client.onRoomState.stream + .firstWhere((event) { + return event.roomId == spaceId && + event.state.type == PangeaEventTypes.coursePlan; + }) + .timeout(const Duration(seconds: 10)); } return spaceId; } @@ -76,9 +76,7 @@ class CourseInvitePageController extends State child: Center( child: Container( padding: const EdgeInsets.all(20.0), - constraints: const BoxConstraints( - maxWidth: 750, - ), + constraints: const BoxConstraints(maxWidth: 750), child: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ @@ -97,10 +95,7 @@ class CourseInvitePageController extends State spacing: 10.0, mainAxisAlignment: MainAxisAlignment.center, children: [ - const Icon( - Icons.map_outlined, - size: 40.0, - ), + const Icon(Icons.map_outlined, size: 40.0), Flexible( child: Text( course!.title, @@ -121,8 +116,8 @@ class CourseInvitePageController extends State ), ) : loadingCourse - ? const CircularProgressIndicator.adaptive() - : const SizedBox(), + ? const CircularProgressIndicator.adaptive() + : const SizedBox(), Padding( padding: const EdgeInsets.all(8.0), child: Column( @@ -144,13 +139,15 @@ class CourseInvitePageController extends State mainAxisSize: MainAxisSize.min, children: [ FutureBuilder( - future: - client.getProfileFromUserId(client.userID!), + future: client.getProfileFromUserId( + client.userID!, + ), builder: (context, snapshot) { return Avatar( size: avatarSize, mxContent: snapshot.data?.avatarUrl, - name: snapshot.data?.displayName ?? + name: + snapshot.data?.displayName ?? client.userID!.localpart, userId: client.userID!, ); @@ -170,10 +167,7 @@ class CourseInvitePageController extends State ), ); }), - const Icon( - Icons.more_horiz, - size: 24.0, - ), + const Icon(Icons.more_horiz, size: 24.0), ], ); }, @@ -229,9 +223,7 @@ class CourseInvitePageController extends State child: Row( spacing: 8.0, mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text(L10n.of(context).playWithAI), - ], + children: [Text(L10n.of(context).playWithAI)], ), ), ], diff --git a/lib/pangea/course_creation/course_language_filter.dart b/lib/pangea/course_creation/course_language_filter.dart index e5c45cdf5..701f77ad7 100644 --- a/lib/pangea/course_creation/course_language_filter.dart +++ b/lib/pangea/course_creation/course_language_filter.dart @@ -25,11 +25,8 @@ class CourseLanguageFilter extends StatelessWidget { displayname: (v) => v.getDisplayName(context), enableSearch: true, defaultName: L10n.of(context).allLanguages, - searchMatchFn: (item, searchValue) => LanguageModel.search( - item.value, - searchValue, - context, - ), + searchMatchFn: (item, searchValue) => + LanguageModel.search(item.value, searchValue, context), ); } } diff --git a/lib/pangea/course_creation/course_plan_filter_widget.dart b/lib/pangea/course_creation/course_plan_filter_widget.dart index 8f95e6779..6512af83e 100644 --- a/lib/pangea/course_creation/course_plan_filter_widget.dart +++ b/lib/pangea/course_creation/course_plan_filter_widget.dart @@ -49,10 +49,7 @@ class CoursePlanFilterState extends State> { borderRadius: BorderRadius.circular(40.0), color: theme.colorScheme.surfaceContainerHighest, ), - padding: const EdgeInsets.symmetric( - horizontal: 16.0, - vertical: 12.0, - ), + padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 12.0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ @@ -61,9 +58,7 @@ class CoursePlanFilterState extends State> { ? widget.displayname(widget.value as T) : widget.defaultName, ), - const Icon( - Icons.arrow_drop_down, - ), + const Icon(Icons.arrow_drop_down), ], ), ), @@ -83,9 +78,7 @@ class CoursePlanFilterState extends State> { .toList(), onChanged: widget.onChanged, buttonStyleData: ButtonStyleData( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(40), - ), + decoration: BoxDecoration(borderRadius: BorderRadius.circular(40)), ), dropdownStyleData: DropdownStyleData( elevation: 8, @@ -94,9 +87,7 @@ class CoursePlanFilterState extends State> { color: theme.colorScheme.surfaceContainerHigh, ), ), - menuItemStyleData: const MenuItemStyleData( - padding: EdgeInsets.zero, - ), + menuItemStyleData: const MenuItemStyleData(padding: EdgeInsets.zero), dropdownSearchData: widget.enableSearch ? DropdownSearchData( searchController: _searchController, diff --git a/lib/pangea/course_creation/course_plan_tile_widget.dart b/lib/pangea/course_creation/course_plan_tile_widget.dart index af39160fe..22a7c40f0 100644 --- a/lib/pangea/course_creation/course_plan_tile_widget.dart +++ b/lib/pangea/course_creation/course_plan_tile_widget.dart @@ -39,8 +39,9 @@ class CoursePlanTile extends StatelessWidget { onTap: onTap, child: Container( decoration: BoxDecoration( - color: - hovered ? theme.colorScheme.onSurface.withAlpha(10) : null, + color: hovered + ? theme.colorScheme.onSurface.withAlpha(10) + : null, ), child: Row( spacing: 4.0, @@ -68,9 +69,7 @@ class CoursePlanTile extends StatelessWidget { course.title, maxLines: 1, overflow: TextOverflow.ellipsis, - style: TextStyle( - fontSize: titleFontSize, - ), + style: TextStyle(fontSize: titleFontSize), ), CourseInfoChips( courseId, diff --git a/lib/pangea/course_creation/public_course_preview.dart b/lib/pangea/course_creation/public_course_preview.dart index 15b5f3424..8a56b1b32 100644 --- a/lib/pangea/course_creation/public_course_preview.dart +++ b/lib/pangea/course_creation/public_course_preview.dart @@ -19,10 +19,7 @@ import 'package:fluffychat/widgets/matrix.dart'; class PublicCoursePreview extends StatefulWidget { final String? roomID; - const PublicCoursePreview({ - super.key, - required this.roomID, - }); + const PublicCoursePreview({super.key, required this.roomID}); @override PublicCoursePreviewController createState() => @@ -110,10 +107,7 @@ class PublicCoursePreviewController extends State return; } - final roomId = await SpaceCodeController.joinSpaceWithCode( - context, - code, - ); + final roomId = await SpaceCodeController.joinSpaceWithCode(context, code); if (roomId != null) { final room = Matrix.of(context).client.getRoomById(roomId); @@ -149,11 +143,7 @@ class PublicCoursePreviewController extends State ? await client.knockRoom(widget.roomID!) : await client.joinRoom(widget.roomID!); } catch (e, s) { - ErrorHandler.logError( - e: e, - s: s, - data: {'roomID': widget.roomID}, - ); + ErrorHandler.logError(e: e, s: s, data: {'roomID': widget.roomID}); rethrow; } diff --git a/lib/pangea/course_creation/public_course_preview_view.dart b/lib/pangea/course_creation/public_course_preview_view.dart index 213560f07..f9d991ee6 100644 --- a/lib/pangea/course_creation/public_course_preview_view.dart +++ b/lib/pangea/course_creation/public_course_preview_view.dart @@ -16,10 +16,7 @@ import 'package:fluffychat/widgets/matrix.dart'; class PublicCoursePreviewView extends StatelessWidget { final PublicCoursePreviewController controller; - const PublicCoursePreviewView( - this.controller, { - super.key, - }); + const PublicCoursePreviewView(this.controller, {super.key}); @override Widget build(BuildContext context) { @@ -32,9 +29,7 @@ class PublicCoursePreviewView extends StatelessWidget { const double smallIconSize = 12.0; return Scaffold( - appBar: AppBar( - title: Text(L10n.of(context).joinWithClassCode), - ), + appBar: AppBar(title: Text(L10n.of(context).joinWithClassCode)), body: SafeArea( child: Container( alignment: Alignment.topCenter, @@ -122,10 +117,10 @@ class PublicCoursePreviewView extends StatelessWidget { ), CourseInfoChip( icon: Icons.person, - text: - L10n.of(context).countParticipants( - summary.membershipSummary.length, - ), + text: L10n.of(context) + .countParticipants( + summary.membershipSummary.length, + ), fontSize: descFontSize, iconSize: smallIconSize, ), @@ -211,10 +206,10 @@ class PublicCoursePreviewView extends StatelessWidget { ), ), Padding( - padding: const EdgeInsetsGeometry - .symmetric( - vertical: 2.0, - ), + padding: + const EdgeInsetsGeometry.symmetric( + vertical: 2.0, + ), child: Row( spacing: 8.0, mainAxisSize: MainAxisSize.min, @@ -265,13 +260,9 @@ class PublicCoursePreviewView extends StatelessWidget { Row( spacing: 8.0, children: [ - const Expanded( - child: Divider(), - ), + const Expanded(child: Divider()), Text(L10n.of(context).or), - const Expanded( - child: Divider(), - ), + const Expanded(child: Divider()), ], ), ], @@ -328,19 +319,14 @@ class _CourseAdminDisplay extends StatelessWidget { children: [ ...summary.adminUserIDs.map((adminId) { return FutureBuilder( - future: Matrix.of(context).client.getProfileFromUserId( - adminId, - ), + future: Matrix.of(context).client.getProfileFromUserId(adminId), builder: (context, snapshot) { final profile = snapshot.data; final displayName = profile?.displayName ?? adminId.localpart ?? adminId; return InkWell( onTap: profile != null - ? () => UserDialog.show( - context: context, - profile: profile, - ) + ? () => UserDialog.show(context: context, profile: profile) : null, child: Container( decoration: BoxDecoration( @@ -361,9 +347,7 @@ class _CourseAdminDisplay extends StatelessWidget { userId: adminId, ), ConstrainedBox( - constraints: const BoxConstraints( - maxWidth: 80.0, - ), + constraints: const BoxConstraints(maxWidth: 80.0), child: Text( displayName, style: TextStyle( diff --git a/lib/pangea/course_creation/selected_course_page.dart b/lib/pangea/course_creation/selected_course_page.dart index 86468890f..e6b33f165 100644 --- a/lib/pangea/course_creation/selected_course_page.dart +++ b/lib/pangea/course_creation/selected_course_page.dart @@ -25,12 +25,7 @@ class SelectedCourse extends StatefulWidget { /// In join mode, the ID of the space to join that already has this course. final String? spaceId; - const SelectedCourse( - this.courseId, - this.mode, { - super.key, - this.spaceId, - }); + const SelectedCourse(this.courseId, this.mode, {super.key, this.spaceId}); @override SelectedCourseController createState() => SelectedCourseController(); @@ -75,10 +70,7 @@ class SelectedCourseController extends State return; } - final roomId = await SpaceCodeController.joinSpaceWithCode( - context, - code, - ); + final roomId = await SpaceCodeController.joinSpaceWithCode(context, code); if (roomId != null) { final room = Matrix.of(context).client.getRoomById(roomId); @@ -97,10 +89,7 @@ class SelectedCourseController extends State } } - Future launchCourse( - String courseId, - CoursePlanModel course, - ) async { + Future launchCourse(String courseId, CoursePlanModel course) async { final client = Matrix.of(context).client; final Completer completer = Completer(); client @@ -112,9 +101,7 @@ class SelectedCourseController extends State initialState: [ sdk.StateEvent( type: PangeaEventTypes.coursePlan, - content: { - "uuid": courseId, - }, + content: {"uuid": courseId}, ), ], avatarUrl: course.imageUrl.toString(), @@ -123,10 +110,7 @@ class SelectedCourseController extends State .then((spaceId) => completer.complete(spaceId)) .catchError((error) => completer.completeError(error)); - context.go( - "/rooms/course/own/${widget.courseId}/invite", - extra: completer, - ); + context.go("/rooms/course/own/${widget.courseId}/invite", extra: completer); } Future addCourseToSpace(CoursePlanModel course) async { diff --git a/lib/pangea/course_creation/selected_course_view.dart b/lib/pangea/course_creation/selected_course_view.dart index 29d57d970..12159cf9a 100644 --- a/lib/pangea/course_creation/selected_course_view.dart +++ b/lib/pangea/course_creation/selected_course_view.dart @@ -12,10 +12,7 @@ import 'package:fluffychat/widgets/future_loading_dialog.dart'; class SelectedCourseView extends StatelessWidget { final SelectedCourseController controller; - const SelectedCourseView( - this.controller, { - super.key, - }); + const SelectedCourseView(this.controller, {super.key}); @override Widget build(BuildContext context) { @@ -30,11 +27,7 @@ class SelectedCourseView extends StatelessWidget { final course = controller.course; return Scaffold( - appBar: AppBar( - title: Text( - controller.title, - ), - ), + appBar: AppBar(title: Text(controller.title)), body: SafeArea( child: Container( alignment: Alignment.topCenter, @@ -43,263 +36,253 @@ class SelectedCourseView extends StatelessWidget { child: controller.loadingCourse ? const Center(child: CircularProgressIndicator.adaptive()) : controller.courseError != null || course == null - ? Center( - child: ErrorIndicator( - message: L10n.of(context).oopsSomethingWentWrong, - ), - ) - : Column( - children: [ - Expanded( - child: Padding( - padding: const EdgeInsets.only( - top: 12.0, - left: 12.0, - right: 12.0, - ), - child: ListView.builder( - itemCount: course.topicIds.length + 2, - itemBuilder: (context, index) { - final String displayname = course.title; + ? Center( + child: ErrorIndicator( + message: L10n.of(context).oopsSomethingWentWrong, + ), + ) + : Column( + children: [ + Expanded( + child: Padding( + padding: const EdgeInsets.only( + top: 12.0, + left: 12.0, + right: 12.0, + ), + child: ListView.builder( + itemCount: course.topicIds.length + 2, + itemBuilder: (context, index) { + final String displayname = course.title; - if (index == 0) { - return Column( - spacing: 8.0, - children: [ - ClipPath( - clipper: MapClipper(), - child: ImageByUrl( - imageUrl: course.imageUrl, - width: 100.0, - borderRadius: - BorderRadius.circular(0.0), - replacement: Avatar( - name: displayname, - size: 100.0, - borderRadius: - BorderRadius.circular(0.0), - ), + if (index == 0) { + return Column( + spacing: 8.0, + children: [ + ClipPath( + clipper: MapClipper(), + child: ImageByUrl( + imageUrl: course.imageUrl, + width: 100.0, + borderRadius: BorderRadius.circular( + 0.0, + ), + replacement: Avatar( + name: displayname, + size: 100.0, + borderRadius: BorderRadius.circular( + 0.0, ), ), - Text( - displayname, - style: const TextStyle( - fontSize: titleFontSize, - ), - ), - Text( - course.description, - style: const TextStyle( - fontSize: descFontSize, - ), - ), - CourseInfoChips( - controller.widget.courseId, - fontSize: descFontSize, - iconSize: smallIconSize, - ), - Padding( - padding: const EdgeInsets.only( - top: 4.0, - bottom: 8.0, - ), - child: Row( - spacing: 4.0, - children: [ - const Icon( - Icons.map, - size: largeIconSize, - ), - Text( - L10n.of(context).coursePlan, - style: const TextStyle( - fontSize: titleFontSize, - ), - ), - ], - ), - ), - ], - ); - } - - index--; - - if (index >= course.topicIds.length) { - return const SizedBox(height: 12.0); - } - - final topicId = course.topicIds[index]; - final topic = course.loadedTopics[topicId]; - - if (topic == null) { - return const SizedBox(); - } - - return Padding( - padding: const EdgeInsets.symmetric( - vertical: 4.0, + ), ), - child: Row( - spacing: 8.0, - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - ClipPath( - clipper: PinClipper(), - child: ImageByUrl( - imageUrl: topic.imageUrl, - width: 45.0, - replacement: Container( - width: 45.0, - height: 45.0, - decoration: BoxDecoration( - color: - theme.colorScheme.secondary, - ), + Text( + displayname, + style: const TextStyle( + fontSize: titleFontSize, + ), + ), + Text( + course.description, + style: const TextStyle( + fontSize: descFontSize, + ), + ), + CourseInfoChips( + controller.widget.courseId, + fontSize: descFontSize, + iconSize: smallIconSize, + ), + Padding( + padding: const EdgeInsets.only( + top: 4.0, + bottom: 8.0, + ), + child: Row( + spacing: 4.0, + children: [ + const Icon( + Icons.map, + size: largeIconSize, + ), + Text( + L10n.of(context).coursePlan, + style: const TextStyle( + fontSize: titleFontSize, ), ), + ], + ), + ), + ], + ); + } + + index--; + + if (index >= course.topicIds.length) { + return const SizedBox(height: 12.0); + } + + final topicId = course.topicIds[index]; + final topic = course.loadedTopics[topicId]; + + if (topic == null) { + return const SizedBox(); + } + + return Padding( + padding: const EdgeInsets.symmetric( + vertical: 4.0, + ), + child: Row( + spacing: 8.0, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ClipPath( + clipper: PinClipper(), + child: ImageByUrl( + imageUrl: topic.imageUrl, + width: 45.0, + replacement: Container( + width: 45.0, + height: 45.0, + decoration: BoxDecoration( + color: theme.colorScheme.secondary, + ), ), - Flexible( - child: Column( - spacing: 4.0, - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - Text( - topic.title, - style: const TextStyle( - fontSize: titleFontSize, - ), - ), - Text( - topic.description, - style: const TextStyle( - fontSize: descFontSize, - ), - ), - Padding( - padding: - const EdgeInsetsGeometry - .symmetric( + ), + ), + Flexible( + child: Column( + spacing: 4.0, + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Text( + topic.title, + style: const TextStyle( + fontSize: titleFontSize, + ), + ), + Text( + topic.description, + style: const TextStyle( + fontSize: descFontSize, + ), + ), + Padding( + padding: + const EdgeInsetsGeometry.symmetric( vertical: 2.0, ), - child: Row( - spacing: 8.0, - mainAxisSize: - MainAxisSize.min, - children: [ - if (topic.location != null) - CourseInfoChip( - icon: Icons.location_on, - text: topic.location!, - fontSize: descFontSize, - iconSize: smallIconSize, - ), - ], - ), - ), - ], + child: Row( + spacing: 8.0, + mainAxisSize: MainAxisSize.min, + children: [ + if (topic.location != null) + CourseInfoChip( + icon: Icons.location_on, + text: topic.location!, + fontSize: descFontSize, + iconSize: smallIconSize, + ), + ], + ), ), - ), - ], + ], + ), ), - ); - }, - ), + ], + ), + ); + }, + ), + ), + ), + Container( + decoration: BoxDecoration( + color: theme.colorScheme.surface, + border: Border( + top: BorderSide( + color: theme.dividerColor, + width: 1.0, ), ), - Container( - decoration: BoxDecoration( - color: theme.colorScheme.surface, - border: Border( - top: BorderSide( - color: theme.dividerColor, - width: 1.0, - ), - ), - ), - padding: const EdgeInsets.all(12.0), - child: Column( - spacing: 8.0, - mainAxisSize: MainAxisSize.min, + ), + padding: const EdgeInsets.all(12.0), + child: Column( + spacing: 8.0, + mainAxisSize: MainAxisSize.min, + children: [ + Row( + spacing: 12.0, children: [ - Row( - spacing: 12.0, - children: [ - const Icon( - Icons.edit, - size: mediumIconSize, + const Icon(Icons.edit, size: mediumIconSize), + Flexible( + child: Text( + L10n.of(context).editCourseLater, + style: const TextStyle( + fontSize: descFontSize, ), - Flexible( - child: Text( - L10n.of(context).editCourseLater, - style: const TextStyle( - fontSize: descFontSize, - ), - ), - ), - ], - ), - Row( - spacing: 12.0, - children: [ - const Icon( - Icons.shield, - size: mediumIconSize, - ), - Flexible( - child: Text( - L10n.of(context).newCourseAccess, - style: const TextStyle( - fontSize: descFontSize, - ), - ), - ), - ], - ), - Padding( - padding: const EdgeInsets.only(top: 8.0), - child: Column( - spacing: 8.0, - children: [ - ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: theme - .colorScheme.primaryContainer, - foregroundColor: theme - .colorScheme.onPrimaryContainer, - ), - onPressed: () => - showFutureLoadingDialog( - context: context, - future: () => - controller.submit(course), - ), - child: Row( - spacing: 8.0, - mainAxisAlignment: - MainAxisAlignment.center, - children: [ - const Icon(Icons.map_outlined), - Text( - controller.buttonText, - style: const TextStyle( - fontSize: titleFontSize, - ), - ), - ], - ), - ), - ], ), ), ], ), - ), - ], + Row( + spacing: 12.0, + children: [ + const Icon(Icons.shield, size: mediumIconSize), + Flexible( + child: Text( + L10n.of(context).newCourseAccess, + style: const TextStyle( + fontSize: descFontSize, + ), + ), + ), + ], + ), + Padding( + padding: const EdgeInsets.only(top: 8.0), + child: Column( + spacing: 8.0, + children: [ + ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: + theme.colorScheme.primaryContainer, + foregroundColor: + theme.colorScheme.onPrimaryContainer, + ), + onPressed: () => showFutureLoadingDialog( + context: context, + future: () => controller.submit(course), + ), + child: Row( + spacing: 8.0, + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + const Icon(Icons.map_outlined), + Text( + controller.buttonText, + style: const TextStyle( + fontSize: titleFontSize, + ), + ), + ], + ), + ), + ], + ), + ), + ], + ), ), + ], + ), ), ), ), diff --git a/lib/pangea/course_plans/course_activities/activity_summaries_provider.dart b/lib/pangea/course_plans/course_activities/activity_summaries_provider.dart index daf7be1a1..2780905b1 100644 --- a/lib/pangea/course_plans/course_activities/activity_summaries_provider.dart +++ b/lib/pangea/course_plans/course_activities/activity_summaries_provider.dart @@ -77,15 +77,14 @@ mixin ActivitySummariesProvider on State { Map activitySessions(String activityId) => Map.fromEntries( - roomSummaries?.entries - .where((v) => v.value.activityPlan?.activityId == activityId) ?? + roomSummaries?.entries.where( + (v) => v.value.activityPlan?.activityId == activityId, + ) ?? [], ); Map> - activitySessionStatuses( - String activityId, - ) { + activitySessionStatuses(String activityId) { final statuses = >{ ActivitySummaryStatus.notStarted: {}, ActivitySummaryStatus.inProgress: {}, @@ -145,10 +144,7 @@ mixin ActivitySummariesProvider on State { .toSet(); } - bool hasCompletedActivity( - String userID, - String activityID, - ) { + bool hasCompletedActivity(String userID, String activityID) { final completed = _completedActivities(userID); return completed.contains(activityID); } @@ -159,8 +155,9 @@ mixin ActivitySummariesProvider on State { int? activitiesToCompleteOverride, ) { final topicActivityIds = topic.activityIds.toSet(); - final completedTopicActivities = - _completedActivities(userID).intersection(topicActivityIds); + final completedTopicActivities = _completedActivities( + userID, + ).intersection(topicActivityIds); if (completedTopicActivities.length >= topicActivityIds.length) { return true; @@ -192,11 +189,7 @@ mixin ActivitySummariesProvider on State { if (topic == null) continue; if (!topic.activityListComplete) continue; - if (!_hasCompletedTopic( - userID, - topic, - activitiesToCompleteOverride, - ) && + if (!_hasCompletedTopic(userID, topic, activitiesToCompleteOverride) && topic.activityIds.isNotEmpty) { return topicId; } diff --git a/lib/pangea/course_plans/course_activities/course_activity_repo.dart b/lib/pangea/course_plans/course_activities/course_activity_repo.dart index d0e6175df..c29657a35 100644 --- a/lib/pangea/course_plans/course_activities/course_activity_repo.dart +++ b/lib/pangea/course_plans/course_activities/course_activity_repo.dart @@ -22,8 +22,9 @@ class CourseActivityRepo { await _storage.initStorage; final activities = getCached(request).plans; - final toFetch = - request.activityIds.where((id) => !activities.containsKey(id)).toList(); + final toFetch = request.activityIds + .where((id) => !activities.containsKey(id)) + .toList(); if (toFetch.isNotEmpty) { final fetchedActivities = await _fetch(request, batchId); @@ -82,9 +83,7 @@ class CourseActivityRepo { } } - static TranslateActivityResponse getCached( - TranslateActivityRequest request, - ) { + static TranslateActivityResponse getCached(TranslateActivityRequest request) { final Map activities = {}; for (final id in request.activityIds) { final cacheKey = "${id}_${request.l1}"; @@ -142,10 +141,7 @@ class CourseActivityRepo { return {}; } - static Future setSentFeedback( - String activityId, - String l1, - ) async { + static Future setSentFeedback(String activityId, String l1) async { final currentValue = sentFeedback; currentValue["${activityId}_$l1"] = DateTime.now(); await _storage.write( @@ -154,10 +150,7 @@ class CourseActivityRepo { ); } - static Future _clearSentFeedback( - String activityId, - String l1, - ) async { + static Future _clearSentFeedback(String activityId, String l1) async { final currentValue = sentFeedback; currentValue.remove("${activityId}_$l1"); await _storage.write( diff --git a/lib/pangea/course_plans/course_activities/course_activity_translation_request.dart b/lib/pangea/course_plans/course_activities/course_activity_translation_request.dart index 0f6cf2cf2..a7af6e29c 100644 --- a/lib/pangea/course_plans/course_activities/course_activity_translation_request.dart +++ b/lib/pangea/course_plans/course_activities/course_activity_translation_request.dart @@ -2,15 +2,9 @@ class TranslateActivityRequest { List activityIds; String l1; - TranslateActivityRequest({ - required this.activityIds, - required this.l1, - }); + TranslateActivityRequest({required this.activityIds, required this.l1}); - Map toJson() => { - "activity_ids": activityIds, - "l1": l1, - }; + Map toJson() => {"activity_ids": activityIds, "l1": l1}; factory TranslateActivityRequest.fromJson(Map json) { return TranslateActivityRequest( diff --git a/lib/pangea/course_plans/course_activities/course_activity_translation_response.dart b/lib/pangea/course_plans/course_activities/course_activity_translation_response.dart index ac1e995aa..43de19435 100644 --- a/lib/pangea/course_plans/course_activities/course_activity_translation_response.dart +++ b/lib/pangea/course_plans/course_activities/course_activity_translation_response.dart @@ -8,18 +8,13 @@ class TranslateActivityResponse { factory TranslateActivityResponse.fromJson(Map json) { final plansEntry = json['plans'] as Map; return TranslateActivityResponse( - plans: plansEntry.map( - (key, value) { - return MapEntry( - key, - ActivityPlanModel.fromJson(value), - ); - }, - ), + plans: plansEntry.map((key, value) { + return MapEntry(key, ActivityPlanModel.fromJson(value)); + }), ); } Map toJson() => { - "plans": plans.map((key, value) => MapEntry(key, value.toJson())), - }; + "plans": plans.map((key, value) => MapEntry(key, value.toJson())), + }; } diff --git a/lib/pangea/course_plans/course_info_batch_request.dart b/lib/pangea/course_plans/course_info_batch_request.dart index 9aecf6c4e..ecab1f9ed 100644 --- a/lib/pangea/course_plans/course_info_batch_request.dart +++ b/lib/pangea/course_plans/course_info_batch_request.dart @@ -2,8 +2,5 @@ class CourseInfoBatchRequest { final String batchId; final List uuids; - CourseInfoBatchRequest({ - required this.batchId, - required this.uuids, - }); + CourseInfoBatchRequest({required this.batchId, required this.uuids}); } diff --git a/lib/pangea/course_plans/course_locations/course_location_media_repo.dart b/lib/pangea/course_plans/course_locations/course_location_media_repo.dart index 28c78e5dd..5fc87ff3c 100644 --- a/lib/pangea/course_plans/course_locations/course_location_media_repo.dart +++ b/lib/pangea/course_plans/course_locations/course_location_media_repo.dart @@ -12,8 +12,9 @@ import 'package:fluffychat/widgets/matrix.dart'; class CourseLocationMediaRepo { static final Map> _cache = {}; - static final GetStorage _storage = - GetStorage('course_location_media_storage'); + static final GetStorage _storage = GetStorage( + 'course_location_media_storage', + ); static Future get( CourseInfoBatchRequest request, @@ -27,10 +28,7 @@ class CourseLocationMediaRepo { if (toFetch.isNotEmpty) { final fetched = await _fetch( - CourseInfoBatchRequest( - batchId: request.batchId, - uuids: toFetch, - ), + CourseInfoBatchRequest(batchId: request.batchId, uuids: toFetch), ); urls.addAll(fetched.mediaUrls); @@ -82,20 +80,13 @@ class CourseLocationMediaRepo { } } - static CourseLocationMediaResponse getCached( - CourseInfoBatchRequest request, - ) { + static CourseLocationMediaResponse getCached(CourseInfoBatchRequest request) { final List urls = []; for (final uuid in request.uuids) { try { final url = _storage.read(uuid) as String?; if (url != null) { - urls.add( - CourseMediaInfo( - uuid: uuid, - url: url, - ), - ); + urls.add(CourseMediaInfo(uuid: uuid, url: url)); } } catch (e) { // If parsing fails, remove the corrupted cache entry diff --git a/lib/pangea/course_plans/course_locations/course_location_media_response.dart b/lib/pangea/course_plans/course_locations/course_location_media_response.dart index 2eff7b9d5..a884c666d 100644 --- a/lib/pangea/course_plans/course_locations/course_location_media_response.dart +++ b/lib/pangea/course_plans/course_locations/course_location_media_response.dart @@ -5,23 +5,16 @@ import 'package:fluffychat/pangea/payload_client/paginated_response.dart'; class CourseLocationMediaResponse { final List mediaUrls; - CourseLocationMediaResponse({ - required this.mediaUrls, - }); + CourseLocationMediaResponse({required this.mediaUrls}); factory CourseLocationMediaResponse.fromCmsResponse( PayloadPaginatedResponse - cmsCoursePlanTopicLocationMediasResult, + cmsCoursePlanTopicLocationMediasResult, ) { return CourseLocationMediaResponse( mediaUrls: cmsCoursePlanTopicLocationMediasResult.docs .where((e) => e.url != null) - .map( - (e) => CourseMediaInfo( - uuid: e.id, - url: e.url!, - ), - ) + .map((e) => CourseMediaInfo(uuid: e.id, url: e.url!)) .toList(), ); } diff --git a/lib/pangea/course_plans/course_locations/course_location_model.dart b/lib/pangea/course_plans/course_locations/course_location_model.dart index ad931a6c9..1845d8ebe 100644 --- a/lib/pangea/course_plans/course_locations/course_location_model.dart +++ b/lib/pangea/course_plans/course_locations/course_location_model.dart @@ -13,7 +13,8 @@ class CourseLocationModel { return CourseLocationModel( uuid: json['uuid'] as String, name: json['name'] as String, - mediaIds: (json['media_ids'] as List?) + mediaIds: + (json['media_ids'] as List?) ?.map((e) => e as String) .toList() ?? [], @@ -21,10 +22,6 @@ class CourseLocationModel { } Map toJson() { - return { - 'uuid': uuid, - 'name': name, - 'media_ids': mediaIds, - }; + return {'uuid': uuid, 'name': name, 'media_ids': mediaIds}; } } diff --git a/lib/pangea/course_plans/course_locations/course_location_repo.dart b/lib/pangea/course_plans/course_locations/course_location_repo.dart index 6931ddff1..c19e037db 100644 --- a/lib/pangea/course_plans/course_locations/course_location_repo.dart +++ b/lib/pangea/course_plans/course_locations/course_location_repo.dart @@ -28,10 +28,7 @@ class CourseLocationRepo { if (toFetch.isNotEmpty) { final fetchedLocations = await _fetch( - CourseInfoBatchRequest( - batchId: request.batchId, - uuids: toFetch, - ), + CourseInfoBatchRequest(batchId: request.batchId, uuids: toFetch), ); locations.addAll(fetchedLocations.locations); await _setCached(fetchedLocations); @@ -83,16 +80,15 @@ class CourseLocationRepo { } } - static CourseLocationResponse getCached( - CourseInfoBatchRequest request, - ) { + static CourseLocationResponse getCached(CourseInfoBatchRequest request) { final List locations = []; for (final uuid in request.uuids) { final json = _storage.read(uuid); if (json != null) { try { - final location = - CourseLocationModel.fromJson(Map.from(json)); + final location = CourseLocationModel.fromJson( + Map.from(json), + ); locations.add(location); } catch (e) { // If parsing fails, remove the corrupted cache entry diff --git a/lib/pangea/course_plans/course_locations/course_location_response.dart b/lib/pangea/course_plans/course_locations/course_location_response.dart index ba177d8ed..51546cc45 100644 --- a/lib/pangea/course_plans/course_locations/course_location_response.dart +++ b/lib/pangea/course_plans/course_locations/course_location_response.dart @@ -5,9 +5,7 @@ import 'package:fluffychat/pangea/payload_client/paginated_response.dart'; class CourseLocationResponse { final List locations; - CourseLocationResponse({ - required this.locations, - }); + CourseLocationResponse({required this.locations}); factory CourseLocationResponse.fromCmsResponse( PayloadPaginatedResponse response, diff --git a/lib/pangea/course_plans/course_media/course_media_info.dart b/lib/pangea/course_plans/course_media/course_media_info.dart index 7556e66b4..e1e342e53 100644 --- a/lib/pangea/course_plans/course_media/course_media_info.dart +++ b/lib/pangea/course_plans/course_media/course_media_info.dart @@ -2,8 +2,5 @@ class CourseMediaInfo { final String uuid; final String url; - CourseMediaInfo({ - required this.uuid, - required this.url, - }); + CourseMediaInfo({required this.uuid, required this.url}); } diff --git a/lib/pangea/course_plans/course_media/course_media_repo.dart b/lib/pangea/course_plans/course_media/course_media_repo.dart index a2d84546f..90b59940a 100644 --- a/lib/pangea/course_plans/course_media/course_media_repo.dart +++ b/lib/pangea/course_plans/course_media/course_media_repo.dart @@ -14,9 +14,7 @@ class CourseMediaRepo { static final Map> _cache = {}; static final GetStorage _storage = GetStorage('course_media_storage'); - static Future get( - CourseInfoBatchRequest request, - ) async { + static Future get(CourseInfoBatchRequest request) async { final urls = []; await _storage.initStorage; @@ -28,10 +26,7 @@ class CourseMediaRepo { if (toFetch.isNotEmpty) { final fetchedUrls = await _fetch( - CourseInfoBatchRequest( - batchId: request.batchId, - uuids: toFetch, - ), + CourseInfoBatchRequest(batchId: request.batchId, uuids: toFetch), ); urls.addAll(fetchedUrls.mediaUrls); await _setCached(fetchedUrls); @@ -93,12 +88,7 @@ class CourseMediaRepo { for (final uuid in request.uuids) { final cached = _storage.read(uuid); if (cached != null && cached is String) { - urls.add( - CourseMediaInfo( - uuid: uuid, - url: cached, - ), - ); + urls.add(CourseMediaInfo(uuid: uuid, url: cached)); } } diff --git a/lib/pangea/course_plans/course_media/course_media_response.dart b/lib/pangea/course_plans/course_media/course_media_response.dart index ed595f389..89731a5f9 100644 --- a/lib/pangea/course_plans/course_media/course_media_response.dart +++ b/lib/pangea/course_plans/course_media/course_media_response.dart @@ -5,9 +5,7 @@ import 'package:fluffychat/pangea/payload_client/paginated_response.dart'; class CourseMediaResponse { final List mediaUrls; - CourseMediaResponse({ - required this.mediaUrls, - }); + CourseMediaResponse({required this.mediaUrls}); factory CourseMediaResponse.fromCmsResponse( PayloadPaginatedResponse response, @@ -15,12 +13,7 @@ class CourseMediaResponse { return CourseMediaResponse( mediaUrls: response.docs .where((e) => e.url != null) - .map( - (e) => CourseMediaInfo( - uuid: e.id, - url: e.url!, - ), - ) + .map((e) => CourseMediaInfo(uuid: e.id, url: e.url!)) .toList(), ); } diff --git a/lib/pangea/course_plans/course_topics/course_topic_model.dart b/lib/pangea/course_plans/course_topics/course_topic_model.dart index aa2f3434d..6920eb67e 100644 --- a/lib/pangea/course_plans/course_topics/course_topic_model.dart +++ b/lib/pangea/course_plans/course_topics/course_topic_model.dart @@ -30,17 +30,11 @@ class CourseTopicModel { locationIds.length == loadedLocations.locations.length; CourseLocationResponse get loadedLocations => CourseLocationRepo.getCached( - CourseInfoBatchRequest( - batchId: uuid, - uuids: locationIds, - ), - ); + CourseInfoBatchRequest(batchId: uuid, uuids: locationIds), + ); Future _fetchLocations() => CourseLocationRepo.get( - CourseInfoBatchRequest( - batchId: uuid, - uuids: locationIds, - ), - ); + CourseInfoBatchRequest(batchId: uuid, uuids: locationIds), + ); String? get location => loadedLocations.locations.firstOrNull?.name; @@ -53,10 +47,7 @@ class CourseTopicModel { List get loadedLocationMediaIds => loadedLocations.locations .map( (location) => CourseLocationMediaRepo.getCached( - CourseInfoBatchRequest( - batchId: uuid, - uuids: location.mediaIds, - ), + CourseInfoBatchRequest(batchId: uuid, uuids: location.mediaIds), ).mediaUrls, ) .expand((e) => e) @@ -68,10 +59,7 @@ class CourseTopicModel { final locationResp = await _fetchLocations(); for (final location in locationResp.locations) { final mediaResp = await CourseLocationMediaRepo.get( - CourseInfoBatchRequest( - batchId: uuid, - uuids: location.mediaIds, - ), + CourseInfoBatchRequest(batchId: uuid, uuids: location.mediaIds), ); allLocationMedia.addAll(mediaResp.mediaUrls.map((e) => e.url)); @@ -110,10 +98,10 @@ class CourseTopicModel { factory CourseTopicModel.fromJson(Map json) { final List? activityIdsEntry = json['activity_ids'] as List? ?? - json['activityIds'] as List?; + json['activityIds'] as List?; final List? locationIdsEntry = json['location_ids'] as List? ?? - json['locationIds'] as List?; + json['locationIds'] as List?; return CourseTopicModel( title: json['title'] as String, diff --git a/lib/pangea/course_plans/course_topics/course_topic_repo.dart b/lib/pangea/course_plans/course_topics/course_topic_repo.dart index 1b0a152bc..b7fd22289 100644 --- a/lib/pangea/course_plans/course_topics/course_topic_repo.dart +++ b/lib/pangea/course_plans/course_topics/course_topic_repo.dart @@ -22,22 +22,17 @@ class CourseTopicRepo { await _storage.initStorage; final topics = getCached(request).topics; - final toFetch = - request.topicIds.where((uuid) => !topics.containsKey(uuid)).toList(); + final toFetch = request.topicIds + .where((uuid) => !topics.containsKey(uuid)) + .toList(); if (toFetch.isNotEmpty) { final fetchedTopics = await _fetch( - TranslateTopicRequest( - topicIds: toFetch, - l1: request.l1, - ), + TranslateTopicRequest(topicIds: toFetch, l1: request.l1), batchId, ); topics.addAll(fetchedTopics.topics); - await _setCached( - fetchedTopics, - request.l1, - ); + await _setCached(fetchedTopics, request.l1); } return TranslateTopicResponse(topics: topics); @@ -91,9 +86,7 @@ class CourseTopicRepo { } } - static TranslateTopicResponse getCached( - TranslateTopicRequest request, - ) { + static TranslateTopicResponse getCached(TranslateTopicRequest request) { final Map topics = {}; for (final uuid in request.topicIds) { final cacheKey = "${uuid}_${request.l1}"; @@ -119,12 +112,7 @@ class CourseTopicRepo { ) async { final List futures = []; for (final entry in response.topics.entries) { - futures.add( - _storage.write( - "${entry.key}_$l1", - entry.value.toJson(), - ), - ); + futures.add(_storage.write("${entry.key}_$l1", entry.value.toJson())); } await Future.wait(futures); } diff --git a/lib/pangea/course_plans/course_topics/course_topic_translation_request.dart b/lib/pangea/course_plans/course_topics/course_topic_translation_request.dart index a2a7fd1ea..9061b4780 100644 --- a/lib/pangea/course_plans/course_topics/course_topic_translation_request.dart +++ b/lib/pangea/course_plans/course_topics/course_topic_translation_request.dart @@ -2,20 +2,15 @@ class TranslateTopicRequest { List topicIds; String l1; - TranslateTopicRequest({ - required this.topicIds, - required this.l1, - }); + TranslateTopicRequest({required this.topicIds, required this.l1}); - Map toJson() => { - "topic_ids": topicIds, - "l1": l1, - }; + Map toJson() => {"topic_ids": topicIds, "l1": l1}; factory TranslateTopicRequest.fromJson(Map json) { return TranslateTopicRequest( - topicIds: - json['topic_ids'] != null ? List.from(json['topic_ids']) : [], + topicIds: json['topic_ids'] != null + ? List.from(json['topic_ids']) + : [], l1: json['l1'], ); } diff --git a/lib/pangea/course_plans/course_topics/course_topic_translation_response.dart b/lib/pangea/course_plans/course_topics/course_topic_translation_response.dart index 68b7a3829..d4aa5e564 100644 --- a/lib/pangea/course_plans/course_topics/course_topic_translation_response.dart +++ b/lib/pangea/course_plans/course_topics/course_topic_translation_response.dart @@ -9,15 +9,12 @@ class TranslateTopicResponse { final topicsEntry = json['topics'] as Map; return TranslateTopicResponse( topics: topicsEntry.map( - (key, value) => MapEntry( - key, - CourseTopicModel.fromJson(value), - ), + (key, value) => MapEntry(key, CourseTopicModel.fromJson(value)), ), ); } Map toJson() => { - "topics": topics.map((key, value) => MapEntry(key, value.toJson())), - }; + "topics": topics.map((key, value) => MapEntry(key, value.toJson())), + }; } diff --git a/lib/pangea/course_plans/courses/course_filter.dart b/lib/pangea/course_plans/courses/course_filter.dart index d34a3ce85..178f212ad 100644 --- a/lib/pangea/course_plans/courses/course_filter.dart +++ b/lib/pangea/course_plans/courses/course_filter.dart @@ -33,9 +33,7 @@ class CourseFilter { } if (languageOfInstructions != null) { where["and"].add({ - "l1": { - "equals": languageOfInstructions!.langCodeShort, - }, + "l1": {"equals": languageOfInstructions!.langCodeShort}, }); } if (targetLanguage != null) { @@ -48,9 +46,7 @@ class CourseFilter { where["cefrLevel"] = {"equals": cefrLevel!.string}; } if (languageOfInstructions != null) { - where["l1"] = { - "equals": languageOfInstructions!.langCodeShort, - }; + where["l1"] = {"equals": languageOfInstructions!.langCodeShort}; } if (targetLanguage != null) { where["l2"] = {"equals": targetLanguage!.langCodeShort}; diff --git a/lib/pangea/course_plans/courses/course_plan_builder.dart b/lib/pangea/course_plans/courses/course_plan_builder.dart index 3f4310328..b08ca0ee2 100644 --- a/lib/pangea/course_plans/courses/course_plan_builder.dart +++ b/lib/pangea/course_plans/courses/course_plan_builder.dart @@ -49,11 +49,7 @@ mixin CoursePlanProvider on State { ); await course!.fetchMediaUrls(); } catch (e, s) { - ErrorHandler.logError( - e: e, - s: s, - data: {'courseId': courseId}, - ); + ErrorHandler.logError(e: e, s: s, data: {'courseId': courseId}); courseError = e; } finally { if (mounted) setState(() => loadingCourse = false); diff --git a/lib/pangea/course_plans/courses/course_plan_client_extension.dart b/lib/pangea/course_plans/courses/course_plan_client_extension.dart index f24514ebd..602e52f88 100644 --- a/lib/pangea/course_plans/courses/course_plan_client_extension.dart +++ b/lib/pangea/course_plans/courses/course_plan_client_extension.dart @@ -4,7 +4,6 @@ import 'package:matrix/matrix.dart'; import 'package:fluffychat/pangea/course_plans/courses/course_plan_room_extension.dart'; extension CoursePlanClientExtension on Client { - Room? getRoomByCourseId(String courseId) => rooms.firstWhereOrNull( - (room) => room.coursePlan?.uuid == courseId, - ); + Room? getRoomByCourseId(String courseId) => + rooms.firstWhereOrNull((room) => room.coursePlan?.uuid == courseId); } diff --git a/lib/pangea/course_plans/courses/course_plan_event.dart b/lib/pangea/course_plans/courses/course_plan_event.dart index 116d28c16..10c1693aa 100644 --- a/lib/pangea/course_plans/courses/course_plan_event.dart +++ b/lib/pangea/course_plans/courses/course_plan_event.dart @@ -4,14 +4,10 @@ class CoursePlanEvent { CoursePlanEvent({required this.uuid}); Map toJson() { - return { - 'uuid': uuid, - }; + return {'uuid': uuid}; } factory CoursePlanEvent.fromJson(Map json) { - return CoursePlanEvent( - uuid: json['uuid'] as String, - ); + return CoursePlanEvent(uuid: json['uuid'] as String); } } diff --git a/lib/pangea/course_plans/courses/course_plan_model.dart b/lib/pangea/course_plans/courses/course_plan_model.dart index f944739ab..ee46a6ffc 100644 --- a/lib/pangea/course_plans/courses/course_plan_model.dart +++ b/lib/pangea/course_plans/courses/course_plan_model.dart @@ -61,11 +61,13 @@ class CoursePlanModel { title: json['title'] as String, description: json['description'] as String, uuid: json['uuid'] as String, - topicIds: (json['topic_ids'] as List?) + topicIds: + (json['topic_ids'] as List?) ?.map((e) => e as String) .toList() ?? [], - mediaIds: (json['media_ids'] as List?) + mediaIds: + (json['media_ids'] as List?) ?.map((e) => e as String) .toList() ?? [], @@ -93,11 +95,11 @@ class CoursePlanModel { bool get topicListComplete => topicIds.length == loadedTopics.length; Map get loadedTopics => CourseTopicRepo.getCached( - TranslateTopicRequest( - topicIds: topicIds, - l1: MatrixState.pangeaController.userController.userL1Code!, - ), - ).topics; + TranslateTopicRequest( + topicIds: topicIds, + l1: MatrixState.pangeaController.userController.userL1Code!, + ), + ).topics; Set get activityIDs => loadedTopics.values.expand((topic) => topic.activityIds).toSet(); @@ -116,21 +118,15 @@ class CoursePlanModel { bool get mediaListComplete => mediaIds.length == loadedMediaUrls.mediaUrls.length; CourseMediaResponse get loadedMediaUrls => CourseMediaRepo.getCached( - CourseInfoBatchRequest( - batchId: uuid, - uuids: mediaIds, - ), - ); + CourseInfoBatchRequest(batchId: uuid, uuids: mediaIds), + ); Future fetchMediaUrls() => CourseMediaRepo.get( - CourseInfoBatchRequest( - batchId: uuid, - uuids: mediaIds, - ), - ); + CourseInfoBatchRequest(batchId: uuid, uuids: mediaIds), + ); Uri? get imageUrl => loadedMediaUrls.mediaUrls.isEmpty ? loadedTopics.values - .lastWhereOrNull((topic) => topic.imageUrl != null) - ?.imageUrl + .lastWhereOrNull((topic) => topic.imageUrl != null) + ?.imageUrl : Uri.tryParse( "${Environment.cmsApi}${loadedMediaUrls.mediaUrls.first.url}", ); diff --git a/lib/pangea/course_plans/courses/course_plan_room_extension.dart b/lib/pangea/course_plans/courses/course_plan_room_extension.dart index 5c7207d06..99727f1ef 100644 --- a/lib/pangea/course_plans/courses/course_plan_room_extension.dart +++ b/lib/pangea/course_plans/courses/course_plan_room_extension.dart @@ -59,14 +59,9 @@ extension CoursePlanRoomExtension on Room { if (coursePlan?.uuid == courseId) return; final future = waitForRoomInSync(); - await client.setRoomStateWithKey( - id, - PangeaEventTypes.coursePlan, - "", - { - "uuid": courseId, - }, - ); + await client.setRoomStateWithKey(id, PangeaEventTypes.coursePlan, "", { + "uuid": courseId, + }); if (coursePlan?.uuid != courseId) { await future; } @@ -104,16 +99,11 @@ extension CoursePlanRoomExtension on Room { ), }).toJson(), ), - RoomDefaults.defaultPowerLevels( - client.userID!, - ), + RoomDefaults.defaultPowerLevels(client.userID!), await client.pangeaJoinRules( 'knock_restricted', allow: [ - { - "type": "m.room_membership", - "room_id": id, - } + {"type": "m.room_membership", "room_id": id}, ], ), ], @@ -153,9 +143,7 @@ extension CoursePlanRoomExtension on Room { return CourseChatsSettingsModel.fromJson(event.content); } - Future setCourseChatsSettings( - CourseChatsSettingsModel settings, - ) async { + Future setCourseChatsSettings(CourseChatsSettingsModel settings) async { await client.setRoomStateWithKey( id, PangeaEventTypes.courseChatList, @@ -165,8 +153,8 @@ extension CoursePlanRoomExtension on Room { } bool hasDefaultChat(CourseDefaultChatsEnum type) => pangeaSpaceChildren.any( - (r) => r.canonicalAlias.localpart?.startsWith(type.alias) == true, - ); + (r) => r.canonicalAlias.localpart?.startsWith(type.alias) == true, + ); bool dismissedDefaultChat(CourseDefaultChatsEnum type) { switch (type) { @@ -183,11 +171,14 @@ extension CoursePlanRoomExtension on Room { }) async { final random = Random(); final String uploadURL = switch (type) { - CourseDefaultChatsEnum.introductions => SpaceConstants - .introChatIcons[random.nextInt(SpaceConstants.introChatIcons.length)], + CourseDefaultChatsEnum.introductions => + SpaceConstants.introChatIcons[random.nextInt( + SpaceConstants.introChatIcons.length, + )], CourseDefaultChatsEnum.announcements => - SpaceConstants.announcementChatIcons[ - random.nextInt(SpaceConstants.announcementChatIcons.length)], + SpaceConstants.announcementChatIcons[random.nextInt( + SpaceConstants.announcementChatIcons.length, + )], }; final resp = await client.createRoom( @@ -197,18 +188,12 @@ extension CoursePlanRoomExtension on Room { roomAliasName: "${type.alias}_${id.localpart}_${DateTime.now().millisecondsSinceEpoch}", initialState: [ - StateEvent( - type: EventTypes.RoomAvatar, - content: {'url': uploadURL}, - ), + StateEvent(type: EventTypes.RoomAvatar, content: {'url': uploadURL}), type.powerLevels(client.userID!), await client.pangeaJoinRules( 'knock_restricted', allow: [ - { - "type": "m.room_membership", - "room_id": id, - } + {"type": "m.room_membership", "room_id": id}, ], ), ], diff --git a/lib/pangea/course_plans/courses/course_plans_repo.dart b/lib/pangea/course_plans/courses/course_plans_repo.dart index 0106046b3..ed28e9ae5 100644 --- a/lib/pangea/course_plans/courses/course_plans_repo.dart +++ b/lib/pangea/course_plans/courses/course_plans_repo.dart @@ -38,9 +38,7 @@ class CoursePlansRepo { // TODO: Currently just getting one course plan at a time // Should take advantage of batch fetching - static Future get( - GetLocalizedCoursesRequest request, - ) async { + static Future get(GetLocalizedCoursesRequest request) async { if (request.coursePlanIds.length != 1) { throw Exception("Get only supports single course plan ID"); } @@ -108,23 +106,15 @@ class CoursePlansRepo { await _courseStorage.initStorage; final missingIds = request.coursePlanIds - .where( - (id) => _courseStorage.read("${id}_${request.l1}") == null, - ) + .where((id) => _courseStorage.read("${id}_${request.l1}") == null) .toList(); if (missingIds.isNotEmpty) { final searchResult = await _fetch( - GetLocalizedCoursesRequest( - coursePlanIds: missingIds, - l1: request.l1, - ), + GetLocalizedCoursesRequest(coursePlanIds: missingIds, l1: request.l1), ); - await _setCachedBatch( - searchResult, - request.l1, - ); + await _setCachedBatch(searchResult, request.l1); } return _getCachedBatch(request); @@ -156,9 +146,7 @@ class CoursePlansRepo { ); } - static CoursePlanModel? _getCached( - GetLocalizedCoursesRequest request, - ) { + static CoursePlanModel? _getCached(GetLocalizedCoursesRequest request) { if (lastUpdated != null && DateTime.now().difference(lastUpdated!) > cacheDuration) { clearCache(); @@ -223,10 +211,7 @@ class CoursePlansRepo { } final cacheKey = "${courseId}_$l1"; - await _courseStorage.write( - cacheKey, - course.toJson(), - ); + await _courseStorage.write(cacheKey, course.toJson()); } static Future _setCachedBatch( @@ -242,10 +227,7 @@ class CoursePlansRepo { final List futures = response.coursePlans.entries.map((entry) { final cacheKey = "${entry.key}_$l1"; - return _courseStorage.write( - cacheKey, - entry.value.toJson(), - ); + return _courseStorage.write(cacheKey, entry.value.toJson()); }).toList(); await Future.wait(futures); diff --git a/lib/pangea/course_plans/courses/get_localized_courses_request.dart b/lib/pangea/course_plans/courses/get_localized_courses_request.dart index f29b1c848..c56d43bce 100644 --- a/lib/pangea/course_plans/courses/get_localized_courses_request.dart +++ b/lib/pangea/course_plans/courses/get_localized_courses_request.dart @@ -2,15 +2,9 @@ class GetLocalizedCoursesRequest { final List coursePlanIds; final String l1; - GetLocalizedCoursesRequest({ - required this.coursePlanIds, - required this.l1, - }); + GetLocalizedCoursesRequest({required this.coursePlanIds, required this.l1}); - Map toJson() => { - "course_plan_ids": coursePlanIds, - "l1": l1, - }; + Map toJson() => {"course_plan_ids": coursePlanIds, "l1": l1}; factory GetLocalizedCoursesRequest.fromJson(Map json) { return GetLocalizedCoursesRequest( diff --git a/lib/pangea/course_plans/courses/get_localized_courses_response.dart b/lib/pangea/course_plans/courses/get_localized_courses_response.dart index 52bad4d0b..4478a1088 100644 --- a/lib/pangea/course_plans/courses/get_localized_courses_response.dart +++ b/lib/pangea/course_plans/courses/get_localized_courses_response.dart @@ -9,20 +9,14 @@ class GetLocalizedCoursesResponse { final plansEntry = json['course_plans'] as Map; return GetLocalizedCoursesResponse( coursePlans: plansEntry.map( - (key, value) => MapEntry( - key, - CoursePlanModel.fromJson(value), - ), + (key, value) => MapEntry(key, CoursePlanModel.fromJson(value)), ), ); } Map toJson() => { - "course_plans": coursePlans.map( - (key, value) => MapEntry( - key, - value.toJson(), - ), - ), - }; + "course_plans": coursePlans.map( + (key, value) => MapEntry(key, value.toJson()), + ), + }; } diff --git a/lib/pangea/course_settings/course_settings.dart b/lib/pangea/course_settings/course_settings.dart index fb081c5b5..45da03d92 100644 --- a/lib/pangea/course_settings/course_settings.dart +++ b/lib/pangea/course_settings/course_settings.dart @@ -31,10 +31,7 @@ class CourseSettings extends StatelessWidget { // final String? courseId; final ChatDetailsController controller; - const CourseSettings({ - super.key, - required this.controller, - }); + const CourseSettings({super.key, required this.controller}); @override Widget build(BuildContext context) { @@ -42,8 +39,9 @@ class CourseSettings extends StatelessWidget { return const Center(child: CircularProgressIndicator.adaptive()); } - final room = - Matrix.of(context).client.getRoomById(controller.widget.roomId); + final room = Matrix.of( + context, + ).client.getRoomById(controller.widget.roomId); if (room == null || !room.isSpace) { return Center( child: Text( @@ -78,13 +76,16 @@ class CourseSettings extends StatelessWidget { ), ElevatedButton( style: ElevatedButton.styleFrom( - backgroundColor: - Theme.of(context).colorScheme.primaryContainer, - foregroundColor: - Theme.of(context).colorScheme.onPrimaryContainer, + backgroundColor: Theme.of( + context, + ).colorScheme.primaryContainer, + foregroundColor: Theme.of( + context, + ).colorScheme.onPrimaryContainer, + ), + onPressed: () => context.go( + "/rooms/spaces/${controller.roomId}/addcourse", ), - onPressed: () => context - .go("/rooms/spaces/${controller.roomId}/addcourse"), child: Row( spacing: 8.0, mainAxisSize: MainAxisSize.min, @@ -221,15 +222,16 @@ class CourseSettings extends StatelessWidget { ), if (constraints.maxWidth < 700.0) Padding( - padding: const EdgeInsetsGeometry - .symmetric( - vertical: 4.0, - ), + padding: + const EdgeInsetsGeometry.symmetric( + vertical: 4.0, + ), child: TopicParticipantList( room: room, users: usersInTopic, - avatarSize: - isColumnMode ? 50.0 : 25.0, + avatarSize: isColumnMode + ? 50.0 + : 25.0, overlap: isColumnMode ? 20.0 : 8.0, ), ), @@ -256,22 +258,21 @@ class CourseSettings extends StatelessWidget { activityCount: topic.activityIds.length, ) : activityError != null - ? ErrorIndicator( - message: - L10n.of(context).oopsSomethingWentWrong, - ) - : topic.loadedActivities.isNotEmpty - ? SizedBox( - height: isColumnMode ? 290.0 : 210.0, - child: TopicActivitiesList( - room: room, - activities: topic.loadedActivities, - loading: controller.loadingCourseSummary, - hasCompletedActivity: - controller.hasCompletedActivity, - ), - ) - : const SizedBox(), + ? ErrorIndicator( + message: L10n.of(context).oopsSomethingWentWrong, + ) + : topic.loadedActivities.isNotEmpty + ? SizedBox( + height: isColumnMode ? 290.0 : 210.0, + child: TopicActivitiesList( + room: room, + activities: topic.loadedActivities, + loading: controller.loadingCourseSummary, + hasCompletedActivity: + controller.hasCompletedActivity, + ), + ) + : const SizedBox(), ], ), ), @@ -286,10 +287,7 @@ class CourseSettings extends StatelessWidget { class ActivityCardPlaceholder extends StatelessWidget { final int activityCount; - const ActivityCardPlaceholder({ - super.key, - required this.activityCount, - }); + const ActivityCardPlaceholder({super.key, required this.activityCount}); @override Widget build(BuildContext context) { diff --git a/lib/pangea/course_settings/teacher_mode_model.dart b/lib/pangea/course_settings/teacher_mode_model.dart index dea77e843..52342833b 100644 --- a/lib/pangea/course_settings/teacher_mode_model.dart +++ b/lib/pangea/course_settings/teacher_mode_model.dart @@ -2,15 +2,9 @@ class TeacherModeModel { final bool enabled; final int? activitiesToUnlockTopic; - const TeacherModeModel({ - required this.enabled, - this.activitiesToUnlockTopic, - }); + const TeacherModeModel({required this.enabled, this.activitiesToUnlockTopic}); - TeacherModeModel copyWith({ - bool? enabled, - int? activitiesToUnlockTopic, - }) { + TeacherModeModel copyWith({bool? enabled, int? activitiesToUnlockTopic}) { return TeacherModeModel( enabled: enabled ?? this.enabled, activitiesToUnlockTopic: @@ -19,9 +13,9 @@ class TeacherModeModel { } Map toJson() => { - 'enabled': enabled, - 'activities_to_unlock_topic': activitiesToUnlockTopic, - }; + 'enabled': enabled, + 'activities_to_unlock_topic': activitiesToUnlockTopic, + }; factory TeacherModeModel.fromJson(Map json) { return TeacherModeModel( diff --git a/lib/pangea/course_settings/topic_participant_list.dart b/lib/pangea/course_settings/topic_participant_list.dart index e0bee5c2a..444027323 100644 --- a/lib/pangea/course_settings/topic_participant_list.dart +++ b/lib/pangea/course_settings/topic_participant_list.dart @@ -61,8 +61,9 @@ class TopicParticipantList extends StatelessWidget { return Stack( children: users.take(maxVisible).mapIndexed((index, user) { final level = publicProfiles[user.id]; - final LinearGradient? gradient = - level != null ? index.leaderboardGradient : null; + final LinearGradient? gradient = level != null + ? index.leaderboardGradient + : null; return Positioned( left: index * (avatarSize - overlap), child: MouseRegion( @@ -86,10 +87,7 @@ class TopicParticipantList extends StatelessWidget { ), ) else - SizedBox( - height: avatarSize, - width: avatarSize, - ), + SizedBox(height: avatarSize, width: avatarSize), Center( child: Avatar( mxContent: user.avatarUrl, @@ -111,9 +109,7 @@ class TopicParticipantList extends StatelessWidget { if (users.length > maxVisible) Text( L10n.of(context).additionalParticipants(users.length - maxVisible), - style: const TextStyle( - fontSize: 12.0, - ), + style: const TextStyle(fontSize: 12.0), ), ], ); diff --git a/lib/pangea/download/download_file_util.dart b/lib/pangea/download/download_file_util.dart index 045665f82..e4f213768 100644 --- a/lib/pangea/download/download_file_util.dart +++ b/lib/pangea/download/download_file_util.dart @@ -19,8 +19,8 @@ class DownloadUtil { if (kIsWeb) { final blob = webfile.Blob([contents], fileType.mimetype, 'native'); webfile.AnchorElement( - href: webfile.Url.createObjectUrlFromBlob(blob).toString(), - ) + href: webfile.Url.createObjectUrlFromBlob(blob).toString(), + ) ..setAttribute("download", filename) ..click(); return; diff --git a/lib/pangea/download/download_room_extension.dart b/lib/pangea/download/download_room_extension.dart index d9eae2236..392032dc7 100644 --- a/lib/pangea/download/download_room_extension.dart +++ b/lib/pangea/download/download_room_extension.dart @@ -40,23 +40,14 @@ class _EventDownloadInfo { class EmptyChatException implements Exception {} extension DownloadExtension on Room { - Future download( - DownloadType type, - BuildContext context, - ) async { + Future download(DownloadType type, BuildContext context) async { List allPangeaMessages; final List allEvents = await getAllEvents(); final TimelineChunk chunk = TimelineChunk(events: allEvents); - final Timeline timeline = Timeline( - room: this, - chunk: chunk, - ); + final Timeline timeline = Timeline(room: this, chunk: chunk); - allPangeaMessages = getPangeaMessageEvents( - allEvents, - timeline, - ); + allPangeaMessages = getPangeaMessageEvents(allEvents, timeline); if (allPangeaMessages.isEmpty) { throw EmptyChatException(); @@ -92,8 +83,9 @@ extension DownloadExtension on Room { .replaceAll(RegExp(r'[^A-Za-z0-9\s]'), "") .replaceAll(RegExp(r'\s+'), "-"); - final String timestamp = - DateFormat('yyyy-MM-dd-hh:mm:ss').format(DateTime.now()); + final String timestamp = DateFormat( + 'yyyy-MM-dd-hh:mm:ss', + ).format(DateTime.now()); return "$roomName-$timestamp.${type.extension}"; } @@ -105,8 +97,9 @@ extension DownloadExtension on Room { String formattedInfo = ""; final l10n = L10n.of(context); for (final _EventDownloadInfo info in eventInfo) { - final String timestamp = - DateFormat('yyyy-MM-dd hh:mm:ss').format(info.timestamp); + final String timestamp = DateFormat( + 'yyyy-MM-dd hh:mm:ss', + ).format(info.timestamp); if (!info.usageAvailable) { formattedInfo += @@ -145,11 +138,12 @@ extension DownloadExtension on Room { l10n.sentMessage, l10n.taTooltip, l10n.gaTooltip, - ] + ], ]; for (final _EventDownloadInfo info in eventInfo) { - final String timestamp = - DateFormat('yyyy-MM-dd hh:mm:ss').format(info.timestamp); + final String timestamp = DateFormat( + 'yyyy-MM-dd hh:mm:ss', + ).format(info.timestamp); if (!info.usageAvailable) { csvData.add([ @@ -185,29 +179,43 @@ extension DownloadExtension on Room { final Sheet sheetObject = excel['Sheet1']; sheetObject .cell(CellIndex.indexByColumnRow(columnIndex: 0, rowIndex: 0)) - .value = TextCellValue(l10n.sender); + .value = TextCellValue( + l10n.sender, + ); sheetObject .cell(CellIndex.indexByColumnRow(columnIndex: 1, rowIndex: 0)) - .value = TextCellValue(l10n.time); + .value = TextCellValue( + l10n.time, + ); sheetObject .cell(CellIndex.indexByColumnRow(columnIndex: 2, rowIndex: 0)) - .value = TextCellValue(l10n.originalMessage); + .value = TextCellValue( + l10n.originalMessage, + ); sheetObject .cell(CellIndex.indexByColumnRow(columnIndex: 3, rowIndex: 0)) - .value = TextCellValue(l10n.sentMessage); + .value = TextCellValue( + l10n.sentMessage, + ); sheetObject .cell(CellIndex.indexByColumnRow(columnIndex: 4, rowIndex: 0)) - .value = TextCellValue(l10n.taTooltip); + .value = TextCellValue( + l10n.taTooltip, + ); sheetObject .cell(CellIndex.indexByColumnRow(columnIndex: 5, rowIndex: 0)) - .value = TextCellValue(l10n.gaTooltip); + .value = TextCellValue( + l10n.gaTooltip, + ); for (int i = 0; i < eventInfo.length; i++) { final _EventDownloadInfo info = eventInfo[i]; sheetObject .cell(CellIndex.indexByColumnRow(columnIndex: 0, rowIndex: i + 2)) - .value = TextCellValue(info.sender); + .value = TextCellValue( + info.sender, + ); sheetObject .cell(CellIndex.indexByColumnRow(columnIndex: 1, rowIndex: i + 2)) .value = DateTimeCellValue( @@ -221,17 +229,25 @@ extension DownloadExtension on Room { sheetObject .cell(CellIndex.indexByColumnRow(columnIndex: 2, rowIndex: i + 2)) - .value = TextCellValue(info.originalMsg); + .value = TextCellValue( + info.originalMsg, + ); sheetObject .cell(CellIndex.indexByColumnRow(columnIndex: 3, rowIndex: i + 2)) - .value = TextCellValue(info.sentMsg); + .value = TextCellValue( + info.sentMsg, + ); if (info.usageAvailable) { sheetObject .cell(CellIndex.indexByColumnRow(columnIndex: 4, rowIndex: i + 2)) - .value = TextCellValue(info.includedIT.toString()); + .value = TextCellValue( + info.includedIT.toString(), + ); sheetObject .cell(CellIndex.indexByColumnRow(columnIndex: 5, rowIndex: i + 2)) - .value = TextCellValue(info.includedIGC.toString()); + .value = TextCellValue( + info.includedIGC.toString(), + ); } } diff --git a/lib/pangea/events/event_wrappers/pangea_choreo_event.dart b/lib/pangea/events/event_wrappers/pangea_choreo_event.dart index cd661c0c4..20cc0085c 100644 --- a/lib/pangea/events/event_wrappers/pangea_choreo_event.dart +++ b/lib/pangea/events/event_wrappers/pangea_choreo_event.dart @@ -15,9 +15,7 @@ class ChoreoEvent { ChoreoEvent({required this.event}) { if (event.type != PangeaEventTypes.choreoRecord) { - throw Exception( - "${event.type} should not be used to make a ChoreoEvent", - ); + throw Exception("${event.type} should not be used to make a ChoreoEvent"); } } @@ -27,13 +25,7 @@ class ChoreoEvent { return _content; } catch (err, s) { debugger(when: kDebugMode); - ErrorHandler.logError( - e: err, - s: s, - data: { - "event": event.toJson(), - }, - ); + ErrorHandler.logError(e: err, s: s, data: {"event": event.toJson()}); return null; } } diff --git a/lib/pangea/events/event_wrappers/pangea_message_event.dart b/lib/pangea/events/event_wrappers/pangea_message_event.dart index bb9d629c0..6f930464f 100644 --- a/lib/pangea/events/event_wrappers/pangea_message_event.dart +++ b/lib/pangea/events/event_wrappers/pangea_message_event.dart @@ -50,9 +50,7 @@ class PangeaMessageEvent { debugger(when: kDebugMode); ErrorHandler.logError( m: "${event.type} should not be used to make a PangeaMessageEvent", - data: { - "event": event.toJson(), - }, + data: {"event": event.toJson()}, ); } _event = event; @@ -81,50 +79,40 @@ class PangeaMessageEvent { MatrixState.pangeaController.userController.userL1?.langCode; Event? _latestEditCache; - Event get _latestEdit => _latestEditCache ??= _event - .aggregatedEvents( - timeline, - RelationshipTypes.edit, - ) + Event get _latestEdit => _latestEditCache ??= + _event + .aggregatedEvents(timeline, RelationshipTypes.edit) //sort by event.originServerTs to get the most recent first - .sorted( - (a, b) => b.originServerTs.compareTo(a.originServerTs), - ) + .sorted((a, b) => b.originServerTs.compareTo(a.originServerTs)) .firstOrNull ?? _event; // get audio events that are related to this event Set get allAudio => _latestEdit - .aggregatedEvents( - timeline, - PangeaEventTypes.textToSpeech, - ) - .where((element) { + .aggregatedEvents(timeline, PangeaEventTypes.textToSpeech) + .where((element) { return element.content.tryGet>( ModelKey.transcription, ) != null; - }).toSet(); + }) + .toSet(); List get _repEvents => _latestEdit - .aggregatedEvents( - timeline, - PangeaEventTypes.representation, - ) - .map( - (e) => RepresentationEvent( - event: e, - parentMessageEvent: _latestEdit, - timeline: timeline, - ), - ) - .sorted( - (a, b) { - if (a.event == null) return -1; - if (b.event == null) return 1; - return b.event!.originServerTs.compareTo(a.event!.originServerTs); - }, - ).toList(); + .aggregatedEvents(timeline, PangeaEventTypes.representation) + .map( + (e) => RepresentationEvent( + event: e, + parentMessageEvent: _latestEdit, + timeline: timeline, + ), + ) + .sorted((a, b) { + if (a.event == null) return -1; + if (b.event == null) return 1; + return b.event!.originServerTs.compareTo(a.event!.originServerTs); + }) + .toList(); ChoreoRecordModel? get _embeddedChoreo { try { @@ -201,9 +189,7 @@ class PangeaMessageEvent { m: "error parsing originalSent", e: err, s: s, - data: { - "event": _latestEdit.toJson(), - }, + data: {"event": _latestEdit.toJson()}, ); } @@ -228,9 +214,7 @@ class PangeaMessageEvent { m: "error parsing originalWritten", e: err, s: s, - data: { - "event": _latestEdit.toJson(), - }, + data: {"event": _latestEdit.toJson()}, ); } } @@ -239,11 +223,13 @@ class PangeaMessageEvent { return _representations!; } - RepresentationEvent? get originalSent => representations - .firstWhereOrNull((element) => element.content.originalSent); + RepresentationEvent? get originalSent => representations.firstWhereOrNull( + (element) => element.content.originalSent, + ); - RepresentationEvent? get originalWritten => representations - .firstWhereOrNull((element) => element.content.originalWritten); + RepresentationEvent? get originalWritten => representations.firstWhereOrNull( + (element) => element.content.originalWritten, + ); String get originalWrittenContent { String? written = originalSent?.content.text; @@ -283,8 +269,8 @@ class PangeaMessageEvent { TextDirection get textDirection => LanguageConstants.rtlLanguageCodes.contains(messageDisplayLangCode) - ? TextDirection.rtl - : TextDirection.ltr; + ? TextDirection.rtl + : TextDirection.ltr; void updateLatestEdit() { _latestEditCache = null; @@ -294,18 +280,13 @@ class PangeaMessageEvent { RepresentationEvent? representationByLanguage( String langCode, { bool Function(RepresentationEvent)? filter, - }) => - representations.firstWhereOrNull( - (element) => - element.langCode.split("-")[0] == langCode.split("-")[0] && - (filter?.call(element) ?? true), - ); + }) => representations.firstWhereOrNull( + (element) => + element.langCode.split("-")[0] == langCode.split("-")[0] && + (filter?.call(element) ?? true), + ); - Event? getTextToSpeechLocal( - String langCode, - String text, - String? voice, - ) { + Event? getTextToSpeechLocal(String langCode, String text, String? voice) { for (final audio in allAudio) { final dataMap = audio.content.tryGetMap(ModelKey.transcription); if (dataMap == null || !dataMap.containsKey(ModelKey.tokens)) continue; @@ -325,9 +306,7 @@ class PangeaMessageEvent { ErrorHandler.logError( e: e, s: s, - data: { - "event": audio.toJson(), - }, + data: {"event": audio.toJson()}, m: "error parsing data in getTextToSpeechLocal", ); } @@ -335,17 +314,16 @@ class PangeaMessageEvent { return null; } - RepresentationEvent? _getSpeechToTextRepresentation() => - representations.firstWhereOrNull( - (element) => element.content.speechToText != null, - ); + RepresentationEvent? _getSpeechToTextRepresentation() => representations + .firstWhereOrNull((element) => element.content.speechToText != null); SpeechToTextResponseModel? getSpeechToTextLocal() { final rep = _getSpeechToTextRepresentation()?.content.speechToText; if (rep != null) return rep; - final rawBotTranscription = - event.content.tryGetMap(ModelKey.botTranscription); + final rawBotTranscription = event.content.tryGetMap( + ModelKey.botTranscription, + ); if (rawBotTranscription != null) { try { @@ -356,9 +334,7 @@ class PangeaMessageEvent { ErrorHandler.logError( e: err, s: s, - data: { - "event": _event.toJson(), - }, + data: {"event": _event.toJson()}, m: "error parsing botTranscription", ); return null; @@ -395,9 +371,7 @@ class PangeaMessageEvent { ); if (result.error != null) { - throw Exception( - "Error getting text to speech: ${result.error}", - ); + throw Exception("Error getting text to speech: ${result.error}"); } final response = result.result!; @@ -417,10 +391,7 @@ class PangeaMessageEvent { room.sendFileEvent( file, extraContent: { - 'info': { - ...file.info, - ModelKey.duration: response.durationMillis, - }, + 'info': {...file.info, ModelKey.duration: response.durationMillis}, 'org.matrix.msc3245.voice': {}, 'org.matrix.msc1767.audio': { ModelKey.duration: response.durationMillis, @@ -469,9 +440,7 @@ class PangeaMessageEvent { ); if (result.error != null) { - throw Exception( - "Error getting speech to text: ${result.error}", - ); + throw Exception("Error getting speech to text: ${result.error}"); } if (sendEvent) { @@ -595,7 +564,7 @@ class PangeaMessageEvent { final includedIT = (originalSent?.choreo?.endedWithIT(originalSent!.text) ?? false) && - !(originalSent?.choreo?.includedIGC ?? true); + !(originalSent?.choreo?.includedIGC ?? true); RepresentationEvent? rep; if (!includedIT) { diff --git a/lib/pangea/events/event_wrappers/pangea_representation_event.dart b/lib/pangea/events/event_wrappers/pangea_representation_event.dart index 0dac12547..e9d4380eb 100644 --- a/lib/pangea/events/event_wrappers/pangea_representation_event.dart +++ b/lib/pangea/events/event_wrappers/pangea_representation_event.dart @@ -63,25 +63,13 @@ class RepresentationEvent { List? get detections => _tokens?.detections; Set get tokenEvents => - _event?.aggregatedEvents( - timeline, - PangeaEventTypes.tokens, - ) ?? - {}; + _event?.aggregatedEvents(timeline, PangeaEventTypes.tokens) ?? {}; Set get sttEvents => - _event?.aggregatedEvents( - timeline, - PangeaEventTypes.sttTranslation, - ) ?? - {}; + _event?.aggregatedEvents(timeline, PangeaEventTypes.sttTranslation) ?? {}; Set get choreoEvents => - _event?.aggregatedEvents( - timeline, - PangeaEventTypes.choreoRecord, - ) ?? - {}; + _event?.aggregatedEvents(timeline, PangeaEventTypes.choreoRecord) ?? {}; // Note: in the case where the event is the originalSent or originalWritten event, // the content will be set on initialization by the PangeaMessageEvent @@ -105,11 +93,7 @@ class RepresentationEvent { if (_choreo != null) return _choreo; if (_event == null) { - Sentry.addBreadcrumb( - Breadcrumb( - message: "_event and _choreo both null", - ), - ); + Sentry.addBreadcrumb(Breadcrumb(message: "_event and _choreo both null")); return null; } @@ -130,9 +114,7 @@ class RepresentationEvent { if (content.speechToText == null) return []; if (_event == null) { Sentry.addBreadcrumb( - Breadcrumb( - message: "_event and _sttTranslations both null", - ), + Breadcrumb(message: "_event and _sttTranslations both null"), ); return []; } @@ -141,9 +123,7 @@ class RepresentationEvent { final List sttTranslations = []; for (final event in sttEvents) { try { - sttTranslations.add( - SttTranslationModel.fromJson(event.content), - ); + sttTranslations.add(SttTranslationModel.fromJson(event.content)); } catch (e) { Sentry.addBreadcrumb( Breadcrumb( @@ -227,10 +207,10 @@ class RepresentationEvent { langCode: langCode, senderL1: MatrixState.pangeaController.userController.userL1?.langCode ?? - LanguageKeys.unknownLanguage, + LanguageKeys.unknownLanguage, senderL2: MatrixState.pangeaController.userController.userL2?.langCode ?? - LanguageKeys.unknownLanguage, + LanguageKeys.unknownLanguage, ), ); diff --git a/lib/pangea/events/extensions/pangea_event_extension.dart b/lib/pangea/events/extensions/pangea_event_extension.dart index 6c71c7d22..463531dde 100644 --- a/lib/pangea/events/extensions/pangea_event_extension.dart +++ b/lib/pangea/events/extensions/pangea_event_extension.dart @@ -45,26 +45,28 @@ extension PangeaEvent on Event { if (type != EventTypes.Message || messageType != MessageTypes.Audio) { ErrorHandler.logError( e: "Event is not an audio message", - data: { - "event": toJson(), - }, + data: {"event": toJson()}, ); return null; } - final transcription = - content.tryGetMap(ModelKey.transcription); - final audioContent = - content.tryGetMap('org.matrix.msc1767.audio'); + final transcription = content.tryGetMap( + ModelKey.transcription, + ); + final audioContent = content.tryGetMap( + 'org.matrix.msc1767.audio', + ); final matrixFile = await downloadAndDecryptAttachment(); - final duration = audioContent?.tryGet(ModelKey.duration) ?? + final duration = + audioContent?.tryGet(ModelKey.duration) ?? content .tryGetMap('info') ?.tryGet(ModelKey.duration); - final waveform = audioContent?.tryGetList('waveform') ?? + final waveform = + audioContent?.tryGetList('waveform') ?? content .tryGetMap('org.matrix.msc1767.audio') ?.tryGetList('waveform'); diff --git a/lib/pangea/events/models/content_feedback.dart b/lib/pangea/events/models/content_feedback.dart index 8181dddd4..9634b53b7 100644 --- a/lib/pangea/events/models/content_feedback.dart +++ b/lib/pangea/events/models/content_feedback.dart @@ -12,10 +12,7 @@ class ContentFeedback { ContentFeedback(this.content, this.feedback); Map toJson() { - return { - 'content': content.toJson(), - 'feedback': feedback, - }; + return {'content': content.toJson(), 'feedback': feedback}; } @override diff --git a/lib/pangea/events/models/language_detection_model.dart b/lib/pangea/events/models/language_detection_model.dart index ea68d1a04..5db13c4b6 100644 --- a/lib/pangea/events/models/language_detection_model.dart +++ b/lib/pangea/events/models/language_detection_model.dart @@ -28,7 +28,7 @@ class LanguageDetectionModel { } Map toJson() => { - ModelKey.langCode: langCode, - ModelKey.confidence: confidence, - }; + ModelKey.langCode: langCode, + ModelKey.confidence: confidence, + }; } diff --git a/lib/pangea/events/models/pangea_token_model.dart b/lib/pangea/events/models/pangea_token_model.dart index 080cfaa85..29d287b42 100644 --- a/lib/pangea/events/models/pangea_token_model.dart +++ b/lib/pangea/events/models/pangea_token_model.dart @@ -65,9 +65,7 @@ class PangeaToken { // previously sent tokens have lists of lemmas if (json is Iterable) { return json - .map( - (e) => Lemma.fromJson(e as Map), - ) + .map((e) => Lemma.fromJson(e as Map)) .toList() .cast() .firstOrNull ?? @@ -82,8 +80,9 @@ class PangeaToken { } factory PangeaToken.fromJson(Map json) { - final PangeaTokenText text = - PangeaTokenText.fromJson(json[_textKey] as Map); + final PangeaTokenText text = PangeaTokenText.fromJson( + json[_textKey] as Map, + ); final morph = json['morph'] != null ? (json['morph'] as Map).map( (key, value) => MapEntry( @@ -104,12 +103,10 @@ class PangeaToken { static const String _lemmaKey = ModelKey.lemma; Map toJson() => { - _textKey: text.toJson(), - _lemmaKey: [lemma.toJson()], - 'morph': morph.map( - (key, value) => MapEntry(key.name, value), - ), - }; + _textKey: text.toJson(), + _lemmaKey: [lemma.toJson()], + 'morph': morph.map((key, value) => MapEntry(key.name, value)), + }; /// alias for the offset int get start => text.offset; @@ -179,10 +176,10 @@ class PangeaToken { } ConstructIdentifier get vocabConstructID => ConstructIdentifier( - lemma: lemma.text, - type: ConstructTypeEnum.vocab, - category: pos, - ); + lemma: lemma.text, + type: ConstructTypeEnum.vocab, + category: pos, + ); ConstructForm get vocabForm => ConstructForm(form: text.content, cId: vocabConstructID); @@ -191,8 +188,9 @@ class PangeaToken { MorphFeaturesEnum morphFeature, String morphTag, ) { - final List allTags = - MorphsRepo.cached.getDisplayTags(morphFeature.name); + final List allTags = MorphsRepo.cached.getDisplayTags( + morphFeature.name, + ); final List possibleDistractors = allTags .where( @@ -205,15 +203,18 @@ class PangeaToken { } List get morphsBasicallyEligibleForPracticeByPriority => - MorphFeaturesEnumExtension.eligibleForPractice.where((f) { - return morph.containsKey(f); - }).map((f) { - return ConstructIdentifier( - lemma: getMorphTag(f)!, - type: ConstructTypeEnum.morph, - category: f.name, - ); - }).toList(); + MorphFeaturesEnumExtension.eligibleForPractice + .where((f) { + return morph.containsKey(f); + }) + .map((f) { + return ConstructIdentifier( + lemma: getMorphTag(f)!, + type: ConstructTypeEnum.morph, + category: f.name, + ); + }) + .toList(); bool eligibleForPractice(ActivityTypeEnum activityType) { switch (activityType) { diff --git a/lib/pangea/events/models/representation_content_model.dart b/lib/pangea/events/models/representation_content_model.dart index 1f4d3d45d..e758635d4 100644 --- a/lib/pangea/events/models/representation_content_model.dart +++ b/lib/pangea/events/models/representation_content_model.dart @@ -123,15 +123,16 @@ class PangeaRepresentation { ); // for each token, record whether selected in ga, ta, or wa - List tokensToSave = - tokens.where((token) => token.lemma.saveVocab).toList(); + List tokensToSave = tokens + .where((token) => token.lemma.saveVocab) + .toList(); if (choreo != null && choreo.pastedStrings.isNotEmpty) { tokensToSave = tokensToSave .where( (token) => !choreo.pastedStrings.any( - (pasted) => pasted - .toLowerCase() - .contains(token.text.content.toLowerCase()), + (pasted) => pasted.toLowerCase().contains( + token.text.content.toLowerCase(), + ), ), ) .toList(); @@ -196,13 +197,7 @@ class PangeaRepresentation { if (tokenStep.acceptedOrIgnoredMatch != null && tokenStep.acceptedOrIgnoredMatch?.status != PangeaMatchStatusEnum.accepted) { - uses.addAll( - token.allUses( - ConstructUseTypeEnum.ga, - metadata, - 0, - ), - ); + uses.addAll(token.allUses(ConstructUseTypeEnum.ga, metadata, 0)); continue; } @@ -213,28 +208,16 @@ class PangeaRepresentation { if (selectedChoices == 0) { ErrorHandler.logError( e: "No selected choices for IT step", - data: { - "token": token.text.content, - "step": tokenStep.toJson(), - }, + data: {"token": token.text.content, "step": tokenStep.toJson()}, ); continue; } final corITPoints = ConstructUseTypeEnum.corIt.pointValue; final incITPoints = ConstructUseTypeEnum.incIt.pointValue; - final xp = max( - 0, - corITPoints + (incITPoints * (selectedChoices - 1)), - ); + final xp = max(0, corITPoints + (incITPoints * (selectedChoices - 1))); - uses.addAll( - token.allUses( - ConstructUseTypeEnum.ta, - metadata, - xp, - ), - ); + uses.addAll(token.allUses(ConstructUseTypeEnum.ta, metadata, xp)); } else if (tokenStep.acceptedOrIgnoredMatch!.match.choices != null) { final selectedChoices = tokenStep.acceptedOrIgnoredMatch!.match.choices! .where((choice) => choice.selected) @@ -242,10 +225,7 @@ class PangeaRepresentation { if (selectedChoices == 0) { ErrorHandler.logError( e: "No selected choices for IGC step", - data: { - "token": token.text.content, - "step": tokenStep.toJson(), - }, + data: {"token": token.text.content, "step": tokenStep.toJson()}, ); continue; } @@ -257,13 +237,7 @@ class PangeaRepresentation { corIGCPoints + (incIGCPoints * (selectedChoices - 1)), ); - uses.addAll( - token.allUses( - ConstructUseTypeEnum.ga, - metadata, - xp, - ), - ); + uses.addAll(token.allUses(ConstructUseTypeEnum.ga, metadata, xp)); } } diff --git a/lib/pangea/events/models/stt_translation_model.dart b/lib/pangea/events/models/stt_translation_model.dart index 06becba21..99111d995 100644 --- a/lib/pangea/events/models/stt_translation_model.dart +++ b/lib/pangea/events/models/stt_translation_model.dart @@ -6,10 +6,7 @@ class SttTranslationModel { final String translation; final String langCode; - SttTranslationModel({ - required this.translation, - required this.langCode, - }); + SttTranslationModel({required this.translation, required this.langCode}); factory SttTranslationModel.fromJson(Map json) { final content = json.tryGetMap(PangeaEventTypes.sttTranslation); @@ -24,9 +21,6 @@ class SttTranslationModel { } Map toJson() { - return { - 'translation': translation, - 'lang_code': langCode, - }; + return {'translation': translation, 'lang_code': langCode}; } } diff --git a/lib/pangea/events/models/tokens_event_content_model.dart b/lib/pangea/events/models/tokens_event_content_model.dart index 45260340b..531c4c6d7 100644 --- a/lib/pangea/events/models/tokens_event_content_model.dart +++ b/lib/pangea/events/models/tokens_event_content_model.dart @@ -11,10 +11,7 @@ class PangeaMessageTokens { List tokens; List? detections; - PangeaMessageTokens({ - required this.tokens, - this.detections, - }); + PangeaMessageTokens({required this.tokens, this.detections}); factory PangeaMessageTokens.fromJson(Map json) { // "tokens" was accidentally used as the key in the first implementation @@ -24,14 +21,14 @@ class PangeaMessageTokens { final Iterable tokensIterable = something is Iterable ? something : something is String - ? jsonDecode(json[_tokensKey]) - : null; + ? jsonDecode(json[_tokensKey]) + : null; final Iterable? detectionsIterable = json[_detectionsKey] is Iterable ? json[_detectionsKey] : json[_detectionsKey] is String - ? jsonDecode(json[_detectionsKey]) - : null; + ? jsonDecode(json[_detectionsKey]) + : null; return PangeaMessageTokens( tokens: tokensIterable .map((e) => PangeaToken.fromJson(e)) @@ -50,8 +47,9 @@ class PangeaMessageTokens { Map toJson() { final data = {}; data[_tokensKey] = jsonEncode(tokens.map((e) => e.toJson()).toList()); - data[_detectionsKey] = - jsonEncode(detections?.map((e) => e.toJson()).toList()); + data[_detectionsKey] = jsonEncode( + detections?.map((e) => e.toJson()).toList(), + ); return data; } } diff --git a/lib/pangea/events/repo/language_detection_repo.dart b/lib/pangea/events/repo/language_detection_repo.dart index c4f6a6864..79fd127be 100644 --- a/lib/pangea/events/repo/language_detection_repo.dart +++ b/lib/pangea/events/repo/language_detection_repo.dart @@ -71,11 +71,7 @@ class LanguageDetectionRepo { return Result.value(res); } catch (e, s) { _cache.remove(request.hashCode.toString()); - ErrorHandler.logError( - e: e, - s: s, - data: request.toJson(), - ); + ErrorHandler.logError(e: e, s: s, data: request.toJson()); return Result.error(e); } } @@ -96,9 +92,8 @@ class LanguageDetectionRepo { static void _setCached( LanguageDetectionRequest request, Future response, - ) => - _cache[request.hashCode.toString()] = _LanguageDetectionCacheItem( - data: response, - timestamp: DateTime.now(), - ); + ) => _cache[request.hashCode.toString()] = _LanguageDetectionCacheItem( + data: response, + timestamp: DateTime.now(), + ); } diff --git a/lib/pangea/events/repo/language_detection_request.dart b/lib/pangea/events/repo/language_detection_request.dart index 803d5db83..cee2b7a74 100644 --- a/lib/pangea/events/repo/language_detection_request.dart +++ b/lib/pangea/events/repo/language_detection_request.dart @@ -3,18 +3,10 @@ class LanguageDetectionRequest { final String? senderl1; final String? senderl2; - LanguageDetectionRequest({ - required this.text, - this.senderl1, - this.senderl2, - }); + LanguageDetectionRequest({required this.text, this.senderl1, this.senderl2}); Map toJson() { - return { - 'full_text': text, - 'sender_l1': senderl1, - 'sender_l2': senderl2, - }; + return {'full_text': text, 'sender_l1': senderl1, 'sender_l2': senderl2}; } @override diff --git a/lib/pangea/events/repo/language_detection_response.dart b/lib/pangea/events/repo/language_detection_response.dart index a73d01c60..5000ca7f5 100644 --- a/lib/pangea/events/repo/language_detection_response.dart +++ b/lib/pangea/events/repo/language_detection_response.dart @@ -4,10 +4,7 @@ class LanguageDetectionResponse { List detections; String fullText; - LanguageDetectionResponse({ - required this.detections, - required this.fullText, - }); + LanguageDetectionResponse({required this.detections, required this.fullText}); factory LanguageDetectionResponse.fromJson(Map json) { return LanguageDetectionResponse( diff --git a/lib/pangea/events/repo/token_api_models.dart b/lib/pangea/events/repo/token_api_models.dart index 13c245723..9f14c20f7 100644 --- a/lib/pangea/events/repo/token_api_models.dart +++ b/lib/pangea/events/repo/token_api_models.dart @@ -31,11 +31,11 @@ class TokensRequestModel { }); Map toJson() => { - ModelKey.fullText: fullText, - ModelKey.userL1: senderL1, - ModelKey.userL2: senderL2, - ModelKey.langCode: langCode ?? LanguageKeys.unknownLanguage, - }; + ModelKey.fullText: fullText, + ModelKey.userL1: senderL1, + ModelKey.userL2: senderL2, + ModelKey.langCode: langCode ?? LanguageKeys.unknownLanguage, + }; // override equals and hashcode @override @@ -63,9 +63,7 @@ class TokensResponseModel { required this.detections, }); - factory TokensResponseModel.fromJson( - Map json, - ) => + factory TokensResponseModel.fromJson(Map json) => TokensResponseModel( tokens: (json[ModelKey.tokens] as Iterable) .map( diff --git a/lib/pangea/events/repo/tokens_repo.dart b/lib/pangea/events/repo/tokens_repo.dart index 0b849bc3c..e108da161 100644 --- a/lib/pangea/events/repo/tokens_repo.dart +++ b/lib/pangea/events/repo/tokens_repo.dart @@ -14,10 +14,7 @@ class _TokensCacheItem { final Future data; final DateTime timestamp; - const _TokensCacheItem({ - required this.data, - required this.timestamp, - }); + const _TokensCacheItem({required this.data, required this.timestamp}); } class TokensRepo { @@ -33,10 +30,7 @@ class TokensRepo { return _getResult(request, cached); } - final future = _fetch( - accessToken, - request: request, - ); + final future = _fetch(accessToken, request: request); _setCached(request, future); return _getResult(request, future); } @@ -60,17 +54,15 @@ class TokensRepo { ); } - final Map json = - jsonDecode(utf8.decode(res.bodyBytes).toString()); + final Map json = jsonDecode( + utf8.decode(res.bodyBytes).toString(), + ); final tokens = TokensResponseModel.fromJson(json); if (tokens.tokens.any((t) => t.pos == 'other')) { ErrorHandler.logError( e: Exception('Received token with pos "other"'), - data: { - "request": request.toJson(), - "response": json, - }, + data: {"request": request.toJson(), "response": json}, level: SentryLevel.warning, ); } @@ -86,23 +78,17 @@ class TokensRepo { return Result.value(res); } catch (e, s) { _tokensCache.remove(request.hashCode.toString()); - ErrorHandler.logError( - e: e, - s: s, - data: request.toJson(), - ); + ErrorHandler.logError(e: e, s: s, data: request.toJson()); return Result.error(e); } } - static Future? _getCached( - TokensRequestModel request, - ) { + static Future? _getCached(TokensRequestModel request) { final cacheKeys = [..._tokensCache.keys]; for (final key in cacheKeys) { - if (_tokensCache[key]! - .timestamp - .isBefore(DateTime.now().subtract(_cacheDuration))) { + if (_tokensCache[key]!.timestamp.isBefore( + DateTime.now().subtract(_cacheDuration), + )) { _tokensCache.remove(key); } } @@ -113,9 +99,8 @@ class TokensRepo { static void _setCached( TokensRequestModel request, Future response, - ) => - _tokensCache[request.hashCode.toString()] = _TokensCacheItem( - data: response, - timestamp: DateTime.now(), - ); + ) => _tokensCache[request.hashCode.toString()] = _TokensCacheItem( + data: response, + timestamp: DateTime.now(), + ); } diff --git a/lib/pangea/events/utils/report_message.dart b/lib/pangea/events/utils/report_message.dart index 5d20ec97b..6de7a0530 100644 --- a/lib/pangea/events/utils/report_message.dart +++ b/lib/pangea/events/utils/report_message.dart @@ -13,13 +13,8 @@ import 'package:fluffychat/widgets/future_loading_dialog.dart'; import 'package:fluffychat/widgets/matrix.dart'; Future getReportsDM(User teacher, Room space) async { - final String roomId = await teacher.startDirectChat( - enableEncryption: false, - ); - space.setSpaceChild( - roomId, - suggested: false, - ); + final String roomId = await teacher.startDirectChat(enableEncryption: false); + space.setSpaceChild(roomId, suggested: false); return space.client.getRoomById(roomId)!; } @@ -34,18 +29,9 @@ void reportEvent( message: L10n.of(context).whyDoYouWantToReportThis, cancelLabel: L10n.of(context).cancel, actions: [ - AdaptiveModalAction( - value: 1, - label: L10n.of(context).offensive, - ), - AdaptiveModalAction( - value: 2, - label: L10n.of(context).translationProblem, - ), - AdaptiveModalAction( - value: 3, - label: L10n.of(context).other, - ), + AdaptiveModalAction(value: 1, label: L10n.of(context).offensive), + AdaptiveModalAction(value: 2, label: L10n.of(context).translationProblem), + AdaptiveModalAction(value: 3, label: L10n.of(context).other), ], ); if (score == null) return; @@ -103,8 +89,10 @@ Future reportOffensiveMessage( final resp = await showFutureLoadingDialog>( context: context, future: () async { - final List teachers = - await getReportTeachers(context, reportedInRoom); + final List teachers = await getReportTeachers( + context, + reportedInRoom, + ); if (teachers.isEmpty) { throw L10n.of(context).noTeachersFound; } @@ -141,15 +129,12 @@ Future reportOffensiveMessage( final String reportingUserId = Matrix.of(context).client.userID ?? ""; final String roomName = reportedInRoom.getLocalizedDisplayname(); - final String messageTitle = L10n.of(context).reportMessageTitle( - reportingUserId, - reportedUserId, - roomName, - ); - final String messageBody = L10n.of(context).reportMessageBody( - reportedMessage, - reason ?? L10n.of(context).none, - ); + final String messageTitle = L10n.of( + context, + ).reportMessageTitle(reportingUserId, reportedUserId, roomName); + final String messageBody = L10n.of( + context, + ).reportMessageBody(reportedMessage, reason ?? L10n.of(context).none); final String message = "$messageTitle\n\n$messageBody"; for (final Room reportDM in reportDMs) { final event = { @@ -190,9 +175,7 @@ Future> getReportTeachers( } } - final List otherSpaces = Matrix.of(context) - .client - .rooms + final List otherSpaces = Matrix.of(context).client.rooms .where((room) => room.isSpace && !reportRoomParentSpaces.contains(room)) .toList(); diff --git a/lib/pangea/extensions/join_rule_extension.dart b/lib/pangea/extensions/join_rule_extension.dart index ede8eef50..aac92c69b 100644 --- a/lib/pangea/extensions/join_rule_extension.dart +++ b/lib/pangea/extensions/join_rule_extension.dart @@ -13,23 +13,20 @@ extension JoinRuleExtension on Client { try { joinCode = await requestSpaceCode(); } catch (e, s) { - ErrorHandler.logError( - e: e, - s: s, - data: { - 'joinRule': joinRule, - }, - ); + ErrorHandler.logError(e: e, s: s, data: {'joinRule': joinRule}); } - return StateEvent( - type: EventTypes.RoomJoinRules, - content: { - ModelKey.joinRule: joinRule, - if (joinCode != null) ModelKey.accessCode: joinCode, - if (allow != null) 'allow': allow, - }, - ); + final Map content = {ModelKey.joinRule: joinRule}; + + if (joinCode != null) { + content[ModelKey.accessCode] = joinCode; + } + + if (allow != null) { + content['allow'] = allow; + } + + return StateEvent(type: EventTypes.RoomJoinRules, content: content); } } @@ -59,10 +56,7 @@ extension JoinRuleExtensionOnRoom on Room { String joinRule, { List>? allow, }) async { - final currentJoinRule = getState( - EventTypes.RoomJoinRules, - )?.content ?? - {}; + final currentJoinRule = getState(EventTypes.RoomJoinRules)?.content ?? {}; if (currentJoinRule[ModelKey.joinRule] == joinRule && (currentJoinRule['allow'] == allow)) { diff --git a/lib/pangea/extensions/pangea_room_extension.dart b/lib/pangea/extensions/pangea_room_extension.dart index 85c869ba3..a9c99c5ad 100644 --- a/lib/pangea/extensions/pangea_room_extension.dart +++ b/lib/pangea/extensions/pangea_room_extension.dart @@ -42,5 +42,5 @@ part "room_space_settings_extension.dart"; part "room_user_permissions_extension.dart"; extension PangeaRoom on Room { -// analytics + // analytics } diff --git a/lib/pangea/extensions/pangea_rooms_chunk_extension.dart b/lib/pangea/extensions/pangea_rooms_chunk_extension.dart index bf9dc4d99..eeca86dab 100644 --- a/lib/pangea/extensions/pangea_rooms_chunk_extension.dart +++ b/lib/pangea/extensions/pangea_rooms_chunk_extension.dart @@ -9,8 +9,8 @@ extension PangeaRoomsChunk on PublishedRoomsChunk { /// avatar associated with this space String defaultAvatar() { final int seed = roomId.hashCode; - return SpaceConstants.publicSpaceIcons[Random(seed).nextInt( - SpaceConstants.publicSpaceIcons.length, - )]; + return SpaceConstants.publicSpaceIcons[Random( + seed, + ).nextInt(SpaceConstants.publicSpaceIcons.length)]; } } diff --git a/lib/pangea/extensions/room_capacity_extension.dart b/lib/pangea/extensions/room_capacity_extension.dart index 5b38b4aab..95c9a2a04 100644 --- a/lib/pangea/extensions/room_capacity_extension.dart +++ b/lib/pangea/extensions/room_capacity_extension.dart @@ -2,12 +2,9 @@ part of "pangea_room_extension.dart"; extension RoomCapacityExtension on Room { Future updateRoomCapacity(int newCapacity) => - client.setRoomStateWithKey( - id, - PangeaEventTypes.capacity, - '', - {'capacity': newCapacity}, - ); + client.setRoomStateWithKey(id, PangeaEventTypes.capacity, '', { + 'capacity': newCapacity, + }); int? get capacity { final t = getState(PangeaEventTypes.capacity)?.content['capacity']; diff --git a/lib/pangea/extensions/room_children_and_parents_extension.dart b/lib/pangea/extensions/room_children_and_parents_extension.dart index b79828301..7e1b8d6f7 100644 --- a/lib/pangea/extensions/room_children_and_parents_extension.dart +++ b/lib/pangea/extensions/room_children_and_parents_extension.dart @@ -11,31 +11,18 @@ extension ChildrenAndParentsRoomExtension on Room { } List get pangeaSpaceParents => client.rooms - .where( - (r) => r.isSpace, - ) - .where( - (space) => space.spaceChildren.any( - (room) => room.roomId == id, - ), - ) + .where((r) => r.isSpace) + .where((space) => space.spaceChildren.any((room) => room.roomId == id)) .toList(); List get pangeaSpaceChildren => client.rooms - .where( - (r) => spaceChildren.any( - (child) => r.id == child.roomId, - ), - ) + .where((r) => spaceChildren.any((child) => r.id == child.roomId)) .toList(); /// Wrapper around call to setSpaceChild with added functionality /// to prevent adding one room to multiple spaces, and resets the /// subspace's JoinRules and Visibility to defaults. - Future addToSpace( - String roomId, { - bool? suggested, - }) async { + Future addToSpace(String roomId, {bool? suggested}) async { final Room? child = client.getRoomById(roomId); if (child == null) return; @@ -46,18 +33,12 @@ extension ChildrenAndParentsRoomExtension on Room { ErrorHandler.logError( e: e, m: 'Failed to remove child from parent', - data: { - "roomID": roomId, - "parentID": parent.id, - }, + data: {"roomID": roomId, "parentID": parent.id}, ); } } - await _trySetSpaceChild( - roomId, - suggested: suggested, - ); + await _trySetSpaceChild(roomId, suggested: suggested); } Future _trySetSpaceChild( @@ -136,10 +117,7 @@ extension ChildrenAndParentsRoomExtension on Room { await client.pangeaJoinRules( 'knock_restricted', allow: [ - { - "type": "m.room_membership", - "room_id": id, - } + {"type": "m.room_membership", "room_id": id}, ], ), ], diff --git a/lib/pangea/extensions/room_events_extension.dart b/lib/pangea/extensions/room_events_extension.dart index 0f10dcbe6..fb56d313c 100644 --- a/lib/pangea/extensions/room_events_extension.dart +++ b/lib/pangea/extensions/room_events_extension.dart @@ -14,26 +14,14 @@ extension EventsRoomExtension on Room { try { await room.leave(); } catch (e, s) { - ErrorHandler.logError( - e: e, - s: s, - data: { - 'roomID': room.id, - }, - ); + ErrorHandler.logError(e: e, s: s, data: {'roomID': room.id}); } } try { await leave(); } catch (e, s) { - ErrorHandler.logError( - e: e, - s: s, - data: { - 'roomID': id, - }, - ); + ErrorHandler.logError(e: e, s: s, data: {'roomID': id}); } } @@ -111,19 +99,21 @@ extension EventsRoomExtension on Room { replyText = replyText.split('\n').map((line) => '> $line').join('\n'); content['format'] = 'org.matrix.custom.html'; // be sure that we strip any previous reply fallbacks - final replyHtml = (inReplyTo.formattedText.isNotEmpty - ? inReplyTo.formattedText - : htmlEscape.convert(inReplyTo.body).replaceAll('\n', '
')) - .replaceAll( - RegExp( - r'.*', - caseSensitive: false, - multiLine: false, - dotAll: true, - ), - '', - ); - final repliedHtml = content.tryGet('formatted_body') ?? + final replyHtml = + (inReplyTo.formattedText.isNotEmpty + ? inReplyTo.formattedText + : htmlEscape.convert(inReplyTo.body).replaceAll('\n', '
')) + .replaceAll( + RegExp( + r'.*', + caseSensitive: false, + multiLine: false, + dotAll: true, + ), + '', + ); + final repliedHtml = + content.tryGet('formatted_body') ?? htmlEscape .convert(content.tryGet('body') ?? '') .replaceAll('\n', '
'); @@ -134,9 +124,7 @@ extension EventsRoomExtension on Room { content['body'] = '${replyText.replaceAll('@room', '@\u200broom')}\n\n${content.tryGet('body') ?? ''}'; content['m.relates_to'] = { - 'm.in_reply_to': { - 'event_id': inReplyTo.eventId, - }, + 'm.in_reply_to': {'event_id': inReplyTo.eventId}, }; } @@ -190,13 +178,7 @@ extension EventsRoomExtension on Room { nextBatch: '', rooms: RoomsUpdate( join: { - id: JoinedRoomUpdate( - timeline: TimelineUpdate( - events: [ - event, - ], - ), - ), + id: JoinedRoomUpdate(timeline: TimelineUpdate(events: [event])), }, ), ); @@ -234,10 +216,7 @@ extension EventsRoomExtension on Room { // ); // } - final event = { - 'msgtype': msgtype, - 'body': message, - }; + final event = {'msgtype': msgtype, 'body': message}; if (choreo != null) { event[ModelKey.choreoRecord] = choreo.toJson(); } @@ -305,9 +284,7 @@ extension EventsRoomExtension on Room { await timeline.requestFuture( historyCount: 100, filter: StateFilter( - types: [ - PangeaEventTypes.construct, - ], + types: [PangeaEventTypes.construct], senders: [userID], ), ); @@ -322,9 +299,7 @@ extension EventsRoomExtension on Room { await timeline.requestHistory( historyCount: 100, filter: StateFilter( - types: [ - PangeaEventTypes.construct, - ], + types: [PangeaEventTypes.construct], senders: [userID], ), ); @@ -349,8 +324,10 @@ extension EventsRoomExtension on Room { } Future> getAllEvents({String? since}) async { - final GetRoomEventsResponse initalResp = - await client.getRoomEvents(id, Direction.b); + final GetRoomEventsResponse initalResp = await client.getRoomEvents( + id, + Direction.b, + ); if (initalResp.end == null) return []; String? nextStartToken = initalResp.end; diff --git a/lib/pangea/extensions/room_information_extension.dart b/lib/pangea/extensions/room_information_extension.dart index cb2fbbb86..b5253e840 100644 --- a/lib/pangea/extensions/room_information_extension.dart +++ b/lib/pangea/extensions/room_information_extension.dart @@ -10,9 +10,7 @@ extension RoomInformationRoomExtension on Room { Future get botIsInRoom async { final List participants = await requestParticipants(); - return participants.any( - (User user) => user.id == BotName.byEnvironment, - ); + return participants.any((User user) => user.id == BotName.byEnvironment); } String? get roomType => diff --git a/lib/pangea/extensions/room_space_settings_extension.dart b/lib/pangea/extensions/room_space_settings_extension.dart index 47dea0d74..92c21a69a 100644 --- a/lib/pangea/extensions/room_space_settings_extension.dart +++ b/lib/pangea/extensions/room_space_settings_extension.dart @@ -26,12 +26,12 @@ extension SpaceRoomExtension on Room { final List participants = await requestParticipants(); return isSpace ? participants - .where( - (e) => - e.powerLevel == SpaceConstants.powerLevelOfAdmin && - e.id != BotName.byEnvironment, - ) - .toList() + .where( + (e) => + e.powerLevel == SpaceConstants.powerLevelOfAdmin && + e.id != BotName.byEnvironment, + ) + .toList() : participants; } } diff --git a/lib/pangea/instructions/instruction_settings.dart b/lib/pangea/instructions/instruction_settings.dart index 20933ff5e..6b4550ff2 100644 --- a/lib/pangea/instructions/instruction_settings.dart +++ b/lib/pangea/instructions/instruction_settings.dart @@ -40,7 +40,7 @@ class InstructionSettings { for (final key in InstructionsEnum.values) { instructions[key.toString()] = (accountData[key.toString()]?.content[key.toString()] as bool?) ?? - false; + false; } return InstructionSettings(instructions); } @@ -83,8 +83,6 @@ class InstructionSettings { final entries = _instructions.entries.toList() ..sort((a, b) => a.key.hashCode.compareTo(b.key.hashCode)); - return Object.hashAll( - entries.map((e) => Object.hash(e.key, e.value)), - ); + return Object.hashAll(entries.map((e) => Object.hash(e.key, e.value))); } } diff --git a/lib/pangea/instructions/instructions_enum.dart b/lib/pangea/instructions/instructions_enum.dart index 10f058054..7103186bf 100644 --- a/lib/pangea/instructions/instructions_enum.dart +++ b/lib/pangea/instructions/instructions_enum.dart @@ -74,9 +74,7 @@ extension InstructionsEnumExtension on InstructionsEnum { ErrorHandler.logError( e: Exception("No title for this instruction"), m: 'InstructionsEnumExtension.title', - data: { - 'this': this, - }, + data: {'this': this}, ); debugger(when: kDebugMode); return ""; @@ -144,9 +142,12 @@ extension InstructionsEnumExtension on InstructionsEnum { } } - bool get isToggledOff => - MatrixState.pangeaController.userController.profile.instructionSettings - .getStatus(this); + bool get isToggledOff => MatrixState + .pangeaController + .userController + .profile + .instructionSettings + .getStatus(this); void setToggledOff(bool value) { final userController = MatrixState.pangeaController.userController; diff --git a/lib/pangea/instructions/instructions_inline_tooltip.dart b/lib/pangea/instructions/instructions_inline_tooltip.dart index 5839d5657..0d81adda0 100644 --- a/lib/pangea/instructions/instructions_inline_tooltip.dart +++ b/lib/pangea/instructions/instructions_inline_tooltip.dart @@ -146,7 +146,8 @@ class InlineTooltipState extends State child: Center( child: Text( widget.message, - style: widget.textStyle ?? + style: + widget.textStyle ?? (FluffyThemes.isColumnMode(context) ? Theme.of(context).textTheme.titleSmall : Theme.of(context).textTheme.bodyMedium), diff --git a/lib/pangea/instructions/instructions_toggle.dart b/lib/pangea/instructions/instructions_toggle.dart index b2b653e44..62516dee3 100644 --- a/lib/pangea/instructions/instructions_toggle.dart +++ b/lib/pangea/instructions/instructions_toggle.dart @@ -9,10 +9,7 @@ import 'package:fluffychat/widgets/matrix.dart'; /// User can toggle on to prevent Instruction Card /// from appearing in future sessions class InstructionsToggle extends StatefulWidget { - const InstructionsToggle({ - super.key, - required this.instructionsKey, - }); + const InstructionsToggle({super.key, required this.instructionsKey}); final InstructionsEnum instructionsKey; diff --git a/lib/pangea/instructions/reset_instructions_list_tile.dart b/lib/pangea/instructions/reset_instructions_list_tile.dart index 4154498ee..7293271e9 100644 --- a/lib/pangea/instructions/reset_instructions_list_tile.dart +++ b/lib/pangea/instructions/reset_instructions_list_tile.dart @@ -5,10 +5,7 @@ import 'package:fluffychat/pangea/learning_settings/settings_learning.dart'; import 'package:fluffychat/widgets/adaptive_dialogs/show_ok_cancel_alert_dialog.dart'; class ResetInstructionsListTile extends StatelessWidget { - const ResetInstructionsListTile({ - super.key, - required this.controller, - }); + const ResetInstructionsListTile({super.key, required this.controller}); final SettingsLearningController controller; @@ -17,12 +14,8 @@ class ResetInstructionsListTile extends StatelessWidget { //TODO: add to L10n return ListTile( leading: const Icon(Icons.lightbulb), - title: Text( - L10n.of(context).resetInstructionTooltipsTitle, - ), - subtitle: Text( - L10n.of(context).resetInstructionTooltipsDesc, - ), + title: Text(L10n.of(context).resetInstructionTooltipsTitle), + subtitle: Text(L10n.of(context).resetInstructionTooltipsDesc), onTap: () async { final resp = await showOkCancelAlertDialog( context: context, diff --git a/lib/pangea/join_codes/knock_space_extension.dart b/lib/pangea/join_codes/knock_space_extension.dart index a958299df..984db1b1f 100644 --- a/lib/pangea/join_codes/knock_space_extension.dart +++ b/lib/pangea/join_codes/knock_space_extension.dart @@ -6,17 +6,11 @@ import 'package:matrix/matrix_api_lite/generated/api.dart'; extension on Api { Future knockSpace(String code) async { - final requestUri = Uri( - path: '_synapse/client/pangea/v1/knock_with_code', - ); + final requestUri = Uri(path: '_synapse/client/pangea/v1/knock_with_code'); final request = Request('POST', baseUri!.resolveUri(requestUri)); request.headers['content-type'] = 'application/json'; request.headers['authorization'] = 'Bearer ${bearerToken!}'; - request.bodyBytes = utf8.encode( - jsonEncode({ - 'access_code': code, - }), - ); + request.bodyBytes = utf8.encode(jsonEncode({'access_code': code})); final response = await httpClient.send(request); if (response.statusCode != 200) { if (response.statusCode == 429) { diff --git a/lib/pangea/join_codes/space_code_controller.dart b/lib/pangea/join_codes/space_code_controller.dart index e1590a130..844213d84 100644 --- a/lib/pangea/join_codes/space_code_controller.dart +++ b/lib/pangea/join_codes/space_code_controller.dart @@ -23,15 +23,13 @@ class SpaceCodeController extends BaseController { static Future joinCachedSpaceCode(BuildContext context) async { final String? spaceCode = SpaceCodeRepo.spaceCode; if (spaceCode == null) return null; - final spaceId = await joinSpaceWithCode( - context, - spaceCode, - ); + final spaceId = await joinSpaceWithCode(context, spaceCode); await SpaceCodeRepo.clearSpaceCode(); if (spaceId != null) { - final room = - MatrixState.pangeaController.matrixState.client.getRoomById(spaceId); + final room = MatrixState.pangeaController.matrixState.client.getRoomById( + spaceId, + ); room?.isSpace ?? true ? context.go('/rooms/spaces/$spaceId/details') : context.go('/rooms/${room?.id}'); @@ -51,8 +49,9 @@ class SpaceCodeController extends BaseController { final resp = await showFutureLoadingDialog( context: context, future: () async { - final KnockSpaceResponse knockResult = - await client.knockWithCode(spaceCode); + final KnockSpaceResponse knockResult = await client.knockWithCode( + spaceCode, + ); if (knockResult.roomIds.isEmpty && knockResult.alreadyJoined.isEmpty && @@ -117,10 +116,7 @@ class SpaceCodeController extends BaseController { Room? room = client.getRoomById(spaceId); if (room == null) { - await client.waitForRoomInSync( - spaceId, - join: true, - ); + await client.waitForRoomInSync(spaceId, join: true); room = client.getRoomById(spaceId); if (room == null) { throw Exception("Failed to join space with id $spaceId"); diff --git a/lib/pangea/join_codes/space_code_repo.dart b/lib/pangea/join_codes/space_code_repo.dart index af6ab3fd8..1c5270104 100644 --- a/lib/pangea/join_codes/space_code_repo.dart +++ b/lib/pangea/join_codes/space_code_repo.dart @@ -13,17 +13,11 @@ class SpaceCodeRepo { static Future setSpaceCode(String code) async { if (code.isEmpty) return; - await _spaceStorage.write( - PLocalKey.cachedSpaceCodeToJoin, - code, - ); + await _spaceStorage.write(PLocalKey.cachedSpaceCodeToJoin, code); } static Future setRecentCode(String code) async { - await _spaceStorage.write( - PLocalKey.justInputtedCode, - code, - ); + await _spaceStorage.write(PLocalKey.justInputtedCode, code); } static Future clearSpaceCode() async { diff --git a/lib/pangea/join_codes/too_many_requests_dialog.dart b/lib/pangea/join_codes/too_many_requests_dialog.dart index 778bfb6ce..e18a3f780 100644 --- a/lib/pangea/join_codes/too_many_requests_dialog.dart +++ b/lib/pangea/join_codes/too_many_requests_dialog.dart @@ -9,18 +9,13 @@ class TooManyRequestsDialog extends StatelessWidget { @override Widget build(BuildContext context) { return Dialog( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12.0), - ), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12.0)), child: Padding( padding: const EdgeInsets.all(16.0), child: Column( mainAxisSize: MainAxisSize.min, children: [ - const BotFace( - width: 100, - expression: BotExpression.idle, - ), + const BotFace(width: 100, expression: BotExpression.idle), const SizedBox(height: 16), Text( L10n.of(context).areYouLikeMe, diff --git a/lib/pangea/languages/language_arc_model.dart b/lib/pangea/languages/language_arc_model.dart index c55d8a66b..832b9000e 100644 --- a/lib/pangea/languages/language_arc_model.dart +++ b/lib/pangea/languages/language_arc_model.dart @@ -4,10 +4,7 @@ class LanguageArc { final LanguageModel l1; final LanguageModel l2; - LanguageArc({ - required this.l1, - required this.l2, - }); + LanguageArc({required this.l1, required this.l2}); factory LanguageArc.fromJson(Map json) { return LanguageArc( @@ -17,10 +14,7 @@ class LanguageArc { } Map toJson() { - return { - 'l1': l1.toJson(), - 'l2': l2.toJson(), - }; + return {'l1': l1.toJson(), 'l2': l2.toJson()}; } @override diff --git a/lib/pangea/languages/language_constants.dart b/lib/pangea/languages/language_constants.dart index 89a005ce5..1c0b3dc3a 100644 --- a/lib/pangea/languages/language_constants.dart +++ b/lib/pangea/languages/language_constants.dart @@ -20,1135 +20,427 @@ class LanguageConstants { ]; static List> get languageList => [ - { - "language_code": "ab", - "language_name": "Abkhazian", - "l2_support": "na", - }, - { - "language_code": "ace", - "language_name": "Achinese", - "l2_support": "na", - }, - { - "language_code": "ach", - "language_name": "Acoli", - "l2_support": "na", - }, - { - "language_code": "af", - "language_name": "Afrikaans", - "l2_support": "na", - }, - { - "language_code": "ak", - "language_name": "Akan", - "l2_support": "na", - }, - { - "language_code": "alz", - "language_name": "Alur", - "l2_support": "na", - }, - { - "language_code": "am", - "language_name": "Amharic", - "l2_support": "beta", - }, - { - "language_code": "ar", - "language_name": "Arabic", - "l2_support": "beta", - }, - { - "language_code": "as", - "language_name": "Assamese", - "l2_support": "na", - }, - { - "language_code": "awa", - "language_name": "Awadhi", - "l2_support": "na", - }, - { - "language_code": "ay", - "language_name": "Aymara", - "l2_support": "na", - }, - { - "language_code": "az", - "language_name": "Azerbaijani", - "l2_support": "na", - }, - { - "language_code": "ba", - "language_name": "Bashkir", - "l2_support": "na", - }, - { - "language_code": "ban", - "language_name": "Balinese", - "l2_support": "na", - }, - { - "language_code": "bbc", - "language_name": "Batak Toba", - "l2_support": "na", - }, - { - "language_code": "be", - "language_name": "Belarusian", - "l2_support": "na", - }, - { - "language_code": "bem", - "language_name": "Bemba", - "l2_support": "na", - }, - { - "language_code": "bew", - "language_name": "Betawi", - "l2_support": "na", - }, - { - "language_code": "bg", - "language_name": "Bulgarian", - "l2_support": "beta", - }, - { - "language_code": "bho", - "language_name": "Bhojpuri", - "l2_support": "na", - }, - { - "language_code": "bik", - "language_name": "Bikol", - "l2_support": "na", - }, - { - "language_code": "bm", - "language_name": "Bambara", - "l2_support": "na", - }, - { - "language_code": "bn", - "language_name": "Bangla", - "l2_support": "beta", - }, - { - "language_code": "bn-BD", - "language_name": "Bengali (Bangladesh)", - "l2_support": "beta", - }, - { - "language_code": "bn-IN", - "language_name": "Bengali (India)", - "l2_support": "beta", - }, - { - "language_code": "br", - "language_name": "Breton", - "l2_support": "na", - }, - { - "language_code": "bs", - "language_name": "Bosnian", - "l2_support": "na", - }, - { - "language_code": "bts", - "language_name": "Batak Simalungun", - "l2_support": "na", - }, - { - "language_code": "btx", - "language_name": "Batak Karo", - "l2_support": "na", - }, - { - "language_code": "bua", - "language_name": "Buriat", - "l2_support": "na", - }, - { - "language_code": "ca", - "language_name": "Catalan", - "l2_support": "full", - }, - { - "language_code": "ceb", - "language_name": "Cebuano", - "l2_support": "na", - }, - { - "language_code": "cgg", - "language_name": "Chiga", - "l2_support": "na", - }, - { - "language_code": "chm", - "language_name": "Mari", - "l2_support": "na", - }, - { - "language_code": "ckb", - "language_name": "Central Kurdish", - "l2_support": "na", - }, - { - "language_code": "cnh", - "language_name": "Hakha Chin", - "l2_support": "na", - }, - { - "language_code": "co", - "language_name": "Corsican", - "l2_support": "na", - }, - { - "language_code": "crh", - "language_name": "Crimean Turkish", - "l2_support": "na", - }, - { - "language_code": "crs", - "language_name": "Seselwa Creole French", - "l2_support": "na", - }, - { - "language_code": "cs", - "language_name": "Czech", - "l2_support": "beta", - }, - { - "language_code": "cv", - "language_name": "Chuvash", - "l2_support": "na", - }, - { - "language_code": "cy", - "language_name": "Welsh", - "l2_support": "na", - }, - { - "language_code": "da", - "language_name": "Danish", - "l2_support": "beta", - }, - { - "language_code": "de", - "language_name": "German", - "l2_support": "full", - }, - { - "language_code": "din", - "language_name": "Dinka", - "l2_support": "na", - }, - { - "language_code": "doi", - "language_name": "Dogri", - "l2_support": "na", - }, - { - "language_code": "dov", - "language_name": "Dombe", - "l2_support": "na", - }, - { - "language_code": "dv", - "language_name": "Divehi", - "l2_support": "na", - }, - { - "language_code": "dz", - "language_name": "Dzongkha", - "l2_support": "na", - }, - { - "language_code": "ee", - "language_name": "Ewe", - "l2_support": "na", - }, - { - "language_code": "el", - "language_name": "Greek", - "l2_support": "beta", - }, - { - "language_code": "en", - "language_name": "English", - "l2_support": "full", - }, - { - "language_code": "en-AU", - "language_name": "English (Australia)", - "l2_support": "full", - }, - { - "language_code": "en-GB", - "language_name": "English (UK)", - "l2_support": "full", - }, - { - "language_code": "en-IN", - "language_name": "English (India)", - "l2_support": "full", - }, - { - "language_code": "en-US", - "language_name": "English (US)", - "l2_support": "full", - }, - { - "language_code": "eo", - "language_name": "Esperanto", - "l2_support": "na", - }, - { - "language_code": "es", - "language_name": "Spanish", - "l2_support": "full", - }, - { - "language_code": "es-ES", - "language_name": "Spanish (Spain)", - "l2_support": "full", - }, - { - "language_code": "es-MX", - "language_name": "Spanish (Mexico)", - "l2_support": "full", - }, - { - "language_code": "et", - "language_name": "Estonian", - "l2_support": "beta", - }, - { - "language_code": "eu", - "language_name": "Basque", - "l2_support": "beta", - }, - { - "language_code": "fa", - "language_name": "Persian", - "l2_support": "na", - }, - { - "language_code": "ff", - "language_name": "Fulah", - "l2_support": "na", - }, - { - "language_code": "fi", - "language_name": "Finnish", - "l2_support": "beta", - }, - { - "language_code": "fil", - "language_name": "Filipino", - "l2_support": "na", - }, - { - "language_code": "fj", - "language_name": "Fijian", - "l2_support": "na", - }, - { - "language_code": "fo", - "language_name": "Faroese", - "l2_support": "na", - }, - { - "language_code": "fr", - "language_name": "French", - "l2_support": "full", - }, - { - "language_code": "fr-CA", - "language_name": "French (Canada)", - "l2_support": "full", - }, - { - "language_code": "fr-FR", - "language_name": "French (France)", - "l2_support": "full", - }, - { - "language_code": "fy", - "language_name": "Western Frisian", - "l2_support": "na", - }, - { - "language_code": "ga", - "language_name": "Irish", - "l2_support": "na", - }, - { - "language_code": "gaa", - "language_name": "Ga", - "l2_support": "na", - }, - { - "language_code": "gd", - "language_name": "Scottish Gaelic", - "l2_support": "na", - }, - { - "language_code": "gl", - "language_name": "Galician", - "l2_support": "beta", - }, - { - "language_code": "gn", - "language_name": "Guarani", - "l2_support": "na", - }, - { - "language_code": "gom", - "language_name": "Goan Konkani", - "l2_support": "na", - }, - { - "language_code": "gu", - "language_name": "Gujarati", - "l2_support": "beta", - }, - { - "language_code": "ha", - "language_name": "Hausa", - "l2_support": "na", - }, - { - "language_code": "haw", - "language_name": "Hawaiian", - "l2_support": "na", - }, - { - "language_code": "he", - "language_name": "Hebrew", - "l2_support": "na", - }, - { - "language_code": "hi", - "language_name": "Hindi", - "l2_support": "beta", - }, - { - "language_code": "hil", - "language_name": "Hiligaynon", - "l2_support": "na", - }, - { - "language_code": "hmn", - "language_name": "Hmong", - "l2_support": "na", - }, - { - "language_code": "hne", - "language_name": "Chhattisgarhi", - "l2_support": "na", - }, - { - "language_code": "hr", - "language_name": "Croatian", - "l2_support": "na", - }, - { - "language_code": "hrx", - "language_name": "Hunsrik", - "l2_support": "na", - }, - { - "language_code": "ht", - "language_name": "Haitian Creole", - "l2_support": "na", - }, - { - "language_code": "hu", - "language_name": "Hungarian", - "l2_support": "beta", - }, - { - "language_code": "hy", - "language_name": "Armenian", - "l2_support": "na", - }, - { - "language_code": "id", - "language_name": "Indonesian", - "l2_support": "beta", - }, - { - "language_code": "ig", - "language_name": "Igbo", - "l2_support": "na", - }, - { - "language_code": "ilo", - "language_name": "Iloko", - "l2_support": "na", - }, - { - "language_code": "is", - "language_name": "Icelandic", - "l2_support": "na", - }, - { - "language_code": "it", - "language_name": "Italian", - "l2_support": "full", - }, - { - "language_code": "iw", - "language_name": "Hebrew", - "l2_support": "na", - }, - { - "language_code": "ja", - "language_name": "Japanese", - "l2_support": "full", - }, - { - "language_code": "jv", - "language_name": "Javanese", - "l2_support": "na", - }, - { - "language_code": "ka", - "language_name": "Georgian", - "l2_support": "na", - }, - { - "language_code": "kk", - "language_name": "Kazakh", - "l2_support": "na", - }, - { - "language_code": "km", - "language_name": "Khmer", - "l2_support": "na", - }, - { - "language_code": "kn", - "language_name": "Kannada", - "l2_support": "beta", - }, - { - "language_code": "ko", - "language_name": "Korean", - "l2_support": "full", - }, - { - "language_code": "kok", - "language_name": "Konkani", - "l2_support": "na", - }, - { - "language_code": "kri", - "language_name": "Krio", - "l2_support": "na", - }, - { - "language_code": "ks", - "language_name": "Kashmiri", - "l2_support": "na", - }, - { - "language_code": "ktu", - "language_name": "Kituba (Democratic Republic of Congo)", - "l2_support": "na", - }, - { - "language_code": "ku", - "language_name": "Kurdish", - "l2_support": "na", - }, - { - "language_code": "ky", - "language_name": "Kyrgyz", - "l2_support": "na", - }, - { - "language_code": "la", - "language_name": "Latin", - "l2_support": "na", - }, - { - "language_code": "lb", - "language_name": "Luxembourgish", - "l2_support": "na", - }, - { - "language_code": "lg", - "language_name": "Ganda", - "l2_support": "na", - }, - { - "language_code": "li", - "language_name": "Limburgish", - "l2_support": "na", - }, - { - "language_code": "lij", - "language_name": "Ligurian", - "l2_support": "na", - }, - { - "language_code": "lmo", - "language_name": "Lombard", - "l2_support": "na", - }, - { - "language_code": "ln", - "language_name": "Lingala", - "l2_support": "na", - }, - { - "language_code": "lo", - "language_name": "Lao", - "l2_support": "na", - }, - { - "language_code": "lt", - "language_name": "Lithuanian", - "l2_support": "beta", - }, - { - "language_code": "ltg", - "language_name": "Latgalian", - "l2_support": "na", - }, - { - "language_code": "luo", - "language_name": "Luo (Kenya and Tanzania)", - "l2_support": "na", - }, - { - "language_code": "lus", - "language_name": "Mizo", - "l2_support": "na", - }, - { - "language_code": "lv", - "language_name": "Latvian", - "l2_support": "beta", - }, - { - "language_code": "mai", - "language_name": "Maithili", - "l2_support": "na", - }, - { - "language_code": "mak", - "language_name": "Makasar", - "l2_support": "na", - }, - { - "language_code": "mg", - "language_name": "Malagasy", - "l2_support": "na", - }, - { - "language_code": "mi", - "language_name": "Māori", - "l2_support": "na", - }, - { - "language_code": "min", - "language_name": "Minangkabau", - "l2_support": "na", - }, - { - "language_code": "mk", - "language_name": "Macedonian", - "l2_support": "na", - }, - { - "language_code": "ml", - "language_name": "Malayalam", - "l2_support": "na", - }, - { - "language_code": "mn", - "language_name": "Mongolian", - "l2_support": "beta", - }, - { - "language_code": "mni", - "language_name": "Manipuri", - "l2_support": "na", - }, - { - "language_code": "mr", - "language_name": "Marathi", - "l2_support": "beta", - }, - { - "language_code": "ms", - "language_name": "Malay", - "l2_support": "beta", - }, - { - "language_code": "ms-Arab", - "language_name": "Malay (Arabic)", - "l2_support": "beta", - }, - { - "language_code": "ms-MY", - "language_name": "Malay (Malaysia)", - "l2_support": "beta", - }, - { - "language_code": "mt", - "language_name": "Maltese", - "l2_support": "na", - }, - { - "language_code": "mwr", - "language_name": "Marwari", - "l2_support": "na", - }, - { - "language_code": "my", - "language_name": "Burmese", - "l2_support": "na", - }, - { - "language_code": "nan", - "language_name": "Min Nan", - "l2_support": "na", - }, - { - "language_code": "nb", - "language_name": "Norwegian (Bokmål)", - "l2_support": "na", - }, - { - "language_code": "ne", - "language_name": "Nepali", - "l2_support": "na", - }, - { - "language_code": "new", - "language_name": "Newari", - "l2_support": "na", - }, - { - "language_code": "nl", - "language_name": "Dutch", - "l2_support": "beta", - }, - { - "language_code": "nl-BE", - "language_name": "Flemish", - "l2_support": "beta", - }, - { - "language_code": "no", - "language_name": "Norwegian", - "l2_support": "na", - }, - { - "language_code": "nr", - "language_name": "South Ndebele", - "l2_support": "na", - }, - { - "language_code": "nso", - "language_name": "Northern Sotho", - "l2_support": "na", - }, - { - "language_code": "nus", - "language_name": "Nuer", - "l2_support": "na", - }, - { - "language_code": "ny", - "language_name": "Nyanja", - "l2_support": "na", - }, - { - "language_code": "oc", - "language_name": "Occitan", - "l2_support": "na", - }, - { - "language_code": "om", - "language_name": "Oromo", - "l2_support": "na", - }, - { - "language_code": "or", - "language_name": "Odia", - "l2_support": "na", - }, - { - "language_code": "pa", - "language_name": "Punjabi", - "l2_support": "beta", - }, - { - "language_code": "pa-Arab", - "language_name": "Punjabi (Shahmukhi)", - "l2_support": "beta", - }, - { - "language_code": "pa-IN", - "language_name": "Punjabi (Gurmukhi)", - "l2_support": "beta", - }, - { - "language_code": "pag", - "language_name": "Pangasinan", - "l2_support": "na", - }, - { - "language_code": "pam", - "language_name": "Pampanga", - "l2_support": "na", - }, - { - "language_code": "pap", - "language_name": "Papiamento", - "l2_support": "na", - }, - { - "language_code": "pl", - "language_name": "Polish", - "l2_support": "beta", - }, - { - "language_code": "ps", - "language_name": "Pashto", - "l2_support": "na", - }, - { - "language_code": "pt", - "language_name": "Portuguese", - "l2_support": "full", - }, - { - "language_code": "pt-BR", - "language_name": "Portuguese (Brazil)", - "l2_support": "full", - }, - { - "language_code": "pt-PT", - "language_name": "Portuguese (Portugal)", - "l2_support": "full", - }, - { - "language_code": "qu", - "language_name": "Quechua", - "l2_support": "na", - }, - { - "language_code": "raj", - "language_name": "Rajasthani", - "l2_support": "na", - }, - { - "language_code": "rn", - "language_name": "Rundi", - "l2_support": "na", - }, - { - "language_code": "ro", - "language_name": "Romanian", - "l2_support": "beta", - }, - { - "language_code": "ro-MD", - "language_name": "Moldovan", - "l2_support": "beta", - }, - { - "language_code": "ro-RO", - "language_name": "Romanian (Romania)", - "l2_support": "beta", - }, - { - "language_code": "rom", - "language_name": "Romany", - "l2_support": "na", - }, - { - "language_code": "ru", - "language_name": "Russian", - "l2_support": "full", - }, - { - "language_code": "rw", - "language_name": "Kinyarwanda", - "l2_support": "na", - }, - { - "language_code": "sa", - "language_name": "Sanskrit", - "l2_support": "na", - }, - { - "language_code": "sat", - "language_name": "Santali", - "l2_support": "na", - }, - { - "language_code": "scn", - "language_name": "Sicilian", - "l2_support": "na", - }, - { - "language_code": "sd", - "language_name": "Sindhi", - "l2_support": "na", - }, - { - "language_code": "sg", - "language_name": "Sango", - "l2_support": "na", - }, - { - "language_code": "shn", - "language_name": "Shan", - "l2_support": "na", - }, - { - "language_code": "si", - "language_name": "Sinhala", - "l2_support": "na", - }, - { - "language_code": "sk", - "language_name": "Slovak", - "l2_support": "beta", - }, - { - "language_code": "sl", - "language_name": "Slovenian", - "l2_support": "na", - }, - { - "language_code": "sm", - "language_name": "Samoan", - "l2_support": "na", - }, - { - "language_code": "sn", - "language_name": "Shona", - "l2_support": "na", - }, - { - "language_code": "so", - "language_name": "Somali", - "l2_support": "na", - }, - { - "language_code": "sq", - "language_name": "Albanian", - "l2_support": "na", - }, - { - "language_code": "sr", - "language_name": "Serbian", - "l2_support": "beta", - }, - { - "language_code": "sr-ME", - "language_name": "Montenegrin", - "l2_support": "beta", - }, - { - "language_code": "sr-RS", - "language_name": "Serbian", - "l2_support": "beta", - }, - { - "language_code": "ss", - "language_name": "Swati", - "l2_support": "na", - }, - { - "language_code": "st", - "language_name": "Southern Sotho", - "l2_support": "na", - }, - { - "language_code": "su", - "language_name": "Sundanese", - "l2_support": "na", - }, - { - "language_code": "sv", - "language_name": "Swedish", - "l2_support": "na", - }, - { - "language_code": "sw", - "language_name": "Swahili", - "l2_support": "na", - }, - { - "language_code": "szl", - "language_name": "Silesian", - "l2_support": "na", - }, - { - "language_code": "ta", - "language_name": "Tamil", - "l2_support": "na", - }, - { - "language_code": "te", - "language_name": "Telugu", - "l2_support": "na", - }, - { - "language_code": "tet", - "language_name": "Tetum", - "l2_support": "na", - }, - { - "language_code": "tg", - "language_name": "Tajik", - "l2_support": "na", - }, - { - "language_code": "th", - "language_name": "Thai", - "l2_support": "na", - }, - { - "language_code": "ti", - "language_name": "Tigrinya", - "l2_support": "na", - }, - { - "language_code": "tk", - "language_name": "Turkmen", - "l2_support": "na", - }, - { - "language_code": "tl", - "language_name": "Tagalog", - "l2_support": "na", - }, - { - "language_code": "tn", - "language_name": "Tswana", - "l2_support": "na", - }, - { - "language_code": "tr", - "language_name": "Turkish", - "l2_support": "na", - }, - { - "language_code": "ts", - "language_name": "Tsonga", - "l2_support": "na", - }, - { - "language_code": "tt", - "language_name": "Tatar", - "l2_support": "na", - }, - { - "language_code": "ug", - "language_name": "Uyghur", - "l2_support": "na", - }, - { - "language_code": "uk", - "language_name": "Ukrainian", - "l2_support": "beta", - }, - { - "language_code": "ur", - "language_name": "Urdu", - "l2_support": "beta", - }, - { - "language_code": "ur-IN", - "language_name": "Urdu (India)", - "l2_support": "beta", - }, - { - "language_code": "ur-PK", - "language_name": "Urdu (Pakistan)", - "l2_support": "beta", - }, - { - "language_code": "uz", - "language_name": "Uzbek", - "l2_support": "na", - }, - { - "language_code": "vi", - "language_name": "Vietnamese", - "l2_support": "full", - }, - { - "language_code": "wuu", - "language_name": "Wu", - "l2_support": "na", - }, - { - "language_code": "xh", - "language_name": "Xhosa", - "l2_support": "na", - }, - { - "language_code": "yi", - "language_name": "Yiddish", - "l2_support": "na", - }, - { - "language_code": "yo", - "language_name": "Yoruba", - "l2_support": "na", - }, - { - "language_code": "yua", - "language_name": "Yucateco", - "l2_support": "na", - }, - { - "language_code": "yue", - "language_name": "Cantonese", - "l2_support": "beta", - }, - { - "language_code": "yue-CN", - "language_name": "Cantonese (China)", - "l2_support": "beta", - }, - { - "language_code": "yue-HK", - "language_name": "Cantonese (Hong Kong)", - "l2_support": "beta", - }, - { - "language_code": "zh", - "language_name": "Chinese", - "l2_support": "full", - }, - { - "language_code": "zh-CN", - "language_name": "Chinese (Simplified)", - "l2_support": "full", - }, - { - "language_code": "zh-TW", - "language_name": "Chinese (Traditional)", - "l2_support": "full", - }, - { - "language_code": "zu", - "language_name": "Zulu", - "l2_support": "na", - } - ]; + {"language_code": "ab", "language_name": "Abkhazian", "l2_support": "na"}, + {"language_code": "ace", "language_name": "Achinese", "l2_support": "na"}, + {"language_code": "ach", "language_name": "Acoli", "l2_support": "na"}, + {"language_code": "af", "language_name": "Afrikaans", "l2_support": "na"}, + {"language_code": "ak", "language_name": "Akan", "l2_support": "na"}, + {"language_code": "alz", "language_name": "Alur", "l2_support": "na"}, + {"language_code": "am", "language_name": "Amharic", "l2_support": "beta"}, + {"language_code": "ar", "language_name": "Arabic", "l2_support": "beta"}, + {"language_code": "as", "language_name": "Assamese", "l2_support": "na"}, + {"language_code": "awa", "language_name": "Awadhi", "l2_support": "na"}, + {"language_code": "ay", "language_name": "Aymara", "l2_support": "na"}, + {"language_code": "az", "language_name": "Azerbaijani", "l2_support": "na"}, + {"language_code": "ba", "language_name": "Bashkir", "l2_support": "na"}, + {"language_code": "ban", "language_name": "Balinese", "l2_support": "na"}, + {"language_code": "bbc", "language_name": "Batak Toba", "l2_support": "na"}, + {"language_code": "be", "language_name": "Belarusian", "l2_support": "na"}, + {"language_code": "bem", "language_name": "Bemba", "l2_support": "na"}, + {"language_code": "bew", "language_name": "Betawi", "l2_support": "na"}, + {"language_code": "bg", "language_name": "Bulgarian", "l2_support": "beta"}, + {"language_code": "bho", "language_name": "Bhojpuri", "l2_support": "na"}, + {"language_code": "bik", "language_name": "Bikol", "l2_support": "na"}, + {"language_code": "bm", "language_name": "Bambara", "l2_support": "na"}, + {"language_code": "bn", "language_name": "Bangla", "l2_support": "beta"}, + { + "language_code": "bn-BD", + "language_name": "Bengali (Bangladesh)", + "l2_support": "beta", + }, + { + "language_code": "bn-IN", + "language_name": "Bengali (India)", + "l2_support": "beta", + }, + {"language_code": "br", "language_name": "Breton", "l2_support": "na"}, + {"language_code": "bs", "language_name": "Bosnian", "l2_support": "na"}, + { + "language_code": "bts", + "language_name": "Batak Simalungun", + "l2_support": "na", + }, + {"language_code": "btx", "language_name": "Batak Karo", "l2_support": "na"}, + {"language_code": "bua", "language_name": "Buriat", "l2_support": "na"}, + {"language_code": "ca", "language_name": "Catalan", "l2_support": "full"}, + {"language_code": "ceb", "language_name": "Cebuano", "l2_support": "na"}, + {"language_code": "cgg", "language_name": "Chiga", "l2_support": "na"}, + {"language_code": "chm", "language_name": "Mari", "l2_support": "na"}, + { + "language_code": "ckb", + "language_name": "Central Kurdish", + "l2_support": "na", + }, + {"language_code": "cnh", "language_name": "Hakha Chin", "l2_support": "na"}, + {"language_code": "co", "language_name": "Corsican", "l2_support": "na"}, + { + "language_code": "crh", + "language_name": "Crimean Turkish", + "l2_support": "na", + }, + { + "language_code": "crs", + "language_name": "Seselwa Creole French", + "l2_support": "na", + }, + {"language_code": "cs", "language_name": "Czech", "l2_support": "beta"}, + {"language_code": "cv", "language_name": "Chuvash", "l2_support": "na"}, + {"language_code": "cy", "language_name": "Welsh", "l2_support": "na"}, + {"language_code": "da", "language_name": "Danish", "l2_support": "beta"}, + {"language_code": "de", "language_name": "German", "l2_support": "full"}, + {"language_code": "din", "language_name": "Dinka", "l2_support": "na"}, + {"language_code": "doi", "language_name": "Dogri", "l2_support": "na"}, + {"language_code": "dov", "language_name": "Dombe", "l2_support": "na"}, + {"language_code": "dv", "language_name": "Divehi", "l2_support": "na"}, + {"language_code": "dz", "language_name": "Dzongkha", "l2_support": "na"}, + {"language_code": "ee", "language_name": "Ewe", "l2_support": "na"}, + {"language_code": "el", "language_name": "Greek", "l2_support": "beta"}, + {"language_code": "en", "language_name": "English", "l2_support": "full"}, + { + "language_code": "en-AU", + "language_name": "English (Australia)", + "l2_support": "full", + }, + { + "language_code": "en-GB", + "language_name": "English (UK)", + "l2_support": "full", + }, + { + "language_code": "en-IN", + "language_name": "English (India)", + "l2_support": "full", + }, + { + "language_code": "en-US", + "language_name": "English (US)", + "l2_support": "full", + }, + {"language_code": "eo", "language_name": "Esperanto", "l2_support": "na"}, + {"language_code": "es", "language_name": "Spanish", "l2_support": "full"}, + { + "language_code": "es-ES", + "language_name": "Spanish (Spain)", + "l2_support": "full", + }, + { + "language_code": "es-MX", + "language_name": "Spanish (Mexico)", + "l2_support": "full", + }, + {"language_code": "et", "language_name": "Estonian", "l2_support": "beta"}, + {"language_code": "eu", "language_name": "Basque", "l2_support": "beta"}, + {"language_code": "fa", "language_name": "Persian", "l2_support": "na"}, + {"language_code": "ff", "language_name": "Fulah", "l2_support": "na"}, + {"language_code": "fi", "language_name": "Finnish", "l2_support": "beta"}, + {"language_code": "fil", "language_name": "Filipino", "l2_support": "na"}, + {"language_code": "fj", "language_name": "Fijian", "l2_support": "na"}, + {"language_code": "fo", "language_name": "Faroese", "l2_support": "na"}, + {"language_code": "fr", "language_name": "French", "l2_support": "full"}, + { + "language_code": "fr-CA", + "language_name": "French (Canada)", + "l2_support": "full", + }, + { + "language_code": "fr-FR", + "language_name": "French (France)", + "l2_support": "full", + }, + { + "language_code": "fy", + "language_name": "Western Frisian", + "l2_support": "na", + }, + {"language_code": "ga", "language_name": "Irish", "l2_support": "na"}, + {"language_code": "gaa", "language_name": "Ga", "l2_support": "na"}, + { + "language_code": "gd", + "language_name": "Scottish Gaelic", + "l2_support": "na", + }, + {"language_code": "gl", "language_name": "Galician", "l2_support": "beta"}, + {"language_code": "gn", "language_name": "Guarani", "l2_support": "na"}, + { + "language_code": "gom", + "language_name": "Goan Konkani", + "l2_support": "na", + }, + {"language_code": "gu", "language_name": "Gujarati", "l2_support": "beta"}, + {"language_code": "ha", "language_name": "Hausa", "l2_support": "na"}, + {"language_code": "haw", "language_name": "Hawaiian", "l2_support": "na"}, + {"language_code": "he", "language_name": "Hebrew", "l2_support": "na"}, + {"language_code": "hi", "language_name": "Hindi", "l2_support": "beta"}, + {"language_code": "hil", "language_name": "Hiligaynon", "l2_support": "na"}, + {"language_code": "hmn", "language_name": "Hmong", "l2_support": "na"}, + { + "language_code": "hne", + "language_name": "Chhattisgarhi", + "l2_support": "na", + }, + {"language_code": "hr", "language_name": "Croatian", "l2_support": "na"}, + {"language_code": "hrx", "language_name": "Hunsrik", "l2_support": "na"}, + { + "language_code": "ht", + "language_name": "Haitian Creole", + "l2_support": "na", + }, + {"language_code": "hu", "language_name": "Hungarian", "l2_support": "beta"}, + {"language_code": "hy", "language_name": "Armenian", "l2_support": "na"}, + { + "language_code": "id", + "language_name": "Indonesian", + "l2_support": "beta", + }, + {"language_code": "ig", "language_name": "Igbo", "l2_support": "na"}, + {"language_code": "ilo", "language_name": "Iloko", "l2_support": "na"}, + {"language_code": "is", "language_name": "Icelandic", "l2_support": "na"}, + {"language_code": "it", "language_name": "Italian", "l2_support": "full"}, + {"language_code": "iw", "language_name": "Hebrew", "l2_support": "na"}, + {"language_code": "ja", "language_name": "Japanese", "l2_support": "full"}, + {"language_code": "jv", "language_name": "Javanese", "l2_support": "na"}, + {"language_code": "ka", "language_name": "Georgian", "l2_support": "na"}, + {"language_code": "kk", "language_name": "Kazakh", "l2_support": "na"}, + {"language_code": "km", "language_name": "Khmer", "l2_support": "na"}, + {"language_code": "kn", "language_name": "Kannada", "l2_support": "beta"}, + {"language_code": "ko", "language_name": "Korean", "l2_support": "full"}, + {"language_code": "kok", "language_name": "Konkani", "l2_support": "na"}, + {"language_code": "kri", "language_name": "Krio", "l2_support": "na"}, + {"language_code": "ks", "language_name": "Kashmiri", "l2_support": "na"}, + { + "language_code": "ktu", + "language_name": "Kituba (Democratic Republic of Congo)", + "l2_support": "na", + }, + {"language_code": "ku", "language_name": "Kurdish", "l2_support": "na"}, + {"language_code": "ky", "language_name": "Kyrgyz", "l2_support": "na"}, + {"language_code": "la", "language_name": "Latin", "l2_support": "na"}, + { + "language_code": "lb", + "language_name": "Luxembourgish", + "l2_support": "na", + }, + {"language_code": "lg", "language_name": "Ganda", "l2_support": "na"}, + {"language_code": "li", "language_name": "Limburgish", "l2_support": "na"}, + {"language_code": "lij", "language_name": "Ligurian", "l2_support": "na"}, + {"language_code": "lmo", "language_name": "Lombard", "l2_support": "na"}, + {"language_code": "ln", "language_name": "Lingala", "l2_support": "na"}, + {"language_code": "lo", "language_name": "Lao", "l2_support": "na"}, + { + "language_code": "lt", + "language_name": "Lithuanian", + "l2_support": "beta", + }, + {"language_code": "ltg", "language_name": "Latgalian", "l2_support": "na"}, + { + "language_code": "luo", + "language_name": "Luo (Kenya and Tanzania)", + "l2_support": "na", + }, + {"language_code": "lus", "language_name": "Mizo", "l2_support": "na"}, + {"language_code": "lv", "language_name": "Latvian", "l2_support": "beta"}, + {"language_code": "mai", "language_name": "Maithili", "l2_support": "na"}, + {"language_code": "mak", "language_name": "Makasar", "l2_support": "na"}, + {"language_code": "mg", "language_name": "Malagasy", "l2_support": "na"}, + {"language_code": "mi", "language_name": "Māori", "l2_support": "na"}, + { + "language_code": "min", + "language_name": "Minangkabau", + "l2_support": "na", + }, + {"language_code": "mk", "language_name": "Macedonian", "l2_support": "na"}, + {"language_code": "ml", "language_name": "Malayalam", "l2_support": "na"}, + {"language_code": "mn", "language_name": "Mongolian", "l2_support": "beta"}, + {"language_code": "mni", "language_name": "Manipuri", "l2_support": "na"}, + {"language_code": "mr", "language_name": "Marathi", "l2_support": "beta"}, + {"language_code": "ms", "language_name": "Malay", "l2_support": "beta"}, + { + "language_code": "ms-Arab", + "language_name": "Malay (Arabic)", + "l2_support": "beta", + }, + { + "language_code": "ms-MY", + "language_name": "Malay (Malaysia)", + "l2_support": "beta", + }, + {"language_code": "mt", "language_name": "Maltese", "l2_support": "na"}, + {"language_code": "mwr", "language_name": "Marwari", "l2_support": "na"}, + {"language_code": "my", "language_name": "Burmese", "l2_support": "na"}, + {"language_code": "nan", "language_name": "Min Nan", "l2_support": "na"}, + { + "language_code": "nb", + "language_name": "Norwegian (Bokmål)", + "l2_support": "na", + }, + {"language_code": "ne", "language_name": "Nepali", "l2_support": "na"}, + {"language_code": "new", "language_name": "Newari", "l2_support": "na"}, + {"language_code": "nl", "language_name": "Dutch", "l2_support": "beta"}, + { + "language_code": "nl-BE", + "language_name": "Flemish", + "l2_support": "beta", + }, + {"language_code": "no", "language_name": "Norwegian", "l2_support": "na"}, + { + "language_code": "nr", + "language_name": "South Ndebele", + "l2_support": "na", + }, + { + "language_code": "nso", + "language_name": "Northern Sotho", + "l2_support": "na", + }, + {"language_code": "nus", "language_name": "Nuer", "l2_support": "na"}, + {"language_code": "ny", "language_name": "Nyanja", "l2_support": "na"}, + {"language_code": "oc", "language_name": "Occitan", "l2_support": "na"}, + {"language_code": "om", "language_name": "Oromo", "l2_support": "na"}, + {"language_code": "or", "language_name": "Odia", "l2_support": "na"}, + {"language_code": "pa", "language_name": "Punjabi", "l2_support": "beta"}, + { + "language_code": "pa-Arab", + "language_name": "Punjabi (Shahmukhi)", + "l2_support": "beta", + }, + { + "language_code": "pa-IN", + "language_name": "Punjabi (Gurmukhi)", + "l2_support": "beta", + }, + {"language_code": "pag", "language_name": "Pangasinan", "l2_support": "na"}, + {"language_code": "pam", "language_name": "Pampanga", "l2_support": "na"}, + {"language_code": "pap", "language_name": "Papiamento", "l2_support": "na"}, + {"language_code": "pl", "language_name": "Polish", "l2_support": "beta"}, + {"language_code": "ps", "language_name": "Pashto", "l2_support": "na"}, + { + "language_code": "pt", + "language_name": "Portuguese", + "l2_support": "full", + }, + { + "language_code": "pt-BR", + "language_name": "Portuguese (Brazil)", + "l2_support": "full", + }, + { + "language_code": "pt-PT", + "language_name": "Portuguese (Portugal)", + "l2_support": "full", + }, + {"language_code": "qu", "language_name": "Quechua", "l2_support": "na"}, + {"language_code": "raj", "language_name": "Rajasthani", "l2_support": "na"}, + {"language_code": "rn", "language_name": "Rundi", "l2_support": "na"}, + {"language_code": "ro", "language_name": "Romanian", "l2_support": "beta"}, + { + "language_code": "ro-MD", + "language_name": "Moldovan", + "l2_support": "beta", + }, + { + "language_code": "ro-RO", + "language_name": "Romanian (Romania)", + "l2_support": "beta", + }, + {"language_code": "rom", "language_name": "Romany", "l2_support": "na"}, + {"language_code": "ru", "language_name": "Russian", "l2_support": "full"}, + {"language_code": "rw", "language_name": "Kinyarwanda", "l2_support": "na"}, + {"language_code": "sa", "language_name": "Sanskrit", "l2_support": "na"}, + {"language_code": "sat", "language_name": "Santali", "l2_support": "na"}, + {"language_code": "scn", "language_name": "Sicilian", "l2_support": "na"}, + {"language_code": "sd", "language_name": "Sindhi", "l2_support": "na"}, + {"language_code": "sg", "language_name": "Sango", "l2_support": "na"}, + {"language_code": "shn", "language_name": "Shan", "l2_support": "na"}, + {"language_code": "si", "language_name": "Sinhala", "l2_support": "na"}, + {"language_code": "sk", "language_name": "Slovak", "l2_support": "beta"}, + {"language_code": "sl", "language_name": "Slovenian", "l2_support": "na"}, + {"language_code": "sm", "language_name": "Samoan", "l2_support": "na"}, + {"language_code": "sn", "language_name": "Shona", "l2_support": "na"}, + {"language_code": "so", "language_name": "Somali", "l2_support": "na"}, + {"language_code": "sq", "language_name": "Albanian", "l2_support": "na"}, + {"language_code": "sr", "language_name": "Serbian", "l2_support": "beta"}, + { + "language_code": "sr-ME", + "language_name": "Montenegrin", + "l2_support": "beta", + }, + { + "language_code": "sr-RS", + "language_name": "Serbian", + "l2_support": "beta", + }, + {"language_code": "ss", "language_name": "Swati", "l2_support": "na"}, + { + "language_code": "st", + "language_name": "Southern Sotho", + "l2_support": "na", + }, + {"language_code": "su", "language_name": "Sundanese", "l2_support": "na"}, + {"language_code": "sv", "language_name": "Swedish", "l2_support": "na"}, + {"language_code": "sw", "language_name": "Swahili", "l2_support": "na"}, + {"language_code": "szl", "language_name": "Silesian", "l2_support": "na"}, + {"language_code": "ta", "language_name": "Tamil", "l2_support": "na"}, + {"language_code": "te", "language_name": "Telugu", "l2_support": "na"}, + {"language_code": "tet", "language_name": "Tetum", "l2_support": "na"}, + {"language_code": "tg", "language_name": "Tajik", "l2_support": "na"}, + {"language_code": "th", "language_name": "Thai", "l2_support": "na"}, + {"language_code": "ti", "language_name": "Tigrinya", "l2_support": "na"}, + {"language_code": "tk", "language_name": "Turkmen", "l2_support": "na"}, + {"language_code": "tl", "language_name": "Tagalog", "l2_support": "na"}, + {"language_code": "tn", "language_name": "Tswana", "l2_support": "na"}, + {"language_code": "tr", "language_name": "Turkish", "l2_support": "na"}, + {"language_code": "ts", "language_name": "Tsonga", "l2_support": "na"}, + {"language_code": "tt", "language_name": "Tatar", "l2_support": "na"}, + {"language_code": "ug", "language_name": "Uyghur", "l2_support": "na"}, + {"language_code": "uk", "language_name": "Ukrainian", "l2_support": "beta"}, + {"language_code": "ur", "language_name": "Urdu", "l2_support": "beta"}, + { + "language_code": "ur-IN", + "language_name": "Urdu (India)", + "l2_support": "beta", + }, + { + "language_code": "ur-PK", + "language_name": "Urdu (Pakistan)", + "l2_support": "beta", + }, + {"language_code": "uz", "language_name": "Uzbek", "l2_support": "na"}, + { + "language_code": "vi", + "language_name": "Vietnamese", + "l2_support": "full", + }, + {"language_code": "wuu", "language_name": "Wu", "l2_support": "na"}, + {"language_code": "xh", "language_name": "Xhosa", "l2_support": "na"}, + {"language_code": "yi", "language_name": "Yiddish", "l2_support": "na"}, + {"language_code": "yo", "language_name": "Yoruba", "l2_support": "na"}, + {"language_code": "yua", "language_name": "Yucateco", "l2_support": "na"}, + { + "language_code": "yue", + "language_name": "Cantonese", + "l2_support": "beta", + }, + { + "language_code": "yue-CN", + "language_name": "Cantonese (China)", + "l2_support": "beta", + }, + { + "language_code": "yue-HK", + "language_name": "Cantonese (Hong Kong)", + "l2_support": "beta", + }, + {"language_code": "zh", "language_name": "Chinese", "l2_support": "full"}, + { + "language_code": "zh-CN", + "language_name": "Chinese (Simplified)", + "l2_support": "full", + }, + { + "language_code": "zh-TW", + "language_name": "Chinese (Traditional)", + "l2_support": "full", + }, + {"language_code": "zu", "language_name": "Zulu", "l2_support": "na"}, + ]; } diff --git a/lib/pangea/languages/language_model.dart b/lib/pangea/languages/language_model.dart index 1ff1ae5bd..6470e6e76 100644 --- a/lib/pangea/languages/language_model.dart +++ b/lib/pangea/languages/language_model.dart @@ -26,11 +26,9 @@ class LanguageModel { }) : _textDirection = textDirection; factory LanguageModel.fromJson(Map json) { - final String code = json['language_code'] ?? - codeFromNameOrCode( - json['language_name'], - json['language_flag'], - ); + final String code = + json['language_code'] ?? + codeFromNameOrCode(json['language_name'], json['language_flag']); return LanguageModel( langCode: code, @@ -50,14 +48,14 @@ class LanguageModel { } Map toJson() => { - 'language_code': langCode, - 'language_name': displayName, - 'script': script, - 'l2_support': l2Support.storageString, - 'text_direction': textDirection.name, - 'locale_emoji': localeEmoji, - 'voices': voices, - }; + 'language_code': langCode, + 'language_name': displayName, + 'script': script, + 'l2_support': l2Support.storageString, + 'text_direction': textDirection.name, + 'locale_emoji': localeEmoji, + 'voices': voices, + }; bool get l2 => l2Support != L2SupportEnum.na; @@ -74,9 +72,9 @@ class LanguageModel { //PTODO - add flag for unknown static LanguageModel get unknown => LanguageModel( - langCode: LanguageKeys.unknownLanguage, - displayName: "Unknown", - ); + langCode: LanguageKeys.unknownLanguage, + displayName: "Unknown", + ); String getDisplayName(BuildContext context) { final langKey = "${langCode.replaceAll("-", "")}DisplayName"; diff --git a/lib/pangea/languages/language_repo.dart b/lib/pangea/languages/language_repo.dart index 9ad7b6329..6f0f26731 100644 --- a/lib/pangea/languages/language_repo.dart +++ b/lib/pangea/languages/language_repo.dart @@ -23,13 +23,9 @@ class LanguageRepo { } static Future> _fetch() async { - final Requests req = Requests( - choreoApiKey: Environment.choreoApiKey, - ); + final Requests req = Requests(choreoApiKey: Environment.choreoApiKey); - final Response res = await req.get( - url: PApiUrls.getLanguages, - ); + final Response res = await req.get(url: PApiUrls.getLanguages); if (res.statusCode != 200) { throw Exception( diff --git a/lib/pangea/languages/p_language_store.dart b/lib/pangea/languages/p_language_store.dart index 98a72d3a2..6cfe4b042 100644 --- a/lib/pangea/languages/p_language_store.dart +++ b/lib/pangea/languages/p_language_store.dart @@ -37,7 +37,8 @@ class PLanguageStore { static Future initialize({bool forceRefresh = false}) async { _langList = await _getCachedLanguages(); final isOutdated = await _shouldFetch; - final shouldFetch = forceRefresh || + final shouldFetch = + forceRefresh || isOutdated || _langList.isEmpty || _langList.every((lang) => !lang.l2); @@ -47,8 +48,8 @@ class PLanguageStore { _langList = result.isValue ? result.asValue!.value : LanguageConstants.languageList - .map((e) => LanguageModel.fromJson(e)) - .toList(); + .map((e) => LanguageModel.fromJson(e)) + .toList(); await _MyShared.saveJson(PrefKey.languagesKey, { PrefKey.languagesKey: _langList.map((e) => e.toJson()).toList(), @@ -105,9 +106,7 @@ class PLanguageStore { } static LanguageModel? byLangCode(String langCode) => - _langList.firstWhereOrNull( - (element) => element.langCode == langCode, - ); + _langList.firstWhereOrNull((element) => element.langCode == langCode); } class _MyShared { diff --git a/lib/pangea/learning_settings/country_picker_tile.dart b/lib/pangea/learning_settings/country_picker_tile.dart index 250b4e6ba..84ef86f1a 100644 --- a/lib/pangea/learning_settings/country_picker_tile.dart +++ b/lib/pangea/learning_settings/country_picker_tile.dart @@ -33,7 +33,8 @@ class CountryPickerDropdownState extends State { Widget build(BuildContext context) { final countries = CountryService().getAll(); return DropdownButtonFormField2( - customButton: widget.learningController.country != null && + customButton: + widget.learningController.country != null && countries.any( (country) => country.name == widget.learningController.country!.name, @@ -43,9 +44,7 @@ class CountryPickerDropdownState extends State { isDropdown: true, ) : null, - menuItemStyleData: const MenuItemStyleData( - padding: EdgeInsets.zero, - ), + menuItemStyleData: const MenuItemStyleData(padding: EdgeInsets.zero), isExpanded: true, decoration: InputDecoration( labelText: L10n.of(context).countryInformation, @@ -65,10 +64,7 @@ class CountryPickerDropdownState extends State { color: widget.learningController.country == country ? Theme.of(context).colorScheme.primary.withAlpha(20) : Colors.transparent, - padding: const EdgeInsets.symmetric( - vertical: 8, - horizontal: 12, - ), + padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 12), child: CountryPickerTile(country), ), ), @@ -84,9 +80,7 @@ class CountryPickerDropdownState extends State { child: TextField( autofocus: true, controller: _searchController, - decoration: const InputDecoration( - prefixIcon: Icon(Icons.search), - ), + decoration: const InputDecoration(prefixIcon: Icon(Icons.search)), ), ), searchMatchFn: (item, searchValue) { @@ -108,11 +102,7 @@ class CountryPickerTile extends StatelessWidget { final Country country; final bool isDropdown; - const CountryPickerTile( - this.country, { - super.key, - this.isDropdown = false, - }); + const CountryPickerTile(this.country, {super.key, this.isDropdown = false}); @override Widget build(BuildContext context) { @@ -127,10 +117,7 @@ class CountryPickerTile extends StatelessWidget { ), const SizedBox(width: 10), Text( - CountryDisplayUtil.countryDisplayName( - country.name, - context, - ) ?? + CountryDisplayUtil.countryDisplayName(country.name, context) ?? '', style: const TextStyle().copyWith( color: Theme.of(context).textTheme.bodyLarge!.color, diff --git a/lib/pangea/learning_settings/disable_language_tools_popup.dart b/lib/pangea/learning_settings/disable_language_tools_popup.dart index 120161211..5f37c189d 100644 --- a/lib/pangea/learning_settings/disable_language_tools_popup.dart +++ b/lib/pangea/learning_settings/disable_language_tools_popup.dart @@ -9,19 +9,13 @@ import 'package:fluffychat/widgets/matrix.dart'; class DisableLanguageToolsPopup extends StatelessWidget { final String overlayId; - const DisableLanguageToolsPopup({ - super.key, - required this.overlayId, - }); + const DisableLanguageToolsPopup({super.key, required this.overlayId}); Future _disableLanguageTools() async { - await MatrixState.pangeaController.userController.updateProfile( - (profile) { - profile.toolSettings.autoIGC = false; - return profile; - }, - waitForDataInSync: true, - ); + await MatrixState.pangeaController.userController.updateProfile((profile) { + profile.toolSettings.autoIGC = false; + return profile; + }, waitForDataInSync: true); } @override @@ -53,8 +47,9 @@ class DisableLanguageToolsPopup extends StatelessWidget { MatrixState.pAnyState.closeOverlay(overlayId); }, style: TextButton.styleFrom( - backgroundColor: - Theme.of(context).colorScheme.primary.withAlpha(25), + backgroundColor: Theme.of( + context, + ).colorScheme.primary.withAlpha(25), ), child: Text(L10n.of(context).confirm), ), diff --git a/lib/pangea/learning_settings/gender_dropdown.dart b/lib/pangea/learning_settings/gender_dropdown.dart index 352bf6956..e97ad6fa3 100644 --- a/lib/pangea/learning_settings/gender_dropdown.dart +++ b/lib/pangea/learning_settings/gender_dropdown.dart @@ -28,14 +28,11 @@ class GenderDropdown extends StatelessWidget { final l10n = L10n.of(context); return DropdownButtonFormField2( - customButton: - CustomDropdownTextButton(text: initialGender.title(context)), - menuItemStyleData: const MenuItemStyleData( - padding: EdgeInsets.zero, - ), - decoration: InputDecoration( - labelText: l10n.gender, + customButton: CustomDropdownTextButton( + text: initialGender.title(context), ), + menuItemStyleData: const MenuItemStyleData(padding: EdgeInsets.zero), + decoration: InputDecoration(labelText: l10n.gender), isExpanded: true, dropdownStyleData: DropdownStyleData( maxHeight: kIsWeb ? 500 : null, @@ -50,10 +47,7 @@ class GenderDropdown extends StatelessWidget { value: genderOption, child: Container( color: Colors.transparent, - padding: const EdgeInsets.symmetric( - vertical: 8, - horizontal: 12, - ), + padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 12), child: Text( genderOption.title(context), style: const TextStyle().copyWith( diff --git a/lib/pangea/learning_settings/gender_enum.dart b/lib/pangea/learning_settings/gender_enum.dart index 47f7bc82c..57e7323c2 100644 --- a/lib/pangea/learning_settings/gender_enum.dart +++ b/lib/pangea/learning_settings/gender_enum.dart @@ -2,12 +2,7 @@ import 'package:flutter/material.dart'; import 'package:fluffychat/l10n/l10n.dart'; -enum GenderEnum { - unselected, - woman, - man, - other, -} +enum GenderEnum { unselected, woman, man, other } extension GenderEnumExtension on GenderEnum { String get string { diff --git a/lib/pangea/learning_settings/language_mismatch_popup.dart b/lib/pangea/learning_settings/language_mismatch_popup.dart index 34f0dcb6c..c0e963fe9 100644 --- a/lib/pangea/learning_settings/language_mismatch_popup.dart +++ b/lib/pangea/learning_settings/language_mismatch_popup.dart @@ -21,13 +21,10 @@ class LanguageMismatchPopup extends StatelessWidget { }); Future _updateLanguage() async { - await MatrixState.pangeaController.userController.updateProfile( - (profile) { - profile.userSettings.targetLanguage = targetLanguage; - return profile; - }, - waitForDataInSync: true, - ); + await MatrixState.pangeaController.userController.updateProfile((profile) { + profile.userSettings.targetLanguage = targetLanguage; + return profile; + }, waitForDataInSync: true); onConfirm(); } @@ -60,8 +57,9 @@ class LanguageMismatchPopup extends StatelessWidget { MatrixState.pAnyState.closeOverlay(overlayId); }, style: TextButton.styleFrom( - backgroundColor: - Theme.of(context).colorScheme.primary.withAlpha(25), + backgroundColor: Theme.of( + context, + ).colorScheme.primary.withAlpha(25), ), child: Text(L10n.of(context).confirm), ), diff --git a/lib/pangea/learning_settings/language_mismatch_repo.dart b/lib/pangea/learning_settings/language_mismatch_repo.dart index 430f3a586..d31e30d05 100644 --- a/lib/pangea/learning_settings/language_mismatch_repo.dart +++ b/lib/pangea/learning_settings/language_mismatch_repo.dart @@ -11,10 +11,7 @@ class LanguageMismatchRepo { static Future setRoom(String roomId) async => _set(_roomKey(roomId)); static Future _set(String key) async { - await _storage.write( - key, - DateTime.now().toIso8601String(), - ); + await _storage.write(key, DateTime.now().toIso8601String()); } static bool _get(String key) { diff --git a/lib/pangea/learning_settings/p_language_dialog.dart b/lib/pangea/learning_settings/p_language_dialog.dart index 92a79d816..ae0e61573 100644 --- a/lib/pangea/learning_settings/p_language_dialog.dart +++ b/lib/pangea/learning_settings/p_language_dialog.dart @@ -97,24 +97,17 @@ Future pLanguageDialog( future: () async { try { await pangeaController.userController - .updateProfile( - (profile) { - profile.userSettings.sourceLanguage = - selectedSourceLanguage?.langCode; - profile.userSettings.targetLanguage = - selectedTargetLanguage.langCode; - return profile; - }, - waitForDataInSync: true, - ); + .updateProfile((profile) { + profile.userSettings.sourceLanguage = + selectedSourceLanguage?.langCode; + profile.userSettings.targetLanguage = + selectedTargetLanguage.langCode; + return profile; + }, waitForDataInSync: true); Navigator.pop(context); } catch (err, s) { debugger(when: kDebugMode); - ErrorHandler.logError( - e: err, - s: s, - data: {}, - ); + ErrorHandler.logError(e: err, s: s, data: {}); rethrow; } finally { callback(); @@ -126,8 +119,9 @@ Future pLanguageDialog( content: Text( L10n.of(context).noIdenticalLanguages, ), - backgroundColor: - Theme.of(context).colorScheme.primary, + backgroundColor: Theme.of( + context, + ).colorScheme.primary, ), ); }, diff --git a/lib/pangea/learning_settings/p_language_dropdown.dart b/lib/pangea/learning_settings/p_language_dropdown.dart index 5957e003a..146f4164e 100644 --- a/lib/pangea/learning_settings/p_language_dropdown.dart +++ b/lib/pangea/learning_settings/p_language_dropdown.dart @@ -54,8 +54,9 @@ class PLanguageDropdownState extends State { // if there is no initial language, the system language should be the first in the list // otherwise, display in alphabetical order - final List languagePriority = - widget.initialLanguage == null ? [systemLang] : []; + final List languagePriority = widget.initialLanguage == null + ? [systemLang] + : []; int sortLanguages(LanguageModel a, LanguageModel b) { final String aLang = a.langCode; @@ -85,7 +86,8 @@ class PLanguageDropdownState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ DropdownButtonFormField2( - customButton: widget.initialLanguage != null && + customButton: + widget.initialLanguage != null && sortedLanguages.contains(widget.initialLanguage) ? LanguageDropDownEntry( languageModel: widget.initialLanguage!, @@ -94,9 +96,7 @@ class PLanguageDropdownState extends State { enabled: widget.enabled, ) : null, - menuItemStyleData: const MenuItemStyleData( - padding: EdgeInsets.zero, - ), + menuItemStyleData: const MenuItemStyleData(padding: EdgeInsets.zero), decoration: InputDecoration( labelText: widget.decorationText, enabledBorder: hasError @@ -122,7 +122,8 @@ class PLanguageDropdownState extends State { maxHeight: kIsWeb ? 500 : null, decoration: BoxDecoration( borderRadius: BorderRadius.circular(14), - color: widget.backgroundColor ?? + color: + widget.backgroundColor ?? Theme.of(context).colorScheme.surfaceContainerHigh, ), ), @@ -161,11 +162,8 @@ class PLanguageDropdownState extends State { ), ), ), - searchMatchFn: (item, searchValue) => LanguageModel.search( - item.value, - searchValue, - context, - ), + searchMatchFn: (item, searchValue) => + LanguageModel.search(item.value, searchValue, context), ), onMenuStateChange: (isOpen) { if (!isOpen) _searchController.clear(); @@ -177,9 +175,7 @@ class PLanguageDropdownState extends State { child: widget.error == null ? const SizedBox.shrink() : Padding( - padding: const EdgeInsets.symmetric( - vertical: 5, - ), + padding: const EdgeInsets.symmetric(vertical: 5), child: Text( widget.error!, style: TextStyle( @@ -214,10 +210,7 @@ class LanguageDropDownEntry extends StatelessWidget { children: [ Opacity( opacity: enabled ? 1 : 0.5, - child: Avatar( - name: languageModel.langCode, - size: 30, - ), + child: Avatar(name: languageModel.langCode, size: 30), ), const SizedBox(width: 10), Expanded( diff --git a/lib/pangea/learning_settings/p_settings_switch_list_tile.dart b/lib/pangea/learning_settings/p_settings_switch_list_tile.dart index a0e928def..edb55378d 100644 --- a/lib/pangea/learning_settings/p_settings_switch_list_tile.dart +++ b/lib/pangea/learning_settings/p_settings_switch_list_tile.dart @@ -58,10 +58,7 @@ class PSettingsSwitchListTileState e: err, m: "Failed to updates user setting", s: s, - data: { - "newValue": newValue, - "currentValue": currentValue, - }, + data: {"newValue": newValue, "currentValue": currentValue}, ); } } diff --git a/lib/pangea/learning_settings/settings_learning.dart b/lib/pangea/learning_settings/settings_learning.dart index 64986f00b..739f5514a 100644 --- a/lib/pangea/learning_settings/settings_learning.dart +++ b/lib/pangea/learning_settings/settings_learning.dart @@ -28,10 +28,7 @@ import 'package:fluffychat/widgets/matrix.dart'; class SettingsLearning extends StatefulWidget { final bool isDialog; - const SettingsLearning({ - this.isDialog = true, - super.key, - }); + const SettingsLearning({this.isDialog = true, super.key}); @override SettingsLearningController createState() => SettingsLearningController(); @@ -112,10 +109,7 @@ class SettingsLearningController extends State { await showFutureLoadingDialog( context: context, future: () async => pangeaController.userController - .updateProfile( - (_) => _profile, - waitForDataInSync: true, - ) + .updateProfile((_) => _profile, waitForDataInSync: true) .timeout(const Duration(seconds: 15)), ); Navigator.of(context).pop(); @@ -125,13 +119,11 @@ class SettingsLearningController extends State { _profile.instructionSettings = InstructionSettings(); await showFutureLoadingDialog( context: context, - future: () async => pangeaController.userController.updateProfile( - (profile) { - profile.instructionSettings = InstructionSettings(); - return profile; - }, - waitForDataInSync: true, - ), + future: () async => + pangeaController.userController.updateProfile((profile) { + profile.instructionSettings = InstructionSettings(); + return profile; + }, waitForDataInSync: true), onError: (e, s) { debugger(when: kDebugMode); ErrorHandler.logError( @@ -259,11 +251,7 @@ class SettingsLearningController extends State { crossAxisAlignment: CrossAxisAlignment.center, children: [ Text(title), - if (steps != null) - Text( - steps, - textAlign: TextAlign.start, - ), + if (steps != null) Text(steps, textAlign: TextAlign.start), if (description != null) Text(description), ], ), @@ -275,10 +263,7 @@ class SettingsLearningController extends State { Navigator.of(context).pop(); }, ), - TextButton( - onPressed: buttonAction, - child: Text(buttonText), - ), + TextButton(onPressed: buttonAction, child: Text(buttonText)), ], ); }, @@ -287,8 +272,8 @@ class SettingsLearningController extends State { LanguageModel? get _targetLanguage => _profile.userSettings.targetLanguage != null - ? PLanguageStore.byLangCode(_profile.userSettings.targetLanguage!) - : null; + ? PLanguageStore.byLangCode(_profile.userSettings.targetLanguage!) + : null; GenderEnum get gender => _profile.userSettings.gender; @@ -330,13 +315,13 @@ class SettingsLearningController extends State { LanguageModel? get _selectedBaseLanguage => _profile.userSettings.sourceLanguage != null - ? PLanguageStore.byLangCode(_profile.userSettings.sourceLanguage!) - : null; + ? PLanguageStore.byLangCode(_profile.userSettings.sourceLanguage!) + : null; LanguageModel? get _selectedTargetLanguage => _profile.userSettings.targetLanguage != null - ? PLanguageStore.byLangCode(_profile.userSettings.targetLanguage!) - : null; + ? PLanguageStore.byLangCode(_profile.userSettings.targetLanguage!) + : null; LanguageModel? get userL1 => pangeaController.userController.userL1; LanguageModel? get userL2 => pangeaController.userController.userL2; diff --git a/lib/pangea/learning_settings/settings_learning_view.dart b/lib/pangea/learning_settings/settings_learning_view.dart index 1f11f2872..b665fac00 100644 --- a/lib/pangea/learning_settings/settings_learning_view.dart +++ b/lib/pangea/learning_settings/settings_learning_view.dart @@ -35,9 +35,7 @@ class SettingsLearningView extends StatelessWidget { appBar: AppBar( automaticallyImplyLeading: !controller.widget.isDialog, centerTitle: true, - title: Text( - L10n.of(context).learningSettings, - ), + title: Text(L10n.of(context).learningSettings), leading: controller.widget.isDialog ? IconButton( icon: const Icon(Icons.close), @@ -60,46 +58,53 @@ class SettingsLearningView extends StatelessWidget { spacing: 16.0, children: [ Padding( - padding: - const EdgeInsets.symmetric(horizontal: 16.0), + padding: const EdgeInsets.symmetric( + horizontal: 16.0, + ), child: Column( spacing: 16.0, children: [ PLanguageDropdown( onChange: (lang) => controller.setSelectedLanguage( - sourceLanguage: lang, - ), + sourceLanguage: lang, + ), initialLanguage: controller.selectedSourceLanguage ?? - LanguageModel.unknown, - languages: MatrixState.pangeaController - .pLanguageStore.baseOptions, + LanguageModel.unknown, + languages: MatrixState + .pangeaController + .pLanguageStore + .baseOptions, isL2List: false, - decorationText: - L10n.of(context).myBaseLanguage, + decorationText: L10n.of( + context, + ).myBaseLanguage, hasError: controller.languageMatchError != null, - backgroundColor: Theme.of(context) - .colorScheme - .surfaceContainerHigh, + backgroundColor: Theme.of( + context, + ).colorScheme.surfaceContainerHigh, ), PLanguageDropdown( onChange: (lang) => controller.setSelectedLanguage( - targetLanguage: lang, - ), + targetLanguage: lang, + ), initialLanguage: controller.selectedTargetLanguage, - languages: MatrixState.pangeaController - .pLanguageStore.targetOptions, + languages: MatrixState + .pangeaController + .pLanguageStore + .targetOptions, isL2List: true, - decorationText: - L10n.of(context).iWantToLearn, + decorationText: L10n.of( + context, + ).iWantToLearn, error: controller.languageMatchError, - backgroundColor: Theme.of(context) - .colorScheme - .surfaceContainerHigh, + backgroundColor: Theme.of( + context, + ).colorScheme.surfaceContainerHigh, ), if (controller.userL1?.langCodeShort == controller.userL2?.langCodeShort) @@ -112,18 +117,19 @@ class SettingsLearningView extends StatelessWidget { children: [ Icon( Icons.info_outlined, - color: Theme.of(context) - .colorScheme - .error, + color: Theme.of( + context, + ).colorScheme.error, ), Flexible( child: Text( - L10n.of(context) - .noIdenticalLanguages, + L10n.of( + context, + ).noIdenticalLanguages, style: TextStyle( - color: Theme.of(context) - .colorScheme - .error, + color: Theme.of( + context, + ).colorScheme.error, ), ), ), @@ -148,13 +154,12 @@ class SettingsLearningView extends StatelessWidget { ), ), ...ToolSetting.values - .where( - (tool) => tool.isAvailableSetting, - ) + .where((tool) => tool.isAvailableSetting) .map( (toolSetting) => _ProfileSwitchTile( - value: - controller.getToolSetting(toolSetting), + value: controller.getToolSetting( + toolSetting, + ), setting: toolSetting, onChanged: (v) { controller.updateToolSetting( @@ -172,17 +177,13 @@ class SettingsLearningView extends StatelessWidget { SwitchListTile.adaptive( value: controller.publicProfile, onChanged: controller.setPublicProfile, - title: Text( - L10n.of(context).publicProfileTitle, - ), + title: Text(L10n.of(context).publicProfileTitle), subtitle: Text( L10n.of(context).publicProfileDesc, ), activeThumbColor: AppConfig.activeToggleColor, ), - ResetInstructionsListTile( - controller: controller, - ), + ResetInstructionsListTile(controller: controller), ], ), ), diff --git a/lib/pangea/learning_settings/voice_dropdown.dart b/lib/pangea/learning_settings/voice_dropdown.dart index ba105c60d..6362481ef 100644 --- a/lib/pangea/learning_settings/voice_dropdown.dart +++ b/lib/pangea/learning_settings/voice_dropdown.dart @@ -23,17 +23,16 @@ class VoiceDropdown extends StatelessWidget { @override Widget build(BuildContext context) { final voices = (language?.voices ?? []); - final value = - this.value != null && voices.contains(this.value) ? this.value : null; + final value = this.value != null && voices.contains(this.value) + ? this.value + : null; return DropdownButtonFormField2( - customButton: - value != null ? CustomDropdownTextButton(text: value) : null, + customButton: value != null + ? CustomDropdownTextButton(text: value) + : null, menuItemStyleData: const MenuItemStyleData( - padding: EdgeInsets.symmetric( - vertical: 8.0, - horizontal: 16.0, - ), + padding: EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0), ), decoration: InputDecoration( labelText: L10n.of(context).voiceDropdownTitle, @@ -47,10 +46,7 @@ class VoiceDropdown extends StatelessWidget { ), ), items: voices.map((voice) { - return DropdownMenuItem( - value: voice, - child: Text(voice), - ); + return DropdownMenuItem(value: voice, child: Text(voice)); }).toList(), onChanged: enabled ? onChanged : null, value: voices.contains(value) ? value : null, diff --git a/lib/pangea/lemmas/lemma.dart b/lib/pangea/lemmas/lemma.dart index 26a551620..243d101f6 100644 --- a/lib/pangea/lemmas/lemma.dart +++ b/lib/pangea/lemmas/lemma.dart @@ -11,11 +11,7 @@ class Lemma { /// server handles this determination final bool saveVocab; - Lemma({ - required this.text, - required this.saveVocab, - required this.form, - }); + Lemma({required this.text, required this.saveVocab, required this.form}); factory Lemma.fromJson(Map json) { return Lemma( @@ -26,9 +22,7 @@ class Lemma { } Map toJson() { - final Map data = { - 'text': text, - }; + final Map data = {'text': text}; if (saveVocab) { data['save_vocab'] = saveVocab; diff --git a/lib/pangea/lemmas/lemma_highlight_emoji_row.dart b/lib/pangea/lemmas/lemma_highlight_emoji_row.dart index 21396f612..fe49071ed 100644 --- a/lib/pangea/lemmas/lemma_highlight_emoji_row.dart +++ b/lib/pangea/lemmas/lemma_highlight_emoji_row.dart @@ -53,56 +53,56 @@ class LemmaHighlightEmojiRowState extends State return switch (controller.state) { AsyncError() => const SizedBox.shrink(), AsyncLoaded(value: final lemmaInfo) => SizedBox( - height: 70.0, - child: Row( - spacing: 4.0, - mainAxisSize: MainAxisSize.min, - children: [ - ...lemmaInfo.emoji.map( - (emoji) { - final targetId = "${widget.targetId}-$emoji"; - return EmojiChoiceItem( - cId: widget.cId, - emoji: emoji, - onSelectEmoji: () => - widget.onEmojiSelected(emoji, targetId), - selected: widget.emoji == emoji, - transformTargetId: targetId, - badge: widget.emoji == emoji - ? widget.selectedEmojiBadge - : null, - showShimmer: widget.emoji == null, - enabled: widget.enabled, - ); - }, - ), - ], - ), + height: 70.0, + child: Row( + spacing: 4.0, + mainAxisSize: MainAxisSize.min, + children: [ + ...lemmaInfo.emoji.map((emoji) { + final targetId = "${widget.targetId}-$emoji"; + return EmojiChoiceItem( + cId: widget.cId, + emoji: emoji, + onSelectEmoji: () => + widget.onEmojiSelected(emoji, targetId), + selected: widget.emoji == emoji, + transformTargetId: targetId, + badge: widget.emoji == emoji + ? widget.selectedEmojiBadge + : null, + showShimmer: widget.emoji == null, + enabled: widget.enabled, + ); + }), + ], ), + ), _ => SizedBox( - height: 70.0, - child: Row( - spacing: 4.0, - mainAxisSize: MainAxisSize.min, - children: List.generate( - 3, - (_) => Shimmer.fromColors( - baseColor: Colors.transparent, - highlightColor: - Theme.of(context).colorScheme.primary.withAlpha(70), - child: Container( - height: 55.0, - width: 55.0, - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.primary, - borderRadius: - BorderRadius.circular(AppConfig.borderRadius), + height: 70.0, + child: Row( + spacing: 4.0, + mainAxisSize: MainAxisSize.min, + children: List.generate( + 3, + (_) => Shimmer.fromColors( + baseColor: Colors.transparent, + highlightColor: Theme.of( + context, + ).colorScheme.primary.withAlpha(70), + child: Container( + height: 55.0, + width: 55.0, + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.primary, + borderRadius: BorderRadius.circular( + AppConfig.borderRadius, ), ), ), ), ), ), + ), }; }, ); @@ -208,18 +208,15 @@ class EmojiChoiceItemState extends State { padding: const EdgeInsets.all(10), decoration: BoxDecoration( color: widget.enabled && (hovered || widget.selected) - ? Theme.of(context) - .colorScheme - .secondary - .withAlpha(30) + ? Theme.of( + context, + ).colorScheme.secondary.withAlpha(30) : Colors.transparent, - borderRadius: - BorderRadius.circular(AppConfig.borderRadius), + borderRadius: BorderRadius.circular( + AppConfig.borderRadius, + ), border: widget.selected - ? Border.all( - color: Colors.transparent, - width: 4, - ) + ? Border.all(color: Colors.transparent, width: 4) : null, ), child: Text( @@ -230,11 +227,7 @@ class EmojiChoiceItemState extends State { ), ), if (widget.badge != null) - Positioned( - right: 6, - bottom: 6, - child: widget.badge!, - ), + Positioned(right: 6, bottom: 6, child: widget.badge!), ], ), ), diff --git a/lib/pangea/lemmas/lemma_info_repo.dart b/lib/pangea/lemmas/lemma_info_repo.dart index 0ed7b408b..9ff293002 100644 --- a/lib/pangea/lemmas/lemma_info_repo.dart +++ b/lib/pangea/lemmas/lemma_info_repo.dart @@ -75,11 +75,7 @@ class LemmaInfoRepo { await _storage.write(key, resultFuture.toJson()); _cache.remove(key); // Invalidate in-memory cache } catch (e, s) { - ErrorHandler.logError( - e: e, - s: s, - data: {'lemma': request.lemma}, - ); + ErrorHandler.logError(e: e, s: s, data: {'lemma': request.lemma}); } } @@ -123,9 +119,7 @@ class LemmaInfoRepo { ); } - return LemmaInfoResponse.fromJson( - jsonDecode(utf8.decode(res.bodyBytes)), - ); + return LemmaInfoResponse.fromJson(jsonDecode(utf8.decode(res.bodyBytes))); } static Future>? _getCached( @@ -153,9 +147,7 @@ class LemmaInfoRepo { await set(request, result.asValue!.value); } - static LemmaInfoResponse? _getStored( - LemmaInfoRequest request, - ) { + static LemmaInfoResponse? _getStored(LemmaInfoRequest request) { final key = request.hashCode.toString(); try { final entry = _storage.read(key); @@ -163,11 +155,7 @@ class LemmaInfoRepo { return LemmaInfoResponse.fromJson(entry); } catch (e, s) { - ErrorHandler.logError( - e: e, - s: s, - data: {'lemma': request.lemma}, - ); + ErrorHandler.logError(e: e, s: s, data: {'lemma': request.lemma}); _storage.remove(key); return null; } diff --git a/lib/pangea/lemmas/lemma_info_request.dart b/lib/pangea/lemmas/lemma_info_request.dart index 75ca7dd8a..baebb72a3 100644 --- a/lib/pangea/lemmas/lemma_info_request.dart +++ b/lib/pangea/lemmas/lemma_info_request.dart @@ -20,8 +20,8 @@ class LemmaInfoRequest { required this.lemma, required this.messageInfo, this.feedback = const [], - }) : partOfSpeech = partOfSpeech.toLowerCase(), - lemmaLang = lemmaLang.toLowerCase(); + }) : partOfSpeech = partOfSpeech.toLowerCase(), + lemmaLang = lemmaLang.toLowerCase(); Map toJson() { return { @@ -56,8 +56,8 @@ class LemmaInfoRequest { } ConstructIdentifier get cId => ConstructIdentifier( - lemma: lemma, - type: ConstructTypeEnum.vocab, - category: partOfSpeech, - ); + lemma: lemma, + type: ConstructTypeEnum.vocab, + category: partOfSpeech, + ); } diff --git a/lib/pangea/lemmas/lemma_info_response.dart b/lib/pangea/lemmas/lemma_info_response.dart index 1035cd6e7..517e3bbf0 100644 --- a/lib/pangea/lemmas/lemma_info_response.dart +++ b/lib/pangea/lemmas/lemma_info_response.dart @@ -6,10 +6,7 @@ class LemmaInfoResponse implements JsonSerializable { final List emoji; final String meaning; - LemmaInfoResponse({ - required this.emoji, - required this.meaning, - }); + LemmaInfoResponse({required this.emoji, required this.meaning}); factory LemmaInfoResponse.fromJson(Map json) { return LemmaInfoResponse( @@ -19,17 +16,12 @@ class LemmaInfoResponse implements JsonSerializable { ); } - static LemmaInfoResponse get error => LemmaInfoResponse( - emoji: [], - meaning: 'ERROR', - ); + static LemmaInfoResponse get error => + LemmaInfoResponse(emoji: [], meaning: 'ERROR'); @override Map toJson() { - return { - 'emoji': emoji, - 'meaning': meaning, - }; + return {'emoji': emoji, 'meaning': meaning}; } @override diff --git a/lib/pangea/lemmas/lemma_meaning_builder.dart b/lib/pangea/lemmas/lemma_meaning_builder.dart index c7c99ae36..7ea5f5fb2 100644 --- a/lib/pangea/lemmas/lemma_meaning_builder.dart +++ b/lib/pangea/lemmas/lemma_meaning_builder.dart @@ -17,7 +17,8 @@ class LemmaMeaningBuilder extends StatefulWidget { final Widget Function( BuildContext context, LemmaMeaningBuilderState controller, - ) builder; + ) + builder; const LemmaMeaningBuilder({ super.key, @@ -33,8 +34,9 @@ class LemmaMeaningBuilder extends StatefulWidget { } class LemmaMeaningBuilderState extends State { - final ValueNotifier> _loader = - ValueNotifier(const AsyncState.idle()); + final ValueNotifier> _loader = ValueNotifier( + const AsyncState.idle(), + ); int _loadVersion = 0; @@ -68,13 +70,14 @@ class LemmaMeaningBuilderState extends State { isLoaded ? (_loader.value as AsyncLoaded).value : null; LemmaInfoRequest get _request => LemmaInfoRequest( - lemma: widget.constructId.lemma, - partOfSpeech: widget.constructId.category, - lemmaLang: widget.langCode, - userL1: MatrixState.pangeaController.userController.userL1?.langCode ?? - LanguageKeys.defaultLanguage, - messageInfo: widget.messageInfo, - ); + lemma: widget.constructId.lemma, + partOfSpeech: widget.constructId.category, + lemmaLang: widget.langCode, + userL1: + MatrixState.pangeaController.userController.userL1?.langCode ?? + LanguageKeys.defaultLanguage, + messageInfo: widget.messageInfo, + ); Future _load() async { final int version = ++_loadVersion; @@ -97,10 +100,7 @@ class LemmaMeaningBuilderState extends State { Widget build(BuildContext context) { return ValueListenableBuilder( valueListenable: _loader, - builder: (context, _, __) => widget.builder( - context, - this, - ), + builder: (context, _, _) => widget.builder(context, this), ); } } diff --git a/lib/pangea/lemmas/user_set_lemma_info.dart b/lib/pangea/lemmas/user_set_lemma_info.dart index 33d1ed6ca..7d95a217c 100644 --- a/lib/pangea/lemmas/user_set_lemma_info.dart +++ b/lib/pangea/lemmas/user_set_lemma_info.dart @@ -4,10 +4,7 @@ class UserSetLemmaInfo { final String? meaning; final List? emojis; - UserSetLemmaInfo({ - this.emojis, - this.meaning, - }); + UserSetLemmaInfo({this.emojis, this.meaning}); factory UserSetLemmaInfo.fromJson(Map json) { return UserSetLemmaInfo( @@ -17,16 +14,10 @@ class UserSetLemmaInfo { } Map toJson() { - return { - 'emojis': emojis, - 'meaning': meaning, - }; + return {'emojis': emojis, 'meaning': meaning}; } - UserSetLemmaInfo copyWith({ - List? emojis, - String? meaning, - }) { + UserSetLemmaInfo copyWith({List? emojis, String? meaning}) { return UserSetLemmaInfo( emojis: emojis ?? this.emojis, meaning: meaning ?? this.meaning, diff --git a/lib/pangea/login/pages/course_code_page.dart b/lib/pangea/login/pages/course_code_page.dart index fd2e36cb3..9df8c8aa8 100644 --- a/lib/pangea/login/pages/course_code_page.dart +++ b/lib/pangea/login/pages/course_code_page.dart @@ -10,9 +10,7 @@ import 'package:fluffychat/pangea/spaces/space_constants.dart'; import 'package:fluffychat/widgets/matrix.dart'; class CourseCodePage extends StatefulWidget { - const CourseCodePage({ - super.key, - }); + const CourseCodePage({super.key}); @override State createState() => CourseCodePageState(); @@ -40,10 +38,7 @@ class CourseCodePageState extends State { return; } - final roomId = await SpaceCodeController.joinSpaceWithCode( - context, - _code, - ); + final roomId = await SpaceCodeController.joinSpaceWithCode(context, _code); if (roomId != null) { final room = Matrix.of(context).client.getRoomById(roomId); @@ -57,17 +52,12 @@ class CourseCodePageState extends State { Widget build(BuildContext context) { final theme = Theme.of(context); return Scaffold( - appBar: AppBar( - title: Text(L10n.of(context).joinWithCode), - ), + appBar: AppBar(title: Text(L10n.of(context).joinWithCode)), body: SafeArea( child: Center( child: Container( padding: const EdgeInsets.all(20.0), - constraints: const BoxConstraints( - maxWidth: 350, - maxHeight: 600, - ), + constraints: const BoxConstraints(maxWidth: 350, maxHeight: 600), child: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ @@ -104,9 +94,7 @@ class CourseCodePageState extends State { ), child: Row( mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text(L10n.of(context).submit), - ], + children: [Text(L10n.of(context).submit)], ), ), ], diff --git a/lib/pangea/login/pages/create_pangea_account_page.dart b/lib/pangea/login/pages/create_pangea_account_page.dart index eaa7c38fc..0953b7aaa 100644 --- a/lib/pangea/login/pages/create_pangea_account_page.dart +++ b/lib/pangea/login/pages/create_pangea_account_page.dart @@ -21,9 +21,7 @@ import 'package:fluffychat/pangea/login/utils/lang_code_repo.dart'; import 'package:fluffychat/widgets/matrix.dart'; class CreatePangeaAccountPage extends StatefulWidget { - const CreatePangeaAccountPage({ - super.key, - }); + const CreatePangeaAccountPage({super.key}); @override CreatePangeaAccountPageState createState() => CreatePangeaAccountPageState(); @@ -116,19 +114,14 @@ class CreatePangeaAccountPageState extends State { try { final random = Random(); final selectedAvatarPath = avatarPath(random.nextInt(4) + 1); - final avatarUrl = - Uri.parse("${AppConfig.assetsBaseURL}/$selectedAvatarPath"); - await client.setProfileField( - client.userID!, - 'avatar_url', - {'avatar_url': avatarUrl}, + final avatarUrl = Uri.parse( + "${AppConfig.assetsBaseURL}/$selectedAvatarPath", ); + await client.setProfileField(client.userID!, 'avatar_url', { + 'avatar_url': avatarUrl, + }); } catch (err, s) { - ErrorHandler.logError( - e: err, - s: s, - data: {}, - ); + ErrorHandler.logError(e: err, s: s, data: {}); } } @@ -139,16 +132,13 @@ class CreatePangeaAccountPageState extends State { return; } - await MatrixState.pangeaController.userController.updateProfile( - (profile) { - profile.userSettings.targetLanguage = target; - if (base != null) { - profile.userSettings.sourceLanguage = base; - } - return profile; - }, - waitForDataInSync: true, - ); + await MatrixState.pangeaController.userController.updateProfile((profile) { + profile.userSettings.targetLanguage = target; + if (base != null) { + profile.userSettings.sourceLanguage = base; + } + return profile; + }, waitForDataInSync: true); } Future _createUserInPangea() async { @@ -178,17 +168,14 @@ class CreatePangeaAccountPageState extends State { final updateFuture = [ _setAvatar(), - MatrixState.pangeaController.userController.updateProfile( - (profile) { - profile.userSettings.targetLanguage = targetLangCode; - if (baseLangCode != null) { - profile.userSettings.sourceLanguage = baseLangCode; - } - profile.userSettings.createdAt = DateTime.now(); - return profile; - }, - waitForDataInSync: true, - ), + MatrixState.pangeaController.userController.updateProfile((profile) { + profile.userSettings.targetLanguage = targetLangCode; + if (baseLangCode != null) { + profile.userSettings.sourceLanguage = baseLangCode; + } + profile.userSettings.createdAt = DateTime.now(); + return profile; + }, waitForDataInSync: true), if (targetLangCode != null) MatrixState.pangeaController.userController.updateAnalyticsProfile( targetLanguage: PLanguageStore.byLangCode(targetLangCode), @@ -232,30 +219,30 @@ class CreatePangeaAccountPageState extends State { child: _loading ? const CircularProgressIndicator.adaptive() : _profileError != null || _courseError != null - ? Column( + ? Column( + spacing: 8.0, + mainAxisSize: MainAxisSize.min, + children: [ + ErrorIndicator( + message: L10n.of(context).oopsSomethingWentWrong, + ), + Row( spacing: 8.0, mainAxisSize: MainAxisSize.min, children: [ - ErrorIndicator( - message: L10n.of(context).oopsSomethingWentWrong, + TextButton( + onPressed: _createUserInPangea, + child: Text(L10n.of(context).tryAgain), ), - Row( - spacing: 8.0, - mainAxisSize: MainAxisSize.min, - children: [ - TextButton( - onPressed: _createUserInPangea, - child: Text(L10n.of(context).tryAgain), - ), - TextButton( - onPressed: Navigator.of(context).pop, - child: Text(L10n.of(context).cancel), - ), - ], + TextButton( + onPressed: Navigator.of(context).pop, + child: Text(L10n.of(context).cancel), ), ], - ) - : null, + ), + ], + ) + : null, ), ), ); diff --git a/lib/pangea/login/pages/find_course_page.dart b/lib/pangea/login/pages/find_course_page.dart index 4f0eda0a4..fdb9a686e 100644 --- a/lib/pangea/login/pages/find_course_page.dart +++ b/lib/pangea/login/pages/find_course_page.dart @@ -83,36 +83,30 @@ class FindCoursePageState extends State { .where( (c) => !Matrix.of(context).client.rooms.any( - (r) => - r.id == c.room.roomId && - r.membership == Membership.join, - ) && + (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(); + 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(); + 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 @@ -129,9 +123,9 @@ class FindCoursePageState extends State { Future _loadPublicSpaces() async { try { - final resp = await Matrix.of(context).client.requestPublicCourses( - since: nextBatch, - ); + 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)) { @@ -142,13 +136,7 @@ class FindCoursePageState extends State { nextBatch = resp.nextBatch; } catch (e, s) { error = e; - ErrorHandler.logError( - e: e, - s: s, - data: { - 'nextBatch': nextBatch, - }, - ); + ErrorHandler.logError(e: e, s: s, data: {'nextBatch': nextBatch}); } } @@ -177,8 +165,10 @@ class FindCoursePageState extends State { try { final resp = await CoursePlansRepo.search( GetLocalizedCoursesRequest( - coursePlanIds: - discoveredCourses.map((c) => c.courseId).toSet().toList(), + coursePlanIds: discoveredCourses + .map((c) => c.courseId) + .toSet() + .toList(), l1: MatrixState.pangeaController.userController.userL1Code!, ), ); @@ -193,8 +183,9 @@ class FindCoursePageState extends State { e: e, s: s, data: { - 'discoveredCourses': - discoveredCourses.map((c) => c.courseId).toList(), + 'discoveredCourses': discoveredCourses + .map((c) => c.courseId) + .toList(), }, ); } finally { @@ -222,10 +213,7 @@ class FindCoursePageState extends State { class FindCoursePageView extends StatelessWidget { final FindCoursePageState controller; - const FindCoursePageView({ - super.key, - required this.controller, - }); + const FindCoursePageView({super.key, required this.controller}); @override Widget build(BuildContext context) { @@ -253,16 +241,12 @@ class FindCoursePageView extends StatelessWidget { ? null : theme.colorScheme.secondaryContainer, border: OutlineInputBorder( - borderSide: - isColumnMode ? const BorderSide() : BorderSide.none, + borderSide: isColumnMode + ? const BorderSide() + : BorderSide.none, borderRadius: BorderRadius.circular(100), ), - contentPadding: const EdgeInsets.fromLTRB( - 0, - 0, - 20.0, - 0, - ), + contentPadding: const EdgeInsets.fromLTRB(0, 0, 20.0, 0), hintText: L10n.of(context).findCourse, hintStyle: TextStyle( color: theme.colorScheme.onPrimaryContainer, @@ -343,7 +327,7 @@ class FindCoursePageView extends StatelessWidget { ), ValueListenableBuilder( valueListenable: controller.searchController, - builder: (context, _, __) { + builder: (context, _, _) { if (controller.error != null) { return ErrorIndicator( message: L10n.of(context).oopsSomethingWentWrong, @@ -355,9 +339,7 @@ class FindCoursePageView extends StatelessWidget { } if (controller.filteredCourses.isEmpty) { - return Text( - L10n.of(context).nothingFound, - ); + return Text(L10n.of(context).nothingFound); } return Expanded( @@ -386,17 +368,10 @@ class _PublicCourseTile extends StatelessWidget { final PublicCoursesChunk chunk; final CoursePlanModel? course; - const _PublicCourseTile({ - required this.chunk, - this.course, - }); + const _PublicCourseTile({required this.chunk, this.course}); - void _navigateToCoursePage( - BuildContext context, - ) { - context.go( - '/rooms/course/${Uri.encodeComponent(chunk.room.roomId)}', - ); + void _navigateToCoursePage(BuildContext context) { + context.go('/rooms/course/${Uri.encodeComponent(chunk.room.roomId)}'); } @override @@ -410,12 +385,8 @@ class _PublicCourseTile extends StatelessWidget { return Padding( padding: isColumnMode - ? const EdgeInsets.only( - bottom: 32.0, - ) - : const EdgeInsets.only( - bottom: 16.0, - ), + ? const EdgeInsets.only(bottom: 32.0) + : const EdgeInsets.only(bottom: 16.0), child: Material( type: MaterialType.transparency, child: InkWell( @@ -425,9 +396,7 @@ class _PublicCourseTile extends StatelessWidget { padding: const EdgeInsets.all(12.0), decoration: BoxDecoration( borderRadius: BorderRadius.circular(12.0), - border: Border.all( - color: theme.colorScheme.primary, - ), + border: Border.all(color: theme.colorScheme.primary), ), child: Column( spacing: 4.0, @@ -443,9 +412,7 @@ class _PublicCourseTile extends StatelessWidget { borderRadius: BorderRadius.circular(10.0), replacement: Avatar( name: displayname, - borderRadius: BorderRadius.circular( - 10.0, - ), + borderRadius: BorderRadius.circular(10.0), size: 58.0, ), ), @@ -464,14 +431,11 @@ class _PublicCourseTile extends StatelessWidget { spacing: 4.0, mainAxisSize: MainAxisSize.min, children: [ - const Icon( - Icons.group, - size: 16.0, - ), + const Icon(Icons.group, size: 16.0), Text( - L10n.of(context).countParticipants( - space.numJoinedMembers, - ), + L10n.of( + context, + ).countParticipants(space.numJoinedMembers), style: theme.textTheme.bodyMedium, ), ], @@ -482,30 +446,19 @@ class _PublicCourseTile extends StatelessWidget { ], ), if (course != null) ...[ - CourseInfoChips( - courseId, - iconSize: 12.0, - fontSize: 12.0, - ), - Text( - course!.description, - style: theme.textTheme.bodyMedium, - ), + 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: () => _navigateToCoursePage(context), style: ElevatedButton.styleFrom( - backgroundColor: - theme.colorScheme.primaryContainer.withAlpha( - hovered ? 255 : 200, - ), + backgroundColor: theme.colorScheme.primaryContainer + .withAlpha(hovered ? 255 : 200), foregroundColor: theme.colorScheme.onPrimaryContainer, shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular( - 12.0, - ), + borderRadius: BorderRadius.circular(12.0), ), ), child: Row( @@ -513,12 +466,8 @@ class _PublicCourseTile extends StatelessWidget { children: [ Text( space.joinRule == JoinRules.knock.name - ? L10n.of( - context, - ).knock - : L10n.of( - context, - ).join, + ? L10n.of(context).knock + : L10n.of(context).join, ), ], ), diff --git a/lib/pangea/login/pages/language_selection_page.dart b/lib/pangea/login/pages/language_selection_page.dart index f1f3f22e7..8972a050c 100644 --- a/lib/pangea/login/pages/language_selection_page.dart +++ b/lib/pangea/login/pages/language_selection_page.dart @@ -48,8 +48,9 @@ class LanguageSelectionPageState extends State { void _setFromCache() { LangCodeRepo.get().then((langSettings) { if (langSettings == null) return; - final cachedTargetLang = - PLanguageStore.byLangCode(langSettings.targetLangCode); + final cachedTargetLang = PLanguageStore.byLangCode( + langSettings.targetLangCode, + ); final cachedBaseLang = langSettings.baseLangCode != null ? PLanguageStore.byLangCode(langSettings.baseLangCode!) : null; @@ -105,16 +106,12 @@ class LanguageSelectionPageState extends State { return Scaffold( appBar: AppBar( title: ConstrainedBox( - constraints: const BoxConstraints( - maxWidth: 500, - ), + constraints: const BoxConstraints(maxWidth: 500), child: Row( spacing: 12.0, children: [ Navigator.of(context).canPop() - ? BackButton( - onPressed: Navigator.of(context).maybePop, - ) + ? BackButton(onPressed: Navigator.of(context).maybePop) : const SizedBox(width: 40.0), Expanded( child: LayoutBuilder( @@ -127,9 +124,7 @@ class LanguageSelectionPageState extends State { }, ), ), - const SizedBox( - width: 40.0, - ), + const SizedBox(width: 40.0), ], ), ), @@ -139,9 +134,7 @@ class LanguageSelectionPageState extends State { child: Center( child: Container( padding: const EdgeInsets.all(20.0), - constraints: const BoxConstraints( - maxWidth: 500, - ), + constraints: const BoxConstraints(maxWidth: 500), child: Column( spacing: 24.0, children: [ @@ -162,7 +155,7 @@ class LanguageSelectionPageState extends State { alignment: Alignment.topCenter, child: ValueListenableBuilder( valueListenable: _searchController, - builder: (context, val, __) { + builder: (context, val, _) { return SingleChildScrollView( child: Padding( padding: const EdgeInsets.only( @@ -202,8 +195,8 @@ class LanguageSelectionPageState extends State { ), backgroundColor: _selectedLanguage == l - ? theme.colorScheme.primary - : theme.colorScheme.surface, + ? theme.colorScheme.primary + : theme.colorScheme.surface, padding: const EdgeInsets.symmetric( horizontal: 8.0, vertical: 4.0, @@ -252,7 +245,8 @@ class LanguageSelectionPageState extends State { ), AnimatedSize( duration: FluffyThemes.animationDuration, - child: _selectedLanguage != null && + child: + _selectedLanguage != null && _selectedLanguage?.langCodeShort == _baseLanguage?.langCodeShort ? PLanguageDropdown( @@ -280,9 +274,7 @@ class LanguageSelectionPageState extends State { ), child: Row( mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text(L10n.of(context).letsGo), - ], + children: [Text(L10n.of(context).letsGo)], ), ), ), diff --git a/lib/pangea/login/pages/login_options_view.dart b/lib/pangea/login/pages/login_options_view.dart index c6a73b9e4..2f2c6564e 100644 --- a/lib/pangea/login/pages/login_options_view.dart +++ b/lib/pangea/login/pages/login_options_view.dart @@ -22,19 +22,13 @@ class LoginOptionsView extends StatelessWidget { return Scaffold( appBar: AppBar( title: ConstrainedBox( - constraints: const BoxConstraints( - maxWidth: 450, - ), + constraints: const BoxConstraints(maxWidth: 450), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - BackButton( - onPressed: Navigator.of(context).pop, - ), + BackButton(onPressed: Navigator.of(context).pop), Text(L10n.of(context).login), - const SizedBox( - width: 40.0, - ), + const SizedBox(width: 40.0), ], ), ), @@ -43,10 +37,7 @@ class LoginOptionsView extends StatelessWidget { body: SafeArea( child: Center( child: ConstrainedBox( - constraints: const BoxConstraints( - maxWidth: 300, - maxHeight: 600, - ), + constraints: const BoxConstraints(maxWidth: 300, maxHeight: 600), child: Column( spacing: 16.0, mainAxisAlignment: MainAxisAlignment.end, @@ -78,8 +69,9 @@ class LoginOptionsView extends StatelessWidget { children: [ PangeaLogoSvg( width: 20, - forceColor: - Theme.of(context).colorScheme.onPrimaryContainer, + forceColor: Theme.of( + context, + ).colorScheme.onPrimaryContainer, ), Text(L10n.of(context).email), ], @@ -104,8 +96,9 @@ class LoginOptionsView extends StatelessWidget { }, ), TextSpan( - text: - L10n.of(context).andCertifyIAmAtLeast13YearsOfAge, + text: L10n.of( + context, + ).andCertifyIAmAtLeast13YearsOfAge, ), ], style: TextStyle( diff --git a/lib/pangea/login/pages/login_or_signup_view.dart b/lib/pangea/login/pages/login_or_signup_view.dart index d4b078e1e..916689809 100644 --- a/lib/pangea/login/pages/login_or_signup_view.dart +++ b/lib/pangea/login/pages/login_or_signup_view.dart @@ -63,9 +63,7 @@ class LoginOrSignupViewState extends State { body: SafeArea( child: Center( child: ConstrainedBox( - constraints: const BoxConstraints( - maxWidth: 300, - ), + constraints: const BoxConstraints(maxWidth: 300), child: Column( spacing: 50.0, mainAxisSize: MainAxisSize.min, @@ -79,8 +77,9 @@ class LoginOrSignupViewState extends State { ), Text( AppSettings.applicationName.value, - style: theme.textTheme.headlineSmall - ?.copyWith(fontWeight: FontWeight.bold), + style: theme.textTheme.headlineSmall?.copyWith( + fontWeight: FontWeight.bold, + ), ), ], ), @@ -109,9 +108,7 @@ class LoginOrSignupViewState extends State { ), child: Row( mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text(L10n.of(context).start), - ], + children: [Text(L10n.of(context).start)], ), ), ElevatedButton( @@ -122,9 +119,7 @@ class LoginOrSignupViewState extends State { ), child: Row( mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text(L10n.of(context).loginToAccount), - ], + children: [Text(L10n.of(context).loginToAccount)], ), ), ], diff --git a/lib/pangea/login/pages/new_course_page.dart b/lib/pangea/login/pages/new_course_page.dart index fd15070a6..3daf6dbb1 100644 --- a/lib/pangea/login/pages/new_course_page.dart +++ b/lib/pangea/login/pages/new_course_page.dart @@ -46,16 +46,18 @@ class NewCoursePageState extends State { final ValueNotifier?> _courses = ValueNotifier(null); - final ValueNotifier _targetLanguageFilter = - ValueNotifier(null); + final ValueNotifier _targetLanguageFilter = ValueNotifier( + null, + ); @override void initState() { super.initState(); if (widget.initialLanguageCode != null) { - _targetLanguageFilter.value = - PLanguageStore.byLangCode(widget.initialLanguageCode!); + _targetLanguageFilter.value = PLanguageStore.byLangCode( + widget.initialLanguageCode!, + ); } if (_targetLanguageFilter.value == null) { @@ -74,9 +76,7 @@ class NewCoursePageState extends State { } CourseFilter get _filter { - return CourseFilter( - targetLanguage: _targetLanguageFilter.value, - ); + return CourseFilter(targetLanguage: _targetLanguageFilter.value); } void _setTargetLanguageFilter(LanguageModel? language) { @@ -96,26 +96,19 @@ class NewCoursePageState extends State { if (resp.coursePlans.isEmpty) { ErrorHandler.logError( e: "No courses found", - data: { - 'filter': _filter.toJson(), - }, + data: {'filter': _filter.toJson()}, ); } } catch (e, s) { - ErrorHandler.logError( - e: e, - s: s, - data: { - 'filter': _filter.toJson(), - }, - ); + ErrorHandler.logError(e: e, s: s, data: {'filter': _filter.toJson()}); _courses.value = Result.error(e); } } Future _onSelect(CoursePlanModel course) async { - final existingRoom = - Matrix.of(context).client.getRoomByCourseId(course.uuid); + final existingRoom = Matrix.of( + context, + ).client.getRoomByCourseId(course.uuid); if (existingRoom == null || widget.spaceId != null) { context.go( @@ -132,12 +125,7 @@ class NewCoursePageState extends State { builder: (context) => AlertDialog.adaptive( title: ConstrainedBox( constraints: const BoxConstraints(maxWidth: 256), - child: Center( - child: Text( - course.title, - textAlign: TextAlign.center, - ), - ), + child: Center(child: Text(course.title, textAlign: TextAlign.center)), ), content: ConstrainedBox( constraints: const BoxConstraints(maxWidth: 256, maxHeight: 256), @@ -155,16 +143,12 @@ class NewCoursePageState extends State { AdaptiveDialogAction( onPressed: () => Navigator.of(context).pop(1), bigButtons: true, - child: Text( - L10n.of(context).goToExistingCourse, - ), + child: Text(L10n.of(context).goToExistingCourse), ), AdaptiveDialogAction( onPressed: () => Navigator.of(context).pop(null), bigButtons: true, - child: Text( - L10n.of(context).cancel, - ), + child: Text(L10n.of(context).cancel), ), ], ), @@ -182,10 +166,7 @@ class NewCoursePageState extends State { } else { ErrorHandler.logError( e: "Existing course room is not a space", - data: { - 'roomId': existingRoom.id, - 'courseId': course.uuid, - }, + data: {'roomId': existingRoom.id, 'courseId': course.uuid}, ); context.go('/rooms/${existingRoom.id}'); } @@ -208,9 +189,7 @@ class NewCoursePageState extends State { child: Center( child: Container( padding: const EdgeInsets.all(20.0), - constraints: const BoxConstraints( - maxWidth: 450, - ), + constraints: const BoxConstraints(maxWidth: 450), child: Column( children: [ if (widget.showFilters) ...[ @@ -224,7 +203,7 @@ class NewCoursePageState extends State { children: [ ValueListenableBuilder( valueListenable: _targetLanguageFilter, - builder: (context, value, __) { + builder: (context, value, _) { return CourseLanguageFilter( value: _targetLanguageFilter.value, onChanged: _setTargetLanguageFilter, @@ -240,7 +219,7 @@ class NewCoursePageState extends State { ], ValueListenableBuilder( valueListenable: _courses, - builder: (context, value, __) { + builder: (context, value, _) { final loading = value == null; if (loading || value.isError || @@ -264,22 +243,20 @@ class NewCoursePageState extends State { style: theme.textTheme.bodyLarge, ), ElevatedButton( - onPressed: () => context.go( - '/rooms', - ), + onPressed: () => context.go('/rooms'), style: ElevatedButton.styleFrom( backgroundColor: theme - .colorScheme.primaryContainer, + .colorScheme + .primaryContainer, foregroundColor: theme - .colorScheme.onPrimaryContainer, + .colorScheme + .onPrimaryContainer, ), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - Text( - L10n.of(context).continueText, - ), + Text(L10n.of(context).continueText), ], ), ), @@ -330,8 +307,9 @@ class NewCoursePageState extends State { ImageByUrl( imageUrl: course.imageUrl, width: 58.0, - borderRadius: - BorderRadius.circular(10.0), + borderRadius: BorderRadius.circular( + 10.0, + ), replacement: Avatar( name: course.title, borderRadius: BorderRadius.circular( diff --git a/lib/pangea/login/pages/pangea_login_scaffold.dart b/lib/pangea/login/pages/pangea_login_scaffold.dart index 31c32efd4..2de62a449 100644 --- a/lib/pangea/login/pages/pangea_login_scaffold.dart +++ b/lib/pangea/login/pages/pangea_login_scaffold.dart @@ -31,23 +31,17 @@ class PangeaLoginScaffold extends StatelessWidget { final isColumnMode = FluffyThemes.isColumnMode(context); return SafeArea( child: Scaffold( - appBar: customAppBar ?? - AppBar( - toolbarHeight: isColumnMode ? null : 40.0, - actions: actions, - ), + appBar: + customAppBar ?? + AppBar(toolbarHeight: isColumnMode ? null : 40.0, actions: actions), body: LayoutBuilder( builder: (context, constraints) { return SingleChildScrollView( child: ConstrainedBox( - constraints: BoxConstraints( - minHeight: constraints.maxHeight, - ), + constraints: BoxConstraints(minHeight: constraints.maxHeight), child: Center( child: ConstrainedBox( - constraints: const BoxConstraints( - maxWidth: 300, - ), + constraints: const BoxConstraints(maxWidth: 300), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ @@ -65,21 +59,18 @@ class PangeaLoginScaffold extends StatelessWidget { fit: BoxFit.cover, ) : mainAssetUrl != null - ? mainAssetUrl!.toString().startsWith("mxc") - ? MxcImage( - uri: mainAssetUrl, - fit: BoxFit.cover, - width: isColumnMode ? 175 : 125, - height: isColumnMode ? 175 : 125, - ) - : Image.network( - mainAssetUrl.toString(), - fit: BoxFit.cover, - ) - : Image.asset( - mainAssetPath, - fit: BoxFit.cover, - ), + ? mainAssetUrl!.toString().startsWith("mxc") + ? MxcImage( + uri: mainAssetUrl, + fit: BoxFit.cover, + width: isColumnMode ? 175 : 125, + height: isColumnMode ? 175 : 125, + ) + : Image.network( + mainAssetUrl.toString(), + fit: BoxFit.cover, + ) + : Image.asset(mainAssetPath, fit: BoxFit.cover), ), ), if (showAppName) diff --git a/lib/pangea/login/pages/pangea_login_view.dart b/lib/pangea/login/pages/pangea_login_view.dart index 8690136aa..eafa08513 100644 --- a/lib/pangea/login/pages/pangea_login_view.dart +++ b/lib/pangea/login/pages/pangea_login_view.dart @@ -16,19 +16,13 @@ class PasswordLoginView extends StatelessWidget { child: Scaffold( appBar: AppBar( title: ConstrainedBox( - constraints: const BoxConstraints( - maxWidth: 450, - ), + constraints: const BoxConstraints(maxWidth: 450), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - BackButton( - onPressed: Navigator.of(context).pop, - ), + BackButton(onPressed: Navigator.of(context).pop), Text(L10n.of(context).loginWithEmail), - const SizedBox( - width: 40.0, - ), + const SizedBox(width: 40.0), ], ), ), @@ -37,10 +31,7 @@ class PasswordLoginView extends StatelessWidget { body: SafeArea( child: Center( child: ConstrainedBox( - constraints: const BoxConstraints( - maxWidth: 300, - maxHeight: 600, - ), + constraints: const BoxConstraints(maxWidth: 300, maxHeight: 600), child: Column( spacing: 16.0, mainAxisAlignment: MainAxisAlignment.end, @@ -80,8 +71,9 @@ class PasswordLoginView extends StatelessWidget { }, validator: (value) { if (value == null || value.isEmpty) { - return L10n.of(context) - .pleaseEnterYourPassword; + return L10n.of( + context, + ).pleaseEnterYourPassword; } return null; }, @@ -101,7 +93,8 @@ class PasswordLoginView extends StatelessWidget { FocusManager.instance.primaryFocus?.unfocus(), ), TextButton( - onPressed: controller.loadingSignIn || + onPressed: + controller.loadingSignIn || controller.client == null ? () {} : controller.passwordForgotten, @@ -120,17 +113,16 @@ class PasswordLoginView extends StatelessWidget { ), ), ElevatedButton( - onPressed: - controller.enabledSignIn ? controller.login : null, + onPressed: controller.enabledSignIn + ? controller.login + : null, style: ElevatedButton.styleFrom( backgroundColor: theme.colorScheme.primaryContainer, foregroundColor: theme.colorScheme.onPrimaryContainer, ), child: Row( mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text(L10n.of(context).login), - ], + children: [Text(L10n.of(context).login)], ), ), ], diff --git a/lib/pangea/login/pages/signup.dart b/lib/pangea/login/pages/signup.dart index 7fb53b457..ab6510684 100644 --- a/lib/pangea/login/pages/signup.dart +++ b/lib/pangea/login/pages/signup.dart @@ -14,10 +14,7 @@ import 'package:fluffychat/widgets/matrix.dart'; class SignupPage extends StatefulWidget { final bool withEmail; - const SignupPage({ - this.withEmail = false, - super.key, - }); + const SignupPage({this.withEmail = false, super.key}); @override SignupPageController createState() => SignupPageController(); @@ -107,8 +104,9 @@ class SignupPageController extends State { return L10n.of(context).chooseAStrongPassword; } if (value.length < minPassLength) { - return L10n.of(context) - .pleaseChooseAtLeastChars(minPassLength.toString()); + return L10n.of( + context, + ).pleaseChooseAtLeastChars(minPassLength.toString()); } return null; } @@ -166,14 +164,15 @@ class SignupPageController extends State { final client = await Matrix.of(context).getLoginClient(); final email = emailController.text; if (email.isNotEmpty) { - Matrix.of(context).currentClientSecret = - DateTime.now().millisecondsSinceEpoch.toString(); - Matrix.of(context).currentThreepidCreds = - await client.requestTokenToRegisterEmail( - Matrix.of(context).currentClientSecret, - email, - 0, - ); + Matrix.of(context).currentClientSecret = DateTime.now() + .millisecondsSinceEpoch + .toString(); + Matrix.of(context).currentThreepidCreds = await client + .requestTokenToRegisterEmail( + Matrix.of(context).currentClientSecret, + email, + 0, + ); } final displayname = usernameController.text; @@ -195,11 +194,9 @@ class SignupPageController extends State { GoogleAnalytics.login("pangea", registerRes?.userId); if (displayname != localPart && client.userID != null) { - await client.setProfileField( - client.userID!, - 'displayname', - {'displayname': displayname}, - ); + await client.setProfileField(client.userID!, 'displayname', { + 'displayname': displayname, + }); } } diff --git a/lib/pangea/login/pages/signup_view.dart b/lib/pangea/login/pages/signup_view.dart index 6b79ee241..cd2db3e87 100644 --- a/lib/pangea/login/pages/signup_view.dart +++ b/lib/pangea/login/pages/signup_view.dart @@ -33,13 +33,9 @@ class SignupPageView extends StatelessWidget { child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - BackButton( - onPressed: Navigator.of(context).pop, - ), + BackButton(onPressed: Navigator.of(context).pop), Text(L10n.of(context).signUp), - const SizedBox( - width: 40.0, - ), + const SizedBox(width: 40.0), ], ), ), @@ -48,10 +44,7 @@ class SignupPageView extends StatelessWidget { body: SafeArea( child: Center( child: ConstrainedBox( - constraints: const BoxConstraints( - maxWidth: 300, - maxHeight: 600, - ), + constraints: const BoxConstraints(maxWidth: 300, maxHeight: 600), child: Column( spacing: 16.0, mainAxisAlignment: MainAxisAlignment.end, @@ -66,9 +59,7 @@ class SignupPageView extends StatelessWidget { const PangeaSsoButton(provider: SSOProvider.apple), const PangeaSsoButton(provider: SSOProvider.google), ElevatedButton( - onPressed: () => context.go( - '/home/language/signup/email', - ), + onPressed: () => context.go('/home/language/signup/email'), style: ElevatedButton.styleFrom( backgroundColor: theme.colorScheme.primaryContainer, foregroundColor: theme.colorScheme.onPrimaryContainer, @@ -79,8 +70,9 @@ class SignupPageView extends StatelessWidget { children: [ PangeaLogoSvg( width: 20, - forceColor: - Theme.of(context).colorScheme.onPrimaryContainer, + forceColor: Theme.of( + context, + ).colorScheme.onPrimaryContainer, ), Text(L10n.of(context).withEmail), ], @@ -105,8 +97,9 @@ class SignupPageView extends StatelessWidget { }, ), TextSpan( - text: L10n.of(context) - .andCertifyIAmAtLeast13YearsOfAge, + text: L10n.of( + context, + ).andCertifyIAmAtLeast13YearsOfAge, ), ], style: TextStyle( diff --git a/lib/pangea/login/pages/signup_with_email_view.dart b/lib/pangea/login/pages/signup_with_email_view.dart index 840e43812..7d33de127 100644 --- a/lib/pangea/login/pages/signup_with_email_view.dart +++ b/lib/pangea/login/pages/signup_with_email_view.dart @@ -17,18 +17,12 @@ class SignupWithEmailView extends StatelessWidget { child: Scaffold( appBar: AppBar( title: ConstrainedBox( - constraints: const BoxConstraints( - maxWidth: 450, - ), + constraints: const BoxConstraints(maxWidth: 450), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - BackButton( - onPressed: Navigator.of(context).pop, - ), - const SizedBox( - width: 40.0, - ), + BackButton(onPressed: Navigator.of(context).pop), + const SizedBox(width: 40.0), ], ), ), @@ -37,10 +31,7 @@ class SignupWithEmailView extends StatelessWidget { body: SafeArea( child: Center( child: ConstrainedBox( - constraints: const BoxConstraints( - maxWidth: 300, - maxHeight: 600, - ), + constraints: const BoxConstraints(maxWidth: 300, maxHeight: 600), child: Column( spacing: 24.0, mainAxisAlignment: MainAxisAlignment.end, @@ -76,8 +67,9 @@ class SignupWithEmailView extends StatelessWidget { obscureText: !controller.showPassword, validator: controller.password1TextFieldValidator, controller: controller.passwordController, - onFieldSubmitted: - controller.enableSignUp ? controller.signup : null, + onFieldSubmitted: controller.enableSignUp + ? controller.signup + : null, decoration: InputDecoration( hintText: L10n.of(context).password, suffixIcon: IconButton( @@ -94,17 +86,16 @@ class SignupWithEmailView extends StatelessWidget { FocusManager.instance.primaryFocus?.unfocus(), ), ElevatedButton( - onPressed: - controller.enableSignUp ? controller.signup : null, + onPressed: controller.enableSignUp + ? controller.signup + : null, style: ElevatedButton.styleFrom( backgroundColor: theme.colorScheme.primaryContainer, foregroundColor: theme.colorScheme.onPrimaryContainer, ), child: Row( mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text(L10n.of(context).createAccount), - ], + children: [Text(L10n.of(context).createAccount)], ), ), ], diff --git a/lib/pangea/login/utils/lang_code_repo.dart b/lib/pangea/login/utils/lang_code_repo.dart index 8e1572ae8..4e76718e5 100644 --- a/lib/pangea/login/utils/lang_code_repo.dart +++ b/lib/pangea/login/utils/lang_code_repo.dart @@ -4,15 +4,12 @@ class LanguageSettings { final String targetLangCode; final String? baseLangCode; - LanguageSettings({ - required this.targetLangCode, - this.baseLangCode, - }); + LanguageSettings({required this.targetLangCode, this.baseLangCode}); Map toJson() => { - 'targetLangCode': targetLangCode, - 'baseLangCode': baseLangCode, - }; + 'targetLangCode': targetLangCode, + 'baseLangCode': baseLangCode, + }; factory LanguageSettings.fromJson(Map json) => LanguageSettings( diff --git a/lib/pangea/login/utils/sso_login_action.dart b/lib/pangea/login/utils/sso_login_action.dart index fa2aac089..4a005e2fb 100644 --- a/lib/pangea/login/utils/sso_login_action.dart +++ b/lib/pangea/login/utils/sso_login_action.dart @@ -21,14 +21,12 @@ Future pangeaSSOLoginAction( final bool isDefaultPlatform = (PlatformInfos.isMobile || PlatformInfos.isWeb || PlatformInfos.isMacOS); final redirectUrl = kIsWeb - ? Uri.parse(html.window.location.href) - .resolveUri( - Uri(pathSegments: ['auth.html']), - ) - .toString() + ? Uri.parse( + html.window.location.href, + ).resolveUri(Uri(pathSegments: ['auth.html'])).toString() : isDefaultPlatform - ? '${AppConfig.appOpenUrlScheme.toLowerCase()}://login' - : 'http://localhost:3001//login'; + ? '${AppConfig.appOpenUrlScheme.toLowerCase()}://login' + : 'http://localhost:3001//login'; final client = await Matrix.of(context).getLoginClient(); final url = client.homeserver!.replace( path: '/_matrix/client/v3/login/sso/redirect/${provider.id ?? ''}', @@ -57,15 +55,14 @@ Future pangeaSSOLoginAction( final redirect = client.onLoginStateChanged.stream .where((state) => state == LoginState.loggedIn) .first - .then( - (_) { - final route = FluffyChatApp.router.state.fullPath; - if (route == null || - (!route.contains("/rooms") && !route.contains('registration'))) { - context.go('/rooms'); - } - }, - ).timeout(const Duration(seconds: 30)); + .then((_) { + final route = FluffyChatApp.router.state.fullPath; + if (route == null || + (!route.contains("/rooms") && !route.contains('registration'))) { + context.go('/rooms'); + } + }) + .timeout(const Duration(seconds: 30)); final loginRes = await client.login( LoginType.mLoginToken, diff --git a/lib/pangea/login/widgets/app_config_dialog.dart b/lib/pangea/login/widgets/app_config_dialog.dart index 454fdad1f..950bb6e1e 100644 --- a/lib/pangea/login/widgets/app_config_dialog.dart +++ b/lib/pangea/login/widgets/app_config_dialog.dart @@ -6,10 +6,7 @@ import 'package:fluffychat/widgets/adaptive_dialogs/adaptive_dialog_action.dart' class AppConfigDialog extends StatefulWidget { final List overrides; - const AppConfigDialog({ - super.key, - required this.overrides, - }); + const AppConfigDialog({super.key, required this.overrides}); @override State createState() => AppConfigDialogState(); @@ -38,9 +35,7 @@ class AppConfigDialogState extends State { type: MaterialType.transparency, child: Container( padding: const EdgeInsets.all(16.0), - constraints: const BoxConstraints( - maxWidth: 256, - ), + constraints: const BoxConstraints(maxWidth: 256), child: SingleChildScrollView( child: RadioGroup( groupValue: selectedOverride, @@ -59,14 +54,13 @@ class AppConfigDialogState extends State { ), value: override, ); - }).toList() - ..insert( - 0, - RadioListTile.adaptive( - title: Text(L10n.of(context).defaultOption), - value: null, - ), + }).toList()..insert( + 0, + RadioListTile.adaptive( + title: Text(L10n.of(context).defaultOption), + value: null, ), + ), ], ), ), diff --git a/lib/pangea/login/widgets/full_width_button.dart b/lib/pangea/login/widgets/full_width_button.dart index fe30be714..abbb30fde 100644 --- a/lib/pangea/login/widgets/full_width_button.dart +++ b/lib/pangea/login/widgets/full_width_button.dart @@ -50,8 +50,8 @@ class FullWidthButtonState extends State { decoration: BoxDecoration( color: widget.enabled ? depressed - ? shadowColor - : Theme.of(context).colorScheme.primary + ? shadowColor + : Theme.of(context).colorScheme.primary : Theme.of(context).disabledColor, borderRadius: BorderRadius.circular(36), ), @@ -74,8 +74,9 @@ class FullWidthButtonState extends State { Text( widget.title, style: TextStyle( - color: - Theme.of(context).colorScheme.onPrimary, + color: Theme.of( + context, + ).colorScheme.onPrimary, fontSize: 16, ), ), @@ -154,9 +155,7 @@ class FullWidthTextField extends StatelessWidget { decoration: InputDecoration( labelText: labelText, hintText: hintText, - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(36.0), - ), + border: OutlineInputBorder(borderRadius: BorderRadius.circular(36.0)), contentPadding: const EdgeInsets.symmetric( horizontal: 30, vertical: 8.0, diff --git a/lib/pangea/login/widgets/p_sso_button.dart b/lib/pangea/login/widgets/p_sso_button.dart index a02219333..79ad16ce9 100644 --- a/lib/pangea/login/widgets/p_sso_button.dart +++ b/lib/pangea/login/widgets/p_sso_button.dart @@ -21,18 +21,12 @@ class PangeaSsoButton extends StatelessWidget { final SSOProvider provider; final String? title; - const PangeaSsoButton({ - required this.provider, - this.title, - super.key, - }); + const PangeaSsoButton({required this.provider, this.title, super.key}); Future _runSSOLogin(BuildContext context) async { final token = await showAdaptiveDialog( context: context, - builder: (context) => SSODialog( - future: () => _getSSOToken(context), - ), + builder: (context) => SSODialog(future: () => _getSSOToken(context)), ); if (token == null || token.isEmpty) { @@ -46,18 +40,17 @@ class PangeaSsoButton extends StatelessWidget { } Future _getSSOToken(BuildContext context) async { - final bool isDefaultPlatform = (PlatformInfos.isMobile || + final bool isDefaultPlatform = + (PlatformInfos.isMobile || PlatformInfos.isWeb || PlatformInfos.isMacOS); final redirectUrl = kIsWeb - ? Uri.parse(html.window.location.href) - .resolveUri( - Uri(pathSegments: ['auth.html']), - ) - .toString() + ? Uri.parse( + html.window.location.href, + ).resolveUri(Uri(pathSegments: ['auth.html'])).toString() : isDefaultPlatform - ? '${AppConfig.appOpenUrlScheme.toLowerCase()}://login' - : 'http://localhost:3001//login'; + ? '${AppConfig.appOpenUrlScheme.toLowerCase()}://login' + : 'http://localhost:3001//login'; final client = await Matrix.of(context).getLoginClient(); final url = client.homeserver!.replace( path: '/_matrix/client/v3/login/sso/redirect/${provider.id}', @@ -85,23 +78,19 @@ class PangeaSsoButton extends StatelessWidget { return token; } - Future _ssoAction( - String token, - BuildContext context, - ) async { + Future _ssoAction(String token, BuildContext context) async { final client = Matrix.of(context).client; final redirect = client.onLoginStateChanged.stream .where((state) => state == LoginState.loggedIn) .first - .then( - (_) { - final route = FluffyChatApp.router.state.fullPath; - if (route == null || - (!route.contains("/rooms") && !route.contains('registration'))) { - context.go('/rooms'); - } - }, - ).timeout(const Duration(seconds: 30)); + .then((_) { + final route = FluffyChatApp.router.state.fullPath; + if (route == null || + (!route.contains("/rooms") && !route.contains('registration'))) { + context.go('/rooms'); + } + }) + .timeout(const Duration(seconds: 30)); final loginRes = await client.login( LoginType.mLoginToken, diff --git a/lib/pangea/login/widgets/p_sso_dialog.dart b/lib/pangea/login/widgets/p_sso_dialog.dart index 2620c3a11..94b6bc37b 100644 --- a/lib/pangea/login/widgets/p_sso_dialog.dart +++ b/lib/pangea/login/widgets/p_sso_dialog.dart @@ -9,10 +9,7 @@ import 'package:fluffychat/utils/url_launcher.dart'; class SSODialog extends StatefulWidget { final Future Function() future; - const SSODialog({ - super.key, - required this.future, - }); + const SSODialog({super.key, required this.future}); @override SSODialogState createState() => SSODialogState(); @@ -51,9 +48,7 @@ class SSODialogState extends State { @override Widget build(BuildContext context) { return Dialog( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12.0), - ), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12.0)), backgroundColor: Theme.of(context).colorScheme.surface, child: Container( padding: const EdgeInsets.all(12.0), diff --git a/lib/pangea/morphs/default_morph_mapping.dart b/lib/pangea/morphs/default_morph_mapping.dart index 4721d4389..fb6003db5 100644 --- a/lib/pangea/morphs/default_morph_mapping.dart +++ b/lib/pangea/morphs/default_morph_mapping.dart @@ -228,7 +228,7 @@ final MorphFeaturesAndTags defaultMorphMapping = MorphFeaturesAndTags.fromJson({ { "feature": "x", "tag": ["X"], - } + }, ], }); diff --git a/lib/pangea/morphs/get_grammar_copy.dart b/lib/pangea/morphs/get_grammar_copy.dart index ce811ba63..00aa0fe9d 100644 --- a/lib/pangea/morphs/get_grammar_copy.dart +++ b/lib/pangea/morphs/get_grammar_copy.dart @@ -506,19 +506,14 @@ String? getGrammarCopy({ ErrorHandler.logError( e: Exception('Empty tag'), m: 'Empty tag in getGrammarCopy', - data: { - 'context': context, - }, + data: {'context': context}, ); return L10n.of(context).grammarCopyUnknown; default: // debugger(when: kDebugMode); ErrorHandler.logError( e: 'Need to add copy to intl_en.arb', - data: { - 'tag': key, - 'context': context, - }, + data: {'tag': key, 'context': context}, level: SentryLevel.warning, ); return lemma; // Fallback to the lemma itself if no match is found diff --git a/lib/pangea/morphs/morph_feature_display.dart b/lib/pangea/morphs/morph_feature_display.dart index a3dbcc23d..db3dab703 100644 --- a/lib/pangea/morphs/morph_feature_display.dart +++ b/lib/pangea/morphs/morph_feature_display.dart @@ -4,10 +4,7 @@ import 'package:fluffychat/pangea/morphs/morph_features_enum.dart'; import 'package:fluffychat/pangea/morphs/morph_icon.dart'; class MorphFeatureDisplay extends StatelessWidget { - const MorphFeatureDisplay({ - super.key, - required this.morphFeature, - }); + const MorphFeatureDisplay({super.key, required this.morphFeature}); final MorphFeaturesEnum morphFeature; @@ -19,10 +16,7 @@ class MorphFeatureDisplay extends StatelessWidget { SizedBox( width: 24.0, height: 24.0, - child: MorphIcon( - morphFeature: morphFeature, - morphTag: null, - ), + child: MorphIcon(morphFeature: morphFeature, morphTag: null), ), const SizedBox(width: 10.0), Text( diff --git a/lib/pangea/morphs/morph_features_enum.dart b/lib/pangea/morphs/morph_features_enum.dart index 5c8fb7567..20084549c 100644 --- a/lib/pangea/morphs/morph_features_enum.dart +++ b/lib/pangea/morphs/morph_features_enum.dart @@ -153,33 +153,33 @@ extension MorphFeaturesEnumExtension on MorphFeaturesEnum { /// the subset of morphological categories that are important to practice for learning the language /// by order of importance static List get eligibleForPractice => [ - MorphFeaturesEnum.Pos, - MorphFeaturesEnum.Tense, - MorphFeaturesEnum.VerbForm, - MorphFeaturesEnum.VerbType, - MorphFeaturesEnum.Voice, - MorphFeaturesEnum.AdvType, - MorphFeaturesEnum.Aspect, - MorphFeaturesEnum.Case, - MorphFeaturesEnum.ConjType, - MorphFeaturesEnum.Definite, - MorphFeaturesEnum.Degree, - MorphFeaturesEnum.Evident, - MorphFeaturesEnum.Gender, - MorphFeaturesEnum.Mood, - MorphFeaturesEnum.NounType, - MorphFeaturesEnum.NumForm, - MorphFeaturesEnum.NumType, - MorphFeaturesEnum.Number, - MorphFeaturesEnum.NumberPsor, - MorphFeaturesEnum.Person, - MorphFeaturesEnum.Polarity, - MorphFeaturesEnum.Polite, - MorphFeaturesEnum.Poss, - MorphFeaturesEnum.PrepCase, - MorphFeaturesEnum.PronType, - MorphFeaturesEnum.Reflex, - ]; + MorphFeaturesEnum.Pos, + MorphFeaturesEnum.Tense, + MorphFeaturesEnum.VerbForm, + MorphFeaturesEnum.VerbType, + MorphFeaturesEnum.Voice, + MorphFeaturesEnum.AdvType, + MorphFeaturesEnum.Aspect, + MorphFeaturesEnum.Case, + MorphFeaturesEnum.ConjType, + MorphFeaturesEnum.Definite, + MorphFeaturesEnum.Degree, + MorphFeaturesEnum.Evident, + MorphFeaturesEnum.Gender, + MorphFeaturesEnum.Mood, + MorphFeaturesEnum.NounType, + MorphFeaturesEnum.NumForm, + MorphFeaturesEnum.NumType, + MorphFeaturesEnum.Number, + MorphFeaturesEnum.NumberPsor, + MorphFeaturesEnum.Person, + MorphFeaturesEnum.Polarity, + MorphFeaturesEnum.Polite, + MorphFeaturesEnum.Poss, + MorphFeaturesEnum.PrepCase, + MorphFeaturesEnum.PronType, + MorphFeaturesEnum.Reflex, + ]; bool get isEligibleForPractice { return eligibleForPractice.contains(this); diff --git a/lib/pangea/morphs/morph_icon.dart b/lib/pangea/morphs/morph_icon.dart index 745de3588..ce9735f75 100644 --- a/lib/pangea/morphs/morph_icon.dart +++ b/lib/pangea/morphs/morph_icon.dart @@ -40,10 +40,7 @@ class MorphIcon extends StatelessWidget { context: context, ), colorReplacements: theme.brightness == Brightness.dark - ? { - "white": theme.cardColor.hexValue.toString(), - "black": "white", - } + ? {"white": theme.cardColor.hexValue.toString(), "black": "white"} : {}, errorIcon: Icon(morphFeature.fallbackIcon), width: size?.width, diff --git a/lib/pangea/morphs/morph_meaning/morph_info_repo.dart b/lib/pangea/morphs/morph_meaning/morph_info_repo.dart index 9a418b203..204b6a8b1 100644 --- a/lib/pangea/morphs/morph_meaning/morph_info_repo.dart +++ b/lib/pangea/morphs/morph_meaning/morph_info_repo.dart @@ -29,7 +29,7 @@ class MorphInfoRepo { static final Map _cache = {}; static const Duration _cacheDuration = Duration(minutes: 10); -// Persistent storage + // Persistent storage static final GetStorage _storage = GetStorage('morph_info_storage'); static Future> get( @@ -72,11 +72,7 @@ class MorphInfoRepo { await _storage.write(key, resultFuture.toJson()); _cache.remove(key); // Invalidate in-memory cache } catch (e, s) { - ErrorHandler.logError( - e: e, - s: s, - data: {'request': request.toJson()}, - ); + ErrorHandler.logError(e: e, s: s, data: {'request': request.toJson()}); } } @@ -88,7 +84,8 @@ class MorphInfoRepo { }) async { try { final cachedJson = await _getCached(request); - final resp = cachedJson?.result ?? + final resp = + cachedJson?.result ?? MorphInfoResponse( userL1: request.userL1, userL2: request.userL2, @@ -98,11 +95,7 @@ class MorphInfoRepo { resp.setMorphDefinition(feature.name, tag, definition); await set(request, resp); } catch (e, s) { - ErrorHandler.logError( - e: e, - s: s, - data: {'request': request.toJson()}, - ); + ErrorHandler.logError(e: e, s: s, data: {'request': request.toJson()}); } } @@ -140,9 +133,7 @@ class MorphInfoRepo { ); } - return MorphInfoResponse.fromJson( - jsonDecode(utf8.decode(res.bodyBytes)), - ); + return MorphInfoResponse.fromJson(jsonDecode(utf8.decode(res.bodyBytes))); } static Future>? _getCached( @@ -170,9 +161,7 @@ class MorphInfoRepo { await set(request, result.asValue!.value); } - static MorphInfoResponse? _getStored( - MorphInfoRequest request, - ) { + static MorphInfoResponse? _getStored(MorphInfoRequest request) { final key = request.storageKey; try { final entry = _storage.read(key); @@ -180,11 +169,7 @@ class MorphInfoRepo { return MorphInfoResponse.fromJson(entry); } catch (e, s) { - ErrorHandler.logError( - e: e, - s: s, - data: {'request': request.toJson()}, - ); + ErrorHandler.logError(e: e, s: s, data: {'request': request.toJson()}); _storage.remove(key); return null; } diff --git a/lib/pangea/morphs/morph_meaning/morph_info_request.dart b/lib/pangea/morphs/morph_meaning/morph_info_request.dart index 1d3eb2ea7..f3f916706 100644 --- a/lib/pangea/morphs/morph_meaning/morph_info_request.dart +++ b/lib/pangea/morphs/morph_meaning/morph_info_request.dart @@ -2,16 +2,10 @@ class MorphInfoRequest { final String userL1; final String userL2; - MorphInfoRequest({ - required this.userL1, - required this.userL2, - }); + MorphInfoRequest({required this.userL1, required this.userL2}); Map toJson() { - return { - 'user_l1': userL1, - 'user_l2': userL2, - }; + return {'user_l1': userL1, 'user_l2': userL2}; } @override diff --git a/lib/pangea/morphs/morph_meaning/morph_info_response.dart b/lib/pangea/morphs/morph_meaning/morph_info_response.dart index a7e044651..ab19180ee 100644 --- a/lib/pangea/morphs/morph_meaning/morph_info_response.dart +++ b/lib/pangea/morphs/morph_meaning/morph_info_response.dart @@ -20,11 +20,7 @@ class MorphologicalTag { } Map toJson() { - return { - 'code': code, - 'l1_title': l1Title, - 'l1_description': l1Description, - }; + return {'code': code, 'l1_title': l1Title, 'l1_description': l1Description}; } } @@ -41,8 +37,9 @@ class MorphologicalFeature { factory MorphologicalFeature.fromJson(Map json) { final tagsFromJson = json['tags'] as List; - final List tagsList = - tagsFromJson.map((tag) => MorphologicalTag.fromJson(tag)).toList(); + final List tagsList = tagsFromJson + .map((tag) => MorphologicalTag.fromJson(tag)) + .toList(); return MorphologicalFeature( code: json['code'], @@ -131,17 +128,17 @@ class MorphInfoResponse { } final tagIndex = features[featureIndex].tags.indexWhere( - (tag) => tag.code.toLowerCase() == morphTag.toLowerCase(), - ); + (tag) => tag.code.toLowerCase() == morphTag.toLowerCase(), + ); if (tagIndex == -1) { features[featureIndex].tags.add( - MorphologicalTag( - code: morphTag, - l1Title: morphTag, - l1Description: defintion, - ), - ); + MorphologicalTag( + code: morphTag, + l1Title: morphTag, + l1Description: defintion, + ), + ); return; } diff --git a/lib/pangea/morphs/morph_models.dart b/lib/pangea/morphs/morph_models.dart index c10fb1f0c..cff569dc1 100644 --- a/lib/pangea/morphs/morph_models.dart +++ b/lib/pangea/morphs/morph_models.dart @@ -27,10 +27,7 @@ class MorphFeature { .toList(); Map toJson() { - return { - 'feature': feature, - 'tag': tags, - }; + return {'feature': feature, 'tag': tags}; } } @@ -67,9 +64,7 @@ class MorphFeaturesAndTags { debugger(when: kDebugMode); ErrorHandler.logError( m: "Morph construct category $feature not found in morph categories and labels", - data: { - "feature": feature, - }, + data: {"feature": feature}, ); return []; } @@ -86,11 +81,8 @@ class MorphFeaturesAndTags { ?.displayTags ?? []; - List get displayFeatures => features - .where( - (f) => f.feature.toLowerCase() != "foreign", - ) - .toList(); + List get displayFeatures => + features.where((f) => f.feature.toLowerCase() != "foreign").toList(); List get categories => features.map((e) => e.feature).toList(); @@ -105,9 +97,7 @@ class MorphFeaturesAndTags { } ErrorHandler.logError( m: "Morph construct lemma $morphLemma not found in morph categories and labels", - data: { - "morphLemma": morphLemma, - }, + data: {"morphLemma": morphLemma}, ); return "Other"; } diff --git a/lib/pangea/morphs/morph_repo.dart b/lib/pangea/morphs/morph_repo.dart index 40f5d0a37..473582956 100644 --- a/lib/pangea/morphs/morph_repo.dart +++ b/lib/pangea/morphs/morph_repo.dart @@ -32,10 +32,7 @@ class MorphsRepo { static const int _cacheDurationMinutes = 1; static void set(String languageCode, MorphFeaturesAndTags response) { - _morphsStorage.write( - languageCode, - response.toJson(), - ); + _morphsStorage.write(languageCode, response.toJson()); } static MorphFeaturesAndTags fromJson(Map json) { @@ -61,13 +58,7 @@ class MorphsRepo { return response; } catch (e, s) { debugger(when: kDebugMode); - ErrorHandler.logError( - e: e, - s: s, - data: { - "languageCode": languageCode, - }, - ); + ErrorHandler.logError(e: e, s: s, data: {"languageCode": languageCode}); return defaultMorphMapping; } } diff --git a/lib/pangea/morphs/morph_tag_display.dart b/lib/pangea/morphs/morph_tag_display.dart index 814579020..801488ae2 100644 --- a/lib/pangea/morphs/morph_tag_display.dart +++ b/lib/pangea/morphs/morph_tag_display.dart @@ -10,8 +10,8 @@ class MorphTagDisplay extends StatelessWidget { required MorphFeaturesEnum morphFeature, required String morphTag, required this.textColor, - }) : _morphFeature = morphFeature, - _morphTag = morphTag; + }) : _morphFeature = morphFeature, + _morphTag = morphTag; final MorphFeaturesEnum _morphFeature; final String _morphTag; @@ -36,9 +36,9 @@ class MorphTagDisplay extends StatelessWidget { context: context, ) ?? _morphTag, - style: Theme.of(context).textTheme.titleLarge?.copyWith( - color: textColor, - ), + style: Theme.of( + context, + ).textTheme.titleLarge?.copyWith(color: textColor), ), ], ); diff --git a/lib/pangea/morphs/parts_of_speech_enum.dart b/lib/pangea/morphs/parts_of_speech_enum.dart index b8f919be9..9c88b43ef 100644 --- a/lib/pangea/morphs/parts_of_speech_enum.dart +++ b/lib/pangea/morphs/parts_of_speech_enum.dart @@ -45,12 +45,12 @@ enum PartOfSpeechEnum { } bool get isContentWord => [ - PartOfSpeechEnum.noun, - PartOfSpeechEnum.verb, - PartOfSpeechEnum.adj, - PartOfSpeechEnum.adv, - PartOfSpeechEnum.idiom, - PartOfSpeechEnum.phrasalv, - PartOfSpeechEnum.compn, - ].contains(this); + PartOfSpeechEnum.noun, + PartOfSpeechEnum.verb, + PartOfSpeechEnum.adj, + PartOfSpeechEnum.adv, + PartOfSpeechEnum.idiom, + PartOfSpeechEnum.phrasalv, + PartOfSpeechEnum.compn, + ].contains(this); } diff --git a/lib/pangea/payload_client/image_sizes.dart b/lib/pangea/payload_client/image_sizes.dart index e8d2c42a2..06d2b032b 100644 --- a/lib/pangea/payload_client/image_sizes.dart +++ b/lib/pangea/payload_client/image_sizes.dart @@ -3,19 +3,16 @@ class ImageSizes { final ImageSize? medium; final ImageSize? large; - const ImageSizes({ - this.thumbnail, - this.medium, - this.large, - }); + const ImageSizes({this.thumbnail, this.medium, this.large}); factory ImageSizes.fromJson(Map json) { return ImageSizes( thumbnail: json['thumbnail'] != null ? ImageSize.fromJson(json['thumbnail']) : null, - medium: - json['medium'] != null ? ImageSize.fromJson(json['medium']) : null, + medium: json['medium'] != null + ? ImageSize.fromJson(json['medium']) + : null, large: json['large'] != null ? ImageSize.fromJson(json['large']) : null, ); } diff --git a/lib/pangea/payload_client/join_field.dart b/lib/pangea/payload_client/join_field.dart index 133482281..96e871b30 100644 --- a/lib/pangea/payload_client/join_field.dart +++ b/lib/pangea/payload_client/join_field.dart @@ -3,15 +3,9 @@ class JoinField { final bool? hasNextPage; final int? totalDocs; - const JoinField({ - this.docs, - this.hasNextPage, - this.totalDocs, - }); + const JoinField({this.docs, this.hasNextPage, this.totalDocs}); - factory JoinField.fromJson( - Map json, - ) { + factory JoinField.fromJson(Map json) { final raw = json['docs']; final list = (raw is List) ? raw.map((e) => e as String).toList() : null; @@ -23,10 +17,6 @@ class JoinField { } Map toJson() { - return { - 'docs': docs, - 'hasNextPage': hasNextPage, - 'totalDocs': totalDocs, - }; + return {'docs': docs, 'hasNextPage': hasNextPage, 'totalDocs': totalDocs}; } } diff --git a/lib/pangea/payload_client/models/course_plan/cms_course_plan_topic_location_media.dart b/lib/pangea/payload_client/models/course_plan/cms_course_plan_topic_location_media.dart index aae5ff103..9c15af5cf 100644 --- a/lib/pangea/payload_client/models/course_plan/cms_course_plan_topic_location_media.dart +++ b/lib/pangea/payload_client/models/course_plan/cms_course_plan_topic_location_media.dart @@ -48,8 +48,9 @@ class CmsCoursePlanTopicLocationMedia { return CmsCoursePlanTopicLocationMedia( id: json['id'], alt: json['alt'], - coursePlanTopicLocations: - List.from(json['coursePlanTopicLocations'] as List), + coursePlanTopicLocations: List.from( + json['coursePlanTopicLocations'] as List, + ), createdBy: json['createdBy'] != null ? PolymorphicRelationship.fromJson(json['createdBy']) : null, diff --git a/lib/pangea/payload_client/payload_client.dart b/lib/pangea/payload_client/payload_client.dart index 786164ff6..a3a64af5c 100644 --- a/lib/pangea/payload_client/payload_client.dart +++ b/lib/pangea/payload_client/payload_client.dart @@ -10,10 +10,7 @@ class PayloadClient { final String accessToken; final String basePath = "/cms/api"; - PayloadClient({ - required this.baseUrl, - required this.accessToken, - }); + PayloadClient({required this.baseUrl, required this.accessToken}); Map get _headers { final headers = { @@ -188,8 +185,9 @@ class PayloadClient { build('$prefix[$i]', value[i]); } } else { - final String encodedKey = - encode ? Uri.encodeQueryComponent(prefix) : prefix; + final String encodedKey = encode + ? Uri.encodeQueryComponent(prefix) + : prefix; final String encodedVal = encode ? Uri.encodeQueryComponent(value.toString()) : value.toString(); diff --git a/lib/pangea/payload_client/polymorphic_relationship.dart b/lib/pangea/payload_client/polymorphic_relationship.dart index 5f786ec0f..b5242fb95 100644 --- a/lib/pangea/payload_client/polymorphic_relationship.dart +++ b/lib/pangea/payload_client/polymorphic_relationship.dart @@ -2,10 +2,7 @@ class PolymorphicRelationship { final String relationTo; final String value; - PolymorphicRelationship({ - required this.relationTo, - required this.value, - }); + PolymorphicRelationship({required this.relationTo, required this.value}); factory PolymorphicRelationship.fromJson(Map json) { return PolymorphicRelationship( @@ -15,9 +12,6 @@ class PolymorphicRelationship { } Map toJson() { - return { - 'relationTo': relationTo, - 'value': value, - }; + return {'relationTo': relationTo, 'value': value}; } } diff --git a/lib/pangea/phonetic_transcription/phonetic_transcription_builder.dart b/lib/pangea/phonetic_transcription/phonetic_transcription_builder.dart index 3627f78a3..e15079d09 100644 --- a/lib/pangea/phonetic_transcription/phonetic_transcription_builder.dart +++ b/lib/pangea/phonetic_transcription/phonetic_transcription_builder.dart @@ -16,7 +16,8 @@ class PhoneticTranscriptionBuilder extends StatefulWidget { final Widget Function( BuildContext context, PhoneticTranscriptionBuilderState controller, - ) builder; + ) + builder; const PhoneticTranscriptionBuilder({ super.key, @@ -33,8 +34,9 @@ class PhoneticTranscriptionBuilder extends StatefulWidget { class PhoneticTranscriptionBuilderState extends State { - final ValueNotifier> _loader = - ValueNotifier(const AsyncState.idle()); + final ValueNotifier> _loader = ValueNotifier( + const AsyncState.idle(), + ); @override void initState() { @@ -66,12 +68,12 @@ class PhoneticTranscriptionBuilderState isLoaded ? (_loader.value as AsyncLoaded).value : null; PhoneticTranscriptionRequest get _request => PhoneticTranscriptionRequest( - arc: LanguageArc( - l1: MatrixState.pangeaController.userController.userL1!, - l2: widget.textLanguage, - ), - content: PangeaTokenText.fromString(widget.text), - ); + arc: LanguageArc( + l1: MatrixState.pangeaController.userController.userL1!, + l2: widget.textLanguage, + ), + content: PangeaTokenText.fromString(widget.text), + ); Future _load() async { _loader.value = const AsyncState.loading(); @@ -84,8 +86,14 @@ class PhoneticTranscriptionBuilderState resp.isError ? _loader.value = AsyncState.error(resp.asError!.error) : _loader.value = AsyncState.loaded( - resp.asValue!.value.phoneticTranscriptionResult - .phoneticTranscription.first.phoneticL1Transcription.content, + resp + .asValue! + .value + .phoneticTranscriptionResult + .phoneticTranscription + .first + .phoneticL1Transcription + .content, ); } @@ -93,10 +101,7 @@ class PhoneticTranscriptionBuilderState Widget build(BuildContext context) { return ValueListenableBuilder( valueListenable: _loader, - builder: (context, _, __) => widget.builder( - context, - this, - ), + builder: (context, _, _) => widget.builder(context, this), ); } } diff --git a/lib/pangea/phonetic_transcription/phonetic_transcription_repo.dart b/lib/pangea/phonetic_transcription/phonetic_transcription_repo.dart index d7df0b778..76b3a3e66 100644 --- a/lib/pangea/phonetic_transcription/phonetic_transcription_repo.dart +++ b/lib/pangea/phonetic_transcription/phonetic_transcription_repo.dart @@ -54,9 +54,10 @@ class PhoneticTranscriptionRepo { static const Duration _cacheDuration = Duration(minutes: 10); static const Duration _storageDuration = Duration(days: 7); -// Persistent storage - static final GetStorage _storage = - GetStorage('phonetic_transcription_storage'); + // Persistent storage + static final GetStorage _storage = GetStorage( + 'phonetic_transcription_storage', + ); static Future> get( String accessToken, @@ -105,11 +106,7 @@ class PhoneticTranscriptionRepo { await _storage.write(key, item.toJson()); _cache.remove(key); // Invalidate in-memory cache } catch (e, s) { - ErrorHandler.logError( - e: e, - s: s, - data: {'request': request.toJson()}, - ); + ErrorHandler.logError(e: e, s: s, data: {'request': request.toJson()}); } } @@ -192,11 +189,7 @@ class PhoneticTranscriptionRepo { } return item.response; } catch (e, s) { - ErrorHandler.logError( - e: e, - s: s, - data: {'request': request.toJson()}, - ); + ErrorHandler.logError(e: e, s: s, data: {'request': request.toJson()}); _storage.remove(key); return null; } diff --git a/lib/pangea/phonetic_transcription/phonetic_transcription_request.dart b/lib/pangea/phonetic_transcription/phonetic_transcription_request.dart index 464193b01..f9e164f6f 100644 --- a/lib/pangea/phonetic_transcription/phonetic_transcription_request.dart +++ b/lib/pangea/phonetic_transcription/phonetic_transcription_request.dart @@ -15,8 +15,9 @@ class PhoneticTranscriptionRequest { factory PhoneticTranscriptionRequest.fromJson(Map json) { return PhoneticTranscriptionRequest( arc: LanguageArc.fromJson(json['arc'] as Map), - content: - PangeaTokenText.fromJson(json['content'] as Map), + content: PangeaTokenText.fromJson( + json['content'] as Map, + ), requiresTokenization: json['requires_tokenization'] ?? true, ); } diff --git a/lib/pangea/phonetic_transcription/phonetic_transcription_response.dart b/lib/pangea/phonetic_transcription/phonetic_transcription_response.dart index 612ef42c1..7512215b1 100644 --- a/lib/pangea/phonetic_transcription/phonetic_transcription_response.dart +++ b/lib/pangea/phonetic_transcription/phonetic_transcription_response.dart @@ -39,8 +39,9 @@ class PhoneticTranscriptionToken { factory PhoneticTranscriptionToken.fromJson(Map json) { return PhoneticTranscriptionToken( arc: LanguageArc.fromJson(json['arc'] as Map), - tokenL2: - PangeaTokenText.fromJson(json['token_l2'] as Map), + tokenL2: PangeaTokenText.fromJson( + json['token_l2'] as Map, + ), phoneticL1Transcription: PangeaTokenText.fromJson( json['phonetic_l1_transcription'] as Map, ), @@ -48,10 +49,10 @@ class PhoneticTranscriptionToken { } Map toJson() => { - 'arc': arc.toJson(), - 'token_l2': tokenL2.toJson(), - 'phonetic_l1_transcription': phoneticL1Transcription.toJson(), - }; + 'arc': arc.toJson(), + 'token_l2': tokenL2.toJson(), + 'phonetic_l1_transcription': phoneticL1Transcription.toJson(), + }; } class PhoneticTranscription { @@ -88,19 +89,20 @@ class PhoneticTranscription { } Map toJson() => { - 'arc': arc.toJson(), - 'transcription_l2': transcriptionL2.toJson(), - 'phonetic_transcription': - phoneticTranscription.map((e) => e.toJson()).toList(), - 'delim': delim.value, - }; + 'arc': arc.toJson(), + 'transcription_l2': transcriptionL2.toJson(), + 'phonetic_transcription': phoneticTranscription + .map((e) => e.toJson()) + .toList(), + 'delim': delim.value, + }; } class PhoneticTranscriptionResponse { final LanguageArc arc; final PangeaTokenText content; final Map - tokenization; // You can define a typesafe model if needed + tokenization; // You can define a typesafe model if needed final PhoneticTranscription phoneticTranscriptionResult; PhoneticTranscriptionResponse({ @@ -113,8 +115,9 @@ class PhoneticTranscriptionResponse { factory PhoneticTranscriptionResponse.fromJson(Map json) { return PhoneticTranscriptionResponse( arc: LanguageArc.fromJson(json['arc'] as Map), - content: - PangeaTokenText.fromJson(json['content'] as Map), + content: PangeaTokenText.fromJson( + json['content'] as Map, + ), tokenization: Map.from(json['tokenization'] as Map), phoneticTranscriptionResult: PhoneticTranscription.fromJson( json['phonetic_transcription_result'] as Map, diff --git a/lib/pangea/phonetic_transcription/phonetic_transcription_widget.dart b/lib/pangea/phonetic_transcription/phonetic_transcription_widget.dart index 8f5737125..ddbe72f29 100644 --- a/lib/pangea/phonetic_transcription/phonetic_transcription_widget.dart +++ b/lib/pangea/phonetic_transcription/phonetic_transcription_widget.dart @@ -70,8 +70,9 @@ class _PhoneticTranscriptionWidgetState return HoverBuilder( builder: (context, hovering) { return Tooltip( - message: - _isPlaying ? L10n.of(context).stop : L10n.of(context).playAudio, + message: _isPlaying + ? L10n.of(context).stop + : L10n.of(context).playAudio, child: GestureDetector( onTap: () => _handleAudioTap(targetId), child: AnimatedContainer( @@ -95,46 +96,46 @@ class _PhoneticTranscriptionWidgetState AsyncError(error: final error) => error is UnsubscribedException ? ErrorIndicator( - message: L10n.of(context) - .subscribeToUnlockTranscriptions, + message: L10n.of( + context, + ).subscribeToUnlockTranscriptions, onTap: () { MatrixState - .pangeaController.subscriptionController + .pangeaController + .subscriptionController .showPaywall(context); }, ) : ErrorIndicator( - message: - L10n.of(context).failedToFetchTranscription, + message: L10n.of( + context, + ).failedToFetchTranscription, ), AsyncLoaded(value: final transcription) => Row( - spacing: 8.0, - mainAxisSize: MainAxisSize.min, - children: [ - Flexible( - child: Text( - transcription, - textScaler: TextScaler.noScaling, - style: widget.style ?? - Theme.of(context).textTheme.bodyMedium, - maxLines: widget.maxLines, - overflow: TextOverflow.ellipsis, - ), + spacing: 8.0, + mainAxisSize: MainAxisSize.min, + children: [ + Flexible( + child: Text( + transcription, + textScaler: TextScaler.noScaling, + style: + widget.style ?? + Theme.of(context).textTheme.bodyMedium, + maxLines: widget.maxLines, + overflow: TextOverflow.ellipsis, ), - Icon( - _isPlaying - ? Icons.pause_outlined - : Icons.volume_up, - size: widget.iconSize ?? 24, - color: widget.iconColor ?? - Theme.of(context).iconTheme.color, - ), - ], - ), - _ => const TextLoadingShimmer( - width: 125.0, - height: 20.0, - ), + ), + Icon( + _isPlaying ? Icons.pause_outlined : Icons.volume_up, + size: widget.iconSize ?? 24, + color: + widget.iconColor ?? + Theme.of(context).iconTheme.color, + ), + ], + ), + _ => const TextLoadingShimmer(width: 125.0, height: 20.0), }; }, ), diff --git a/lib/pangea/practice_activities/activity_type_enum.dart b/lib/pangea/practice_activities/activity_type_enum.dart index b8e493d9d..366a8fb9d 100644 --- a/lib/pangea/practice_activities/activity_type_enum.dart +++ b/lib/pangea/practice_activities/activity_type_enum.dart @@ -119,25 +119,13 @@ enum ActivityTypeEnum { ConstructUseTypeEnum.ignMM, ]; case ActivityTypeEnum.lemmaAudio: - return [ - ConstructUseTypeEnum.corLA, - ConstructUseTypeEnum.incLA, - ]; + return [ConstructUseTypeEnum.corLA, ConstructUseTypeEnum.incLA]; case ActivityTypeEnum.lemmaMeaning: - return [ - ConstructUseTypeEnum.corLM, - ConstructUseTypeEnum.incLM, - ]; + return [ConstructUseTypeEnum.corLM, ConstructUseTypeEnum.incLM]; case ActivityTypeEnum.grammarCategory: - return [ - ConstructUseTypeEnum.corGC, - ConstructUseTypeEnum.incGC, - ]; + return [ConstructUseTypeEnum.corGC, ConstructUseTypeEnum.incGC]; case ActivityTypeEnum.grammarError: - return [ - ConstructUseTypeEnum.corGE, - ConstructUseTypeEnum.incGE, - ]; + return [ConstructUseTypeEnum.corGE, ConstructUseTypeEnum.incGE]; } } @@ -238,21 +226,21 @@ enum ActivityTypeEnum { } static List get practiceTypes => [ - ActivityTypeEnum.emoji, - ActivityTypeEnum.wordMeaning, - ActivityTypeEnum.wordFocusListening, - ActivityTypeEnum.morphId, - ]; + ActivityTypeEnum.emoji, + ActivityTypeEnum.wordMeaning, + ActivityTypeEnum.wordFocusListening, + ActivityTypeEnum.morphId, + ]; static List get _vocabPracticeTypes => [ - ActivityTypeEnum.lemmaMeaning, - // ActivityTypeEnum.lemmaAudio, - ]; + ActivityTypeEnum.lemmaMeaning, + // ActivityTypeEnum.lemmaAudio, + ]; static List get _grammarPracticeTypes => [ - ActivityTypeEnum.grammarCategory, - ActivityTypeEnum.grammarError, - ]; + ActivityTypeEnum.grammarCategory, + ActivityTypeEnum.grammarError, + ]; static List analyticsPracticeTypes( ConstructTypeEnum constructType, diff --git a/lib/pangea/practice_activities/emoji_activity_generator.dart b/lib/pangea/practice_activities/emoji_activity_generator.dart index 5b8881a5a..29ec38d7c 100644 --- a/lib/pangea/practice_activities/emoji_activity_generator.dart +++ b/lib/pangea/practice_activities/emoji_activity_generator.dart @@ -42,8 +42,9 @@ class EmojiActivityGenerator { .map((token) => token.vocabConstructID.getLemmaInfo(messageInfo)) .toList(); - final List> lemmaInfos = - await Future.wait(lemmaInfoFutures); + final List> lemmaInfos = await Future.wait( + lemmaInfoFutures, + ); for (int i = 0; i < missingEmojis.length; i++) { if (lemmaInfos[i].isError) { @@ -51,11 +52,10 @@ class EmojiActivityGenerator { } final e = lemmaInfos[i].asValue!.value.emoji.firstWhere( - (e) => !usedEmojis.contains(e), - orElse: () => throw Exception( - "Not enough unique emojis for tokens in message", - ), - ); + (e) => !usedEmojis.contains(e), + orElse: () => + throw Exception("Not enough unique emojis for tokens in message"), + ); final token = missingEmojis[i]; matchInfo[token.vocabForm] ??= []; @@ -67,9 +67,7 @@ class EmojiActivityGenerator { activity: EmojiPracticeActivityModel( tokens: req.target.tokens, langCode: req.userL2, - matchContent: PracticeMatchActivity( - matchInfo: matchInfo, - ), + matchContent: PracticeMatchActivity(matchInfo: matchInfo), ), ); } diff --git a/lib/pangea/practice_activities/lemma_activity_generator.dart b/lib/pangea/practice_activities/lemma_activity_generator.dart index 83ff095de..a42322e04 100644 --- a/lib/pangea/practice_activities/lemma_activity_generator.dart +++ b/lib/pangea/practice_activities/lemma_activity_generator.dart @@ -11,9 +11,7 @@ import 'package:fluffychat/pangea/practice_activities/practice_activity_model.da import 'package:fluffychat/widgets/matrix.dart'; class LemmaActivityGenerator { - static Future get( - MessageActivityRequest req, - ) async { + static Future get(MessageActivityRequest req) async { debugger(when: kDebugMode && req.target.tokens.length != 1); final token = req.target.tokens.first; @@ -36,16 +34,17 @@ class LemmaActivityGenerator { PangeaToken token, ) async { final constructs = await MatrixState - .pangeaController.matrixState.analyticsDataService + .pangeaController + .matrixState + .analyticsDataService .getAggregatedConstructs(ConstructTypeEnum.vocab); final List constructIds = constructs.keys.toList(); // Offload computation to an isolate - final Map distances = - await compute(_computeDistancesInIsolate, { - 'lemmas': constructIds, - 'target': token.lemma.text, - }); + final Map distances = await compute( + _computeDistancesInIsolate, + {'lemmas': constructIds, 'target': token.lemma.text}, + ); // Sort lemmas by distance final sortedLemmas = distances.keys.toList() @@ -69,8 +68,9 @@ class LemmaActivityGenerator { } // Ensure the target lemma (token.vocabConstructID) is included while keeping unique lemma texts - final int existingIndex = uniqueByLemma - .indexWhere((c) => c.lemma == token.vocabConstructID.lemma); + final int existingIndex = uniqueByLemma.indexWhere( + (c) => c.lemma == token.vocabConstructID.lemma, + ); if (existingIndex >= 0) { uniqueByLemma[existingIndex] = token.vocabConstructID; } else { @@ -119,9 +119,13 @@ class LemmaActivityGenerator { } else if (s[i - 1] == t[j - 1]) { dp[i][j] = dp[i - 1][j - 1]; } else { - dp[i][j] = 1 + - [dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]] - .reduce((a, b) => a < b ? a : b); + dp[i][j] = + 1 + + [ + dp[i - 1][j], + dp[i][j - 1], + dp[i - 1][j - 1], + ].reduce((a, b) => a < b ? a : b); } } } diff --git a/lib/pangea/practice_activities/lemma_meaning_activity_generator.dart b/lib/pangea/practice_activities/lemma_meaning_activity_generator.dart index 3e32611b0..c5e30baa8 100644 --- a/lib/pangea/practice_activities/lemma_meaning_activity_generator.dart +++ b/lib/pangea/practice_activities/lemma_meaning_activity_generator.dart @@ -15,12 +15,14 @@ class LemmaMeaningActivityGenerator { required Map messageInfo, }) async { final List>> lemmaInfoFutures = req - .target.tokens + .target + .tokens .map((token) => token.vocabConstructID.getLemmaInfo(messageInfo)) .toList(); - final List> lemmaInfos = - await Future.wait(lemmaInfoFutures); + final List> lemmaInfos = await Future.wait( + lemmaInfoFutures, + ); if (lemmaInfos.any((result) => result.isError)) { throw lemmaInfos.firstWhere((result) => result.isError).error!; @@ -35,9 +37,7 @@ class LemmaMeaningActivityGenerator { activity: LemmaMeaningPracticeActivityModel( tokens: req.target.tokens, langCode: req.userL2, - matchContent: PracticeMatchActivity( - matchInfo: matchInfo, - ), + matchContent: PracticeMatchActivity(matchInfo: matchInfo), ), ); } diff --git a/lib/pangea/practice_activities/message_activity_request.dart b/lib/pangea/practice_activities/message_activity_request.dart index ec6a9e491..4657b364a 100644 --- a/lib/pangea/practice_activities/message_activity_request.dart +++ b/lib/pangea/practice_activities/message_activity_request.dart @@ -147,9 +147,7 @@ class MessageActivityRequest { class MessageActivityResponse { final PracticeActivityModel activity; - MessageActivityResponse({ - required this.activity, - }); + MessageActivityResponse({required this.activity}); factory MessageActivityResponse.fromJson(Map json) { if (!json.containsKey('activity')) { diff --git a/lib/pangea/practice_activities/morph_activity_generator.dart b/lib/pangea/practice_activities/morph_activity_generator.dart index 0c2e2bf5b..2e5ed1690 100644 --- a/lib/pangea/practice_activities/morph_activity_generator.dart +++ b/lib/pangea/practice_activities/morph_activity_generator.dart @@ -14,9 +14,7 @@ typedef POSActivitySequence = List; class MorphActivityGenerator { /// Generate a morphological activity for a given token and morphological feature - static MessageActivityResponse get( - MessageActivityRequest req, - ) { + static MessageActivityResponse get(MessageActivityRequest req) { debugger(when: kDebugMode && req.target.tokens.length != 1); debugger(when: kDebugMode && req.target.morphFeature == null); diff --git a/lib/pangea/practice_activities/multiple_choice_activity_model.dart b/lib/pangea/practice_activities/multiple_choice_activity_model.dart index 8ab9119b2..f715185a8 100644 --- a/lib/pangea/practice_activities/multiple_choice_activity_model.dart +++ b/lib/pangea/practice_activities/multiple_choice_activity_model.dart @@ -9,10 +9,7 @@ class MultipleChoiceActivity { final Set choices; final Set answers; - MultipleChoiceActivity({ - required this.choices, - required this.answers, - }); + MultipleChoiceActivity({required this.choices, required this.answers}); Color choiceColor(String value) => answers.contains(value) ? AppConfig.success : AppConfig.warning; @@ -35,10 +32,7 @@ class MultipleChoiceActivity { } Map toJson() { - return { - 'choices': List.from(choices), - 'answer': List.from(answers), - }; + return {'choices': List.from(choices), 'answer': List.from(answers)}; } // ovveride operator == and hashCode diff --git a/lib/pangea/practice_activities/practice_activity_model.dart b/lib/pangea/practice_activities/practice_activity_model.dart index eddbdacf1..f185c6760 100644 --- a/lib/pangea/practice_activities/practice_activity_model.dart +++ b/lib/pangea/practice_activities/practice_activity_model.dart @@ -15,21 +15,18 @@ sealed class PracticeActivityModel { final List tokens; final String langCode; - const PracticeActivityModel({ - required this.tokens, - required this.langCode, - }); + const PracticeActivityModel({required this.tokens, required this.langCode}); String get storageKey => '${activityType.name}-${tokens.map((e) => e.text.content).join("-")}'; PracticeTarget get practiceTarget => PracticeTarget( - activityType: activityType, - tokens: tokens, - morphFeature: this is MorphPracticeActivityModel - ? (this as MorphPracticeActivityModel).morphFeature - : null, - ); + activityType: activityType, + tokens: tokens, + morphFeature: this is MorphPracticeActivityModel + ? (this as MorphPracticeActivityModel).morphFeature + : null, + ); ActivityTypeEnum get activityType { switch (this) { @@ -56,27 +53,21 @@ sealed class PracticeActivityModel { factory PracticeActivityModel.fromJson(Map json) { if (json['lang_code'] is! String) { - Sentry.addBreadcrumb( - Breadcrumb(data: {"json": json}), - ); + Sentry.addBreadcrumb(Breadcrumb(data: {"json": json})); throw ("lang_code is not a string in PracticeActivityModel.fromJson"); } final targetConstructsEntry = json['tgt_constructs'] ?? json['target_constructs']; if (targetConstructsEntry is! List) { - Sentry.addBreadcrumb( - Breadcrumb(data: {"json": json}), - ); + Sentry.addBreadcrumb(Breadcrumb(data: {"json": json})); throw ("tgt_constructs is not a list in PracticeActivityModel.fromJson"); } final type = ActivityTypeEnum.fromString(json['activity_type']); final morph = json['morph_feature'] != null - ? MorphFeaturesEnumExtension.fromString( - json['morph_feature'] as String, - ) + ? MorphFeaturesEnumExtension.fromString(json['morph_feature'] as String) : null; final tokens = (json['target_tokens'] as List) @@ -233,17 +224,15 @@ sealed class MultipleChoicePracticeActivityModel extends PracticeActivityModel { OneConstructUse constructUse(String choiceContent) { final correct = multipleChoiceContent.isCorrect(choiceContent); - final useType = - correct ? activityType.correctUse : activityType.incorrectUse; + final useType = correct + ? activityType.correctUse + : activityType.incorrectUse; final token = tokens.first; return OneConstructUse( useType: useType, constructType: ConstructTypeEnum.vocab, - metadata: ConstructUseMetaData( - roomId: null, - timeStamp: DateTime.now(), - ), + metadata: ConstructUseMetaData(roomId: null, timeStamp: DateTime.now()), category: token.pos, lemma: token.lemma.text, form: token.lemma.text, @@ -268,10 +257,7 @@ sealed class MatchPracticeActivityModel extends PracticeActivityModel { required this.matchContent, }); - bool isCorrect( - PangeaToken token, - String choice, - ) => + bool isCorrect(PangeaToken token, String choice) => matchContent.matchInfo[token.vocabForm]!.contains(choice); @override @@ -319,17 +305,15 @@ class MorphCategoryPracticeActivityModel extends MorphPracticeActivityModel { OneConstructUse constructUse(String choiceContent) { final correct = multipleChoiceContent.isCorrect(choiceContent); final token = tokens.first; - final useType = - correct ? activityType.correctUse : activityType.incorrectUse; + final useType = correct + ? activityType.correctUse + : activityType.incorrectUse; final tag = token.getMorphTag(morphFeature)!; return OneConstructUse( useType: useType, constructType: ConstructTypeEnum.morph, - metadata: ConstructUseMetaData( - roomId: null, - timeStamp: DateTime.now(), - ), + metadata: ConstructUseMetaData(roomId: null, timeStamp: DateTime.now()), category: morphFeature.name, lemma: tag, form: token.lemma.form, diff --git a/lib/pangea/practice_activities/practice_choice.dart b/lib/pangea/practice_activities/practice_choice.dart index b5b9a4c9d..64806d392 100644 --- a/lib/pangea/practice_activities/practice_choice.dart +++ b/lib/pangea/practice_activities/practice_choice.dart @@ -7,10 +7,7 @@ class PracticeChoice { /// Form of the associated token final ConstructForm form; - PracticeChoice({ - required this.choiceContent, - required this.form, - }); + PracticeChoice({required this.choiceContent, required this.form}); @override bool operator ==(Object other) { diff --git a/lib/pangea/practice_activities/practice_generation_repo.dart b/lib/pangea/practice_activities/practice_generation_repo.dart index 35a961940..4fd9a1148 100644 --- a/lib/pangea/practice_activities/practice_generation_repo.dart +++ b/lib/pangea/practice_activities/practice_generation_repo.dart @@ -32,26 +32,24 @@ class _RequestCacheItem { final PracticeActivityModel practiceActivity; final DateTime timestamp; - _RequestCacheItem({ - required this.practiceActivity, - required this.timestamp, - }); + _RequestCacheItem({required this.practiceActivity, required this.timestamp}); bool get isExpired => DateTime.now().difference(timestamp) > PracticeRepo._cacheDuration; factory _RequestCacheItem.fromJson(Map json) { return _RequestCacheItem( - practiceActivity: - PracticeActivityModel.fromJson(json['practiceActivity']), + practiceActivity: PracticeActivityModel.fromJson( + json['practiceActivity'], + ), timestamp: DateTime.parse(json['timestamp']), ); } Map toJson() => { - 'practiceActivity': practiceActivity.toJson(), - 'timestamp': timestamp.toIso8601String(), - }; + 'practiceActivity': practiceActivity.toJson(), + 'timestamp': timestamp.toIso8601String(), + }; } /// Controller for handling activity completions. @@ -144,16 +142,11 @@ class PracticeRepo { case ActivityTypeEnum.wordFocusListening: return WordFocusListeningGenerator.get(req); case ActivityTypeEnum.hiddenWordListening: - return _fetch( - accessToken: accessToken, - requestModel: req, - ); + return _fetch(accessToken: accessToken, requestModel: req); } } - static PracticeActivityModel? _getCached( - MessageActivityRequest req, - ) { + static PracticeActivityModel? _getCached(MessageActivityRequest req) { final keys = List.from(_storage.getKeys()); for (final k in keys) { try { @@ -180,12 +173,11 @@ class PracticeRepo { static Future _setCached( MessageActivityRequest req, MessageActivityResponse res, - ) => - _storage.write( - req.hashCode.toString(), - _RequestCacheItem( - practiceActivity: res.activity, - timestamp: DateTime.now(), - ).toJson(), - ); + ) => _storage.write( + req.hashCode.toString(), + _RequestCacheItem( + practiceActivity: res.activity, + timestamp: DateTime.now(), + ).toJson(), + ); } diff --git a/lib/pangea/practice_activities/practice_match.dart b/lib/pangea/practice_activities/practice_match.dart index e621f6978..84ae13be5 100644 --- a/lib/pangea/practice_activities/practice_match.dart +++ b/lib/pangea/practice_activities/practice_match.dart @@ -12,21 +12,15 @@ class PracticeMatchActivity { List choices = List.empty(growable: true); - PracticeMatchActivity({ - required this.matchInfo, - }) { + PracticeMatchActivity({required this.matchInfo}) { for (final ith in matchInfo.entries) { - debugPrint( - 'Construct: ${ith.key.form}, Forms: ${ith.value}', - ); + debugPrint('Construct: ${ith.key.form}, Forms: ${ith.value}'); } final List usedForms = []; for (final matchEntry in matchInfo.entries) { if (matchEntry.value.isEmpty) { - throw Exception( - "No forms available for construct ${matchEntry.key}", - ); + throw Exception("No forms available for construct ${matchEntry.key}"); } final String choiceContent = matchEntry.value.firstWhere( @@ -37,10 +31,7 @@ class PracticeMatchActivity { ); choices.add( - PracticeChoice( - choiceContent: choiceContent, - form: matchEntry.key, - ), + PracticeChoice(choiceContent: choiceContent, form: matchEntry.key), ); usedForms.add(choiceContent); @@ -58,28 +49,22 @@ class PracticeMatchActivity { final Map> matchInfo = {}; for (final constructJson in json['match_info']) { final ConstructForm cId = ConstructForm.fromJson(constructJson['cId']); - final List surfaceForms = - List.from(constructJson['forms']); + final List surfaceForms = List.from( + constructJson['forms'], + ); matchInfo[cId] = surfaceForms; } - return PracticeMatchActivity( - matchInfo: matchInfo, - ); + return PracticeMatchActivity(matchInfo: matchInfo); } Map toJson() { final List> matchInfo = []; for (final cId in this.matchInfo.keys) { - matchInfo.add({ - 'cId': cId.toJson(), - 'forms': this.matchInfo[cId], - }); + matchInfo.add({'cId': cId.toJson(), 'forms': this.matchInfo[cId]}); } - return { - 'match_info': matchInfo, - }; + return {'match_info': matchInfo}; } @override diff --git a/lib/pangea/practice_activities/practice_record.dart b/lib/pangea/practice_activities/practice_record.dart index 61e8e2d55..9e2ba338a 100644 --- a/lib/pangea/practice_activities/practice_record.dart +++ b/lib/pangea/practice_activities/practice_record.dart @@ -27,9 +27,7 @@ class PracticeRecord { } } - factory PracticeRecord.fromJson( - Map json, - ) { + factory PracticeRecord.fromJson(Map json) { return PracticeRecord( responses: (json['responses'] as List) .map( @@ -43,9 +41,7 @@ class PracticeRecord { } Map toJson() { - return { - 'responses': responses.map((e) => e.toJson()).toList(), - }; + return {'responses': responses.map((e) => e.toJson()).toList()}; } int get completeResponses => @@ -61,13 +57,8 @@ class PracticeRecord { return responses[responses.length - 1]; } - bool alreadyHasMatchResponse( - ConstructIdentifier cId, - String text, - ) => - responses.any( - (element) => element.cId == cId && element.text == text, - ); + bool alreadyHasMatchResponse(ConstructIdentifier cId, String text) => + responses.any((element) => element.cId == cId && element.text == text); /// [target] needed for saving the record, little funky /// [cId] identifies the construct in the case of match activities which have multiple diff --git a/lib/pangea/practice_activities/practice_record_repo.dart b/lib/pangea/practice_activities/practice_record_repo.dart index 431ceda4f..9aecd0f8d 100644 --- a/lib/pangea/practice_activities/practice_record_repo.dart +++ b/lib/pangea/practice_activities/practice_record_repo.dart @@ -5,10 +5,7 @@ class _PracticeRecordCacheEntry { final PracticeRecord record; final DateTime timestamp; - _PracticeRecordCacheEntry({ - required this.record, - required this.timestamp, - }); + _PracticeRecordCacheEntry({required this.record, required this.timestamp}); bool get isExpired => DateTime.now().difference(timestamp).inMinutes > 15; } @@ -17,9 +14,7 @@ class _PracticeRecordCacheEntry { class PracticeRecordRepo { static final Map _cache = {}; - static PracticeRecord get( - PracticeTarget target, - ) { + static PracticeRecord get(PracticeTarget target) { final cached = _getCached(target); if (cached != null) return cached; @@ -29,15 +24,10 @@ class PracticeRecordRepo { return entry; } - static void set( - PracticeTarget selection, - PracticeRecord entry, - ) => + static void set(PracticeTarget selection, PracticeRecord entry) => _setCached(selection, entry); - static PracticeRecord? _getCached( - PracticeTarget target, - ) { + static PracticeRecord? _getCached(PracticeTarget target) { final keys = List.from(_cache.keys); for (final k in keys) { final item = _cache[k]!; @@ -49,10 +39,7 @@ class PracticeRecordRepo { return _cache[target.storageKey]?.record; } - static void _setCached( - PracticeTarget target, - PracticeRecord entry, - ) { + static void _setCached(PracticeTarget target, PracticeRecord entry) { _cache[target.storageKey] = _PracticeRecordCacheEntry( record: entry, timestamp: DateTime.now(), diff --git a/lib/pangea/practice_activities/practice_selection.dart b/lib/pangea/practice_activities/practice_selection.dart index 39a28c782..b39c6872b 100644 --- a/lib/pangea/practice_activities/practice_selection.dart +++ b/lib/pangea/practice_activities/practice_selection.dart @@ -17,22 +17,17 @@ class PracticeSelection { PracticeTarget? getTarget(ActivityTypeEnum type) => activities(type).firstOrNull; - PracticeTarget? getMorphTarget( - PangeaToken t, - MorphFeaturesEnum morph, - ) => + PracticeTarget? getMorphTarget(PangeaToken t, MorphFeaturesEnum morph) => activities(ActivityTypeEnum.morphId).firstWhereOrNull( (entry) => entry.tokens.contains(t) && entry.morphFeature == morph, ); Map toJson() => { - 'activityQueue': _activityQueue.map( - (key, value) => MapEntry( - key.toString(), - value.map((e) => e.toJson()).toList(), - ), - ), - }; + 'activityQueue': _activityQueue.map( + (key, value) => + MapEntry(key.toString(), value.map((e) => e.toJson()).toList()), + ), + }; static PracticeSelection fromJson(Map json) { return PracticeSelection( diff --git a/lib/pangea/practice_activities/practice_selection_repo.dart b/lib/pangea/practice_activities/practice_selection_repo.dart index 31afe6a76..c677cfe8b 100644 --- a/lib/pangea/practice_activities/practice_selection_repo.dart +++ b/lib/pangea/practice_activities/practice_selection_repo.dart @@ -19,9 +19,9 @@ class _PracticeSelectionCacheEntry { bool get isExpired => DateTime.now().difference(timestamp).inDays > 1; Map toJson() => { - 'selection': selection.toJson(), - 'timestamp': timestamp.toIso8601String(), - }; + 'selection': selection.toJson(), + 'timestamp': timestamp.toIso8601String(), + }; factory _PracticeSelectionCacheEntry.fromJson(Map json) { return _PracticeSelectionCacheEntry( @@ -47,10 +47,7 @@ class PracticeSelectionRepo { final cached = _getCached(eventId); if (cached != null) return cached; - final newEntry = await _fetch( - tokens: tokens, - langCode: messageLanguage, - ); + final newEntry = await _fetch(tokens: tokens, langCode: messageLanguage); _setCached(eventId, newEntry); return newEntry; @@ -74,9 +71,7 @@ class PracticeSelectionRepo { return selection; } - static PracticeSelection? _getCached( - String eventId, - ) { + static PracticeSelection? _getCached(String eventId) { try { final keys = List.from(_storage.getKeys()); for (final String key in keys) { @@ -105,10 +100,7 @@ class PracticeSelectionRepo { } } - static void _setCached( - String eventId, - PracticeSelection entry, - ) { + static void _setCached(String eventId, PracticeSelection entry) { final cachedEntry = _PracticeSelectionCacheEntry( selection: entry, timestamp: DateTime.now(), @@ -131,16 +123,14 @@ class PracticeSelectionRepo { PangeaToken b, int aScore, int bScore, - ) => - bScore.compareTo(aScore); + ) => bScore.compareTo(aScore); static int _sortMorphTargets( PracticeTarget a, PracticeTarget b, int aScore, int bScore, - ) => - bScore.compareTo(aScore); + ) => bScore.compareTo(aScore); static List _tokenToMorphTargets(PangeaToken t) { return t.morphsBasicallyEligibleForPracticeByPriority @@ -176,10 +166,7 @@ class PracticeSelectionRepo { return []; } - final scores = await _fetchPriorityScores( - practiceTokens, - activityType, - ); + final scores = await _fetchPriorityScores(practiceTokens, activityType); practiceTokens.sort((a, b) => _sortTokens(a, b, scores[a]!, scores[b]!)); practiceTokens = practiceTokens.take(8).toList(); @@ -231,21 +218,23 @@ class PracticeSelectionRepo { } final ids = tokens.map((t) => t.vocabConstructID).toList(); - final idMap = { - for (final token in tokens) token: token.vocabConstructID, - }; + final idMap = {for (final token in tokens) token: token.vocabConstructID}; final constructs = await MatrixState - .pangeaController.matrixState.analyticsDataService + .pangeaController + .matrixState + .analyticsDataService .getConstructUses(ids); for (final token in tokens) { final construct = constructs[idMap[token]]; - final lastUsed = - construct?.lastUseByTypes(activityType.associatedUseTypes); + final lastUsed = construct?.lastUseByTypes( + activityType.associatedUseTypes, + ); - final daysSinceLastUsed = - lastUsed == null ? 20 : DateTime.now().difference(lastUsed).inDays; + final daysSinceLastUsed = lastUsed == null + ? 20 + : DateTime.now().difference(lastUsed).inDays; scores[token] = daysSinceLastUsed * (token.vocabConstructID.isContentWord ? 10 : 9); diff --git a/lib/pangea/practice_activities/practice_target.dart b/lib/pangea/practice_activities/practice_target.dart index 87c1ce7e7..4b4bc8de5 100644 --- a/lib/pangea/practice_activities/practice_target.dart +++ b/lib/pangea/practice_activities/practice_target.dart @@ -59,8 +59,9 @@ class PracticeTarget { } return PracticeTarget( - tokens: - (json['tokens'] as List).map((e) => PangeaToken.fromJson(e)).toList(), + tokens: (json['tokens'] as List) + .map((e) => PangeaToken.fromJson(e)) + .toList(), activityType: type, morphFeature: json['morphFeature'] == null ? null diff --git a/lib/pangea/practice_activities/word_focus_listening_generator.dart b/lib/pangea/practice_activities/word_focus_listening_generator.dart index 0511b6fdb..4946de532 100644 --- a/lib/pangea/practice_activities/word_focus_listening_generator.dart +++ b/lib/pangea/practice_activities/word_focus_listening_generator.dart @@ -4,9 +4,7 @@ import 'package:fluffychat/pangea/practice_activities/practice_activity_model.da import 'package:fluffychat/pangea/practice_activities/practice_match.dart'; class WordFocusListeningGenerator { - static MessageActivityResponse get( - MessageActivityRequest req, - ) { + static MessageActivityResponse get(MessageActivityRequest req) { if (req.target.tokens.length <= 1) { throw Exception( "Word focus listening activity requires at least 2 tokens", diff --git a/lib/pangea/space_analytics/analytics_request_indicator.dart b/lib/pangea/space_analytics/analytics_request_indicator.dart index 6b9d854a8..b57f5fce1 100644 --- a/lib/pangea/space_analytics/analytics_request_indicator.dart +++ b/lib/pangea/space_analytics/analytics_request_indicator.dart @@ -14,10 +14,7 @@ import 'package:fluffychat/widgets/future_loading_dialog.dart'; class AnalyticsRequestIndicator extends StatefulWidget { final Room room; - const AnalyticsRequestIndicator({ - super.key, - required this.room, - }); + const AnalyticsRequestIndicator({super.key, required this.room}); @override AnalyticsRequestIndicatorState createState() => @@ -62,8 +59,9 @@ class AnalyticsRequestIndicatorState extends State { final analyticsRoomIds = analyticsRooms.map((r) => r.id).toSet(); _analyticsRoomSub?.cancel(); _analyticsRoomSub = widget.room.client.onSync.stream.listen((update) async { - final joined = update.rooms?.join?.entries - .where((e) => analyticsRoomIds.contains(e.key)); + final joined = update.rooms?.join?.entries.where( + (e) => analyticsRoomIds.contains(e.key), + ); if (joined == null || joined.isEmpty) return; final Set updatedRoomIds = {}; @@ -155,14 +153,9 @@ class AnalyticsRequestIndicatorState extends State { child: _knockingAdmins.isEmpty ? const SizedBox() : Padding( - padding: const EdgeInsets.symmetric( - horizontal: 4, - vertical: 1, - ), + padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 1), child: Material( - borderRadius: BorderRadius.circular( - AppConfig.borderRadius, - ), + borderRadius: BorderRadius.circular(AppConfig.borderRadius), clipBehavior: Clip.hardEdge, child: ListTile( minVerticalPadding: 0, diff --git a/lib/pangea/space_analytics/analytics_requests_repo.dart b/lib/pangea/space_analytics/analytics_requests_repo.dart index 2c3b39ffd..01a4816a5 100644 --- a/lib/pangea/space_analytics/analytics_requests_repo.dart +++ b/lib/pangea/space_analytics/analytics_requests_repo.dart @@ -7,22 +7,16 @@ class _AnalyticsRequestEntry { final RequestStatus status; final DateTime timestamp; - _AnalyticsRequestEntry({ - required this.status, - required this.timestamp, - }); + _AnalyticsRequestEntry({required this.status, required this.timestamp}); Map toJson() { - return { - 'status': status.name, - 'timestamp': timestamp.toIso8601String(), - }; + return {'status': status.name, 'timestamp': timestamp.toIso8601String()}; } _AnalyticsRequestEntry.fromJson(Map json) - : status = RequestStatus.fromString(json['status']) ?? - RequestStatus.unrequested, - timestamp = DateTime.parse(json['timestamp']); + : status = + RequestStatus.fromString(json['status']) ?? RequestStatus.unrequested, + timestamp = DateTime.parse(json['timestamp']); bool get isExpired { final now = DateTime.now(); @@ -32,8 +26,9 @@ class _AnalyticsRequestEntry { } class AnalyticsRequestsRepo { - static final GetStorage _requestStorage = - GetStorage('analytics_request_storage'); + static final GetStorage _requestStorage = GetStorage( + 'analytics_request_storage', + ); static String _storageKey(String userId, LanguageModel language) { return 'analytics_request_${userId}_${language.langCodeShort}'; @@ -87,10 +82,7 @@ class AnalyticsRequestsRepo { await _requestStorage.write(key, entry.toJson()); } - static Future remove( - String userId, - LanguageModel language, - ) async { + static Future remove(String userId, LanguageModel language) async { final key = _storageKey(userId, language); await _requestStorage.remove(key); } diff --git a/lib/pangea/space_analytics/download_space_analytics_dialog.dart b/lib/pangea/space_analytics/download_space_analytics_dialog.dart index cae1175f3..b709ba019 100644 --- a/lib/pangea/space_analytics/download_space_analytics_dialog.dart +++ b/lib/pangea/space_analytics/download_space_analytics_dialog.dart @@ -124,11 +124,7 @@ class DownloadAnalyticsDialogState extends State { }); } } catch (e, s) { - ErrorHandler.logError( - e: e, - s: s, - data: {}, - ); + ErrorHandler.logError(e: e, s: s, data: {}); _clean(); _error = e; @@ -146,11 +142,7 @@ class DownloadAnalyticsDialogState extends State { final fileName = "analytics_${widget.space.name}_${DateTime.now().toIso8601String()}.${_downloadType == DownloadType.xlsx ? 'xlsx' : 'csv'}"; - await DownloadUtil.downloadFile( - content, - fileName, - DownloadType.csv, - ); + await DownloadUtil.downloadFile(content, fileName, DownloadType.csv); } Future _getAnalyticsModel( @@ -180,22 +172,14 @@ class DownloadAnalyticsDialogState extends State { ); if (mounted) setState(() => _downloadStatuses[userID] = 2); } catch (e, s) { - ErrorHandler.logError( - e: e, - s: s, - data: { - "userID": userID, - }, - ); + ErrorHandler.logError(e: e, s: s, data: {"userID": userID}); if (mounted) setState(() => _downloadStatuses[userID] = -2); } return summary; } - List _formatExcelRow( - SpaceAnalyticsSummaryModel summary, - ) { + List _formatExcelRow(SpaceAnalyticsSummaryModel summary) { final List row = []; for (int i = 0; i < SpaceAnalyticsSummaryEnum.values.length; i++) { final key = SpaceAnalyticsSummaryEnum.values[i]; @@ -211,21 +195,16 @@ class DownloadAnalyticsDialogState extends State { return row; } - List _getExcelFileContent( - List summaries, - ) { + List _getExcelFileContent(List summaries) { final excel = Excel.createExcel(); final sheet = excel['Sheet1']; for (final key in SpaceAnalyticsSummaryEnum.values) { sheet - .cell( - CellIndex.indexByColumnRow( - rowIndex: 0, - columnIndex: key.index, - ), - ) - .value = TextCellValue(key.header(L10n.of(context))); + .cell(CellIndex.indexByColumnRow(rowIndex: 0, columnIndex: key.index)) + .value = TextCellValue( + key.header(L10n.of(context)), + ); } final rows = summaries.map((summary) => _formatExcelRow(summary)).toList(); @@ -235,16 +214,17 @@ class DownloadAnalyticsDialogState extends State { for (int j = 0; j < row.length; j++) { final cell = row[j]; sheet - .cell(CellIndex.indexByColumnRow(rowIndex: i + 2, columnIndex: j)) - .value = cell; + .cell( + CellIndex.indexByColumnRow(rowIndex: i + 2, columnIndex: j), + ) + .value = + cell; } } return excel.encode() ?? []; } - String _getCSVFileContent( - List summaries, - ) { + String _getCSVFileContent(List summaries) { final List> rows = []; final headerRow = []; for (final key in SpaceAnalyticsSummaryEnum.values) { @@ -280,9 +260,7 @@ class DownloadAnalyticsDialogState extends State { Widget build(BuildContext context) { return Dialog( child: Container( - constraints: const BoxConstraints( - maxWidth: 400, - ), + constraints: const BoxConstraints(maxWidth: 400), padding: const EdgeInsets.symmetric(vertical: 20), child: Column( mainAxisSize: MainAxisSize.min, @@ -290,7 +268,8 @@ class DownloadAnalyticsDialogState extends State { Text( L10n.of(context).fileType, style: TextStyle( - fontSize: AppSettings.fontSizeFactor.value * + fontSize: + AppSettings.fontSizeFactor.value * AppConfig.messageFontSize, ), ), @@ -314,10 +293,7 @@ class DownloadAnalyticsDialogState extends State { Padding( padding: const EdgeInsets.all(8.0), child: ConstrainedBox( - constraints: const BoxConstraints( - maxHeight: 300, - minHeight: 0, - ), + constraints: const BoxConstraints(maxHeight: 300, minHeight: 0), child: ListView.builder( shrinkWrap: true, itemCount: widget.analyticsRooms.length, @@ -342,10 +318,7 @@ class DownloadAnalyticsDialogState extends State { width: 40, height: 30, child: (_downloadStatuses[userId] ?? 0) < 0 - ? const Icon( - Icons.error_outline, - size: 16, - ) + ? const Icon(Icons.error_outline, size: 16) : Center( child: AnimatedContainer( duration: @@ -354,8 +327,9 @@ class DownloadAnalyticsDialogState extends State { width: 12, decoration: BoxDecoration( color: _downloadStatusColor(userId!), - borderRadius: - BorderRadius.circular(100), + borderRadius: BorderRadius.circular( + 100, + ), ), ), ), diff --git a/lib/pangea/space_analytics/space_analytics.dart b/lib/pangea/space_analytics/space_analytics.dart index 5db3b2248..6aa19d514 100644 --- a/lib/pangea/space_analytics/space_analytics.dart +++ b/lib/pangea/space_analytics/space_analytics.dart @@ -160,8 +160,8 @@ class SpaceAnalyticsState extends State { selectedLanguage = availableLanguages.contains(_userL2) || availableLanguages.isEmpty - ? _userL2 - : availableLanguages.firstOrNull; + ? _userL2 + : availableLanguages.firstOrNull; await refresh(); if (mounted) { @@ -193,38 +193,34 @@ class SpaceAnalyticsState extends State { setState(() { downloads = Map.fromEntries( - _availableUsers.map( - (user) { - final room = _analyticsRoomOfUser(user); - final hasLangData = _availableUsersForLang.contains(user); + _availableUsers.map((user) { + final room = _analyticsRoomOfUser(user); + final hasLangData = _availableUsersForLang.contains(user); - RequestStatus? requestStatus; - if (room != null) { - requestStatus = RequestStatus.available; - } else if (!hasLangData) { - requestStatus = RequestStatus.unavailable; - } else { - requestStatus = AnalyticsRequestsRepo.get( - user.id, - selectedLanguage!, - ) ?? - RequestStatus.unrequested; - } + RequestStatus? requestStatus; + if (room != null) { + requestStatus = RequestStatus.available; + } else if (!hasLangData) { + requestStatus = RequestStatus.unavailable; + } else { + requestStatus = + AnalyticsRequestsRepo.get(user.id, selectedLanguage!) ?? + RequestStatus.unrequested; + } - final DownloadStatus downloadStatus = - requestStatus == RequestStatus.available - ? DownloadStatus.loading - : DownloadStatus.unavailable; + final DownloadStatus downloadStatus = + requestStatus == RequestStatus.available + ? DownloadStatus.loading + : DownloadStatus.unavailable; - return MapEntry( - user, - AnalyticsDownload( - requestStatus: requestStatus, - downloadStatus: downloadStatus, - ), - ); - }, - ), + return MapEntry( + user, + AnalyticsDownload( + requestStatus: requestStatus, + downloadStatus: downloadStatus, + ), + ); + }), ); }); @@ -243,12 +239,11 @@ class SpaceAnalyticsState extends State { } } - Future _setAnalyticsModel( - Room analyticsRoom, - ) async { + Future _setAnalyticsModel(Room analyticsRoom) async { final String? userID = analyticsRoom.creatorId; - final user = - room?.getParticipants().firstWhereOrNull((p) => p.id == userID); + final user = room?.getParticipants().firstWhereOrNull( + (p) => p.id == userID, + ); if (user == null) return; SpaceAnalyticsSummaryModel? summary; @@ -291,14 +286,12 @@ class SpaceAnalyticsState extends State { final roomId = _analyticsRoomIdOfUser(user); if (roomId == null) return; await Matrix.of(context).client.knockRoom( - roomId, - via: room?.spaceChildren - .firstWhereOrNull( - (child) => child.roomId == roomId, - ) - ?.via, - reason: widget.roomId, - ); + roomId, + via: room?.spaceChildren + .firstWhereOrNull((child) => child.roomId == roomId) + ?.via, + reason: widget.roomId, + ); status = RequestStatus.requested; } catch (e) { status = RequestStatus.unavailable; @@ -314,11 +307,7 @@ class SpaceAnalyticsState extends State { } } finally { if (status != null) { - await AnalyticsRequestsRepo.set( - user.id, - selectedLanguage!, - status, - ); + await AnalyticsRequestsRepo.set(user.id, selectedLanguage!, status); downloads[user]?.requestStatus = status; } @@ -369,10 +358,10 @@ class SpaceAnalyticsState extends State { Room? _analyticsRoomOfUser(User user) { return Matrix.of(context).client.rooms.firstWhereOrNull( - (r) => - r.isAnalyticsRoomOfUser(user.id) && - r.madeForLang == selectedLanguage?.langCodeShort, - ); + (r) => + r.isAnalyticsRoomOfUser(user.id) && + r.madeForLang == selectedLanguage?.langCodeShort, + ); } void setSelectedLanguage(LanguageModel? lang) { diff --git a/lib/pangea/space_analytics/space_analytics_download_enum.dart b/lib/pangea/space_analytics/space_analytics_download_enum.dart index b928d7734..169314492 100644 --- a/lib/pangea/space_analytics/space_analytics_download_enum.dart +++ b/lib/pangea/space_analytics/space_analytics_download_enum.dart @@ -88,5 +88,5 @@ enum DownloadStatus { loading, /// The data has been downloaded successfully. - complete; + complete, } diff --git a/lib/pangea/space_analytics/space_analytics_inactive_dialog.dart b/lib/pangea/space_analytics/space_analytics_inactive_dialog.dart index 4de0ad719..30bc98a09 100644 --- a/lib/pangea/space_analytics/space_analytics_inactive_dialog.dart +++ b/lib/pangea/space_analytics/space_analytics_inactive_dialog.dart @@ -4,9 +4,7 @@ import 'package:fluffychat/l10n/l10n.dart'; import 'package:fluffychat/pangea/common/widgets/full_width_dialog.dart'; class SpaceAnalyticsInactiveDialog extends StatelessWidget { - const SpaceAnalyticsInactiveDialog({ - super.key, - }); + const SpaceAnalyticsInactiveDialog({super.key}); @override Widget build(BuildContext context) { @@ -15,10 +13,7 @@ class SpaceAnalyticsInactiveDialog extends StatelessWidget { maxWidth: 450.0, dialogContent: SingleChildScrollView( child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: 24.0, - vertical: 40.0, - ), + padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 40.0), child: Column( spacing: 12.0, mainAxisSize: MainAxisSize.min, diff --git a/lib/pangea/space_analytics/space_analytics_request_dialog.dart b/lib/pangea/space_analytics/space_analytics_request_dialog.dart index f47a59217..2ae255878 100644 --- a/lib/pangea/space_analytics/space_analytics_request_dialog.dart +++ b/lib/pangea/space_analytics/space_analytics_request_dialog.dart @@ -10,9 +10,7 @@ import 'package:fluffychat/pangea/analytics_page/analytics_page_constants.dart'; import 'package:fluffychat/pangea/common/widgets/full_width_dialog.dart'; class SpaceAnalyticsRequestDialog extends StatelessWidget { - const SpaceAnalyticsRequestDialog({ - super.key, - }); + const SpaceAnalyticsRequestDialog({super.key}); @override Widget build(BuildContext context) { @@ -42,7 +40,7 @@ class SpaceAnalyticsRequestDialog extends StatelessWidget { imageUrl: "${AppConfig.assetsBaseURL}/${AnalyticsPageConstants.dinoBotFileName}", errorWidget: (context, e, s) => const SizedBox.shrink(), - progressIndicatorBuilder: (context, _, __) => + progressIndicatorBuilder: (context, _, _) => const SizedBox.shrink(), width: 150.0, ), diff --git a/lib/pangea/space_analytics/space_analytics_requested_dialog.dart b/lib/pangea/space_analytics/space_analytics_requested_dialog.dart index 76fbe3dc9..62d6c84ab 100644 --- a/lib/pangea/space_analytics/space_analytics_requested_dialog.dart +++ b/lib/pangea/space_analytics/space_analytics_requested_dialog.dart @@ -52,7 +52,7 @@ class SpaceAnalyticsRequestedDialog extends StatelessWidget { imageUrl: "${AppConfig.assetsBaseURL}/${AnalyticsPageConstants.dinoBotFileName}", errorWidget: (context, e, s) => const SizedBox.shrink(), - progressIndicatorBuilder: (context, _, __) => + progressIndicatorBuilder: (context, _, _) => const SizedBox.shrink(), width: 150.0, ), @@ -120,10 +120,9 @@ class SpaceAnalyticsRequestedDialog extends StatelessWidget { left: 4.0, child: IconButton.filled( style: IconButton.styleFrom( - backgroundColor: Theme.of(context) - .colorScheme - .surfaceContainerHigh - .withAlpha(170), + backgroundColor: Theme.of( + context, + ).colorScheme.surfaceContainerHigh.withAlpha(170), ), icon: Icon( Icons.close_outlined, diff --git a/lib/pangea/space_analytics/space_analytics_view.dart b/lib/pangea/space_analytics/space_analytics_view.dart index 686ecdfe2..e32f29886 100644 --- a/lib/pangea/space_analytics/space_analytics_view.dart +++ b/lib/pangea/space_analytics/space_analytics_view.dart @@ -16,10 +16,7 @@ import 'package:fluffychat/widgets/layouts/max_width_body.dart'; class SpaceAnalyticsView extends StatelessWidget { final SpaceAnalyticsState controller; - const SpaceAnalyticsView({ - super.key, - required this.controller, - }); + const SpaceAnalyticsView({super.key, required this.controller}); @override Widget build(BuildContext context) { @@ -73,9 +70,9 @@ class SpaceAnalyticsView extends StatelessWidget { children: [ if (controller.lastUpdatedString != null) Text( - L10n.of(context).lastUpdated( - controller.lastUpdatedString!, - ), + L10n.of( + context, + ).lastUpdated(controller.lastUpdatedString!), textAlign: TextAlign.end, style: TextStyle( fontSize: !mini ? 12.0 : 8.0, @@ -107,9 +104,9 @@ class SpaceAnalyticsView extends StatelessWidget { Text( mini ? controller.selectedLanguage!.langCode - .toUpperCase() + .toUpperCase() : controller.selectedLanguage! - .getDisplayName(context), + .getDisplayName(context), style: TextStyle( color: theme.colorScheme.onPrimaryContainer, @@ -194,98 +191,95 @@ class SpaceAnalyticsView extends StatelessWidget { ), ], ), - ...controller.sortedDownloads.mapIndexed( - (index, entry) { - final download = entry.value; - return TableRow( - children: [ - TableCell( - child: Opacity( - opacity: download.requestStatus.opacity, - child: Padding( - padding: EdgeInsets.symmetric( - vertical: !mini ? 12.0 : 4.0, - ), - child: Row( - spacing: !mini ? 16.0 : 8.0, - children: [ - Avatar( - size: !mini ? 64.0 : 40.0, - mxContent: entry.key.avatarUrl, - name: entry.key.calcDisplayname(), - userId: entry.key.id, - presenceUserId: entry.key.id, + ...controller.sortedDownloads.mapIndexed(( + index, + entry, + ) { + final download = entry.value; + return TableRow( + children: [ + TableCell( + child: Opacity( + opacity: download.requestStatus.opacity, + child: Padding( + padding: EdgeInsets.symmetric( + vertical: !mini ? 12.0 : 4.0, + ), + child: Row( + spacing: !mini ? 16.0 : 8.0, + children: [ + Avatar( + size: !mini ? 64.0 : 40.0, + mxContent: entry.key.avatarUrl, + name: entry.key.calcDisplayname(), + userId: entry.key.id, + presenceUserId: entry.key.id, + ), + Flexible( + child: Column( + spacing: 4.0, + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + SizedBox( + height: index == 0 ? 8.0 : 0.0, + ), + Text( + entry.key.id, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontSize: !mini ? 16.0 : 12.0, + fontWeight: FontWeight.w500, + ), + ), + _RequestButton( + status: download.requestStatus, + onPressed: () => + controller.requestAnalytics( + entry.key, + ), + mini: mini, + ), + const SizedBox(height: 8.0), + ], ), - Flexible( - child: Column( - spacing: 4.0, - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - SizedBox( - height: - index == 0 ? 8.0 : 0.0, - ), - Text( - entry.key.id, - maxLines: 1, - overflow: - TextOverflow.ellipsis, - style: TextStyle( - fontSize: - !mini ? 16.0 : 12.0, - fontWeight: FontWeight.w500, - ), - ), - _RequestButton( - status: - download.requestStatus, - onPressed: () => controller - .requestAnalytics( - entry.key, - ), - mini: mini, - ), - const SizedBox(height: 8.0), - ], - ), - ), - ], - ), + ), + ], ), ), ), - _TableContentCell( - text: download.summary?.level?.toString(), - downloadStatus: download.downloadStatus, - requestStatus: download.requestStatus, - mini: mini, - ), - _TableContentCell( - text: download.summary?.numLemmas.toString(), - downloadStatus: download.downloadStatus, - requestStatus: download.requestStatus, - mini: mini, - ), - _TableContentCell( - text: download.summary?.numMorphConstructs - .toString(), - downloadStatus: download.downloadStatus, - requestStatus: download.requestStatus, - mini: mini, - ), - _TableContentCell( - text: download.summary?.numCompletedActivities - .toString(), - downloadStatus: download.downloadStatus, - requestStatus: download.requestStatus, - mini: mini, - ), - ], - ); - }, - ), + ), + _TableContentCell( + text: download.summary?.level?.toString(), + downloadStatus: download.downloadStatus, + requestStatus: download.requestStatus, + mini: mini, + ), + _TableContentCell( + text: download.summary?.numLemmas.toString(), + downloadStatus: download.downloadStatus, + requestStatus: download.requestStatus, + mini: mini, + ), + _TableContentCell( + text: download.summary?.numMorphConstructs + .toString(), + downloadStatus: download.downloadStatus, + requestStatus: download.requestStatus, + mini: mini, + ), + _TableContentCell( + text: download.summary?.numCompletedActivities + .toString(), + downloadStatus: download.downloadStatus, + requestStatus: download.requestStatus, + mini: mini, + ), + ], + ); + }), ], ) : const CircularProgressIndicator.adaptive(), @@ -392,22 +386,14 @@ class _TableHeaderCell extends StatelessWidget { child: Tooltip( message: text, child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 6.0, - horizontal: 8.0, - ), + padding: const EdgeInsets.symmetric(vertical: 6.0, horizontal: 8.0), child: Column( spacing: 10.0, children: [ Icon(icon, size: 22.0), mini ? const SizedBox.shrink() - : Text( - text, - style: const TextStyle( - fontSize: 12.0, - ), - ), + : Text(text, style: const TextStyle(fontSize: 12.0)), ], ), ), @@ -432,10 +418,7 @@ class _TableContentCell extends StatelessWidget { @override Widget build(BuildContext context) { if (downloadStatus != DownloadStatus.complete) { - return _MissingContentCell( - downloadStatus, - requestStatus, - ); + return _MissingContentCell(downloadStatus, requestStatus); } return TableCell( @@ -461,10 +444,7 @@ class _MissingContentCell extends StatelessWidget { final DownloadStatus status; final RequestStatus requestStatus; - const _MissingContentCell( - this.status, - this.requestStatus, - ); + const _MissingContentCell(this.status, this.requestStatus); @override Widget build(BuildContext context) { @@ -530,10 +510,7 @@ class _RequestButton extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ if (status.icon != null) - Icon( - status.icon, - size: !mini ? 12.0 : 8.0, - ), + Icon(status.icon, size: !mini ? 12.0 : 8.0), Text( status.label(context), style: TextStyle(fontSize: !mini ? 12.0 : 8.0), diff --git a/lib/pangea/spaces/client_spaces_extension.dart b/lib/pangea/spaces/client_spaces_extension.dart index d72c85a58..64f4dd844 100644 --- a/lib/pangea/spaces/client_spaces_extension.dart +++ b/lib/pangea/spaces/client_spaces_extension.dart @@ -20,18 +20,12 @@ extension SpacesClientExtension on Client { topic: topic?.trim(), powerLevelContentOverride: {'events_default': 100}, initialState: [ - RoomDefaults.defaultSpacePowerLevels( - userID!, - spaceChild: spaceChild, - ), + RoomDefaults.defaultSpacePowerLevels(userID!, spaceChild: spaceChild), await pangeaJoinRules( joinRules.toString().replaceAll('JoinRules.', ''), ), if (avatarUrl != null) - StateEvent( - type: EventTypes.RoomAvatar, - content: {'url': avatarUrl}, - ), + StateEvent(type: EventTypes.RoomAvatar, content: {'url': avatarUrl}), if (initialState != null) ...initialState, ], ); diff --git a/lib/pangea/spaces/knocking_users_indicator.dart b/lib/pangea/spaces/knocking_users_indicator.dart index 9816f3637..fc9d2e666 100644 --- a/lib/pangea/spaces/knocking_users_indicator.dart +++ b/lib/pangea/spaces/knocking_users_indicator.dart @@ -13,10 +13,7 @@ import 'package:fluffychat/utils/stream_extension.dart'; class KnockingUsersIndicator extends StatefulWidget { final Room room; - const KnockingUsersIndicator({ - super.key, - required this.room, - }); + const KnockingUsersIndicator({super.key, required this.room}); @override KnockingUsersIndicatorState createState() => KnockingUsersIndicatorState(); @@ -36,11 +33,13 @@ class KnockingUsersIndicatorState extends State { .rateLimit(const Duration(seconds: 1)) .listen((_) => _setKnockingUsers()); - widget.room.requestParticipants( - [Membership.join, Membership.invite, Membership.knock], - false, - true, - ).then((_) => _setKnockingUsers()); + widget.room + .requestParticipants( + [Membership.join, Membership.invite, Membership.knock], + false, + true, + ) + .then((_) => _setKnockingUsers()); } bool _isMemberUpdate(({String roomId, StrippedStateEvent state}) event) => @@ -68,14 +67,9 @@ class KnockingUsersIndicatorState extends State { child: _knockingUsers.isEmpty || !widget.room.isRoomAdmin ? const SizedBox() : Padding( - padding: const EdgeInsets.symmetric( - horizontal: 4, - vertical: 1, - ), + padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 1), child: Material( - borderRadius: BorderRadius.circular( - AppConfig.borderRadius, - ), + borderRadius: BorderRadius.circular(AppConfig.borderRadius), clipBehavior: Clip.hardEdge, child: ListTile( minVerticalPadding: 0, @@ -94,8 +88,9 @@ class KnockingUsersIndicatorState extends State { child: Text( _knockingUsers.length == 1 ? L10n.of(context).aUserIsKnocking - : L10n.of(context) - .usersAreKnocking(_knockingUsers.length), + : L10n.of( + context, + ).usersAreKnocking(_knockingUsers.length), style: Theme.of(context).textTheme.bodyMedium, ), ), diff --git a/lib/pangea/spaces/load_participants_builder.dart b/lib/pangea/spaces/load_participants_builder.dart index 1ba9ee35a..55fcee0fa 100644 --- a/lib/pangea/spaces/load_participants_builder.dart +++ b/lib/pangea/spaces/load_participants_builder.dart @@ -11,10 +11,8 @@ import 'package:fluffychat/widgets/matrix.dart'; class LoadParticipantsBuilder extends StatefulWidget { final Room? room; final bool loadProfiles; - final Widget Function( - BuildContext context, - LoadParticipantsBuilderState, - ) builder; + final Widget Function(BuildContext context, LoadParticipantsBuilderState) + builder; const LoadParticipantsBuilder({ required this.room, @@ -70,13 +68,7 @@ class LoadParticipantsBuilderState extends State { if (widget.loadProfiles) await _cacheLevels(); } catch (err, s) { error = err.toString(); - ErrorHandler.logError( - e: err, - s: s, - data: { - 'roomId': widget.room?.id, - }, - ); + ErrorHandler.logError(e: err, s: s, data: {'roomId': widget.room?.id}); } finally { if (mounted) { setState(() => loading = false); @@ -114,7 +106,8 @@ class LoadParticipantsBuilderState extends State { for (final user in participants) { if (_levelsCache[user.id] == null && user.membership == Membership.join) { _levelsCache[user.id] = await MatrixState - .pangeaController.userController + .pangeaController + .userController .getPublicAnalyticsProfile(user.id); } } @@ -135,19 +128,15 @@ extension LeaderboardGradient on int { final Color? color = this == 0 ? AppConfig.gold : this == 1 - ? Colors.grey[400]! - : this == 2 - ? Colors.brown[400]! - : null; + ? Colors.grey[400]! + : this == 2 + ? Colors.brown[400]! + : null; if (color == null) return null; return LinearGradient( - colors: [ - color, - Colors.white, - color, - ], + colors: [color, Colors.white, color], begin: Alignment.topLeft, end: Alignment.bottomRight, ); diff --git a/lib/pangea/spaces/public_course_extension.dart b/lib/pangea/spaces/public_course_extension.dart index cd3a6d168..5c1cd917a 100644 --- a/lib/pangea/spaces/public_course_extension.dart +++ b/lib/pangea/spaces/public_course_extension.dart @@ -11,10 +11,7 @@ extension PublicCourseExtension on Api { }) async { final requestUri = Uri( path: '/_synapse/client/unstable/org.pangea/public_courses', - queryParameters: { - 'limit': limit.toString(), - 'since': since, - }, + queryParameters: {'limit': limit.toString(), 'since': since}, ); final request = Request('GET', baseUri!.resolveUri(requestUri)); request.headers['content-type'] = 'application/json'; @@ -36,11 +33,7 @@ extension PublicCoursesRequest on Client { Future requestPublicCourses({ int limit = 10, String? since, - }) => - getPublicCourses( - limit: limit, - since: since, - ); + }) => getPublicCourses(limit: limit, since: since); } class PublicCoursesResponse extends GetPublicRoomsResponse { @@ -56,20 +49,17 @@ class PublicCoursesResponse extends GetPublicRoomsResponse { @override PublicCoursesResponse.fromJson(super.json) - : courses = (json['chunk'] as List) - .map((e) => PublicCoursesChunk.fromJson(e)) - .toList(), - super.fromJson(); + : courses = (json['chunk'] as List) + .map((e) => PublicCoursesChunk.fromJson(e)) + .toList(), + super.fromJson(); } class PublicCoursesChunk { final PublishedRoomsChunk room; final String courseId; - PublicCoursesChunk({ - required this.room, - required this.courseId, - }); + PublicCoursesChunk({required this.room, required this.courseId}); factory PublicCoursesChunk.fromJson(Map json) { return PublicCoursesChunk( @@ -79,9 +69,6 @@ class PublicCoursesChunk { } Map toJson() { - return { - 'room': room.toJson(), - 'course_id': courseId, - }; + return {'room': room.toJson(), 'course_id': courseId}; } } diff --git a/lib/pangea/spaces/space_navigation_column.dart b/lib/pangea/spaces/space_navigation_column.dart index 9cac6b7c6..3dd39e6bd 100644 --- a/lib/pangea/spaces/space_navigation_column.dart +++ b/lib/pangea/spaces/space_navigation_column.dart @@ -96,8 +96,9 @@ class SpaceNavigationColumnState extends State { : FluffyThemes.navRailWidth - 8.0; final double navRailExtraWidth = widget.showNavRail ? 250.0 : 0.0; - final double columnWidth = - isColumnMode ? FluffyThemes.columnWidth + 1.0 : 0; + final double columnWidth = isColumnMode + ? FluffyThemes.columnWidth + 1.0 + : 0; final double railWidth = widget.showNavRail ? navRailWidth + 1.0 : 0; final double baseWidth = columnWidth + railWidth; @@ -124,10 +125,7 @@ class SpaceNavigationColumnState extends State { width: FluffyThemes.columnWidth, child: _MainView(state: widget.state), ), - Container( - width: 1.0, - color: theme.dividerColor, - ), + Container(width: 1.0, color: theme.dividerColor), ], ), ), @@ -156,10 +154,7 @@ class SpaceNavigationColumnState extends State { profile: _profile, onProfileUpdate: _updateProfile, ), - Container( - width: 1, - color: Theme.of(context).dividerColor, - ), + Container(width: 1, color: Theme.of(context).dividerColor), ], ); }, @@ -173,9 +168,7 @@ class SpaceNavigationColumnState extends State { class _MainView extends StatelessWidget { final GoRouterState state; - const _MainView({ - required this.state, - }); + const _MainView({required this.state}); @override Widget build(BuildContext context) { @@ -210,9 +203,8 @@ class _MainView extends StatelessWidget { imageUrl: "${AppConfig.assetsBaseURL}/${SpaceConstants.sideBearFileName}", errorWidget: (context, url, error) => const SizedBox(), - placeholder: (context, url) => const Center( - child: CircularProgressIndicator.adaptive(), - ), + placeholder: (context, url) => + const Center(child: CircularProgressIndicator.adaptive()), ), ), ); diff --git a/lib/pangea/speech_to_text/speech_to_text_repo.dart b/lib/pangea/speech_to_text/speech_to_text_repo.dart index 730db58b9..6c698612d 100644 --- a/lib/pangea/speech_to_text/speech_to_text_repo.dart +++ b/lib/pangea/speech_to_text/speech_to_text_repo.dart @@ -14,10 +14,7 @@ class _SpeechToTextCacheItem { final Future data; final DateTime timestamp; - const _SpeechToTextCacheItem({ - required this.data, - required this.timestamp, - }); + const _SpeechToTextCacheItem({required this.data, required this.timestamp}); } class SpeechToTextRepo { @@ -72,11 +69,7 @@ class SpeechToTextRepo { return Result.value(res); } catch (e, s) { _cache.remove(request.hashCode.toString()); - ErrorHandler.logError( - e: e, - s: s, - data: request.toJson(), - ); + ErrorHandler.logError(e: e, s: s, data: request.toJson()); return Result.error(e); } } @@ -97,9 +90,8 @@ class SpeechToTextRepo { static void _setCached( SpeechToTextRequestModel request, Future response, - ) => - _cache[request.hashCode.toString()] = _SpeechToTextCacheItem( - data: response, - timestamp: DateTime.now(), - ); + ) => _cache[request.hashCode.toString()] = _SpeechToTextCacheItem( + data: response, + timestamp: DateTime.now(), + ); } diff --git a/lib/pangea/speech_to_text/speech_to_text_request_model.dart b/lib/pangea/speech_to_text/speech_to_text_request_model.dart index a0a736ff6..f655fac05 100644 --- a/lib/pangea/speech_to_text/speech_to_text_request_model.dart +++ b/lib/pangea/speech_to_text/speech_to_text_request_model.dart @@ -18,9 +18,9 @@ class SpeechToTextRequestModel { }); Map toJson() => { - "audio_content": base64Encode(audioContent), - "config": config.toJson(), - }; + "audio_content": base64Encode(audioContent), + "config": config.toJson(), + }; @override bool operator ==(Object other) { @@ -33,12 +33,10 @@ class SpeechToTextRequestModel { @override int get hashCode { - final bytesSample = - audioContent.length > 10 ? audioContent.sublist(0, 10) : audioContent; - return Object.hashAll([ - Object.hashAll(bytesSample), - config.hashCode, - ]); + final bytesSample = audioContent.length > 10 + ? audioContent.sublist(0, 10) + : audioContent; + return Object.hashAll([Object.hashAll(bytesSample), config.hashCode]); } } @@ -60,11 +58,11 @@ class SpeechToTextAudioConfigModel { }); Map toJson() => { - "encoding": encoding.value, - "sample_rate_hertz": sampleRateHertz, - "user_l1": userL1, - "user_l2": userL2, - "enable_word_confidence": enableWordConfidence, - "enable_automatic_punctuation": enableAutomaticPunctuation, - }; + "encoding": encoding.value, + "sample_rate_hertz": sampleRateHertz, + "user_l1": userL1, + "user_l2": userL2, + "enable_word_confidence": enableWordConfidence, + "enable_automatic_punctuation": enableAutomaticPunctuation, + }; } diff --git a/lib/pangea/speech_to_text/speech_to_text_response_model.dart b/lib/pangea/speech_to_text/speech_to_text_response_model.dart index e042be077..79658cc91 100644 --- a/lib/pangea/speech_to_text/speech_to_text_response_model.dart +++ b/lib/pangea/speech_to_text/speech_to_text_response_model.dart @@ -8,9 +8,7 @@ import 'package:fluffychat/pangea/events/models/pangea_token_model.dart'; class SpeechToTextResponseModel { final List results; - SpeechToTextResponseModel({ - required this.results, - }); + SpeechToTextResponseModel({required this.results}); Transcript get transcript => results.first.transcripts.first; @@ -29,13 +27,10 @@ class SpeechToTextResponseModel { } Map toJson() => { - "results": results.map((e) => e.toJson()).toList(), - }; + "results": results.map((e) => e.toJson()).toList(), + }; - List constructs( - String roomId, - String eventId, - ) { + List constructs(String roomId, String eventId) { final List constructs = []; final metadata = ConstructUseMetaData( roomId: roomId, @@ -70,8 +65,8 @@ class SpeechToTextResult { ); Map toJson() => { - "transcripts": transcripts.map((e) => e.toJson()).toList(), - }; + "transcripts": transcripts.map((e) => e.toJson()).toList(), + }; } class Transcript { @@ -93,24 +88,24 @@ class Transcript { double? get wordsPerMinute => wordsPerHr != null ? wordsPerHr! / 60 : null; factory Transcript.fromJson(Map json) => Transcript( - text: json['transcript'], - confidence: json['confidence'] <= 100 - ? json['confidence'] - : json['confidence'] / 100, - sttTokens: (json['stt_tokens'] as List) - .map((e) => STTToken.fromJson(e)) - .toList(), - langCode: json['lang_code'], - wordsPerHr: json['words_per_hr'], - ); + text: json['transcript'], + confidence: json['confidence'] <= 100 + ? json['confidence'] + : json['confidence'] / 100, + sttTokens: (json['stt_tokens'] as List) + .map((e) => STTToken.fromJson(e)) + .toList(), + langCode: json['lang_code'], + wordsPerHr: json['words_per_hr'], + ); Map toJson() => { - "transcript": text, - "confidence": confidence, - "stt_tokens": sttTokens.map((e) => e.toJson()).toList(), - "lang_code": langCode, - "words_per_hr": wordsPerHr, - }; + "transcript": text, + "confidence": confidence, + "stt_tokens": sttTokens.map((e) => e.toJson()).toList(), + "lang_code": langCode, + "words_per_hr": wordsPerHr, + }; Color get color => confidence > 80 ? AppConfig.success : AppConfig.warning; } @@ -151,11 +146,11 @@ class STTToken { } Map toJson() => { - "token": token.toJson(), - "start_time": startTime?.inMilliseconds, - "end_time": endTime?.inMilliseconds, - "confidence": confidence, - }; + "token": token.toJson(), + "start_time": startTime?.inMilliseconds, + "end_time": endTime?.inMilliseconds, + "confidence": confidence, + }; @override bool operator ==(Object other) { diff --git a/lib/pangea/subscription/controllers/subscription_controller.dart b/lib/pangea/subscription/controllers/subscription_controller.dart index 20abf8287..444d773e9 100644 --- a/lib/pangea/subscription/controllers/subscription_controller.dart +++ b/lib/pangea/subscription/controllers/subscription_controller.dart @@ -115,15 +115,13 @@ class SubscriptionController with ChangeNotifier { } if (!kIsWeb) { - Purchases.addCustomerInfoUpdateListener( - (CustomerInfo info) async { - final bool? wasSubscribed = isSubscribed; - await updateCustomerInfo(); - if (wasSubscribed == false && isSubscribed == true) { - subscriptionNotifier.value = true; - } - }, - ); + Purchases.addCustomerInfoUpdateListener((CustomerInfo info) async { + final bool? wasSubscribed = isSubscribed; + await updateCustomerInfo(); + if (wasSubscribed == false && isSubscribed == true) { + subscriptionNotifier.value = true; + } + }); } else { if (SubscriptionManagementRepo.getBeganWebPayment()) { await SubscriptionManagementRepo.removeBeganWebPayment(); @@ -184,9 +182,7 @@ class SubscriptionController with ChangeNotifier { ErrorHandler.logError( m: "Tried to subscribe to web SubscriptionDetails with Null duration", s: StackTrace.current, - data: { - "selectedSubscription": selectedSubscription.toJson(), - }, + data: {"selectedSubscription": selectedSubscription.toJson()}, ); return; } @@ -195,10 +191,7 @@ class SubscriptionController with ChangeNotifier { isPromo: isPromo, ); await SubscriptionManagementRepo.setBeganWebPayment(); - launchUrlString( - paymentLink, - webOnlyWindowName: "_self", - ); + launchUrlString(paymentLink, webOnlyWindowName: "_self"); return; } if (selectedSubscription.package == null) { @@ -214,10 +207,7 @@ class SubscriptionController with ChangeNotifier { return; } - GoogleAnalytics.beginPurchaseSubscription( - selectedSubscription, - context, - ); + GoogleAnalytics.beginPurchaseSubscription(selectedSubscription, context); await Purchases.purchasePackage(selectedSubscription.package!); GoogleAnalytics.updateUserSubscriptionStatus(true); } @@ -244,8 +234,8 @@ class SubscriptionController with ChangeNotifier { return isSubscribed! ? SubscriptionStatus.subscribed : shouldShowPaywall - ? SubscriptionStatus.shouldShowPaywall - : SubscriptionStatus.dimissedPaywall; + ? SubscriptionStatus.shouldShowPaywall + : SubscriptionStatus.dimissedPaywall; } /// whether or not the paywall should be shown @@ -272,13 +262,12 @@ class SubscriptionController with ChangeNotifier { clipBehavior: Clip.hardEdge, context: context, constraints: BoxConstraints( - maxHeight: - PlatformInfos.isMobile ? MediaQuery.heightOf(context) - 50 : 600, + maxHeight: PlatformInfos.isMobile + ? MediaQuery.heightOf(context) - 50 + : 600, ), builder: (_) { - return SubscriptionPaywall( - pangeaController: _pangeaController, - ); + return SubscriptionPaywall(pangeaController: _pangeaController); }, ); await SubscriptionManagementRepo.setDismissedPaywall(); @@ -317,15 +306,12 @@ class SubscriptionController with ChangeNotifier { return paymentLink; } - String? get defaultManagementURL => - currentSubscriptionInfo?.currentSubscription - ?.defaultManagementURL(availableSubscriptionInfo?.appIds); + String? get defaultManagementURL => currentSubscriptionInfo + ?.currentSubscription + ?.defaultManagementURL(availableSubscriptionInfo?.appIds); } -enum SubscriptionDuration { - month, - year, -} +enum SubscriptionDuration { month, year } extension SubscriptionDurationExtension on SubscriptionDuration { String get value => this == SubscriptionDuration.month ? "month" : "year"; @@ -371,8 +357,8 @@ class SubscriptionDetails { return appId == appIds?.androidId ? AppConfig.googlePlayMangementUrl : appId == appIds?.appleId - ? AppConfig.appleMangementUrl - : Environment.stripeManagementUrl; + ? AppConfig.appleMangementUrl + : Environment.stripeManagementUrl; } Map toJson() { diff --git a/lib/pangea/subscription/models/base_subscription_info.dart b/lib/pangea/subscription/models/base_subscription_info.dart index 4d530321e..8abd042aa 100644 --- a/lib/pangea/subscription/models/base_subscription_info.dart +++ b/lib/pangea/subscription/models/base_subscription_info.dart @@ -44,8 +44,9 @@ class CurrentSubscriptionInfo { String? get purchasePlatformDisplayName { if (currentSubscription?.appId == null) return null; - return availableSubscriptionInfo.appIds - ?.appDisplayName(currentSubscription!.appId!); + return availableSubscriptionInfo.appIds?.appDisplayName( + currentSubscription!.appId!, + ); } bool get purchasedOnWeb => @@ -74,11 +75,7 @@ class AvailableSubscriptionsInfo { List? allProducts; DateTime? lastUpdated; - AvailableSubscriptionsInfo({ - this.appIds, - this.allProducts, - this.lastUpdated, - }); + AvailableSubscriptionsInfo({this.appIds, this.allProducts, this.lastUpdated}); Future setAvailableSubscriptions() async { final cachedInfo = @@ -132,8 +129,9 @@ class AvailableSubscriptionsInfo { final data = {}; data['app_ids'] = appIds?.toJson(); - data['all_products'] = - allProducts?.map((product) => product.toJson()).toList(); + data['all_products'] = allProducts + ?.map((product) => product.toJson()) + .toList(); data['last_updated'] = (lastUpdated ?? DateTime.now()).toIso8601String(); return data; } diff --git a/lib/pangea/subscription/models/mobile_subscriptions.dart b/lib/pangea/subscription/models/mobile_subscriptions.dart index 23a73de64..6677d0a5a 100644 --- a/lib/pangea/subscription/models/mobile_subscriptions.dart +++ b/lib/pangea/subscription/models/mobile_subscriptions.dart @@ -23,9 +23,7 @@ class MobileSubscriptionInfo extends CurrentSubscriptionInfo { ? PurchasesConfiguration(Environment.rcGoogleKey) : PurchasesConfiguration(Environment.rcIosKey); try { - await Purchases.configure( - configuration..appUserID = userID, - ); + await Purchases.configure(configuration..appUserID = userID); await super.configure(); await setMobilePackages(); } catch (err) { @@ -77,22 +75,23 @@ class MobileSubscriptionInfo extends CurrentSubscriptionInfo { return; } - final List activeEntitlements = - info.entitlements.all.entries - .where( - (MapEntry entry) => - entry.value.isActive && - (entry.value.expirationDate == null || - DateTime.parse(entry.value.expirationDate!) - .isAfter(DateTime.now())), - ) - .map((MapEntry entry) => entry.value) - .toList(); + final List activeEntitlements = info + .entitlements + .all + .entries + .where( + (MapEntry entry) => + entry.value.isActive && + (entry.value.expirationDate == null || + DateTime.parse( + entry.value.expirationDate!, + ).isAfter(DateTime.now())), + ) + .map((MapEntry entry) => entry.value) + .toList(); if (activeEntitlements.length > 1) { - debugPrint( - "User has more than one active entitlement.", - ); + debugPrint("User has more than one active entitlement."); } else if (activeEntitlements.isEmpty) { debugPrint("User has no active entitlements"); resetSubscription(); diff --git a/lib/pangea/subscription/models/web_subscriptions.dart b/lib/pangea/subscription/models/web_subscriptions.dart index 2ceb36d11..040601a53 100644 --- a/lib/pangea/subscription/models/web_subscriptions.dart +++ b/lib/pangea/subscription/models/web_subscriptions.dart @@ -28,8 +28,8 @@ class WebSubscriptionInfo extends CurrentSubscriptionInfo { expirationDate = DateTime.tryParse(currentSubscription.expiresDate); unsubscribeDetectedAt = currentSubscription.unsubscribeDetectedAt != null - ? DateTime.parse(currentSubscription.unsubscribeDetectedAt!) - : null; + ? DateTime.parse(currentSubscription.unsubscribeDetectedAt!) + : null; } } catch (err) { currentSubscriptionId = AppConfig.errorSubscriptionId; diff --git a/lib/pangea/subscription/pages/change_subscription.dart b/lib/pangea/subscription/pages/change_subscription.dart index d7a291c95..670992d2c 100644 --- a/lib/pangea/subscription/pages/change_subscription.dart +++ b/lib/pangea/subscription/pages/change_subscription.dart @@ -12,22 +12,22 @@ import 'package:fluffychat/widgets/matrix.dart'; class ChangeSubscription extends StatelessWidget { final SubscriptionManagementController controller; - ChangeSubscription({ - required this.controller, - super.key, - }); + ChangeSubscription({required this.controller, super.key}); final PangeaController pangeaController = MatrixState.pangeaController; List get subscriptions => - pangeaController.subscriptionController.availableSubscriptionInfo + pangeaController + .subscriptionController + .availableSubscriptionInfo ?.availableSubscriptions ?? []; bool get inTrialWindow => pangeaController.userController.inTrialWindow(); - String get trialEnds => DateFormat.yMMMd() - .format(DateTime.now().add(const Duration(days: kIsWeb ? 0 : 7))); + String get trialEnds => DateFormat.yMMMd().format( + DateTime.now().add(const Duration(days: kIsWeb ? 0 : 7)), + ); @override Widget build(BuildContext context) { @@ -35,9 +35,7 @@ class ChangeSubscription extends StatelessWidget { return const Center( child: Padding( padding: EdgeInsets.all(16.0), - child: CircularProgressIndicator.adaptive( - strokeWidth: 2, - ), + child: CircularProgressIndicator.adaptive(strokeWidth: 2), ), ); } @@ -64,22 +62,21 @@ class ChangeSubscription extends StatelessWidget { child: Column( children: [ ListTile( - title: Text( - subscription.displayName(context), - ), + title: Text(subscription.displayName(context)), trailing: Icon( controller.selectedSubscription?.id != subscription.id ? Icons.keyboard_arrow_right_outlined : Icons.keyboard_arrow_down_outlined, ), - enabled: (!subscription.isTrial || inTrialWindow) && + enabled: + (!subscription.isTrial || inTrialWindow) && !controller.isCurrentSubscription(subscription), onTap: () => controller.selectSubscription(subscription), ), AnimatedSize( duration: FluffyThemes.animationDuration, - child: controller.selectedSubscription?.id != - subscription.id + child: + controller.selectedSubscription?.id != subscription.id ? const SizedBox() : Column( children: [ @@ -101,14 +98,18 @@ class ChangeSubscription extends StatelessWidget { if (!kIsWeb) Container( decoration: BoxDecoration( - color: Theme.of(context) - .colorScheme - .onPrimary, + color: Theme.of( + context, + ).colorScheme.onPrimary, borderRadius: const BorderRadius.only( - topLeft: Radius.circular(16.0), - topRight: Radius.circular(16.0), - ), + topLeft: Radius.circular( + 16.0, + ), + topRight: Radius.circular( + 16.0, + ), + ), ), padding: const EdgeInsets.all(16.0), child: Row( @@ -119,8 +120,9 @@ class ChangeSubscription extends StatelessWidget { L10n.of(context).startingToday, ), Text( - L10n.of(context) - .oneWeekFreeTrial, + L10n.of( + context, + ).oneWeekFreeTrial, ), ], ), @@ -132,8 +134,9 @@ class ChangeSubscription extends StatelessWidget { MainAxisAlignment.spaceBetween, children: [ Text( - L10n.of(context) - .paidSubscriptionStarts( + L10n.of( + context, + ).paidSubscriptionStarts( trialEnds, ), ), @@ -159,13 +162,15 @@ class ChangeSubscription extends StatelessWidget { CrossAxisAlignment.start, children: [ Text( - L10n.of(context) - .cancelInSubscriptionSettings, + L10n.of( + context, + ).cancelInSubscriptionSettings, ), if (!kIsWeb) Text( - L10n.of(context) - .cancelToAvoidCharges(trialEnds), + L10n.of( + context, + ).cancelToAvoidCharges(trialEnds), ), const SizedBox(height: 20.0), ElevatedButton( @@ -179,8 +184,9 @@ class ChangeSubscription extends StatelessWidget { children: [ Text( subscription.isTrial - ? L10n.of(context) - .activateTrial + ? L10n.of( + context, + ).activateTrial : L10n.of(context).pay, ), ], @@ -205,11 +211,7 @@ class ChangeSubscription extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.center, children: [ const Icon(Icons.info_outlined), - Flexible( - child: Text( - L10n.of(context).promoCodeInfo, - ), - ), + Flexible(child: Text(L10n.of(context).promoCodeInfo)), ], ), ), diff --git a/lib/pangea/subscription/pages/settings_subscription.dart b/lib/pangea/subscription/pages/settings_subscription.dart index 37145333a..a342fa83c 100644 --- a/lib/pangea/subscription/pages/settings_subscription.dart +++ b/lib/pangea/subscription/pages/settings_subscription.dart @@ -64,7 +64,9 @@ class SubscriptionManagementController extends State bool get subscriptionsAvailable => subscriptionController - .availableSubscriptionInfo?.availableSubscriptions.isNotEmpty ?? + .availableSubscriptionInfo + ?.availableSubscriptions + .isNotEmpty ?? false; bool get currentSubscriptionAvailable => @@ -76,15 +78,19 @@ class SubscriptionManagementController extends State bool get currentSubscriptionIsTrial => currentSubscriptionAvailable && (subscriptionController - .currentSubscriptionInfo?.currentSubscription?.isTrial ?? + .currentSubscriptionInfo + ?.currentSubscription + ?.isTrial ?? false); String? get purchasePlatformDisplayName => subscriptionController - .currentSubscriptionInfo?.purchasePlatformDisplayName; + .currentSubscriptionInfo + ?.purchasePlatformDisplayName; bool get currentSubscriptionIsPromotional => subscriptionController - .currentSubscriptionInfo?.currentSubscriptionIsPromotional ?? + .currentSubscriptionInfo + ?.currentSubscriptionIsPromotional ?? false; String get currentSubscriptionTitle => @@ -105,7 +111,8 @@ class SubscriptionManagementController extends State return true; } return subscriptionController - .currentSubscriptionInfo!.currentPlatformMatchesPurchasePlatform; + .currentSubscriptionInfo! + .currentPlatformMatchesPurchasePlatform; } DateTime? get expirationDate => @@ -159,10 +166,7 @@ class SubscriptionManagementController extends State ErrorHandler.logError( e: e, s: s, - data: { - "subscription_id": subscription.id, - "is_promo": isPromo, - }, + data: {"subscription_id": subscription.id, "is_promo": isPromo}, ); } finally { if (mounted) setState(() => loading = false); @@ -186,7 +190,9 @@ class SubscriptionManagementController extends State managementUrl += "?prefilled_email=${Uri.encodeComponent(email)}"; } final String? purchaseAppId = subscriptionController - .currentSubscriptionInfo?.currentSubscription?.appId; + .currentSubscriptionInfo + ?.currentSubscription + ?.appId; if (purchaseAppId == null) return; final SubscriptionAppIds? appIds = @@ -241,8 +247,4 @@ class SubscriptionManagementController extends State Widget build(BuildContext context) => SettingsSubscriptionView(this); } -enum ManagementOption { - cancel, - paymentMethod, - history, -} +enum ManagementOption { cancel, paymentMethod, history } diff --git a/lib/pangea/subscription/pages/settings_subscription_view.dart b/lib/pangea/subscription/pages/settings_subscription_view.dart index b48ab2fcf..76c7d1f82 100644 --- a/lib/pangea/subscription/pages/settings_subscription_view.dart +++ b/lib/pangea/subscription/pages/settings_subscription_view.dart @@ -45,17 +45,15 @@ class SettingsSubscriptionView extends StatelessWidget { ListTile( title: Text(L10n.of(context).paymentMethod), trailing: const Icon(Icons.credit_card), - onTap: () => controller.launchMangementUrl( - ManagementOption.paymentMethod, - ), + onTap: () => + controller.launchMangementUrl(ManagementOption.paymentMethod), enabled: controller.showManagementOptions, ), ListTile( title: Text(L10n.of(context).paymentHistory), trailing: const Icon(Icons.keyboard_arrow_right_outlined), - onTap: () => controller.launchMangementUrl( - ManagementOption.history, - ), + onTap: () => + controller.launchMangementUrl(ManagementOption.history), enabled: controller.showManagementOptions, ), if (controller.expirationDate != null) ...[ @@ -80,10 +78,7 @@ class SettingsSubscriptionView extends StatelessWidget { spacing: 8.0, mainAxisSize: MainAxisSize.min, children: [ - const Icon( - Icons.info_outline, - size: 20, - ), + const Icon(Icons.info_outline, size: 20), Flexible( child: Text( L10n.of(context).waitForSubscriptionChanges, @@ -104,9 +99,7 @@ class SettingsSubscriptionView extends StatelessWidget { return Scaffold( appBar: AppBar( centerTitle: true, - title: Text( - L10n.of(context).subscriptionManagement, - ), + title: Text(L10n.of(context).subscriptionManagement), ), body: ListTileTheme( iconColor: Theme.of(context).textTheme.bodyLarge!.color, @@ -116,9 +109,7 @@ class SettingsSubscriptionView extends StatelessWidget { if (isSubscribed == null) const Center(child: CircularProgressIndicator.adaptive()) else if (isSubscribed && !controller.showManagementOptions) - ManagementNotAvailableWarning( - controller: controller, - ) + ManagementNotAvailableWarning(controller: controller) else if (isSubscribed && controller.showManagementOptions) ...managementButtons else @@ -134,10 +125,7 @@ class SettingsSubscriptionView extends StatelessWidget { class ManagementNotAvailableWarning extends StatelessWidget { final SubscriptionManagementController controller; - const ManagementNotAvailableWarning({ - required this.controller, - super.key, - }); + const ManagementNotAvailableWarning({required this.controller, super.key}); @override Widget build(BuildContext context) { @@ -169,10 +157,7 @@ class ManagementNotAvailableWarning extends StatelessWidget { return Center( child: Padding( padding: const EdgeInsets.all(20), - child: Text( - getWarningText(), - textAlign: TextAlign.center, - ), + child: Text(getWarningText(), textAlign: TextAlign.center), ), ); } diff --git a/lib/pangea/subscription/repo/subscription_management_repo.dart b/lib/pangea/subscription/repo/subscription_management_repo.dart index 673a1103b..4ed0d2ab7 100644 --- a/lib/pangea/subscription/repo/subscription_management_repo.dart +++ b/lib/pangea/subscription/repo/subscription_management_repo.dart @@ -20,10 +20,7 @@ class SubscriptionManagementRepo { static Future setAvailableSubscriptionsInfo( AvailableSubscriptionsInfo info, ) async { - await _cache.write( - PLocalKey.availableSubscriptionInfo, - info.toJson(), - ); + await _cache.write(PLocalKey.availableSubscriptionInfo, info.toJson()); } static bool getBeganWebPayment() { @@ -88,10 +85,7 @@ class SubscriptionManagementRepo { } static Future setSubscriptionEndDate(DateTime? date) async { - await _cache.write( - PLocalKey.subscriptionEndDate, - date?.toIso8601String(), - ); + await _cache.write(PLocalKey.subscriptionEndDate, date?.toIso8601String()); } static DateTime? getSubscriptionEndDate() { diff --git a/lib/pangea/subscription/repo/subscription_repo.dart b/lib/pangea/subscription/repo/subscription_repo.dart index f844a20b5..637bd3365 100644 --- a/lib/pangea/subscription/repo/subscription_repo.dart +++ b/lib/pangea/subscription/repo/subscription_repo.dart @@ -21,13 +21,9 @@ class SubscriptionRepo { choreoApiKey: Environment.choreoApiKey, accessToken: MatrixState.pangeaController.userController.accessToken, ); - final http.Response res = await req.get( - url: PApiUrls.rcAppsChoreo, - ); + final http.Response res = await req.get(url: PApiUrls.rcAppsChoreo); - return SubscriptionAppIds.fromJson( - jsonDecode(res.body), - ); + return SubscriptionAppIds.fromJson(jsonDecode(res.body)); } catch (err) { ErrorHandler.logError( m: "Failed to fetch app information for revenuecat API", @@ -44,19 +40,14 @@ class SubscriptionRepo { choreoApiKey: Environment.choreoApiKey, accessToken: MatrixState.pangeaController.userController.accessToken, ); - final http.Response res = await req.get( - url: PApiUrls.rcProductsChoreo, - ); + final http.Response res = await req.get(url: PApiUrls.rcProductsChoreo); final Map json = jsonDecode(res.body); - final RCProductsResponseModel resp = - RCProductsResponseModel.fromJson(json); + final RCProductsResponseModel resp = RCProductsResponseModel.fromJson( + json, + ); return resp.allProducts; } catch (err, s) { - ErrorHandler.logError( - e: err, - s: s, - data: {}, - ); + ErrorHandler.logError(e: err, s: s, data: {}); return null; } } @@ -67,25 +58,16 @@ class SubscriptionRepo { choreoApiKey: Environment.choreoApiKey, accessToken: MatrixState.pangeaController.userController.accessToken, ); - final http.Response res = await req.get( - url: PApiUrls.rcProductsTrial, - ); + final http.Response res = await req.get(url: PApiUrls.rcProductsTrial); if (res.statusCode != 201) { - ErrorHandler.logError( - e: res.body, - data: {}, - ); + ErrorHandler.logError(e: res.body, data: {}); return false; } else { return true; } } catch (err, s) { - ErrorHandler.logError( - e: err, - s: s, - data: {}, - ); + ErrorHandler.logError(e: err, s: s, data: {}); return false; } } @@ -101,10 +83,7 @@ class SubscriptionRepo { final http.Response res = await req.get(url: PApiUrls.rcSubscription); final Map json = jsonDecode(res.body); final RCSubscriptionResponseModel resp = - RCSubscriptionResponseModel.fromJson( - json, - allProducts, - ); + RCSubscriptionResponseModel.fromJson(json, allProducts); return resp; } } @@ -112,13 +91,9 @@ class SubscriptionRepo { class RCProductsResponseModel { List allProducts; - RCProductsResponseModel({ - required this.allProducts, - }); + RCProductsResponseModel({required this.allProducts}); - factory RCProductsResponseModel.fromJson( - Map json, - ) { + factory RCProductsResponseModel.fromJson(Map json) { final List offerings = json["items"] as List; final res = offerings .map((offering) => SubscriptionDetails.fromJson(offering)) @@ -180,18 +155,16 @@ class RCSubscriptionResponseModel { if (activeEntitlements.isEmpty) { debugPrint("User has no active entitlements"); - return RCSubscriptionResponseModel( - allSubscriptions: history, - ); + return RCSubscriptionResponseModel(allSubscriptions: history); } final String currentSubscriptionId = activeEntitlements[0]; - final SubscriptionDetails? currentSubscription = - allProducts?.firstWhereOrNull( - (SubscriptionDetails sub) => - sub.id.contains(currentSubscriptionId) || - currentSubscriptionId.contains(sub.id), - ); + final SubscriptionDetails? currentSubscription = allProducts + ?.firstWhereOrNull( + (SubscriptionDetails sub) => + sub.id.contains(currentSubscriptionId) || + currentSubscriptionId.contains(sub.id), + ); return RCSubscriptionResponseModel( currentSubscription: currentSubscription, @@ -202,8 +175,7 @@ class RCSubscriptionResponseModel { } static List getActiveEntitlements(Map json) { - return json['entitlements'] - .entries + return json['entitlements'].entries .where( (MapEntry entitlement) => DateTime.parse( entitlement.value['expires_date'], @@ -218,8 +190,7 @@ class RCSubscriptionResponseModel { } static List getAllEntitlements(Map json) { - return json['entitlements'] - .entries + return json['entitlements'].entries .map( (MapEntry entitlement) => entitlement.value['product_identifier'], diff --git a/lib/pangea/subscription/utils/subscription_app_id.dart b/lib/pangea/subscription/utils/subscription_app_id.dart index 4ba71ee7a..bb86263cc 100644 --- a/lib/pangea/subscription/utils/subscription_app_id.dart +++ b/lib/pangea/subscription/utils/subscription_app_id.dart @@ -12,8 +12,8 @@ class SubscriptionAppIds { String? get currentAppId => kIsWeb ? stripeId : Platform.isAndroid - ? androidId - : appleId; + ? androidId + : appleId; String? appDisplayName(String appId) { if (appId == stripeId) return "web"; @@ -38,24 +38,20 @@ class SubscriptionAppIds { } } -enum RCPlatform { - stripe, - android, - apple, -} +enum RCPlatform { stripe, android, apple } extension RCPlatformExtension on RCPlatform { RCPlatform get currentPlatform => kIsWeb ? RCPlatform.stripe : Platform.isAndroid - ? RCPlatform.android - : RCPlatform.apple; + ? RCPlatform.android + : RCPlatform.apple; String get string { return currentPlatform == RCPlatform.stripe ? 'stripe' : currentPlatform == RCPlatform.android - ? 'play_store' - : 'app_store'; + ? 'play_store' + : 'app_store'; } } diff --git a/lib/pangea/subscription/widgets/paywall_card.dart b/lib/pangea/subscription/widgets/paywall_card.dart index 6263dd162..faaf743f3 100644 --- a/lib/pangea/subscription/widgets/paywall_card.dart +++ b/lib/pangea/subscription/widgets/paywall_card.dart @@ -10,12 +10,11 @@ import 'package:fluffychat/widgets/matrix.dart'; class PaywallCard extends StatelessWidget { const PaywallCard({super.key}); - static Future show( - BuildContext context, - String targetId, - ) async { + static Future show(BuildContext context, String targetId) async { if (!MatrixState - .pangeaController.subscriptionController.shouldShowPaywall) { + .pangeaController + .subscriptionController + .shouldShowPaywall) { return; } @@ -51,8 +50,9 @@ class PaywallCard extends StatelessWidget { .showPaywall(context); }, style: TextButton.styleFrom( - backgroundColor: - Theme.of(context).colorScheme.primary.withAlpha(25), + backgroundColor: Theme.of( + context, + ).colorScheme.primary.withAlpha(25), ), child: Text(L10n.of(context).getAccess), ), diff --git a/lib/pangea/subscription/widgets/subscription_options.dart b/lib/pangea/subscription/widgets/subscription_options.dart index 95a8e633f..f9e64e7aa 100644 --- a/lib/pangea/subscription/widgets/subscription_options.dart +++ b/lib/pangea/subscription/widgets/subscription_options.dart @@ -9,10 +9,7 @@ import 'package:fluffychat/pangea/subscription/controllers/subscription_controll class SubscriptionOptions extends StatelessWidget { final PangeaController pangeaController; - const SubscriptionOptions({ - super.key, - required this.pangeaController, - }); + const SubscriptionOptions({super.key, required this.pangeaController}); @override Widget build(BuildContext context) { @@ -30,26 +27,25 @@ class SubscriptionOptions extends StatelessWidget { buttonText: L10n.of(context).activateTrial, ), ] - : pangeaController.subscriptionController.availableSubscriptionInfo! - .availableSubscriptions - .map( - (subscription) => SubscriptionCard( - subscription: subscription, - onTap: () { - pangeaController.subscriptionController - .submitSubscriptionChange( - subscription, - context, - ); - }, - title: subscription.displayName(context), - enabled: !subscription.isTrial, - description: subscription.isTrial - ? L10n.of(context).trialPeriodExpired - : null, - ), - ) - .toList(), + : pangeaController + .subscriptionController + .availableSubscriptionInfo! + .availableSubscriptions + .map( + (subscription) => SubscriptionCard( + subscription: subscription, + onTap: () { + pangeaController.subscriptionController + .submitSubscriptionChange(subscription, context); + }, + title: subscription.displayName(context), + enabled: !subscription.isTrial, + description: subscription.isTrial + ? L10n.of(context).trialPeriodExpired + : null, + ), + ) + .toList(), ); } } @@ -102,16 +98,18 @@ class SubscriptionCard extends StatelessWidget { textAlign: TextAlign.center, style: TextStyle( fontSize: 20, - color: - enabled ? null : const Color.fromARGB(255, 174, 174, 174), + color: enabled + ? null + : const Color.fromARGB(255, 174, 174, 174), ), ), Text( description ?? subscription?.displayPrice(context) ?? '', textAlign: TextAlign.center, style: TextStyle( - color: - enabled ? null : const Color.fromARGB(255, 174, 174, 174), + color: enabled + ? null + : const Color.fromARGB(255, 174, 174, 174), ), ), OutlinedButton( @@ -122,9 +120,7 @@ class SubscriptionCard extends StatelessWidget { } : null, style: buttonStyle, - child: Text( - buttonText ?? L10n.of(context).subscribe, - ), + child: Text(buttonText ?? L10n.of(context).subscribe), ), ], ), diff --git a/lib/pangea/subscription/widgets/subscription_paywall.dart b/lib/pangea/subscription/widgets/subscription_paywall.dart index ee4e0b344..4ad6dd899 100644 --- a/lib/pangea/subscription/widgets/subscription_paywall.dart +++ b/lib/pangea/subscription/widgets/subscription_paywall.dart @@ -9,10 +9,7 @@ import 'package:fluffychat/widgets/matrix.dart'; class SubscriptionPaywall extends StatelessWidget { final PangeaController pangeaController; - const SubscriptionPaywall({ - super.key, - required this.pangeaController, - }); + const SubscriptionPaywall({super.key, required this.pangeaController}); @override Widget build(BuildContext context) { @@ -46,9 +43,7 @@ class SubscriptionPaywall extends StatelessWidget { ), const SizedBox(height: 40), Center( - child: SubscriptionOptions( - pangeaController: pangeaController, - ), + child: SubscriptionOptions(pangeaController: pangeaController), ), ], ), diff --git a/lib/pangea/subscription/widgets/subscription_snackbar.dart b/lib/pangea/subscription/widgets/subscription_snackbar.dart index 95cd94b22..b2c5430c0 100644 --- a/lib/pangea/subscription/widgets/subscription_snackbar.dart +++ b/lib/pangea/subscription/widgets/subscription_snackbar.dart @@ -27,9 +27,5 @@ void showSubscribedSnackbar(BuildContext context) { ], ), ); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: text, - ), - ); + ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: text)); } diff --git a/lib/pangea/text_to_speech/text_to_speech_repo.dart b/lib/pangea/text_to_speech/text_to_speech_repo.dart index 3b68486e6..d75afd4c9 100644 --- a/lib/pangea/text_to_speech/text_to_speech_repo.dart +++ b/lib/pangea/text_to_speech/text_to_speech_repo.dart @@ -14,10 +14,7 @@ class _TextToSpeechCacheItem { final Future data; final DateTime timestamp; - const _TextToSpeechCacheItem({ - required this.data, - required this.timestamp, - }); + const _TextToSpeechCacheItem({required this.data, required this.timestamp}); } class TextToSpeechRepo { @@ -72,11 +69,7 @@ class TextToSpeechRepo { return Result.value(res); } catch (e, s) { _cache.remove(request.hashCode.toString()); - ErrorHandler.logError( - e: e, - s: s, - data: request.toJson(), - ); + ErrorHandler.logError(e: e, s: s, data: request.toJson()); return Result.error(e); } } @@ -97,9 +90,8 @@ class TextToSpeechRepo { static void _setCached( TextToSpeechRequestModel request, Future response, - ) => - _cache[request.hashCode.toString()] = _TextToSpeechCacheItem( - data: response, - timestamp: DateTime.now(), - ); + ) => _cache[request.hashCode.toString()] = _TextToSpeechCacheItem( + data: response, + timestamp: DateTime.now(), + ); } diff --git a/lib/pangea/text_to_speech/text_to_speech_request_model.dart b/lib/pangea/text_to_speech/text_to_speech_request_model.dart index c8a13a0fe..a03b57b9e 100644 --- a/lib/pangea/text_to_speech/text_to_speech_request_model.dart +++ b/lib/pangea/text_to_speech/text_to_speech_request_model.dart @@ -19,13 +19,13 @@ class TextToSpeechRequestModel { }); Map toJson() => { - ModelKey.text: text, - ModelKey.langCode: langCode, - ModelKey.userL1: userL1, - ModelKey.userL2: userL2, - ModelKey.tokens: tokens.map((token) => token.toJson()).toList(), - 'voice': voice, - }; + ModelKey.text: text, + ModelKey.langCode: langCode, + ModelKey.userL1: userL1, + ModelKey.userL2: userL2, + ModelKey.tokens: tokens.map((token) => token.toJson()).toList(), + 'voice': voice, + }; @override bool operator ==(Object other) { diff --git a/lib/pangea/text_to_speech/text_to_speech_response_model.dart b/lib/pangea/text_to_speech/text_to_speech_response_model.dart index 645005a3d..6148ade57 100644 --- a/lib/pangea/text_to_speech/text_to_speech_response_model.dart +++ b/lib/pangea/text_to_speech/text_to_speech_response_model.dart @@ -18,9 +18,7 @@ class TextToSpeechResponseModel { required this.ttsTokens, }); - factory TextToSpeechResponseModel.fromJson( - Map json, - ) => + factory TextToSpeechResponseModel.fromJson(Map json) => TextToSpeechResponseModel( audioContent: json["audio_content"], mimeType: json["mime_type"], @@ -33,13 +31,13 @@ class TextToSpeechResponseModel { ); Map toJson() => { - "audio_content": audioContent, - "mime_type": mimeType, - "duration_millis": durationMillis, - "wave_form": List.from(waveform.map((x) => x)), - "file_extension": fileExtension, - "tts_tokens": List.from(ttsTokens.map((x) => x.toJson())), - }; + "audio_content": audioContent, + "mime_type": mimeType, + "duration_millis": durationMillis, + "wave_form": List.from(waveform.map((x) => x)), + "file_extension": fileExtension, + "tts_tokens": List.from(ttsTokens.map((x) => x.toJson())), + }; PangeaAudioEventData toPangeaAudioEventData( String text, @@ -60,23 +58,19 @@ class TTSToken { final int endMS; final PangeaTokenText text; - TTSToken({ - required this.startMS, - required this.endMS, - required this.text, - }); + TTSToken({required this.startMS, required this.endMS, required this.text}); factory TTSToken.fromJson(Map json) => TTSToken( - startMS: json["start_ms"], - endMS: json["end_ms"], - text: PangeaTokenText.fromJson(json["text"]), - ); + startMS: json["start_ms"], + endMS: json["end_ms"], + text: PangeaTokenText.fromJson(json["text"]), + ); Map toJson() => { - "start_ms": startMS, - "end_ms": endMS, - "text": text.toJson(), - }; + "start_ms": startMS, + "end_ms": endMS, + "text": text.toJson(), + }; @override bool operator ==(Object other) { @@ -106,21 +100,22 @@ class PangeaAudioEventData { }); factory PangeaAudioEventData.fromJson(dynamic json) => PangeaAudioEventData( - text: json[ModelKey.text] as String, - langCode: json[ModelKey.langCode] as String, - tokens: List.from( - (json[ModelKey.tokens] as Iterable) - .map((x) => TTSToken.fromJson(x)) - .toList(), - ), - voice: json[ModelKey.voice] as String?, - ); + text: json[ModelKey.text] as String, + langCode: json[ModelKey.langCode] as String, + tokens: List.from( + (json[ModelKey.tokens] as Iterable) + .map((x) => TTSToken.fromJson(x)) + .toList(), + ), + voice: json[ModelKey.voice] as String?, + ); Map toJson() => { - ModelKey.text: text, - ModelKey.langCode: langCode, - ModelKey.tokens: - List>.from(tokens.map((x) => x.toJson())), - if (voice != null) ModelKey.voice: voice, - }; + ModelKey.text: text, + ModelKey.langCode: langCode, + ModelKey.tokens: List>.from( + tokens.map((x) => x.toJson()), + ), + if (voice != null) ModelKey.voice: voice, + }; } diff --git a/lib/pangea/text_to_speech/tts_controller.dart b/lib/pangea/text_to_speech/tts_controller.dart index a67865316..3bc949fcd 100644 --- a/lib/pangea/text_to_speech/tts_controller.dart +++ b/lib/pangea/text_to_speech/tts_controller.dart @@ -42,9 +42,7 @@ class TtsController { if (message != 'canceled' && message != 'interrupted') { error_handler.ErrorHandler.logError( e: 'TTS error', - data: { - 'message': message, - }, + data: {'message': message}, ); } } @@ -55,11 +53,7 @@ class TtsController { await _setAvailableBaseLanguages(); } catch (e, s) { debugger(when: kDebugMode); - error_handler.ErrorHandler.logError( - e: e, - s: s, - data: {}, - ); + error_handler.ErrorHandler.logError(e: e, s: s, data: {}); } } @@ -96,9 +90,7 @@ class TtsController { 'availableLangCodes': _availableLangCodes, }; debugPrint("TTS: Language not supported: $jsonData"); - Sentry.addBreadcrumb( - Breadcrumb.fromJson(jsonData), - ); + Sentry.addBreadcrumb(Breadcrumb.fromJson(jsonData)); } } @@ -112,18 +104,12 @@ class TtsController { if (result != 1) { error_handler.ErrorHandler.logError( m: 'Unexpected result from tts.stop', - data: { - 'result': result, - }, + data: {'result': result}, ); } } catch (e, s) { debugger(when: kDebugMode); - error_handler.ErrorHandler.logError( - e: e, - s: s, - data: {}, - ); + error_handler.ErrorHandler.logError(e: e, s: s, data: {}); } } @@ -182,7 +168,11 @@ class TtsController { await _setSpeakingLanguage(langCode); final enableTTS = MatrixState - .pangeaController.userController.profile.toolSettings.enableTTS; + .pangeaController + .userController + .profile + .toolSettings + .enableTTS; if (enableTTS) { final token = PangeaTokenText( @@ -193,16 +183,8 @@ class TtsController { onStart?.call(); await (_isLangFullySupported(langCode) - ? _speak( - text, - langCode, - [token], - ) - : _speakFromChoreo( - text, - langCode, - [token], - )); + ? _speak(text, langCode, [token]) + : _speakFromChoreo(text, langCode, [token])); } else if (targetID != null && context != null) { await _showTTSDisabledPopup(context, targetID); } @@ -248,13 +230,7 @@ class TtsController { // } } catch (e, s) { debugger(when: kDebugMode); - error_handler.ErrorHandler.logError( - e: e, - s: s, - data: { - 'text': text, - }, - ); + error_handler.ErrorHandler.logError(e: e, s: s, data: {'text': text}); await _speakFromChoreo(text, langCode, tokens); } finally { stop(); @@ -275,9 +251,11 @@ class TtsController { text: text, langCode: langCode, tokens: tokens, - userL1: MatrixState.pangeaController.userController.userL1Code ?? + userL1: + MatrixState.pangeaController.userController.userL1Code ?? LanguageKeys.unknownLanguage, - userL2: MatrixState.pangeaController.userController.userL2Code ?? + userL2: + MatrixState.pangeaController.userController.userL2Code ?? LanguageKeys.unknownLanguage, ), ); @@ -291,20 +269,14 @@ class TtsController { audioPlayer?.dispose(); audioPlayer = AudioPlayer(); await audioPlayer!.setAudioSource( - BytesAudioSource( - audioContent, - ttsRes.mimeType, - ), + BytesAudioSource(audioContent, ttsRes.mimeType), ); await audioPlayer!.play(); } catch (e, s) { error_handler.ErrorHandler.logError( e: 'Error playing audio', s: s, - data: { - 'error': e.toString(), - 'text': text, - }, + data: {'error': e.toString(), 'text': text}, ); } finally { audioPlayer?.dispose(); @@ -328,28 +300,27 @@ class TtsController { static Future _showTTSDisabledPopup( BuildContext context, String targetID, - ) async => - OverlayUtil.showPositionedCard( - context: context, - backDropToDismiss: false, - cardToShow: Column( - spacing: 12.0, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - CardHeader(InstructionsEnum.ttsDisabled.title(L10n.of(context))), - Padding( - padding: const EdgeInsets.all(6.0), - child: Text( - InstructionsEnum.ttsDisabled.body(L10n.of(context)), - style: BotStyle.text(context), - ), - ), - ], + ) async => OverlayUtil.showPositionedCard( + context: context, + backDropToDismiss: false, + cardToShow: Column( + spacing: 12.0, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + CardHeader(InstructionsEnum.ttsDisabled.title(L10n.of(context))), + Padding( + padding: const EdgeInsets.all(6.0), + child: Text( + InstructionsEnum.ttsDisabled.body(L10n.of(context)), + style: BotStyle.text(context), + ), ), - maxHeight: 300, - maxWidth: 300, - transformTargetId: targetID, - closePrevOverlay: false, - overlayKey: InstructionsEnum.ttsDisabled.toString(), - ); + ], + ), + maxHeight: 300, + maxWidth: 300, + transformTargetId: targetID, + closePrevOverlay: false, + overlayKey: InstructionsEnum.ttsDisabled.toString(), + ); } diff --git a/lib/pangea/token_info_feedback/token_info_feedback_dialog.dart b/lib/pangea/token_info_feedback/token_info_feedback_dialog.dart index 856d89495..1fadd9102 100644 --- a/lib/pangea/token_info_feedback/token_info_feedback_dialog.dart +++ b/lib/pangea/token_info_feedback/token_info_feedback_dialog.dart @@ -48,24 +48,20 @@ class TokenInfoFeedbackDialog extends StatelessWidget { // first, update lemma info if changed if (response.updatedLemmaInfo != null) { - await _updateLemmaInfo( - token, - response.updatedLemmaInfo!, - ); + await _updateLemmaInfo(token, response.updatedLemmaInfo!); } // second, update the phonetic info if changed if (response.updatedPhonetics != null) { - await _updatePhoneticTranscription( - response.updatedPhonetics!, - ); + await _updatePhoneticTranscription(response.updatedPhonetics!); } final originalSent = event?.originalSent; // if no other changes, just return the message final hasTokenUpdate = response.updatedToken != null; - final hasLangUpdate = originalSent != null && + final hasLangUpdate = + originalSent != null && response.updatedLanguage != null && response.updatedLanguage != originalSent.langCode; @@ -86,10 +82,7 @@ class TokenInfoFeedbackDialog extends StatelessWidget { tokens: tokens, detections: [ if (updatedLanguage != null) - LanguageDetectionModel( - langCode: updatedLanguage, - confidence: 1, - ), + LanguageDetectionModel(langCode: updatedLanguage, confidence: 1), ], ); @@ -127,22 +120,21 @@ class TokenInfoFeedbackDialog extends StatelessWidget { Future _updateLemmaInfo( PangeaToken token, LemmaInfoResponse response, - ) => - LemmaInfoRepo.set( - token.vocabConstructID.lemmaInfoRequest( - event?.event.content ?? {}, - ), - response, - ); + ) => LemmaInfoRepo.set( + token.vocabConstructID.lemmaInfoRequest(event?.event.content ?? {}), + response, + ); Future _updatePhoneticTranscription( PhoneticTranscriptionResponse response, ) async { final req = PhoneticTranscriptionRequest( arc: LanguageArc( - l1: PLanguageStore.byLangCode(requestData.wordCardL1) ?? + l1: + PLanguageStore.byLangCode(requestData.wordCardL1) ?? MatrixState.pangeaController.userController.userL1!, - l2: PLanguageStore.byLangCode(langCode) ?? + l2: + PLanguageStore.byLangCode(langCode) ?? MatrixState.pangeaController.userController.userL2!, ), content: response.content, diff --git a/lib/pangea/token_info_feedback/token_info_feedback_notification.dart b/lib/pangea/token_info_feedback/token_info_feedback_notification.dart index cc52fbf12..0143f7e7b 100644 --- a/lib/pangea/token_info_feedback/token_info_feedback_notification.dart +++ b/lib/pangea/token_info_feedback/token_info_feedback_notification.dart @@ -8,10 +8,7 @@ import 'package:fluffychat/widgets/matrix.dart'; class TokenFeedbackNotification extends StatefulWidget { final String message; - const TokenFeedbackNotification({ - super.key, - required this.message, - }); + const TokenFeedbackNotification({super.key, required this.message}); @override State createState() => @@ -35,12 +32,7 @@ class _TokenFeedbackNotificationState extends State _slideAnimation = Tween( begin: const Offset(0, -1), end: Offset.zero, - ).animate( - CurvedAnimation( - parent: _slideController, - curve: Curves.easeOut, - ), - ); + ).animate(CurvedAnimation(parent: _slideController, curve: Curves.easeOut)); _slideController.forward(); } @@ -84,10 +76,7 @@ class _TokenFeedbackNotificationState extends State ), child: Row( children: [ - const BotFace( - width: 30, - expression: BotExpression.idle, - ), + const BotFace(width: 30, expression: BotExpression.idle), const SizedBox(width: 12), Expanded( child: Text( diff --git a/lib/pangea/token_info_feedback/token_info_feedback_request.dart b/lib/pangea/token_info_feedback/token_info_feedback_request.dart index c7f7636a8..e7e6f4520 100644 --- a/lib/pangea/token_info_feedback/token_info_feedback_request.dart +++ b/lib/pangea/token_info_feedback/token_info_feedback_request.dart @@ -54,10 +54,7 @@ class TokenInfoFeedbackRequest { final TokenInfoFeedbackRequestData data; final String userFeedback; - TokenInfoFeedbackRequest({ - required this.data, - required this.userFeedback, - }); + TokenInfoFeedbackRequest({required this.data, required this.userFeedback}); Map toJson() { return { diff --git a/lib/pangea/toolbar/layout/measure_render_box.dart b/lib/pangea/toolbar/layout/measure_render_box.dart index 85bbed893..ee749a538 100644 --- a/lib/pangea/toolbar/layout/measure_render_box.dart +++ b/lib/pangea/toolbar/layout/measure_render_box.dart @@ -43,9 +43,7 @@ class MeasureRenderBoxState extends State { WidgetsBinding.instance.addPostFrameCallback((_) => _updateOffset()); return true; }, - child: SizeChangedLayoutNotifier( - child: widget.child, - ), + child: SizeChangedLayoutNotifier(child: widget.child), ); } } diff --git a/lib/pangea/toolbar/layout/message_selection_positioner.dart b/lib/pangea/toolbar/layout/message_selection_positioner.dart index fc8a90463..c7d3c9c00 100644 --- a/lib/pangea/toolbar/layout/message_selection_positioner.dart +++ b/lib/pangea/toolbar/layout/message_selection_positioner.dart @@ -103,27 +103,22 @@ class MessageSelectionPositionerState extends State super.dispose(); } - T _runWithLogging( - Function runner, - String errorMessage, - T defaultValue, - ) { + T _runWithLogging(Function runner, String errorMessage, T defaultValue) { try { return runner(); } catch (e, s) { ErrorHandler.logError( e: "$errorMessage: $e", s: s, - data: { - "eventID": widget.event.eventId, - }, + data: {"eventID": widget.event.eventId}, ); return defaultValue; } } - final Duration transitionAnimationDuration = - const Duration(milliseconds: 300); + final Duration transitionAnimationDuration = const Duration( + milliseconds: 300, + ); double get _horizontalPadding => FluffyThemes.isColumnMode(context) ? 8.0 : 0.0; @@ -159,16 +154,16 @@ class MessageSelectionPositionerState extends State widget.chatController.room.membership == Membership.join; Size? get screenSize => _runWithLogging( - () => MediaQuery.sizeOf(context), - "Error getting media query size", - null, - ); + () => MediaQuery.sizeOf(context), + "Error getting media query size", + null, + ); EdgeInsets? get screenPadding => _runWithLogging( - () => MediaQuery.paddingOf(context), - "Error getting media query padding", - null, - ); + () => MediaQuery.paddingOf(context), + "Error getting media query padding", + null, + ); double get columnWidth => FluffyThemes.isColumnMode(context) ? (FluffyThemes.columnWidth + FluffyThemes.navRailWidth + 2.0) @@ -178,7 +173,8 @@ class MessageSelectionPositionerState extends State const double messageMargin = 16.0; // widget.event.isActivityMessage ? 0 : Avatar.defaultSize + 16 + 8; final bool showingDetails = widget.chatController.displayChatDetailsColumn; - final double totalMaxWidth = FluffyThemes.maxTimelineWidth - + final double totalMaxWidth = + FluffyThemes.maxTimelineWidth - (showingDetails ? FluffyThemes.columnWidth : 0) - messageMargin; double? maxWidth; @@ -198,20 +194,20 @@ class MessageSelectionPositionerState extends State Size get _defaultMessageSize => const Size(FluffyThemes.columnWidth / 2, 100); RenderBox? get _overlayMessageRenderBox => _runWithLogging( - () => MatrixState.pAnyState.getRenderBox( - 'overlay_message_${widget.event.eventId}', - ), - "Error getting overlay message render box", - null, - ); + () => MatrixState.pAnyState.getRenderBox( + 'overlay_message_${widget.event.eventId}', + ), + "Error getting overlay message render box", + null, + ); RenderBox? get _reactionsRenderBox => _runWithLogging( - () => MatrixState.pAnyState.getRenderBox( - 'message_reactions_${widget.event.eventId}', - ), - "Error getting reactions render box", - null, - ); + () => MatrixState.pAnyState.getRenderBox( + 'message_reactions_${widget.event.eventId}', + ), + "Error getting reactions render box", + null, + ); Size? get _overlayMessageSize => _overlayMessageRenderBox?.size; @@ -228,12 +224,10 @@ class MessageSelectionPositionerState extends State } RenderBox? get _messageRenderBox => _runWithLogging( - () => MatrixState.pAnyState.getRenderBox( - widget.event.eventId, - ), - "Error getting message render box", - null, - ); + () => MatrixState.pAnyState.getRenderBox(widget.event.eventId), + "Error getting message render box", + null, + ); Offset? get _originalMessageOffset { if (_messageRenderBox == null || !_messageRenderBox!.hasSize) { @@ -260,9 +254,10 @@ class MessageSelectionPositionerState extends State } bool get isRtl { - final locale = Provider.of(context, listen: false) - .locale - ?.languageCode; + final locale = Provider.of( + context, + listen: false, + ).locale?.languageCode; return locale != null && LanguageConstants.rtlLanguageCodes.contains(locale); } @@ -357,7 +352,8 @@ class MessageSelectionPositionerState extends State final offset = _originalMessageOffset; if (offset == null) return false; - final bottomOffset = offset.dy + + final bottomOffset = + offset.dy + originalMessageSize.height + _reactionsHeight + AppConfig.toolbarMenuHeight + @@ -423,17 +419,19 @@ class MessageSelectionPositionerState extends State Column( children: [ SizedBox( - width: screenSize!.width - + width: + screenSize!.width - columnWidth - (showDetails ? FluffyThemes.columnWidth : 0), height: _screenHeight!, child: Stack( - alignment: - ownMessage ? Alignment.centerRight : Alignment.centerLeft, + alignment: ownMessage + ? Alignment.centerRight + : Alignment.centerLeft, children: [ ValueListenableBuilder( valueListenable: _startedTransition, - builder: (context, started, __) { + builder: (context, started, _) { return !started ? OverMessageOverlay(controller: this) : const SizedBox(); @@ -441,7 +439,7 @@ class MessageSelectionPositionerState extends State ), ValueListenableBuilder( valueListenable: _startedTransition, - builder: (context, started, __) { + builder: (context, started, _) { return !started && shouldScroll ? Positioned( top: 0, @@ -454,9 +452,7 @@ class MessageSelectionPositionerState extends State ), if (readingAssistanceMode == ReadingAssistanceMode.practiceMode) ...[ - CenteredMessage( - controller: this, - ), + CenteredMessage(controller: this), PracticeModeTransitionAnimation( targetId: "overlay_center_message_${widget.event.eventId}", @@ -494,7 +490,8 @@ class MessageSelectionPositionerState extends State final type = practice.practiceMode.associatedActivityType; - final complete = type != null && + final complete = + type != null && practice.isPracticeSessionDone(type); if (instruction != null && !complete) { @@ -519,10 +516,7 @@ class MessageSelectionPositionerState extends State ), ], ), - if (showDetails) - const SizedBox( - width: FluffyThemes.columnWidth, - ), + if (showDetails) const SizedBox(width: FluffyThemes.columnWidth), ], ), ); @@ -531,10 +525,7 @@ class MessageSelectionPositionerState extends State class MessageReactionPicker extends StatelessWidget { final ChatController chatController; - const MessageReactionPicker({ - super.key, - required this.chatController, - }); + const MessageReactionPicker({super.key, required this.chatController}); @override Widget build(BuildContext context) { @@ -564,9 +555,7 @@ class MessageReactionPicker extends StatelessWidget { return Material( elevation: 4, - borderRadius: BorderRadius.circular( - AppConfig.borderRadius, - ), + borderRadius: BorderRadius.circular(AppConfig.borderRadius), shadowColor: theme.colorScheme.surface.withAlpha(128), child: SingleChildScrollView( scrollDirection: Axis.horizontal, @@ -580,26 +569,17 @@ class MessageReactionPicker extends StatelessWidget { padding: EdgeInsets.zero, icon: Center( child: Opacity( - opacity: sentReactions.contains( - emoji, - ) - ? 0.33 - : 1, + opacity: sentReactions.contains(emoji) ? 0.33 : 1, child: Text( emoji, - style: const TextStyle( - fontSize: 20, - ), + style: const TextStyle(fontSize: 20), textAlign: TextAlign.center, ), ), ), onPressed: sentReactions.contains(emoji) ? null - : () => event?.room.sendReaction( - event.eventId, - emoji, - ), + : () => event?.room.sendReaction(event.eventId, emoji), ), ), // IconButton( diff --git a/lib/pangea/toolbar/layout/over_message_overlay.dart b/lib/pangea/toolbar/layout/over_message_overlay.dart index 3e8d0ad23..e217ab1ae 100644 --- a/lib/pangea/toolbar/layout/over_message_overlay.dart +++ b/lib/pangea/toolbar/layout/over_message_overlay.dart @@ -48,14 +48,18 @@ class OverMessageOverlay extends StatelessWidget { child: ValueListenableBuilder( valueListenable: controller.widget.overlayController.selectedMode, - builder: (context, mode, __) { + builder: (context, mode, _) { return OverlayCenterContent( event: controller.widget.event, messageHeight: mode != SelectMode.emoji ? controller.originalMessageSize.height : null, - messageWidth: controller.widget.overlayController - .selectModeController.isShowingExtraContent + messageWidth: + controller + .widget + .overlayController + .selectModeController + .isShowingExtraContent ? max(controller.originalMessageSize.width, 150) : controller.originalMessageSize.width, overlayController: controller.widget.overlayController, @@ -83,7 +87,8 @@ class OverMessageOverlay extends StatelessWidget { AnimatedContainer( duration: FluffyThemes.animationDuration, height: max(0, controller.spaceBelowContent), - width: controller.screenSize!.width - + width: + controller.screenSize!.width - controller.columnWidth - (controller.showDetails ? FluffyThemes.columnWidth : 0), ), diff --git a/lib/pangea/toolbar/layout/overlay_center_content.dart b/lib/pangea/toolbar/layout/overlay_center_content.dart index d2af9e89a..b4810bbd6 100644 --- a/lib/pangea/toolbar/layout/overlay_center_content.dart +++ b/lib/pangea/toolbar/layout/overlay_center_content.dart @@ -54,7 +54,8 @@ class OverlayCenterContent extends StatelessWidget { Widget build(BuildContext context) { final ownMessage = event.senderId == event.room.client.userID; return IgnorePointer( - ignoring: !isTransitionAnimation && + ignoring: + !isTransitionAnimation && readingAssistanceMode != ReadingAssistanceMode.practiceMode, child: Container( constraints: const BoxConstraints( @@ -87,8 +88,8 @@ class OverlayCenterContent extends StatelessWidget { readingAssistanceMode: readingAssistanceMode, canRefresh: (event.eventId == chatController.refreshEventID) && - (readingAssistanceMode != - ReadingAssistanceMode.practiceMode), + (readingAssistanceMode != + ReadingAssistanceMode.practiceMode), ), ), Padding( @@ -98,7 +99,7 @@ class OverlayCenterContent extends StatelessWidget { ), child: ValueListenableBuilder( valueListenable: reactionsWidth, - builder: (context, width, __) => PangeaMessageReactions( + builder: (context, width, _) => PangeaMessageReactions( event, chatController.timeline!, chatController, diff --git a/lib/pangea/toolbar/layout/overlay_message.dart b/lib/pangea/toolbar/layout/overlay_message.dart index cd6963d83..ec9018ace 100644 --- a/lib/pangea/toolbar/layout/overlay_message.dart +++ b/lib/pangea/toolbar/layout/overlay_message.dart @@ -63,11 +63,13 @@ class OverlayMessage extends StatelessWidget { final theme = Theme.of(context); final bool ownMessage = event.senderId == Matrix.of(context).client.userID; - final displayTime = event.type == EventTypes.RoomCreate || + final displayTime = + event.type == EventTypes.RoomCreate || nextEvent == null || !event.originServerTs.sameEnvironment(nextEvent!.originServerTs); - final nextEventSameSender = nextEvent != null && + final nextEventSameSender = + nextEvent != null && { EventTypes.Message, EventTypes.Sticker, @@ -76,7 +78,8 @@ class OverlayMessage extends StatelessWidget { nextEvent!.senderId == event.senderId && !displayTime; - final previousEventSameSender = previousEvent != null && + final previousEventSameSender = + previousEvent != null && { EventTypes.Message, EventTypes.Sticker, @@ -88,14 +91,14 @@ class OverlayMessage extends StatelessWidget { final textColor = event.isActivityMessage ? ThemeData.light().colorScheme.onPrimary : ownMessage - ? ThemeData.dark().colorScheme.onPrimary - : theme.colorScheme.onSurface; + ? ThemeData.dark().colorScheme.onPrimary + : theme.colorScheme.onSurface; final linkColor = theme.brightness == Brightness.light ? theme.colorScheme.primary : ownMessage - ? theme.colorScheme.onPrimary - : theme.colorScheme.onSurface; + ? theme.colorScheme.onPrimary + : theme.colorScheme.onSurface; final displayEvent = event.getDisplayEvent(timeline); const hardCorner = Radius.circular(4); @@ -103,10 +106,12 @@ class OverlayMessage extends StatelessWidget { final borderRadius = BorderRadius.only( topLeft: !ownMessage && nextEventSameSender ? hardCorner : roundedCorner, topRight: ownMessage && nextEventSameSender ? hardCorner : roundedCorner, - bottomLeft: - !ownMessage && previousEventSameSender ? hardCorner : roundedCorner, - bottomRight: - ownMessage && previousEventSameSender ? hardCorner : roundedCorner, + bottomLeft: !ownMessage && previousEventSameSender + ? hardCorner + : roundedCorner, + bottomRight: ownMessage && previousEventSameSender + ? hardCorner + : roundedCorner, ); var color = theme.colorScheme.surfaceContainerHigh; @@ -125,7 +130,8 @@ class OverlayMessage extends StatelessWidget { : theme.colorScheme.primary; } - final noBubble = ({ + final noBubble = + ({ MessageTypes.Video, MessageTypes.Image, MessageTypes.Sticker, @@ -145,9 +151,7 @@ class OverlayMessage extends StatelessWidget { final content = Container( decoration: BoxDecoration( - borderRadius: BorderRadius.circular( - AppConfig.borderRadius, - ), + borderRadius: BorderRadius.circular(AppConfig.borderRadius), ), width: messageWidth, height: messageHeight, @@ -155,26 +159,15 @@ class OverlayMessage extends StatelessWidget { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - if (event.inReplyToEventId( - includingFallback: false, - ) != - null) + if (event.inReplyToEventId(includingFallback: false) != null) FutureBuilder( - future: event.getReplyEvent( - timeline, - ), - builder: ( - BuildContext context, - snapshot, - ) { + future: event.getReplyEvent(timeline), + builder: (BuildContext context, snapshot) { final replyEvent = snapshot.hasData ? snapshot.data! : Event( eventId: event.relationshipEventId!, - content: { - 'msgtype': 'm.text', - 'body': '...', - }, + content: {'msgtype': 'm.text', 'body': '...'}, senderId: "", type: 'm.room.message', room: event.room, @@ -182,19 +175,14 @@ class OverlayMessage extends StatelessWidget { originServerTs: DateTime.now(), ); return Padding( - padding: const EdgeInsets.only( - left: 16, - right: 16, - top: 8, - ), + padding: const EdgeInsets.only(left: 16, right: 16, top: 8), child: Material( color: Colors.transparent, borderRadius: ReplyContent.borderRadius, child: InkWell( borderRadius: ReplyContent.borderRadius, - onTap: () => controller.scrollToEventId( - replyEvent.eventId, - ), + onTap: () => + controller.scrollToEventId(replyEvent.eventId), child: AbsorbPointer( child: ReplyContent( replyEvent, @@ -224,10 +212,7 @@ class OverlayMessage extends StatelessWidget { selected: true, ), ), - if (event.hasAggregatedEvents( - timeline, - RelationshipTypes.edit, - )) + if (event.hasAggregatedEvents(timeline, RelationshipTypes.edit)) Padding( padding: const EdgeInsets.only( bottom: 8.0, @@ -244,14 +229,10 @@ class OverlayMessage extends StatelessWidget { size: 14, ), Text( - displayEvent.originServerTs.localizedTimeShort( - context, - ), + displayEvent.originServerTs.localizedTimeShort(context), textScaler: TextScaler.noScaling, style: TextStyle( - color: textColor.withAlpha( - 164, - ), + color: textColor.withAlpha(164), fontSize: 11, ), ), @@ -272,10 +253,7 @@ class OverlayMessage extends StatelessWidget { : 0.0), ); - final style = AppConfig.messageTextStyle( - event, - textColor, - ); + final style = AppConfig.messageTextStyle(event, textColor); return Material( key: MatrixState.pAnyState.layerLinkAndKey(overlayKey).key, @@ -296,7 +274,8 @@ class OverlayMessage extends StatelessWidget { children: [ _MessageBubbleTranscription( controller: selectModeController, - enabled: event.messageType == MessageTypes.Audio && + enabled: + event.messageType == MessageTypes.Audio && !event.redacted && isSubscribed != false, maxWidth: maxWidth, @@ -344,12 +323,10 @@ class _MessageSelectModeContent extends StatelessWidget { @override Widget build(BuildContext context) { return ListenableBuilder( - listenable: Listenable.merge( - [ - controller.selectedMode, - controller.currentModeStateNotifier, - ], - ), + listenable: Listenable.merge([ + controller.selectedMode, + controller.currentModeStateNotifier, + ]), builder: (context, _) { final mode = controller.selectedMode.value; if (mode == null) { @@ -383,42 +360,38 @@ class _MessageSelectModeContent extends StatelessWidget { padding: const EdgeInsets.all(12.0), child: switch (state) { AsyncLoading() => Row( - mainAxisSize: MainAxisSize.min, - children: [ - CircularProgressIndicator.adaptive( - backgroundColor: style.color, - ), - ], - ), + mainAxisSize: MainAxisSize.min, + children: [ + CircularProgressIndicator.adaptive( + backgroundColor: style.color, + ), + ], + ), AsyncError(error: final _) => Row( - mainAxisSize: MainAxisSize.min, - children: [ - Icon( - Icons.error_outline, - color: Theme.of(context).colorScheme.error, - ), - const SizedBox(width: 8), - Text( - L10n.of(context).translationError, - textScaler: TextScaler.noScaling, - style: style.copyWith(fontStyle: FontStyle.italic), - ), - ], - ), + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + Icons.error_outline, + color: Theme.of(context).colorScheme.error, + ), + const SizedBox(width: 8), + Text( + L10n.of(context).translationError, + textScaler: TextScaler.noScaling, + style: style.copyWith(fontStyle: FontStyle.italic), + ), + ], + ), AsyncLoaded(value: final value) => Container( - constraints: BoxConstraints( - maxWidth: maxWidth, - ), - child: SingleChildScrollView( - child: Text( - value, - textScaler: TextScaler.noScaling, - style: style.copyWith( - fontStyle: FontStyle.italic, - ), - ), + constraints: BoxConstraints(maxWidth: maxWidth), + child: SingleChildScrollView( + child: Text( + value, + textScaler: TextScaler.noScaling, + style: style.copyWith(fontStyle: FontStyle.italic), ), ), + ), _ => const SizedBox(), }, ); diff --git a/lib/pangea/toolbar/layout/practice_mode_transition_animation.dart b/lib/pangea/toolbar/layout/practice_mode_transition_animation.dart index 21d8c0a7c..83eb29664 100644 --- a/lib/pangea/toolbar/layout/practice_mode_transition_animation.dart +++ b/lib/pangea/toolbar/layout/practice_mode_transition_animation.dart @@ -75,30 +75,26 @@ class PracticeModeTransitionAnimationState duration: widget.controller.transitionAnimationDuration, ); - _offsetAnimation = Tween( - begin: startOffset, - end: endOffset, - ).animate( - CurvedAnimation( - parent: _animationController!, - curve: FluffyThemes.animationCurve, - ), - ); + _offsetAnimation = Tween(begin: startOffset, end: endOffset) + .animate( + CurvedAnimation( + parent: _animationController!, + curve: FluffyThemes.animationCurve, + ), + ); final startSize = Size( widget.controller.originalMessageSize.width, widget.controller.originalMessageSize.height, ); - _sizeAnimation = Tween( - begin: startSize, - end: _centerMessageSize!, - ).animate( - CurvedAnimation( - parent: _animationController!, - curve: FluffyThemes.animationCurve, - ), - ); + _sizeAnimation = Tween(begin: startSize, end: _centerMessageSize!) + .animate( + CurvedAnimation( + parent: _animationController!, + curve: FluffyThemes.animationCurve, + ), + ); widget.controller.onStartedTransition(); setState(() {}); @@ -163,16 +159,13 @@ class PracticeModeTransitionAnimationState class CenteredMessage extends StatelessWidget { final MessageSelectionPositionerState controller; - const CenteredMessage({ - super.key, - required this.controller, - }); + const CenteredMessage({super.key, required this.controller}); @override Widget build(BuildContext context) { return ValueListenableBuilder( valueListenable: controller.finishedTransition, - builder: (context, finished, __) { + builder: (context, finished, _) { return Opacity( opacity: finished ? 1.0 : 0.0, child: GestureDetector( diff --git a/lib/pangea/toolbar/message_practice/message_audio_card.dart b/lib/pangea/toolbar/message_practice/message_audio_card.dart index cfc0bc204..6f218ab21 100644 --- a/lib/pangea/toolbar/message_practice/message_audio_card.dart +++ b/lib/pangea/toolbar/message_practice/message_audio_card.dart @@ -18,11 +18,7 @@ class MessageAudioCard extends StatefulWidget { final PangeaMessageEvent messageEvent; final VoidCallback? onError; - const MessageAudioCard({ - super.key, - required this.messageEvent, - this.onError, - }); + const MessageAudioCard({super.key, required this.messageEvent, this.onError}); @override MessageAudioCardState createState() => MessageAudioCardState(); @@ -73,20 +69,20 @@ class MessageAudioCardState extends State { child: _isLoading ? const TextLoadingShimmer(width: 200) : audioFile != null - ? AudioPlayerWidget( - null, - eventId: "${widget.messageEvent.eventId}_practice", - roomId: widget.messageEvent.room.id, - senderId: widget.messageEvent.senderId, - matrixFile: audioFile, - color: Theme.of(context).colorScheme.onPrimaryContainer, - fontSize: AppConfig.messageFontSize * - AppSettings.fontSizeFactor.value, - linkColor: Theme.of(context).brightness == Brightness.light - ? Theme.of(context).colorScheme.primary - : Theme.of(context).colorScheme.onPrimary, - ) - : const SizedBox(), + ? AudioPlayerWidget( + null, + eventId: "${widget.messageEvent.eventId}_practice", + roomId: widget.messageEvent.room.id, + senderId: widget.messageEvent.senderId, + matrixFile: audioFile, + color: Theme.of(context).colorScheme.onPrimaryContainer, + fontSize: + AppConfig.messageFontSize * AppSettings.fontSizeFactor.value, + linkColor: Theme.of(context).brightness == Brightness.light + ? Theme.of(context).colorScheme.primary + : Theme.of(context).colorScheme.onPrimary, + ) + : const SizedBox(), ); } } diff --git a/lib/pangea/toolbar/message_practice/message_morph_choice.dart b/lib/pangea/toolbar/message_practice/message_morph_choice.dart index 458932773..fcdf626e7 100644 --- a/lib/pangea/toolbar/message_practice/message_morph_choice.dart +++ b/lib/pangea/toolbar/message_practice/message_morph_choice.dart @@ -64,25 +64,25 @@ class MessageMorphInputBarContentState } TextStyle? textStyle(BuildContext context) => widget.maxWidth > 600 - ? Theme.of(context).textTheme.bodyLarge?.copyWith( - fontWeight: FontWeight.bold, - ) - : Theme.of(context).textTheme.bodyMedium?.copyWith( - fontWeight: FontWeight.bold, - ); + ? Theme.of( + context, + ).textTheme.bodyLarge?.copyWith(fontWeight: FontWeight.bold) + : Theme.of( + context, + ).textTheme.bodyMedium?.copyWith(fontWeight: FontWeight.bold); @override Widget build(BuildContext context) { final iconSize = widget.maxWidth > 600 ? 28.0 : widget.maxWidth > 600 - ? 24.0 - : 16.0; + ? 24.0 + : 16.0; final spacing = widget.maxWidth > 600 ? 16.0 : widget.maxWidth > 600 - ? 8.0 - : 4.0; + ? 8.0 + : 4.0; return Column( spacing: spacing, @@ -114,41 +114,42 @@ class MessageMorphInputBarContentState runAlignment: WrapAlignment.center, spacing: spacing, runSpacing: spacing, - children: widget.activity.multipleChoiceContent.choices.mapIndexed( - (index, choice) { - final wasCorrect = widget.controller.wasCorrectChoice(choice); + children: widget.activity.multipleChoiceContent.choices.mapIndexed(( + index, + choice, + ) { + final wasCorrect = widget.controller.wasCorrectChoice(choice); - return ChoiceAnimationWidget( - isSelected: selectedTag == choice, - isCorrect: wasCorrect, - child: MessageMorphChoiceItem( - cId: ConstructIdentifier( - lemma: choice, - type: ConstructTypeEnum.morph, - category: morph.name, - ), - onTap: () { - setState(() => selectedTag = choice); - widget.controller.onMatch( - token, - PracticeChoice( - choiceContent: choice, - form: ConstructForm( - cId: widget.activity.tokens.first.morphIdByFeature( - widget.activity.morphFeature, - )!, - form: token.text.content, - ), - ), - ); - }, - isSelected: selectedTag == choice, - isGold: wasCorrect, - shimmer: widget.controller.showChoiceShimmer, + return ChoiceAnimationWidget( + isSelected: selectedTag == choice, + isCorrect: wasCorrect, + child: MessageMorphChoiceItem( + cId: ConstructIdentifier( + lemma: choice, + type: ConstructTypeEnum.morph, + category: morph.name, ), - ); - }, - ).toList(), + onTap: () { + setState(() => selectedTag = choice); + widget.controller.onMatch( + token, + PracticeChoice( + choiceContent: choice, + form: ConstructForm( + cId: widget.activity.tokens.first.morphIdByFeature( + widget.activity.morphFeature, + )!, + form: token.text.content, + ), + ), + ); + }, + isSelected: selectedTag == choice, + isGold: wasCorrect, + shimmer: widget.controller.showChoiceShimmer, + ), + ); + }).toList(), ), if (selectedTag != null) Container( diff --git a/lib/pangea/toolbar/message_practice/message_morph_choice_item.dart b/lib/pangea/toolbar/message_practice/message_morph_choice_item.dart index 7aa99a354..b5053fd45 100644 --- a/lib/pangea/toolbar/message_practice/message_morph_choice_item.dart +++ b/lib/pangea/toolbar/message_practice/message_morph_choice_item.dart @@ -51,10 +51,9 @@ class MessageMorphChoiceItemState extends State { : AppConfig.warning.withAlpha((0.4 * 255).toInt()); } if (widget.isSelected) { - return Theme.of(context) - .colorScheme - .primary - .withAlpha((0.4 * 255).toInt()); + return Theme.of( + context, + ).colorScheme.primary.withAlpha((0.4 * 255).toInt()); } return _isHovered ? Theme.of(context).colorScheme.primary.withAlpha((0.2 * 255).toInt()) diff --git a/lib/pangea/toolbar/message_practice/message_practice_mode_enum.dart b/lib/pangea/toolbar/message_practice/message_practice_mode_enum.dart index e8d851186..1a1fdcb78 100644 --- a/lib/pangea/toolbar/message_practice/message_practice_mode_enum.dart +++ b/lib/pangea/toolbar/message_practice/message_practice_mode_enum.dart @@ -44,10 +44,7 @@ enum MessagePracticeMode { } } - Color iconButtonColor( - BuildContext context, - bool done, - ) => + Color iconButtonColor(BuildContext context, bool done) => done ? AppConfig.gold : Theme.of(context).colorScheme.primaryContainer; ActivityTypeEnum? get associatedActivityType { @@ -66,11 +63,11 @@ enum MessagePracticeMode { } static List get practiceModes => [ - MessagePracticeMode.listening, - MessagePracticeMode.wordMorph, - MessagePracticeMode.wordMeaning, - MessagePracticeMode.wordEmoji, - ]; + MessagePracticeMode.listening, + MessagePracticeMode.wordMorph, + MessagePracticeMode.wordMeaning, + MessagePracticeMode.wordEmoji, + ]; InstructionsEnum? get instruction { switch (this) { diff --git a/lib/pangea/toolbar/message_practice/morph_selection.dart b/lib/pangea/toolbar/message_practice/morph_selection.dart index 612a1698c..2821be0dd 100644 --- a/lib/pangea/toolbar/message_practice/morph_selection.dart +++ b/lib/pangea/toolbar/message_practice/morph_selection.dart @@ -5,10 +5,7 @@ class MorphSelection { PangeaToken token; MorphFeaturesEnum morph; - MorphSelection( - this.token, - this.morph, - ); + MorphSelection(this.token, this.morph); @override bool operator ==(Object other) { diff --git a/lib/pangea/toolbar/message_practice/practice_activity_card.dart b/lib/pangea/toolbar/message_practice/practice_activity_card.dart index 8561ea27a..176f5c072 100644 --- a/lib/pangea/toolbar/message_practice/practice_activity_card.dart +++ b/lib/pangea/toolbar/message_practice/practice_activity_card.dart @@ -43,9 +43,7 @@ class PracticeActivityCardState extends State { @override void initState() { super.initState(); - WidgetsBinding.instance.addPostFrameCallback( - (_) => _fetchActivity(), - ); + WidgetsBinding.instance.addPostFrameCallback((_) => _fetchActivity()); } @override @@ -87,31 +85,28 @@ class PracticeActivityCardState extends State { Widget build(BuildContext context) { return ValueListenableBuilder( valueListenable: _activityState, - builder: (context, state, __) { + builder: (context, state, _) { return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ switch (state) { - AsyncLoading() => const ContentLoadingIndicator( - height: 40, - ), + AsyncLoading() => const ContentLoadingIndicator(height: 40), AsyncError() => CardErrorWidget( - L10n.of(context).errorFetchingActivity, - ), + L10n.of(context).errorFetchingActivity, + ), AsyncLoaded() => switch (state.value) { - MultipleChoicePracticeActivityModel() => - MessageMorphInputBarContent( - controller: widget.controller, - activity: state.value as MorphPracticeActivityModel, - selectedToken: widget.selectedToken, - maxWidth: widget.maxWidth, - ), - MatchPracticeActivityModel() => MatchActivityCard( - currentActivity: - state.value as MatchPracticeActivityModel, - controller: widget.controller, - ), - }, + MultipleChoicePracticeActivityModel() => + MessageMorphInputBarContent( + controller: widget.controller, + activity: state.value as MorphPracticeActivityModel, + selectedToken: widget.selectedToken, + maxWidth: widget.maxWidth, + ), + MatchPracticeActivityModel() => MatchActivityCard( + currentActivity: state.value as MatchPracticeActivityModel, + controller: widget.controller, + ), + }, _ => const SizedBox.shrink(), }, ], diff --git a/lib/pangea/toolbar/message_practice/practice_controller.dart b/lib/pangea/toolbar/message_practice/practice_controller.dart index 5230499c3..1cdef8ae7 100644 --- a/lib/pangea/toolbar/message_practice/practice_controller.dart +++ b/lib/pangea/toolbar/message_practice/practice_controller.dart @@ -83,19 +83,14 @@ class PracticeController with ChangeNotifier { } return target == null || - PracticeRecordController.isCompleteByToken( - target, - token, - ); + PracticeRecordController.isCompleteByToken(target, token); } bool get showChoiceShimmer { if (_activity == null) return false; if (_activity is MorphMatchPracticeActivityModel) { return selectedMorph != null && - !PracticeRecordController.hasResponse( - _activity!.practiceTarget, - ); + !PracticeRecordController.hasResponse(_activity!.practiceTarget); } return selectedChoice == null && @@ -178,13 +173,16 @@ class PracticeController with ChangeNotifier { "message-token-${token.text.uniqueKey}-${pangeaMessageEvent.eventId}"; final updateService = MatrixState - .pangeaController.matrixState.analyticsDataService.updateService; + .pangeaController + .matrixState + .analyticsDataService + .updateService; // we don't take off points for incorrect emoji matches if (_activity is! EmojiPracticeActivityModel || isCorrect) { - final constructUseType = - PracticeRecordController.lastResponse(_activity!.practiceTarget)! - .useType(_activity!.activityType); + final constructUseType = PracticeRecordController.lastResponse( + _activity!.practiceTarget, + )!.useType(_activity!.activityType); final constructs = [ OneConstructUse( @@ -203,10 +201,7 @@ class PracticeController with ChangeNotifier { ), ]; - updateService.addAnalytics( - targetId, - constructs, - ); + updateService.addAnalytics(targetId, constructs); } if (isCorrect) { diff --git a/lib/pangea/toolbar/message_practice/practice_match_card.dart b/lib/pangea/toolbar/message_practice/practice_match_card.dart index 60506e821..189b59508 100644 --- a/lib/pangea/toolbar/message_practice/practice_match_card.dart +++ b/lib/pangea/toolbar/message_practice/practice_match_card.dart @@ -40,17 +40,15 @@ class MatchActivityCard extends StatelessWidget { case WordListeningPracticeActivityModel(): return Padding( padding: const EdgeInsets.all(8), - child: Icon( - Icons.volume_up, - size: fontSize, - ), + child: Icon(Icons.volume_up, size: fontSize), ); } } @override Widget build(BuildContext context) { - double fontSize = (FluffyThemes.isColumnMode(context) + double fontSize = + (FluffyThemes.isColumnMode(context) ? Theme.of(context).textTheme.titleLarge?.fontSize : Theme.of(context).textTheme.titleMedium?.fontSize) ?? 26; @@ -72,31 +70,34 @@ class MatchActivityCard extends StatelessWidget { alignment: WrapAlignment.center, spacing: 4.0, runSpacing: 4.0, - children: currentActivity.matchContent.choices.map( - (PracticeChoice cf) { - final bool? wasCorrect = controller.wasCorrectMatch(cf); - return ChoiceAnimationWidget( + children: currentActivity.matchContent.choices.map(( + PracticeChoice cf, + ) { + final bool? wasCorrect = controller.wasCorrectMatch(cf); + return ChoiceAnimationWidget( + isSelected: controller.selectedChoice == cf, + isCorrect: wasCorrect, + child: PracticeMatchItem( + token: currentActivity.tokens.firstWhereOrNull( + (t) => t.vocabConstructID == cf.form.cId, + ), isSelected: controller.selectedChoice == cf, isCorrect: wasCorrect, - child: PracticeMatchItem( - token: currentActivity.tokens.firstWhereOrNull( - (t) => t.vocabConstructID == cf.form.cId, - ), - isSelected: controller.selectedChoice == cf, - isCorrect: wasCorrect, - constructForm: cf, - content: - choiceDisplayContent(context, cf.choiceContent, fontSize), - audioContent: - currentActivity is WordListeningPracticeActivityModel - ? cf.choiceContent - : null, - controller: controller, - shimmer: controller.showChoiceShimmer, + constructForm: cf, + content: choiceDisplayContent( + context, + cf.choiceContent, + fontSize, ), - ); - }, - ).toList(), + audioContent: + currentActivity is WordListeningPracticeActivityModel + ? cf.choiceContent + : null, + controller: controller, + shimmer: controller.showChoiceShimmer, + ), + ); + }).toList(), ), ], ); diff --git a/lib/pangea/toolbar/message_practice/practice_match_item.dart b/lib/pangea/toolbar/message_practice/practice_match_item.dart index 055250ed9..13b3547b9 100644 --- a/lib/pangea/toolbar/message_practice/practice_match_item.dart +++ b/lib/pangea/toolbar/message_practice/practice_match_item.dart @@ -72,11 +72,7 @@ class PracticeMatchItemState extends State { } } catch (e, s) { debugger(when: kDebugMode); - ErrorHandler.logError( - e: e, - s: s, - data: {"text": widget.audioContent}, - ); + ErrorHandler.logError(e: e, s: s, data: {"text": widget.audioContent}); } finally { if (mounted) { setState(() => _isPlaying = false); @@ -128,14 +124,8 @@ class PracticeMatchItemState extends State { color: color(context).withAlpha((0.4 * 255).toInt()), borderRadius: BorderRadius.circular(AppConfig.borderRadius), border: isSelected - ? Border.all( - color: color(context).withAlpha(255), - width: 2, - ) - : Border.all( - color: Colors.transparent, - width: 2, - ), + ? Border.all(color: color(context).withAlpha(255), width: 2) + : Border.all(color: Colors.transparent, width: 2), ), child: widget.content, ), @@ -145,19 +135,13 @@ class PracticeMatchItemState extends State { return Draggable( data: widget.constructForm, - feedback: Material( - type: MaterialType.transparency, - child: content, - ), + feedback: Material(type: MaterialType.transparency, child: content), onDragStarted: onTap, child: InkWell( onHover: (isHovered) => setState(() => _isHovered = isHovered), borderRadius: BorderRadius.circular(AppConfig.borderRadius), onTap: onTap, - child: ShimmerBackground( - enabled: widget.shimmer, - child: content, - ), + child: ShimmerBackground(enabled: widget.shimmer, child: content), ), ); } diff --git a/lib/pangea/toolbar/message_practice/practice_record_controller.dart b/lib/pangea/toolbar/message_practice/practice_record_controller.dart index 9bb3f396e..831a08da1 100644 --- a/lib/pangea/toolbar/message_practice/practice_record_controller.dart +++ b/lib/pangea/toolbar/message_practice/practice_record_controller.dart @@ -30,10 +30,7 @@ class PracticeRecordController { ); } - static bool? wasCorrectMatch( - PracticeTarget target, - PracticeChoice choice, - ) { + static bool? wasCorrectMatch(PracticeTarget target, PracticeChoice choice) { final record = _recordByTarget(target); for (final response in record.responses) { if (response.text == choice.choiceContent && response.isCorrect) { @@ -48,10 +45,7 @@ class PracticeRecordController { return null; } - static bool? wasCorrectChoice( - PracticeTarget target, - String choice, - ) { + static bool? wasCorrectChoice(PracticeTarget target, String choice) { final record = _recordByTarget(target); for (final response in record.responses) { if (response.text == choice) { @@ -74,14 +68,11 @@ class PracticeRecordController { ); } - static bool isCompleteByToken( - PracticeTarget target, - PangeaToken token, - ) { + static bool isCompleteByToken(PracticeTarget target, PangeaToken token) { final cId = target.targetTokenConstructID(token); - return _recordByTarget(target).responses.any( - (res) => res.cId == cId && res.isCorrect, - ); + return _recordByTarget( + target, + ).responses.any((res) => res.cId == cId && res.isCorrect); } static bool hasAnyCorrectChoices(PracticeTarget target) { diff --git a/lib/pangea/toolbar/message_practice/reading_assistance_input_bar.dart b/lib/pangea/toolbar/message_practice/reading_assistance_input_bar.dart index 5eaf37f51..3385594e4 100644 --- a/lib/pangea/toolbar/message_practice/reading_assistance_input_bar.dart +++ b/lib/pangea/toolbar/message_practice/reading_assistance_input_bar.dart @@ -52,22 +52,21 @@ class ReadingAssistanceInputBarState extends State { spacing: 4.0, mainAxisSize: MainAxisSize.min, children: [ - ...MessagePracticeMode.practiceModes.map( - (m) { - final complete = widget.controller.isPracticeSessionDone( - m.associatedActivityType!, - ); - return ToolbarButton( - mode: m, - setMode: () => widget.controller.updateToolbarMode(m), - isComplete: complete, - isSelected: widget.controller.practiceMode == m, - shimmer: widget.controller.practiceMode == - MessagePracticeMode.noneSelected && - !complete, - ); - }, - ), + ...MessagePracticeMode.practiceModes.map((m) { + final complete = widget.controller.isPracticeSessionDone( + m.associatedActivityType!, + ); + return ToolbarButton( + mode: m, + setMode: () => widget.controller.updateToolbarMode(m), + isComplete: complete, + isSelected: widget.controller.practiceMode == m, + shimmer: + widget.controller.practiceMode == + MessagePracticeMode.noneSelected && + !complete, + ); + }), ], ), Padding( @@ -131,10 +130,7 @@ class _ReadingAssistanceBarContent extends StatelessWidget { case MessagePracticeMode.noneSelected: return controller.isTotallyDone ? const _AllDoneWidget() - : const Icon( - Symbols.fitness_center, - size: 60.0, - ); + : const Icon(Symbols.fitness_center, size: 60.0); case MessagePracticeMode.wordEmoji: case MessagePracticeMode.wordMeaning: @@ -180,12 +176,7 @@ class _ReadingAssistanceBarContent extends StatelessWidget { } if (target == null) { - return const Center( - child: Icon( - Symbols.fitness_center, - size: 60.0, - ), - ); + return const Center(child: Icon(Symbols.fitness_center, size: 60.0)); } return PracticeActivityCard( @@ -209,9 +200,9 @@ class _AllDoneWidget extends StatelessWidget { Text( L10n.of(context).allDone, style: Theme.of(context).textTheme.bodyLarge?.copyWith( - fontWeight: FontWeight.bold, - letterSpacing: 0.5, - ), + fontWeight: FontWeight.bold, + letterSpacing: 0.5, + ), textAlign: TextAlign.center, ), ElevatedButton( diff --git a/lib/pangea/toolbar/message_practice/token_practice_button.dart b/lib/pangea/toolbar/message_practice/token_practice_button.dart index a585e1290..9777308b9 100644 --- a/lib/pangea/toolbar/message_practice/token_practice_button.dart +++ b/lib/pangea/toolbar/message_practice/token_practice_button.dart @@ -42,8 +42,8 @@ class TokenPracticeButton extends StatelessWidget { }); TextStyle get _emojiStyle => TextStyle( - fontSize: (textStyle.fontSize ?? tokenButtonDefaultFontSize) + 4, - ); + fontSize: (textStyle.fontSize ?? tokenButtonDefaultFontSize) + 4, + ); PracticeTarget? get _activity => controller.practiceTargetForToken(token); @@ -85,12 +85,10 @@ class TokenPracticeButton extends StatelessWidget { textColor: textColor, width: tokenButtonHeight, onTap: () => controller.onSelectMorph( - MorphSelection( - token, - _activity!.morphFeature!, - ), + MorphSelection(token, _activity!.morphFeature!), ), - shimmer: controller.selectedMorph == null && + shimmer: + controller.selectedMorph == null && _activity != null && !PracticeRecordController.hasAnyCorrectChoices(_activity!), ); @@ -141,7 +139,8 @@ class _StandardMatchButton extends StatelessWidget { Widget build(BuildContext context) { return DragTarget( builder: (BuildContext context, accepted, rejected) { - final double colorAlpha = 0.3 + + final double colorAlpha = + 0.3 + (selectedChoice != null ? 0.4 : 0.0) + (accepted.isNotEmpty ? 0.3 : 0.0); @@ -151,8 +150,9 @@ class _StandardMatchButton extends StatelessWidget { return Material( type: MaterialType.transparency, child: InkWell( - onTap: - selectedChoice != null ? () => onMatch(selectedChoice!) : null, + onTap: selectedChoice != null + ? () => onMatch(selectedChoice!) + : null, borderRadius: borderRadius, child: CustomPaint( painter: DottedBorderPainter( @@ -258,12 +258,9 @@ class _NoActivityContentButton extends StatelessWidget { if (practiceMode == MessagePracticeMode.wordEmoji && target != null) { final displayEmoji = PracticeRecordController.correctResponse(target!, token)?.text ?? - token.vocabConstructID.userSetEmoji ?? - ''; - return Text( - displayEmoji, - style: emojiStyle, - ); + token.vocabConstructID.userSetEmoji ?? + ''; + return Text(displayEmoji, style: emojiStyle); } if (practiceMode == MessagePracticeMode.wordMorph && target != null) { final morphFeature = target!.morphFeature!; @@ -282,8 +279,8 @@ class _NoActivityContentButton extends StatelessWidget { radius: width / 2, backgroundColor: Theme.of(context).brightness != Brightness.light - ? Theme.of(context).colorScheme.surface.withAlpha(100) - : null, + ? Theme.of(context).colorScheme.surface.withAlpha(100) + : null, child: Padding( padding: const EdgeInsets.all(4.0), child: MorphIcon( diff --git a/lib/pangea/toolbar/message_practice/toolbar_button.dart b/lib/pangea/toolbar/message_practice/toolbar_button.dart index c4981c87e..9c65be8f2 100644 --- a/lib/pangea/toolbar/message_practice/toolbar_button.dart +++ b/lib/pangea/toolbar/message_practice/toolbar_button.dart @@ -37,8 +37,9 @@ class ToolbarButton extends StatelessWidget { color: color, onPressed: setMode, playSound: true, - colorFactor: - Theme.of(context).brightness == Brightness.light ? 0.55 : 0.3, + colorFactor: Theme.of(context).brightness == Brightness.light + ? 0.55 + : 0.3, builder: (context, depressed, shadowColor) => Stack( alignment: Alignment.center, children: [ @@ -53,10 +54,9 @@ class ToolbarButton extends StatelessWidget { if (shimmer) Shimmer.fromColors( baseColor: Colors.transparent, - highlightColor: Theme.of(context) - .colorScheme - .primaryContainer - .withAlpha(0xAA), + highlightColor: Theme.of( + context, + ).colorScheme.primaryContainer.withAlpha(0xAA), child: Container( height: 40.0, width: 40.0, @@ -66,10 +66,7 @@ class ToolbarButton extends StatelessWidget { ), ), ), - Icon( - mode.icon, - size: 20, - ), + Icon(mode.icon, size: 20), ], ), ), diff --git a/lib/pangea/toolbar/message_selection_overlay.dart b/lib/pangea/toolbar/message_selection_overlay.dart index ed66f5c79..84254d64e 100644 --- a/lib/pangea/toolbar/message_selection_overlay.dart +++ b/lib/pangea/toolbar/message_selection_overlay.dart @@ -43,11 +43,11 @@ class MessageSelectionOverlay extends StatefulWidget { required Event? prevEvent, required Timeline timeline, super.key, - }) : _initialSelectedToken = initialSelectedToken, - _nextEvent = nextEvent, - _prevEvent = prevEvent, - _event = event, - _timeline = timeline; + }) : _initialSelectedToken = initialSelectedToken, + _nextEvent = nextEvent, + _prevEvent = prevEvent, + _event = event, + _timeline = timeline; @override MessageOverlayController createState() => MessageOverlayController(); @@ -130,9 +130,7 @@ class MessageOverlayController extends State ErrorHandler.logError( e: e, s: s, - data: { - "eventID": pangeaMessageEvent.eventId, - }, + data: {"eventID": pangeaMessageEvent.eventId}, ); } finally { _initializeSelectedToken(); @@ -232,10 +230,10 @@ class MessageOverlayController extends State } PangeaMessageEvent get pangeaMessageEvent => PangeaMessageEvent( - event: widget._event, - timeline: widget._timeline, - ownMessage: widget._event.room.client.userID == widget._event.senderId, - ); + event: widget._event, + timeline: widget._timeline, + ownMessage: widget._event.room.client.userID == widget._event.senderId, + ); PangeaToken? get selectedToken { if (pangeaMessageEvent.isAudioMessage == true) { @@ -265,8 +263,9 @@ class MessageOverlayController extends State } if (const ListEquality().equals(textToSelect, _highlightedTokens)) return; - _highlightedTokens = - textToSelect.isEmpty ? null : textToSelect.map((t) => t.text).toList(); + _highlightedTokens = textToSelect.isEmpty + ? null + : textToSelect.map((t) => t.text).toList(); setState(() {}); } @@ -275,8 +274,8 @@ class MessageOverlayController extends State pangeaMessageEvent.messageDisplayRepresentation; if (repEvent != null) return repEvent; - final eventID = - await pangeaMessageEvent.requestRepresentationByDetectedLanguage(); + final eventID = await pangeaMessageEvent + .requestRepresentationByDetectedLanguage(); if (eventID == null) return null; final event = await widget._event.room.getEventById(eventID); @@ -288,14 +287,13 @@ class MessageOverlayController extends State ); } - void onClickOverlayMessageToken( - PangeaToken token, - ) => + void onClickOverlayMessageToken(PangeaToken token) => updateSelectedSpan(token.text); /// Whether the given token is currently selected or highlighted bool isTokenSelected(PangeaToken token) { - final isSelected = _selectedSpan?.offset == token.text.offset && + final isSelected = + _selectedSpan?.offset == token.text.offset && _selectedSpan?.length == token.text.length; return isSelected; } diff --git a/lib/pangea/toolbar/reading_assistance/lemma_emoji_choice_item.dart b/lib/pangea/toolbar/reading_assistance/lemma_emoji_choice_item.dart index b1d01164b..279ec4f74 100644 --- a/lib/pangea/toolbar/reading_assistance/lemma_emoji_choice_item.dart +++ b/lib/pangea/toolbar/reading_assistance/lemma_emoji_choice_item.dart @@ -23,10 +23,9 @@ class LemmaEmojiChoiceItemState extends State { Color color(BuildContext context) { if (_isHovered) { - return Theme.of(context) - .colorScheme - .primaryContainer - .withAlpha((0.4 * 255).toInt()); + return Theme.of( + context, + ).colorScheme.primaryContainer.withAlpha((0.4 * 255).toInt()); } return Colors.transparent; @@ -56,10 +55,7 @@ class LemmaEmojiChoiceItemState extends State { } class LemmaEmojiChoicePlaceholder extends StatelessWidget { - const LemmaEmojiChoicePlaceholder({ - super.key, - this.size = 40, - }); + const LemmaEmojiChoicePlaceholder({super.key, this.size = 40}); final double size; @@ -67,8 +63,9 @@ class LemmaEmojiChoicePlaceholder extends StatelessWidget { Widget build(BuildContext context) { return Shimmer.fromColors( baseColor: Colors.transparent, - highlightColor: - Theme.of(context).colorScheme.primaryContainer.withAlpha(0xAA), + highlightColor: Theme.of( + context, + ).colorScheme.primaryContainer.withAlpha(0xAA), child: Container( height: size, width: size, diff --git a/lib/pangea/toolbar/reading_assistance/lemma_emoji_picker.dart b/lib/pangea/toolbar/reading_assistance/lemma_emoji_picker.dart index 965787745..5162a0c76 100644 --- a/lib/pangea/toolbar/reading_assistance/lemma_emoji_picker.dart +++ b/lib/pangea/toolbar/reading_assistance/lemma_emoji_picker.dart @@ -20,10 +20,7 @@ class LemmaEmojiPicker extends StatelessWidget { @override Widget build(BuildContext context) { return Container( - padding: const EdgeInsets.symmetric( - vertical: 4, - horizontal: 8, - ), + padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 8), width: (40 * 5) + (4 * 5) + 16, // 5 items max + padding child: Row( spacing: 4.0, diff --git a/lib/pangea/toolbar/reading_assistance/new_word_overlay.dart b/lib/pangea/toolbar/reading_assistance/new_word_overlay.dart index 3f66827bb..03541e7c1 100644 --- a/lib/pangea/toolbar/reading_assistance/new_word_overlay.dart +++ b/lib/pangea/toolbar/reading_assistance/new_word_overlay.dart @@ -39,29 +39,29 @@ class _NewWordOverlayState extends State _opacityAnim = TweenSequence([ TweenSequenceItem( - tween: Tween(begin: 0.0, end: 1.0) - .chain(CurveTween(curve: Curves.easeIn)), + tween: Tween( + begin: 0.0, + end: 1.0, + ).chain(CurveTween(curve: Curves.easeIn)), weight: 25, ), + TweenSequenceItem(tween: ConstantTween(1.0), weight: 25), TweenSequenceItem( - tween: ConstantTween(1.0), - weight: 25, - ), - TweenSequenceItem( - tween: Tween(begin: 1.0, end: 0.0) - .chain(CurveTween(curve: Curves.easeOut)), + tween: Tween( + begin: 1.0, + end: 0.0, + ).chain(CurveTween(curve: Curves.easeOut)), weight: 50, ), ]).animate(_controller!); _backgroundFadeAnim = TweenSequence([ + TweenSequenceItem(tween: ConstantTween(1.0), weight: 50), TweenSequenceItem( - tween: ConstantTween(1.0), - weight: 50, - ), - TweenSequenceItem( - tween: Tween(begin: 1.0, end: 0.0) - .chain(CurveTween(curve: Curves.easeOut)), + tween: Tween( + begin: 1.0, + end: 0.0, + ).chain(CurveTween(curve: Curves.easeOut)), weight: 50, ), ]).animate(_controller!); @@ -112,10 +112,7 @@ class _NewWordOverlayState extends State return Transform.translate( offset: Offset(0, moveY), - child: Opacity( - opacity: opacity, - child: const NewVocabBubble(), - ), + child: Opacity(opacity: opacity, child: const NewVocabBubble()), ); }, ), @@ -157,18 +154,11 @@ class NewVocabBubble extends StatelessWidget { color: theme.colorScheme.surfaceContainerHighest, borderRadius: const BorderRadius.all(Radius.circular(16.0)), ), - padding: const EdgeInsets.symmetric( - vertical: 8.0, - horizontal: 16.0, - ), + padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0), child: Row( mainAxisSize: MainAxisSize.min, children: [ - Icon( - Symbols.dictionary, - color: theme.colorScheme.primary, - size: 24, - ), + Icon(Symbols.dictionary, color: theme.colorScheme.primary, size: 24), const SizedBox(width: 4.0), Text( "+ 1", diff --git a/lib/pangea/toolbar/reading_assistance/select_mode_buttons.dart b/lib/pangea/toolbar/reading_assistance/select_mode_buttons.dart index 227a8781e..6db9b759e 100644 --- a/lib/pangea/toolbar/reading_assistance/select_mode_buttons.dart +++ b/lib/pangea/toolbar/reading_assistance/select_mode_buttons.dart @@ -198,8 +198,8 @@ class SelectModeButtonsState extends State { final updatedMode = controller.selectedMode.value == mode && mode != SelectMode.audio - ? null - : mode; + ? null + : mode; controller.setSelectMode(updatedMode); if (updatedMode == SelectMode.audio) { @@ -227,9 +227,7 @@ class SelectModeButtonsState extends State { } if (updatedMode == SelectMode.requestRegenerate) { - await widget.controller.requestRegeneration( - messageEvent.eventId, - ); + await widget.controller.requestRegeneration(messageEvent.eventId); if (mounted) { controller.setSelectMode(null); @@ -255,8 +253,9 @@ class SelectModeButtonsState extends State { if (target != null) TextButton( style: TextButton.styleFrom( - foregroundColor: - Theme.of(context).colorScheme.primaryContainer, + foregroundColor: Theme.of( + context, + ).colorScheme.primaryContainer, ), onPressed: () => widget.controller.updateLanguageOnMismatch(target), @@ -270,7 +269,8 @@ class SelectModeButtonsState extends State { Future playAudio() async { final playerID = "${messageEvent.eventId}_button"; - final isPlaying = matrix?.audioPlayer != null && + final isPlaying = + matrix?.audioPlayer != null && matrix?.voiceMessageEventId.value == playerID && matrix!.audioPlayer!.playerState.processingState != ProcessingState.completed; @@ -291,8 +291,9 @@ class SelectModeButtonsState extends State { matrix?.voiceMessageEventId.value = "${messageEvent.eventId}_button"; _playerStateSub?.cancel(); - _playerStateSub = - matrix?.audioPlayer?.playerStateStream.listen(_onUpdatePlayerState); + _playerStateSub = matrix?.audioPlayer?.playerStateStream.listen( + _onUpdatePlayerState, + ); _audioSub?.cancel(); _audioSub = matrix?.audioPlayer?.positionStream.listen(_onPlayAudio); @@ -311,10 +312,7 @@ class SelectModeButtonsState extends State { await matrix?.audioPlayer?.setFilePath(audioFile.path); } else { await matrix?.audioPlayer?.setAudioSource( - BytesAudioSource( - pangeaAudioFile.bytes, - pangeaAudioFile.mimeType, - ), + BytesAudioSource(pangeaAudioFile.bytes, pangeaAudioFile.mimeType), ); } @@ -330,9 +328,7 @@ class SelectModeButtonsState extends State { e: e, s: s, m: 'something wrong playing message audio', - data: { - 'event': messageEvent.event.toJson(), - }, + data: {'event': messageEvent.event.toJson()}, ); } } @@ -374,7 +370,8 @@ class SelectModeButtonsState extends State { if (ttsToken == null) return; - final isPlaying = matrix?.audioPlayer != null && + final isPlaying = + matrix?.audioPlayer != null && matrix!.audioPlayer!.playerState.processingState != ProcessingState.completed; @@ -408,12 +405,10 @@ class SelectModeButtonsState extends State { child: Tooltip( message: mode.tooltip(context), child: ListenableBuilder( - listenable: Listenable.merge( - [ - controller.selectedMode, - controller.modeStateNotifier(mode), - ], - ), + listenable: Listenable.merge([ + controller.selectedMode, + controller.modeStateNotifier(mode), + ]), builder: (context, _) { final selectedMode = controller.selectedMode.value; return Opacity( @@ -422,41 +417,50 @@ class SelectModeButtonsState extends State { borderRadius: BorderRadius.circular(20), depressed: mode == selectedMode || !enabled, color: theme.colorScheme.primaryContainer, - onPressed: - enabled ? () => updateMode(mode) : modeDisabled, + onPressed: enabled + ? () => updateMode(mode) + : modeDisabled, playSound: enabled && mode != SelectMode.audio, - colorFactor: - theme.brightness == Brightness.light ? 0.55 : 0.3, + colorFactor: theme.brightness == Brightness.light + ? 0.55 + : 0.3, builder: (context, depressed, shadowColor) => ShimmerBackground( - enabled: !InstructionsEnum - .shimmerTranslation.isToggledOff && - mode == SelectMode.translate && - enabled, - borderRadius: BorderRadius.circular(100), - child: AnimatedContainer( - duration: FluffyThemes.animationDuration, - height: buttonSize, - width: buttonSize, - decoration: BoxDecoration( - color: depressed - ? shadowColor - : theme.colorScheme.primaryContainer, - shape: BoxShape.circle, - ), - child: ValueListenableBuilder( - valueListenable: _isPlayingNotifier, - builder: (context, playing, __) => - _SelectModeButtonIcon( - mode: mode, - loading: controller.isLoading && - mode == selectedMode, - playing: mode == SelectMode.audio && playing, - color: theme.colorScheme.onPrimaryContainer, + enabled: + !InstructionsEnum + .shimmerTranslation + .isToggledOff && + mode == SelectMode.translate && + enabled, + borderRadius: BorderRadius.circular(100), + child: AnimatedContainer( + duration: FluffyThemes.animationDuration, + height: buttonSize, + width: buttonSize, + decoration: BoxDecoration( + color: depressed + ? shadowColor + : theme.colorScheme.primaryContainer, + shape: BoxShape.circle, + ), + child: ValueListenableBuilder( + valueListenable: _isPlayingNotifier, + builder: (context, playing, _) => + _SelectModeButtonIcon( + mode: mode, + loading: + controller.isLoading && + mode == selectedMode, + playing: + mode == SelectMode.audio && + playing, + color: theme + .colorScheme + .onPrimaryContainer, + ), + ), ), ), - ), - ), ), ); }, @@ -521,10 +525,7 @@ class _MoreButton extends StatelessWidget { final ChatController controller; final PangeaMessageEvent? messageEvent; - const _MoreButton({ - required this.controller, - this.messageEvent, - }); + const _MoreButton({required this.controller, this.messageEvent}); bool _messageActionEnabled(MessageActions action) { if (messageEvent == null) return false; @@ -544,7 +545,8 @@ class _MoreButton extends StatelessWidget { return false; } - final isPinned = events.length == 1 && + final isPinned = + events.length == 1 && controller.room.pinnedEventIds.contains(events.first.eventId); switch (action) { @@ -577,17 +579,14 @@ class _MoreButton extends StatelessWidget { Future _showMenu(BuildContext context) async { final RenderBox button = context.findRenderObject() as RenderBox; - final RenderBox overlay = Overlay.of(context, rootOverlay: true) - .context - .findRenderObject() as RenderBox; + final RenderBox overlay = + Overlay.of(context, rootOverlay: true).context.findRenderObject() + as RenderBox; final Offset offset = button.localToGlobal(Offset.zero, ancestor: overlay); final RelativeRect position = RelativeRect.fromRect( - Rect.fromPoints( - offset, - offset + button.size.bottomRight(Offset.zero), - ), + Rect.fromPoints(offset, offset + button.size.bottomRight(Offset.zero)), Offset.zero & overlay.size, ); @@ -616,10 +615,7 @@ class _MoreButton extends StatelessWidget { _onActionPressed(action, context); } - void _onActionPressed( - MessageActions action, - BuildContext context, - ) { + void _onActionPressed(MessageActions action, BuildContext context) { switch (action) { case MessageActions.reply: controller.replyAction(); @@ -646,11 +642,7 @@ class _MoreButton extends StatelessWidget { case MessageActions.report: final event = controller.selectedEvents.first; controller.clearSelectedEvents(); - reportEvent( - event, - controller, - controller.context, - ); + reportEvent(event, controller, controller.context); break; case MessageActions.info: controller.showEventInfo(); @@ -683,10 +675,7 @@ class _MoreButton extends StatelessWidget { color: depressed ? shadowColor : theme.colorScheme.primaryContainer, shape: BoxShape.circle, ), - child: const Icon( - Icons.more_horiz, - size: 20, - ), + child: const Icon(Icons.more_horiz, size: 20), ), ), ); diff --git a/lib/pangea/toolbar/reading_assistance/select_mode_controller.dart b/lib/pangea/toolbar/reading_assistance/select_mode_controller.dart index 1f1a7890b..b748e4bc0 100644 --- a/lib/pangea/toolbar/reading_assistance/select_mode_controller.dart +++ b/lib/pangea/toolbar/reading_assistance/select_mode_controller.dart @@ -21,9 +21,9 @@ class _TranscriptionLoader extends AsyncLoader { @override Future fetch() => messageEvent.requestSpeechToText( - MatrixState.pangeaController.userController.userL1!.langCodeShort, - MatrixState.pangeaController.userController.userL2!.langCodeShort, - ); + MatrixState.pangeaController.userController.userL1!.langCodeShort, + MatrixState.pangeaController.userController.userL2!.langCodeShort, + ); } class _STTTranslationLoader extends AsyncLoader { @@ -32,13 +32,10 @@ class _STTTranslationLoader extends AsyncLoader { @override Future fetch() => messageEvent.requestSttTranslation( - langCode: - MatrixState.pangeaController.userController.userL1!.langCodeShort, - l1Code: - MatrixState.pangeaController.userController.userL1!.langCodeShort, - l2Code: - MatrixState.pangeaController.userController.userL2!.langCodeShort, - ); + langCode: MatrixState.pangeaController.userController.userL1!.langCodeShort, + l1Code: MatrixState.pangeaController.userController.userL1!.langCodeShort, + l2Code: MatrixState.pangeaController.userController.userL2!.langCodeShort, + ); } class _TranslationLoader extends AsyncLoader { @@ -81,12 +78,11 @@ class SelectModeController with LemmaEmojiSetter { final _AudioLoader _audioLoader; final _STTTranslationLoader _sttTranslationLoader; - SelectModeController( - this.messageEvent, - ) : _transcriptLoader = _TranscriptionLoader(messageEvent), - _translationLoader = _TranslationLoader(messageEvent), - _audioLoader = _AudioLoader(messageEvent), - _sttTranslationLoader = _STTTranslationLoader(messageEvent); + SelectModeController(this.messageEvent) + : _transcriptLoader = _TranscriptionLoader(messageEvent), + _translationLoader = _TranslationLoader(messageEvent), + _audioLoader = _AudioLoader(messageEvent), + _sttTranslationLoader = _STTTranslationLoader(messageEvent); ValueNotifier selectedMode = ValueNotifier(null); @@ -105,15 +101,13 @@ class SelectModeController with LemmaEmojiSetter { } static List get _textModes => [ - SelectMode.audio, - SelectMode.translate, - SelectMode.practice, - SelectMode.emoji, - ]; + SelectMode.audio, + SelectMode.translate, + SelectMode.practice, + SelectMode.emoji, + ]; - static List get _audioModes => [ - SelectMode.speechTranslation, - ]; + static List get _audioModes => [SelectMode.speechTranslation]; ValueNotifier> get translationState => _translationLoader.state; @@ -156,18 +150,20 @@ class SelectModeController with LemmaEmojiSetter { List modes = []; final lang = messageEvent.messageDisplayLangCode.split("-").first; - final matchesL1 = lang == + final matchesL1 = + lang == MatrixState.pangeaController.userController.userL1!.langCodeShort; if (messageEvent.event.messageType == MessageTypes.Text) { - final matchesL2 = lang == + final matchesL2 = + lang == MatrixState.pangeaController.userController.userL2!.langCodeShort; modes = matchesL2 ? _textModes : matchesL1 - ? [] - : [SelectMode.translate]; + ? [] + : [SelectMode.translate]; } else { modes = matchesL1 ? [] : _audioModes; } diff --git a/lib/pangea/toolbar/reading_assistance/stt_transcript_tokens.dart b/lib/pangea/toolbar/reading_assistance/stt_transcript_tokens.dart index 2a25706b9..56d7f2b6b 100644 --- a/lib/pangea/toolbar/reading_assistance/stt_transcript_tokens.dart +++ b/lib/pangea/toolbar/reading_assistance/stt_transcript_tokens.dart @@ -39,18 +39,15 @@ class SttTranscriptTokens extends StatelessWidget { } final messageCharacters = model.transcript.text.characters; - final newTokens = TokensUtil.getNewTokens( - eventId, - tokens, - model.langCode, - ); + final newTokens = TokensUtil.getNewTokens(eventId, tokens, model.langCode); return RichText( textScaler: TextScaler.noScaling, text: TextSpan( style: style ?? DefaultTextStyle.of(context).style, - children: - TokensUtil.getGlobalTokenPositions(tokens).map((tokenPosition) { + children: TokensUtil.getGlobalTokenPositions(tokens).map(( + tokenPosition, + ) { final text = messageCharacters .skip(tokenPosition.startIndex) .take(tokenPosition.endIndex - tokenPosition.startIndex) diff --git a/lib/pangea/toolbar/reading_assistance/token_emoji_button.dart b/lib/pangea/toolbar/reading_assistance/token_emoji_button.dart index f5f5cbc74..a74bc4997 100644 --- a/lib/pangea/toolbar/reading_assistance/token_emoji_button.dart +++ b/lib/pangea/toolbar/reading_assistance/token_emoji_button.dart @@ -68,10 +68,7 @@ class TokenEmojiButton extends StatelessWidget with LemmaEmojiSetter { final layer = MatrixState.pAnyState.layerLinkAndKey(targetId!); content = CompositedTransformTarget( link: layer.link, - child: KeyedSubtree( - key: layer.key, - child: content, - ), + child: KeyedSubtree(key: layer.key, child: content), ); } @@ -97,20 +94,16 @@ class _EmojiText extends StatelessWidget { if (!enabled || token == null) return const SizedBox.shrink(); return StreamBuilder( - stream: Matrix.of(context) - .analyticsDataService - .updateDispatcher + stream: Matrix.of(context).analyticsDataService.updateDispatcher .lemmaUpdateStream(token!.vocabConstructID), builder: (context, snapshot) { - final emoji = snapshot.data?.emojis?.firstOrNull ?? + final emoji = + snapshot.data?.emojis?.firstOrNull ?? token!.vocabConstructID.userSetEmoji; return Text( emoji ?? "-", - style: TextStyle( - fontSize: fontSize, - color: textColor, - ), + style: TextStyle(fontSize: fontSize, color: textColor), textScaler: TextScaler.noScaling, ); }, diff --git a/lib/pangea/toolbar/reading_assistance/token_rendering_util.dart b/lib/pangea/toolbar/reading_assistance/token_rendering_util.dart index 6891fe345..e7278ec11 100644 --- a/lib/pangea/toolbar/reading_assistance/token_rendering_util.dart +++ b/lib/pangea/toolbar/reading_assistance/token_rendering_util.dart @@ -19,10 +19,7 @@ class TokenRenderingUtil { } final textPainter = TextPainter( - text: TextSpan( - text: text, - style: style, - ), + text: TextSpan(text: text, style: style), maxLines: 1, textDirection: TextDirection.ltr, )..layout(); diff --git a/lib/pangea/toolbar/reading_assistance/tokens_util.dart b/lib/pangea/toolbar/reading_assistance/tokens_util.dart index 3f69baa4e..0fe4be59a 100644 --- a/lib/pangea/toolbar/reading_assistance/tokens_util.dart +++ b/lib/pangea/toolbar/reading_assistance/tokens_util.dart @@ -9,20 +9,14 @@ class _TokenPositionCacheItem { final List positions; final DateTime timestamp; - _TokenPositionCacheItem( - this.positions, - this.timestamp, - ); + _TokenPositionCacheItem(this.positions, this.timestamp); } class _NewTokenCacheItem { final List tokens; final DateTime timestamp; - _NewTokenCacheItem( - this.tokens, - this.timestamp, - ); + _NewTokenCacheItem(this.tokens, this.timestamp); } class TokenPosition { @@ -37,10 +31,10 @@ class TokenPosition { }); Map toJson() => { - 'token': token?.toJson(), - 'startIndex': startIndex, - 'endIndex': endIndex, - }; + 'token': token?.toJson(), + 'startIndex': startIndex, + 'endIndex': endIndex, + }; } class TokensUtil { @@ -66,10 +60,7 @@ class TokensUtil { String cacheKey, List tokens, ) { - _newTokenCache[cacheKey] = _NewTokenCacheItem( - tokens, - DateTime.now(), - ); + _newTokenCache[cacheKey] = _NewTokenCacheItem(tokens, DateTime.now()); } static List getNewTokens( @@ -79,11 +70,15 @@ class TokensUtil { int? maxTokens, }) { if (MatrixState - .pangeaController.matrixState.analyticsDataService.isInitializing) { + .pangeaController + .matrixState + .analyticsDataService + .isInitializing) { return []; } - final messageInUserL2 = tokensLangCode.split('-').first == + final messageInUserL2 = + tokensLangCode.split('-').first == MatrixState.pangeaController.userController.userL2?.langCodeShort; final cached = _getCachedNewTokens(cacheKey); @@ -120,18 +115,20 @@ class TokensUtil { return newTokens; } - static List getNewTokensByEvent( - PangeaMessageEvent event, - ) { + static List getNewTokensByEvent(PangeaMessageEvent event) { if (!event.eventId.isValidMatrixId || (MatrixState.pangeaController.subscriptionController.isSubscribed == false) || MatrixState - .pangeaController.matrixState.analyticsDataService.isInitializing) { + .pangeaController + .matrixState + .analyticsDataService + .isInitializing) { return []; } - final messageInUserL2 = event.messageDisplayLangCode.split("-")[0] == + final messageInUserL2 = + event.messageDisplayLangCode.split("-")[0] == MatrixState.pangeaController.userController.userL2?.langCodeShort; final cached = _getCachedNewTokens(event.eventId); @@ -249,9 +246,7 @@ class TokensUtil { } /// Given a list of tokens, reconstructs an original message, including gaps for non-token elements. - static List getGlobalTokenPositions( - List tokens, - ) { + static List getGlobalTokenPositions(List tokens) { final List tokenPositions = []; int tokenPointer = 0; int globalPointer = 0; @@ -264,10 +259,7 @@ class TokensUtil { // If the token starts after the current global pointer, we need to // create a new token position for the gap tokenPositions.add( - TokenPosition( - startIndex: globalPointer, - endIndex: token.text.offset, - ), + TokenPosition(startIndex: globalPointer, endIndex: token.text.offset), ); globalPointer = token.text.offset; @@ -279,9 +271,11 @@ class TokensUtil { final PangeaToken currentToken = tokens[endIndex]; final PangeaToken nextToken = tokens[endIndex + 1]; - final currentIsPunct = currentToken.pos == 'PUNCT' && + final currentIsPunct = + currentToken.pos == 'PUNCT' && currentToken.text.content.trim().isNotEmpty; - final nextIsPunct = nextToken.pos == 'PUNCT' && + final nextIsPunct = + nextToken.pos == 'PUNCT' && nextToken.text.content.trim().isNotEmpty; if (currentToken.text.offset + currentToken.text.length != diff --git a/lib/pangea/toolbar/token_rendering_mixin.dart b/lib/pangea/toolbar/token_rendering_mixin.dart index 81da0912e..4d89aab61 100644 --- a/lib/pangea/toolbar/token_rendering_mixin.dart +++ b/lib/pangea/toolbar/token_rendering_mixin.dart @@ -36,10 +36,7 @@ mixin TokenRenderingMixin { ), ]; - await analyticsService.updateService.addAnalytics( - targetId, - constructs, - ); + await analyticsService.updateService.addAnalytics(targetId, constructs); TokensUtil.clearNewTokenCache(); } } diff --git a/lib/pangea/toolbar/word_card/lemma_meaning_display.dart b/lib/pangea/toolbar/word_card/lemma_meaning_display.dart index 70dd51f3e..2814056a4 100644 --- a/lib/pangea/toolbar/word_card/lemma_meaning_display.dart +++ b/lib/pangea/toolbar/word_card/lemma_meaning_display.dart @@ -34,42 +34,30 @@ class LemmaMeaningDisplay extends StatelessWidget { builder: (context, controller) { return switch (controller.state) { AsyncError() => ErrorIndicator( - message: L10n.of(context).errorFetchingDefinition, - style: const TextStyle(fontSize: 14.0), - ), + message: L10n.of(context).errorFetchingDefinition, + style: const TextStyle(fontSize: 14.0), + ), AsyncLoaded(value: final lemmaInfo) => RichText( - maxLines: 2, - overflow: TextOverflow.ellipsis, - textAlign: TextAlign.center, - text: TextSpan( - style: DefaultTextStyle.of(context).style.copyWith( - fontSize: 14.0, - ), - children: [ - TextSpan( - text: "${constructId.lemma} (${getGrammarCopy( - category: "POS", - lemma: constructId.category, - context: context, - ) ?? L10n.of(context).other})", - ), - const WidgetSpan( - child: SizedBox(width: 8.0), - ), - const TextSpan(text: ":"), - const WidgetSpan( - child: SizedBox(width: 8.0), - ), - TextSpan( - text: lemmaInfo.meaning, - ), - ], - ), - ), - _ => const TextLoadingShimmer( - width: 125.0, - height: 20.0, + maxLines: 2, + overflow: TextOverflow.ellipsis, + textAlign: TextAlign.center, + text: TextSpan( + style: DefaultTextStyle.of( + context, + ).style.copyWith(fontSize: 14.0), + children: [ + TextSpan( + text: + "${constructId.lemma} (${getGrammarCopy(category: "POS", lemma: constructId.category, context: context) ?? L10n.of(context).other})", + ), + const WidgetSpan(child: SizedBox(width: 8.0)), + const TextSpan(text: ":"), + const WidgetSpan(child: SizedBox(width: 8.0)), + TextSpan(text: lemmaInfo.meaning), + ], ), + ), + _ => const TextLoadingShimmer(width: 125.0, height: 20.0), }; }, ); diff --git a/lib/pangea/toolbar/word_card/lemma_reaction_picker.dart b/lib/pangea/toolbar/word_card/lemma_reaction_picker.dart index cc823be64..3a0493314 100644 --- a/lib/pangea/toolbar/word_card/lemma_reaction_picker.dart +++ b/lib/pangea/toolbar/word_card/lemma_reaction_picker.dart @@ -65,9 +65,7 @@ class LemmaReactionPickerState extends State { void _setEmojiSub() { _emojiSub?.cancel(); - _emojiSub = Matrix.of(context) - .analyticsDataService - .updateDispatcher + _emojiSub = Matrix.of(context).analyticsDataService.updateDispatcher .lemmaUpdateStream(widget.constructId) .listen((update) => _setSelectedEmoji(update.emojis?.firstOrNull)); } @@ -82,19 +80,14 @@ class LemmaReactionPickerState extends State { widget.event!.room.timeline!, RelationshipTypes.reaction, ) - .where( - (e) => e.senderId == Matrix.of(context).client.userID, - ); + .where((e) => e.senderId == Matrix.of(context).client.userID); return userSentEmojis.firstWhereOrNull( (e) => e.content.tryGetMap('m.relates_to')?['key'] == emoji, ); } - Future _setEmoji( - String emoji, - String targetId, - ) async { + Future _setEmoji(String emoji, String targetId) async { await widget.setLemmaEmoji( widget.constructId, widget.langCode, @@ -119,18 +112,12 @@ class LemmaReactionPickerState extends State { return; } - await widget.event!.room.sendReaction( - widget.event!.eventId, - emoji, - ); + await widget.event!.room.sendReaction(widget.event!.eventId, emoji); } catch (e, s) { ErrorHandler.logError( e: e, s: s, - data: { - 'emoji': emoji, - 'eventId': widget.event?.eventId, - }, + data: {'emoji': emoji, 'eventId': widget.event?.eventId}, ); } } @@ -147,13 +134,11 @@ class LemmaReactionPickerState extends State { : _sendOrRedactReaction(emoji), emoji: _selectedEmoji, messageInfo: widget.event?.content ?? {}, - selectedEmojiBadge: widget.event != null && + selectedEmojiBadge: + widget.event != null && _selectedEmoji != null && _sentReaction(_selectedEmoji!) == null - ? const Icon( - Icons.add_reaction, - size: 12.0, - ) + ? const Icon(Icons.add_reaction, size: 12.0) : null, enabled: _enabled, ); diff --git a/lib/pangea/toolbar/word_card/message_unsubscribed_card.dart b/lib/pangea/toolbar/word_card/message_unsubscribed_card.dart index d9b2528e5..fc7045696 100644 --- a/lib/pangea/toolbar/word_card/message_unsubscribed_card.dart +++ b/lib/pangea/toolbar/word_card/message_unsubscribed_card.dart @@ -11,9 +11,7 @@ class MessageUnsubscribedCard extends StatelessWidget { @override Widget build(BuildContext context) { return Container( - constraints: const BoxConstraints( - maxWidth: AppConfig.toolbarMinWidth, - ), + constraints: const BoxConstraints(maxWidth: AppConfig.toolbarMinWidth), padding: const EdgeInsets.all(16), child: Column( children: [ @@ -27,8 +25,9 @@ class MessageUnsubscribedCard extends StatelessWidget { width: double.infinity, child: TextButton( onPressed: () { - MatrixState.pangeaController.subscriptionController - .showPaywall(context); + MatrixState.pangeaController.subscriptionController.showPaywall( + context, + ); }, style: ButtonStyle( backgroundColor: WidgetStateProperty.all( diff --git a/lib/pangea/toolbar/word_card/reading_assistance_content.dart b/lib/pangea/toolbar/word_card/reading_assistance_content.dart index 3096171c5..960f6ef48 100644 --- a/lib/pangea/toolbar/word_card/reading_assistance_content.dart +++ b/lib/pangea/toolbar/word_card/reading_assistance_content.dart @@ -23,19 +23,17 @@ class ReadingAssistanceContent extends StatelessWidget { @override Widget build(BuildContext context) { - if (![MessageTypes.Text, MessageTypes.Audio].contains( - overlayController.pangeaMessageEvent.event.messageType, - )) { + if (![ + MessageTypes.Text, + MessageTypes.Audio, + ].contains(overlayController.pangeaMessageEvent.event.messageType)) { return const SizedBox(); } final tokens = overlayController.pangeaMessageEvent.originalSent?.tokens; final selectedToken = overlayController.selectedToken; final selectedTokenIndex = selectedToken != null - ? tokens?.indexWhere( - (t) => t.text == selectedToken.text, - ) ?? - -1 + ? tokens?.indexWhere((t) => t.text == selectedToken.text) ?? -1 : -1; return WordZoomWidget( diff --git a/lib/pangea/toolbar/word_card/token_feedback_button.dart b/lib/pangea/toolbar/word_card/token_feedback_button.dart index c5a7ece94..fb379a50c 100644 --- a/lib/pangea/toolbar/word_card/token_feedback_button.dart +++ b/lib/pangea/toolbar/word_card/token_feedback_button.dart @@ -35,7 +35,8 @@ class TokenFeedbackButton extends StatelessWidget { textLanguage: textLanguage, text: text, builder: (context, transcriptController) { - final enabled = (lemmaController.lemmaInfo != null || + final enabled = + (lemmaController.lemmaInfo != null || lemmaController.isError) && (transcriptController.transcription != null || transcriptController.isError); @@ -50,10 +51,7 @@ class TokenFeedbackButton extends StatelessWidget { icon: const Icon(Icons.flag_outlined), onPressed: enabled ? () { - onFlagTokenInfo( - lemmaInfo, - transcript, - ); + onFlagTokenInfo(lemmaInfo, transcript); } : null, tooltip: enabled ? L10n.of(context).reportWordIssueTooltip : null, diff --git a/lib/pangea/toolbar/word_card/word_card_switcher.dart b/lib/pangea/toolbar/word_card/word_card_switcher.dart index 014273478..2ecbd9e63 100644 --- a/lib/pangea/toolbar/word_card/word_card_switcher.dart +++ b/lib/pangea/toolbar/word_card/word_card_switcher.dart @@ -13,7 +13,7 @@ class WordCardSwitcher extends StatelessWidget { Widget build(BuildContext context) { return ValueListenableBuilder( valueListenable: controller.widget.overlayController.selectedMode, - builder: (context, mode, __) { + builder: (context, mode, _) { return AnimatedSize( alignment: controller.ownMessage ? Alignment.bottomRight @@ -24,13 +24,13 @@ class WordCardSwitcher extends StatelessWidget { overlayController: controller.widget.overlayController, ) : mode != SelectMode.emoji - ? ValueListenableBuilder( - valueListenable: controller.reactionNotifier, - builder: (context, _, __) => MessageReactionPicker( - chatController: controller.widget.chatController, - ), - ) - : const SizedBox.shrink(), + ? ValueListenableBuilder( + valueListenable: controller.reactionNotifier, + builder: (context, _, _) => MessageReactionPicker( + chatController: controller.widget.chatController, + ), + ) + : const SizedBox.shrink(), ); }, ); diff --git a/lib/pangea/toolbar/word_card/word_zoom_widget.dart b/lib/pangea/toolbar/word_card/word_zoom_widget.dart index 4e9b40ffc..51a8baa65 100644 --- a/lib/pangea/toolbar/word_card/word_zoom_widget.dart +++ b/lib/pangea/toolbar/word_card/word_zoom_widget.dart @@ -86,10 +86,7 @@ class WordZoomWidget extends StatelessWidget { icon: const Icon(Icons.close), onPressed: onClose, ) - : const SizedBox( - width: 40.0, - height: 40.0, - ), + : const SizedBox(width: 40.0, height: 40.0), Flexible( child: Container( constraints: const BoxConstraints( @@ -103,7 +100,8 @@ class WordZoomWidget extends StatelessWidget { fontSize: 28.0, fontWeight: FontWeight.w600, height: 1.2, - color: Theme.of(context).brightness == + color: + Theme.of(context).brightness == Brightness.light ? AppConfig.yellowDark : AppConfig.yellowLight, @@ -114,19 +112,15 @@ class WordZoomWidget extends StatelessWidget { ), onFlagTokenInfo != null ? TokenFeedbackButton( - textLanguage: PLanguageStore.byLangCode( - langCode, - ) ?? + textLanguage: + PLanguageStore.byLangCode(langCode) ?? LanguageModel.unknown, constructId: construct, text: token.content, onFlagTokenInfo: onFlagTokenInfo!, messageInfo: event?.content ?? {}, ) - : const SizedBox( - width: 40.0, - height: 40.0, - ), + : const SizedBox(width: 40.0, height: 40.0), ], ), ), @@ -138,9 +132,8 @@ class WordZoomWidget extends StatelessWidget { showTranscript ? PhoneticTranscriptionWidget( text: token.content, - textLanguage: PLanguageStore.byLangCode( - langCode, - ) ?? + textLanguage: + PLanguageStore.byLangCode(langCode) ?? LanguageModel.unknown, style: const TextStyle(fontSize: 14.0), iconSize: 24.0, @@ -206,9 +199,7 @@ class WordZoomWidget extends StatelessWidget { child: Column( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, - children: [ - content, - ], + children: [content], ), ), ), diff --git a/lib/pangea/translation/full_text_translation_repo.dart b/lib/pangea/translation/full_text_translation_repo.dart index b1e621f11..4fbb5dd63 100644 --- a/lib/pangea/translation/full_text_translation_repo.dart +++ b/lib/pangea/translation/full_text_translation_repo.dart @@ -17,10 +17,7 @@ class _TranslateCacheItem { final Future response; final DateTime timestamp; - const _TranslateCacheItem({ - required this.response, - required this.timestamp, - }); + const _TranslateCacheItem({required this.response, required this.timestamp}); } class FullTextTranslationRepo { @@ -75,18 +72,12 @@ class FullTextTranslationRepo { return Result.value(res); } catch (e, s) { _cache.remove(request.hashCode.toString()); - ErrorHandler.logError( - e: e, - s: s, - data: request.toJson(), - ); + ErrorHandler.logError(e: e, s: s, data: request.toJson()); return Result.error(e); } } - static Future? _getCached( - FullTextTranslationRequestModel request, - ) { + static Future? _getCached(FullTextTranslationRequestModel request) { final cacheKeys = [..._cache.keys]; for (final key in cacheKeys) { if (DateTime.now().difference(_cache[key]!.timestamp) >= _cacheDuration) { @@ -100,9 +91,8 @@ class FullTextTranslationRepo { static void _setCached( FullTextTranslationRequestModel request, Future response, - ) => - _cache[request.hashCode.toString()] = _TranslateCacheItem( - response: response, - timestamp: DateTime.now(), - ); + ) => _cache[request.hashCode.toString()] = _TranslateCacheItem( + response: response, + timestamp: DateTime.now(), + ); } diff --git a/lib/pangea/translation/full_text_translation_request_model.dart b/lib/pangea/translation/full_text_translation_request_model.dart index 62375e56c..c14fbc9a8 100644 --- a/lib/pangea/translation/full_text_translation_request_model.dart +++ b/lib/pangea/translation/full_text_translation_request_model.dart @@ -22,15 +22,15 @@ class FullTextTranslationRequestModel { }); Map toJson() => { - ModelKey.text: text, - ModelKey.srcLang: srcLang, - ModelKey.tgtLang: tgtLang, - ModelKey.userL2: userL2, - ModelKey.userL1: userL1, - ModelKey.deepL: deepL, - ModelKey.offset: offset, - ModelKey.length: length, - }; + ModelKey.text: text, + ModelKey.srcLang: srcLang, + ModelKey.tgtLang: tgtLang, + ModelKey.userL2: userL2, + ModelKey.userL1: userL1, + ModelKey.deepL: deepL, + ModelKey.offset: offset, + ModelKey.length: length, + }; // override equals and hashcode @override diff --git a/lib/pangea/translation/full_text_translation_response_model.dart b/lib/pangea/translation/full_text_translation_response_model.dart index ebba1fea1..a46f650cc 100644 --- a/lib/pangea/translation/full_text_translation_response_model.dart +++ b/lib/pangea/translation/full_text_translation_response_model.dart @@ -14,9 +14,7 @@ class FullTextTranslationResponseModel { factory FullTextTranslationResponseModel.fromJson(Map json) { return FullTextTranslationResponseModel( translations: (json["translations"] as Iterable) - .map( - (e) => e, - ) + .map((e) => e) .toList() .cast(), source: json[ModelKey.srcLang], diff --git a/lib/pangea/user/pangea_push_rules_extension.dart b/lib/pangea/user/pangea_push_rules_extension.dart index c7e92462a..95cca5e85 100644 --- a/lib/pangea/user/pangea_push_rules_extension.dart +++ b/lib/pangea/user/pangea_push_rules_extension.dart @@ -6,8 +6,9 @@ import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart'; extension PangeaPushRulesExtension on Client { Future setPangeaPushRules() async { if (!isLogged()) return; - final List analyticsRooms = - rooms.where((room) => room.isAnalyticsRoom).toList(); + final List analyticsRooms = rooms + .where((room) => room.isAnalyticsRoom) + .toList(); for (final Room room in analyticsRooms) { final pushRule = room.pushRuleState; diff --git a/lib/pangea/user/style_settings_repo.dart b/lib/pangea/user/style_settings_repo.dart index 65f452fec..e129b27be 100644 --- a/lib/pangea/user/style_settings_repo.dart +++ b/lib/pangea/user/style_settings_repo.dart @@ -51,13 +51,7 @@ class StyleSettingsRepo { try { return StyleSettings.fromJson(json); } catch (e, s) { - ErrorHandler.logError( - e: e, - s: s, - data: { - "settings_entry": json, - }, - ); + ErrorHandler.logError(e: e, s: s, data: {"settings_entry": json}); _storage.remove(key); return const StyleSettings(); } diff --git a/lib/pangea/user/user_controller.dart b/lib/pangea/user/user_controller.dart index 2e3be4226..ff3cc0d8e 100644 --- a/lib/pangea/user/user_controller.dart +++ b/lib/pangea/user/user_controller.dart @@ -147,11 +147,7 @@ class UserController { await PLanguageStore.initialize(forceRefresh: true); } } catch (err, s) { - ErrorHandler.logError( - e: err, - s: s, - data: {}, - ); + ErrorHandler.logError(e: err, s: s, data: {}); } finally { if (!initCompleter.isCompleted) { initCompleter.complete(); @@ -174,8 +170,9 @@ class UserController { if (client.userID == null) return; try { final resp = await client.getUserProfile(client.userID!); - analyticsProfile = - AnalyticsProfileModel.fromJson(resp.additionalProperties); + analyticsProfile = AnalyticsProfileModel.fromJson( + resp.additionalProperties, + ); } catch (e) { // getting a 404 error for some users without pre-existing profile // still want to set other properties, so catch this error @@ -226,11 +223,7 @@ class UserController { await initialize(); return profile.userSettings.targetLanguage != null; } catch (err, s) { - ErrorHandler.logError( - e: err, - s: s, - data: {}, - ); + ErrorHandler.logError(e: err, s: s, data: {}); return false; } } @@ -260,8 +253,8 @@ class UserController { /// - The user's email address as a [String], or `null` if no email address /// is found. Future get userEmail async { - final List? identifiers = - await client.getAccount3PIDs(); + final List? identifiers = await client + .getAccount3PIDs(); final matrix.ThirdPartyIdentifier? email = identifiers?.firstWhereOrNull( (identifier) => identifier.medium == matrix.ThirdPartyIdentifierMedium.email, @@ -272,12 +265,7 @@ class UserController { Future _savePublicProfileUpdate( String type, Map content, - ) async => - client.setUserProfile( - client.userID!, - type, - content, - ); + ) async => client.setUserProfile(client.userID!, type, content); Future updateAnalyticsProfile({ required int level, @@ -300,11 +288,7 @@ class UserController { analyticsProfile!.baseLanguage = baseLanguage; analyticsProfile!.targetLanguage = targetLanguage; - analyticsProfile!.setLanguageInfo( - targetLanguage, - level, - analyticsRoom?.id, - ); + analyticsProfile!.setLanguageInfo(targetLanguage, level, analyticsRoom?.id); await _savePublicProfileUpdate( PangeaEventTypes.profileAnalytics, analyticsProfile!.toJson(), @@ -319,10 +303,8 @@ class UserController { for (final analyticsRoom in analyticsRooms) { final lang = analyticsRoom.madeForLang?.split("-").first; if (lang == null || analyticsProfile?.languageAnalytics == null) continue; - final langKey = - analyticsProfile!.languageAnalytics!.keys.firstWhereOrNull( - (l) => l.langCodeShort == lang, - ); + final langKey = analyticsProfile!.languageAnalytics!.keys + .firstWhereOrNull((l) => l.langCodeShort == lang); if (langKey == null) continue; if (analyticsProfile!.languageAnalytics![langKey]!.analyticsRoomId == @@ -358,9 +340,7 @@ class UserController { ); } - Future getPublicAnalyticsProfile( - String userId, - ) async { + Future getPublicAnalyticsProfile(String userId) async { try { if (userId == BotName.byEnvironment) { return AnalyticsProfileModel(); @@ -369,13 +349,7 @@ class UserController { final resp = await client.getUserProfile(userId); return AnalyticsProfileModel.fromJson(resp.additionalProperties); } catch (e, s) { - ErrorHandler.logError( - e: e, - s: s, - data: { - userId: userId, - }, - ); + ErrorHandler.logError(e: e, s: s, data: {userId: userId}); return AnalyticsProfileModel(); } } diff --git a/lib/pangea/user/user_model.dart b/lib/pangea/user/user_model.dart index 9f98ee169..05e21210b 100644 --- a/lib/pangea/user/user_model.dart +++ b/lib/pangea/user/user_model.dart @@ -34,28 +34,24 @@ class UserSettings { }); factory UserSettings.fromJson(Map json) => UserSettings( - dateOfBirth: json[ModelKey.userDateOfBirth] != null - ? DateTime.parse(json[ModelKey.userDateOfBirth]) - : null, - createdAt: json[ModelKey.userCreatedAt] != null - ? DateTime.parse(json[ModelKey.userCreatedAt]) - : null, - publicProfile: json[ModelKey.publicProfile], - targetLanguage: json[ModelKey.targetLanguage], - sourceLanguage: json[ModelKey.sourceLanguage], - gender: json[ModelKey.userGender] is String - ? GenderEnumExtension.fromString( - json[ModelKey.userGender], - ) - : GenderEnum.unselected, - country: json[ModelKey.userCountry], - cefrLevel: json[ModelKey.cefrLevel] is String - ? LanguageLevelTypeEnum.fromString( - json[ModelKey.cefrLevel], - ) - : LanguageLevelTypeEnum.a1, - voice: json[ModelKey.voice], - ); + dateOfBirth: json[ModelKey.userDateOfBirth] != null + ? DateTime.parse(json[ModelKey.userDateOfBirth]) + : null, + createdAt: json[ModelKey.userCreatedAt] != null + ? DateTime.parse(json[ModelKey.userCreatedAt]) + : null, + publicProfile: json[ModelKey.publicProfile], + targetLanguage: json[ModelKey.targetLanguage], + sourceLanguage: json[ModelKey.sourceLanguage], + gender: json[ModelKey.userGender] is String + ? GenderEnumExtension.fromString(json[ModelKey.userGender]) + : GenderEnum.unselected, + country: json[ModelKey.userCountry], + cefrLevel: json[ModelKey.cefrLevel] is String + ? LanguageLevelTypeEnum.fromString(json[ModelKey.cefrLevel]) + : LanguageLevelTypeEnum.a1, + voice: json[ModelKey.voice], + ); Map toJson() { final Map data = {}; @@ -105,15 +101,19 @@ class UserSettings { return UserSettings( dateOfBirth: dob, createdAt: createdAt, - publicProfile: (accountData[ModelKey.publicProfile] - ?.content[ModelKey.publicProfile] as bool?) ?? + publicProfile: + (accountData[ModelKey.publicProfile]?.content[ModelKey.publicProfile] + as bool?) ?? false, - targetLanguage: accountData[ModelKey.targetLanguage] - ?.content[ModelKey.targetLanguage] as String?, - sourceLanguage: accountData[ModelKey.sourceLanguage] - ?.content[ModelKey.sourceLanguage] as String?, - country: accountData[ModelKey.userCountry]?.content[ModelKey.userCountry] - as String?, + targetLanguage: + accountData[ModelKey.targetLanguage]?.content[ModelKey.targetLanguage] + as String?, + sourceLanguage: + accountData[ModelKey.sourceLanguage]?.content[ModelKey.sourceLanguage] + as String?, + country: + accountData[ModelKey.userCountry]?.content[ModelKey.userCountry] + as String?, ); } @@ -149,16 +149,16 @@ class UserSettings { @override int get hashCode => Object.hashAll([ - dateOfBirth.hashCode, - createdAt.hashCode, - (publicProfile ?? false).hashCode, - targetLanguage.hashCode, - sourceLanguage.hashCode, - gender.hashCode, - country.hashCode, - cefrLevel.hashCode, - voice.hashCode, - ]); + dateOfBirth.hashCode, + createdAt.hashCode, + (publicProfile ?? false).hashCode, + targetLanguage.hashCode, + sourceLanguage.hashCode, + gender.hashCode, + country.hashCode, + cefrLevel.hashCode, + voice.hashCode, + ]); } /// The user's language tool settings. @@ -212,20 +212,26 @@ class UserToolSettings { return UserToolSettings( interactiveTranslator: (accountData[ToolSetting.interactiveTranslator.toString()] - ?.content[ToolSetting.interactiveTranslator.toString()] - as bool?) ?? - true, + ?.content[ToolSetting.interactiveTranslator.toString()] + as bool?) ?? + true, interactiveGrammar: (accountData[ToolSetting.interactiveGrammar.toString()] - ?.content[ToolSetting.interactiveGrammar.toString()] - as bool?) ?? - true, - immersionMode: false, - definitions: (accountData[ToolSetting.definitions.toString()] - ?.content[ToolSetting.definitions.toString()] as bool?) ?? + ?.content[ToolSetting.interactiveGrammar.toString()] + as bool?) ?? true, - autoIGC: (accountData[ToolSetting.autoIGC.toString()] - ?.content[ToolSetting.autoIGC.toString()] as bool?) ?? + immersionMode: false, + definitions: + (accountData[ToolSetting.definitions.toString()]?.content[ToolSetting + .definitions + .toString()] + as bool?) ?? + true, + autoIGC: + (accountData[ToolSetting.autoIGC.toString()]?.content[ToolSetting + .autoIGC + .toString()] + as bool?) ?? true, ); } @@ -258,14 +264,14 @@ class UserToolSettings { @override int get hashCode => Object.hashAll([ - interactiveTranslator.hashCode, - interactiveGrammar.hashCode, - immersionMode.hashCode, - definitions.hashCode, - autoIGC.hashCode, - enableTTS.hashCode, - enableAutocorrect.hashCode, - ]); + interactiveTranslator.hashCode, + interactiveGrammar.hashCode, + immersionMode.hashCode, + definitions.hashCode, + autoIGC.hashCode, + enableTTS.hashCode, + enableAutocorrect.hashCode, + ]); } /// A wrapper around the matrix account data for the user profile. @@ -296,8 +302,9 @@ class Profile { profileData[ModelKey.instructionsSettings]; return Profile( - userSettings: - UserSettings.fromJson(userSettingsContent as Map), + userSettings: UserSettings.fromJson( + userSettingsContent as Map, + ), toolSettings: toolSettingsContent != null ? UserToolSettings.fromJson( toolSettingsContent as Map, @@ -338,9 +345,7 @@ class Profile { /// Saves the current configuration of the profile to the client's account data. /// If [waitForDataInSync] is true, the function will wait for the updated account /// data to come through in a sync, indicating that it has been set on the matrix server. - Future saveProfileData({ - bool waitForDataInSync = false, - }) async { + Future saveProfileData({bool waitForDataInSync = false}) async { final PangeaController pangeaController = MatrixState.pangeaController; final Client client = pangeaController.matrixState.client; final List profileKeys = [ @@ -359,11 +364,7 @@ class Profile { ), ); } - await client.setAccountData( - client.userID!, - ModelKey.userProfile, - toJson(), - ); + await client.setAccountData(client.userID!, ModelKey.userProfile, toJson()); if (waitForDataInSync) { await waitForUpdate; @@ -426,12 +427,8 @@ class PangeaProfile { }); factory PangeaProfile.fromJson(Map json) { - final l2 = LanguageModel.codeFromNameOrCode( - json[ModelKey.targetLanguage], - ); - final l1 = LanguageModel.codeFromNameOrCode( - json[ModelKey.sourceLanguage], - ); + final l2 = LanguageModel.codeFromNameOrCode(json[ModelKey.targetLanguage]); + final l1 = LanguageModel.codeFromNameOrCode(json[ModelKey.sourceLanguage]); return PangeaProfile( createdAt: json[ModelKey.userCreatedAt], @@ -461,10 +458,7 @@ class PangeaProfileResponse { final PangeaProfile profile; final String access; - PangeaProfileResponse({ - required this.profile, - required this.access, - }); + PangeaProfileResponse({required this.profile, required this.access}); factory PangeaProfileResponse.fromJson(Map json) { return PangeaProfileResponse( diff --git a/lib/utils/account_bundles.dart b/lib/utils/account_bundles.dart index 8bd296e05..7d5619267 100644 --- a/lib/utils/account_bundles.dart +++ b/lib/utils/account_bundles.dart @@ -7,9 +7,9 @@ class AccountBundles { AccountBundles({this.prefix, this.bundles}); AccountBundles.fromJson(Map json) - : prefix = json.tryGet('prefix'), - bundles = json['bundles'] is List - ? json['bundles'] + : prefix = json.tryGet('prefix'), + bundles = json['bundles'] is List + ? json['bundles'] .map((b) { try { return AccountBundle.fromJson(b); @@ -19,13 +19,12 @@ class AccountBundles { }) .whereType() .toList() - : null; + : null; Map toJson() => { - if (prefix != null) 'prefix': prefix, - if (bundles != null) - 'bundles': bundles!.map((v) => v.toJson()).toList(), - }; + if (prefix != null) 'prefix': prefix, + if (bundles != null) 'bundles': bundles!.map((v) => v.toJson()).toList(), + }; } class AccountBundle { @@ -35,13 +34,13 @@ class AccountBundle { AccountBundle({this.name, this.priority}); AccountBundle.fromJson(Map json) - : name = json.tryGet('name'), - priority = json.tryGet('priority'); + : name = json.tryGet('name'), + priority = json.tryGet('priority'); Map toJson() => { - if (name != null) 'name': name, - if (priority != null) 'priority': priority, - }; + if (name != null) 'name': name, + if (priority != null) 'priority': priority, + }; } const accountBundlesType = 'im.fluffychat.account_bundles'; @@ -50,24 +49,21 @@ extension AccountBundlesExtension on Client { List get accountBundles { List? ret; if (accountData.containsKey(accountBundlesType)) { - ret = AccountBundles.fromJson(accountData[accountBundlesType]!.content) - .bundles; + ret = AccountBundles.fromJson( + accountData[accountBundlesType]!.content, + ).bundles; } ret ??= []; if (ret.isEmpty) { - ret.add( - AccountBundle( - name: userID, - priority: 0, - ), - ); + ret.add(AccountBundle(name: userID, priority: 0)); } return ret; } Future setAccountBundle(String name, [int? priority]) async { - final data = - AccountBundles.fromJson(accountData[accountBundlesType]?.content ?? {}); + final data = AccountBundles.fromJson( + accountData[accountBundlesType]?.content ?? {}, + ); var foundBundle = false; final bundles = data.bundles ??= []; for (final bundle in bundles) { @@ -87,16 +83,18 @@ extension AccountBundlesExtension on Client { if (!accountData.containsKey(accountBundlesType)) { return; // nothing to do } - final data = - AccountBundles.fromJson(accountData[accountBundlesType]!.content); + final data = AccountBundles.fromJson( + accountData[accountBundlesType]!.content, + ); if (data.bundles == null) return; data.bundles!.removeWhere((b) => b.name == name); await setAccountData(userID!, accountBundlesType, data.toJson()); } String get sendPrefix { - final data = - AccountBundles.fromJson(accountData[accountBundlesType]?.content ?? {}); + final data = AccountBundles.fromJson( + accountData[accountBundlesType]?.content ?? {}, + ); return data.prefix!; } } diff --git a/lib/utils/account_config.dart b/lib/utils/account_config.dart index a5e2dfd00..7ac107376 100644 --- a/lib/utils/account_config.dart +++ b/lib/utils/account_config.dart @@ -8,19 +8,11 @@ extension ApplicationAccountConfigExtension on Client { accountData[accountDataKey]?.content ?? {}, ); - Future setApplicationAccountConfig( - ApplicationAccountConfig config, - ) => - setAccountData( - userID!, - accountDataKey, - config.toJson(), - ); + Future setApplicationAccountConfig(ApplicationAccountConfig config) => + setAccountData(userID!, accountDataKey, config.toJson()); /// Only updates the specified values in ApplicationAccountConfig - Future updateApplicationAccountConfig( - ApplicationAccountConfig config, - ) { + Future updateApplicationAccountConfig(ApplicationAccountConfig config) { final currentConfig = applicationAccountConfig; return setAccountData( userID!, @@ -57,14 +49,15 @@ class ApplicationAccountConfig { wallpaperUrl: json['wallpaper_url'] is String ? Uri.tryParse(json['wallpaper_url']) : null, - wallpaperOpacity: - _sanitizedOpacity(json.tryGet('wallpaper_opacity')), + wallpaperOpacity: _sanitizedOpacity( + json.tryGet('wallpaper_opacity'), + ), wallpaperBlur: json.tryGet('wallpaper_blur'), ); Map toJson() => { - 'wallpaper_url': wallpaperUrl?.toString(), - 'wallpaper_opacity': wallpaperOpacity, - 'wallpaper_blur': wallpaperBlur, - }; + 'wallpaper_url': wallpaperUrl?.toString(), + 'wallpaper_opacity': wallpaperOpacity, + 'wallpaper_blur': wallpaperBlur, + }; } diff --git a/lib/utils/adaptive_bottom_sheet.dart b/lib/utils/adaptive_bottom_sheet.dart index 7681e54f7..a0e187d3e 100644 --- a/lib/utils/adaptive_bottom_sheet.dart +++ b/lib/utils/adaptive_bottom_sheet.dart @@ -21,10 +21,7 @@ Future showAdaptiveBottomSheet({ builder: (context) => Center( child: Container( margin: const EdgeInsets.all(16), - constraints: const BoxConstraints( - maxWidth: 480, - maxHeight: 720, - ), + constraints: const BoxConstraints(maxWidth: 480, maxHeight: 720), child: Material( elevation: Theme.of(context).dialogTheme.elevation ?? 4, shadowColor: Theme.of(context).dialogTheme.shadowColor, @@ -42,11 +39,9 @@ Future showAdaptiveBottomSheet({ context: context, builder: (context) => ConstrainedBox( constraints: BoxConstraints( - maxHeight: MediaQuery.viewInsetsOf(context).bottom + - min( - MediaQuery.sizeOf(context).height - 32, - 600, - ), + maxHeight: + MediaQuery.viewInsetsOf(context).bottom + + min(MediaQuery.sizeOf(context).height - 32, 600), ), child: builder(context), ), diff --git a/lib/utils/background_push.dart b/lib/utils/background_push.dart index 6c8805512..4cd7cde8f 100644 --- a/lib/utils/background_push.dart +++ b/lib/utils/background_push.dart @@ -65,7 +65,8 @@ class BackgroundPush { Future loadLocale() async { final context = matrix?.context; // inspired by _lookupL10n in .dart_tool/flutter_gen/gen_l10n/l10n.dart - l10n ??= (context != null ? L10n.of(context) : null) ?? + l10n ??= + (context != null ? L10n.of(context) : null) ?? (await L10n.delegate.load(PlatformDispatcher.instance.locale)); } @@ -86,8 +87,26 @@ class BackgroundPush { FirebaseMessaging.instance.getInitialMessage().then(_onOpenNotification); FirebaseMessaging.onMessageOpenedApp.listen(_onOpenNotification); // Pangea# - mainIsolateReceivePort?.listen( - (message) async { + mainIsolateReceivePort?.listen((message) async { + try { + await notificationTap( + NotificationResponseJson.fromJsonString(message), + client: client, + router: FluffyChatApp.router, + l10n: l10n, + ); + } catch (e, s) { + Logs().wtf('Main Notification Tap crashed', e, s); + } + }); + if (PlatformInfos.isAndroid) { + final port = ReceivePort(); + IsolateNameServer.removePortNameMapping('background_tab_port'); + IsolateNameServer.registerPortWithName( + port.sendPort, + 'background_tab_port', + ); + port.listen((message) async { try { await notificationTap( NotificationResponseJson.fromJsonString(message), @@ -98,29 +117,7 @@ class BackgroundPush { } catch (e, s) { Logs().wtf('Main Notification Tap crashed', e, s); } - }, - ); - if (PlatformInfos.isAndroid) { - final port = ReceivePort(); - IsolateNameServer.removePortNameMapping('background_tab_port'); - IsolateNameServer.registerPortWithName( - port.sendPort, - 'background_tab_port', - ); - port.listen( - (message) async { - try { - await notificationTap( - NotificationResponseJson.fromJsonString(message), - client: client, - router: FluffyChatApp.router, - l10n: l10n, - ); - } catch (e, s) { - Logs().wtf('Main Notification Tap crashed', e, s); - } - }, - ); + }); } await _flutterLocalNotificationsPlugin.initialize( const InitializationSettings( @@ -325,13 +322,15 @@ class BackgroundPush { // if (PlatformInfos.isAndroid) { // _flutterLocalNotificationsPlugin // .resolvePlatformSpecificImplementation< - // AndroidFlutterLocalNotificationsPlugin>() + // AndroidFlutterLocalNotificationsPlugin + // >() // ?.requestNotificationsPermission(); // } // Pangea# final clientName = PlatformInfos.clientName; oldTokens ??= {}; - final pushers = await (client.getPushers().catchError((e) { + final pushers = + await (client.getPushers().catchError((e) { Logs().w('[Push] Unable to request pushers', e); return []; })) ?? @@ -366,10 +365,9 @@ class BackgroundPush { // AppSettings.pushNotificationsPusherFormat.value && null && // Pangea# - mapEquals( - currentPushers.single.data.additionalProperties, - {"data_message": pusherDataMessageFormat}, - )) { + mapEquals(currentPushers.single.data.additionalProperties, { + "data_message": pusherDataMessageFormat, + })) { Logs().i('[Push] Pusher already set'); } else { Logs().i('Need to set new pusher'); @@ -420,11 +418,7 @@ class BackgroundPush { } catch (e, s) { Logs().e('[Push] Unable to set pushers', e, s); // #Pangea - ErrorHandler.logError( - e: e, - s: s, - data: {}, - ); + ErrorHandler.logError(e: e, s: s, data: {}); // Pangea# } } @@ -433,8 +427,8 @@ class BackgroundPush { final pusherDataMessageFormat = Platform.isAndroid ? 'android' : Platform.isIOS - ? 'ios' - : null; + ? 'ios' + : null; static bool _wentToRoomOnStartup = false; @@ -458,9 +452,9 @@ class BackgroundPush { } // ignore: unawaited_futures - _flutterLocalNotificationsPlugin - .getNotificationAppLaunchDetails() - .then((details) { + _flutterLocalNotificationsPlugin.getNotificationAppLaunchDetails().then(( + details, + ) { if (details == null || !details.didNotificationLaunchApp || _wentToRoomOnStartup) { @@ -491,9 +485,7 @@ class BackgroundPush { if (PlatformInfos.isAndroid) { onFcmError?.call( l10n!.noGoogleServicesWarning, - link: Uri.parse( - AppConfig.enablePushTutorial, - ), + link: Uri.parse(AppConfig.enablePushTutorial), ); return; } @@ -540,15 +532,13 @@ class BackgroundPush { 'https://matrix.gateway.unifiedpush.org/_matrix/push/v1/notify'; try { final url = Uri.parse(newEndpoint) - .replace( - path: '/_matrix/push/v1/notify', - query: '', - ) + .replace(path: '/_matrix/push/v1/notify', query: '') .toString() .split('?') .first; - final res = - json.decode(utf8.decode((await http.get(Uri.parse(url))).bodyBytes)); + final res = json.decode( + utf8.decode((await http.get(Uri.parse(url))).bodyBytes), + ); if (res['gateway'] == 'matrix' || (res['unifiedpush'] is Map && res['unifiedpush']['gateway'] == 'matrix')) { @@ -579,14 +569,13 @@ class BackgroundPush { upAction = true; Logs().i('[Push] Removing UnifiedPush endpoint...'); final oldEndpoint = AppSettings.unifiedPushEndpoint.value; - await AppSettings.unifiedPushEndpoint - .setItem(AppSettings.unifiedPushEndpoint.defaultValue); + await AppSettings.unifiedPushEndpoint.setItem( + AppSettings.unifiedPushEndpoint.defaultValue, + ); await AppSettings.unifiedPushRegistered.setItem(false); if (oldEndpoint.isNotEmpty) { // remove the old pusher - await setupPusher( - oldTokens: {oldEndpoint}, - ); + await setupPusher(oldTokens: {oldEndpoint}); } } diff --git a/lib/utils/client_download_content_extension.dart b/lib/utils/client_download_content_extension.dart index 3da8a1c51..b93357a0f 100644 --- a/lib/utils/client_download_content_extension.dart +++ b/lib/utils/client_download_content_extension.dart @@ -41,8 +41,9 @@ extension ClientDownloadContentExtension on Client { final response = await httpClient.get( httpUri, - headers: - accessToken == null ? null : {'authorization': 'Bearer $accessToken'}, + headers: accessToken == null + ? null + : {'authorization': 'Bearer $accessToken'}, ); if (response.statusCode != 200) { throw Exception(); diff --git a/lib/utils/client_manager.dart b/lib/utils/client_manager.dart index 357a974d2..378d135ff 100644 --- a/lib/utils/client_manager.dart +++ b/lib/utils/client_manager.dart @@ -43,24 +43,29 @@ abstract class ClientManager { clientNames.add(PlatformInfos.clientName); await store.setStringList(clientNamespace, clientNames.toList()); } - final clients = - await Future.wait(clientNames.map((name) => createClient(name, store))); + final clients = await Future.wait( + clientNames.map((name) => createClient(name, store)), + ); if (initialize) { await Future.wait( clients.map( - (client) => client.initWithRestore( - onMigration: () async { - // #Pangea - // final l10n = await lookupL10n(PlatformDispatcher.instance.locale); - // sendInitNotification( - // l10n.databaseMigrationTitle, - // l10n.databaseMigrationBody, - // ); - // Pangea# - }, - ).catchError( - (e, s) => Logs().e('Unable to initialize client', e, s), - ), + (client) => client + .initWithRestore( + onMigration: () async { + // #Pangea + // final l10n = await lookupL10n( + // PlatformDispatcher.instance.locale, + // ); + // sendInitNotification( + // l10n.databaseMigrationTitle, + // l10n.databaseMigrationBody, + // ); + // Pangea# + }, + ) + .catchError( + (e, s) => Logs().e('Unable to initialize client', e, s), + ), ), ); } @@ -150,16 +155,20 @@ abstract class ClientManager { AuthenticationTypes.sso, }, nativeImplementations: nativeImplementations, - customImageResizer: - PlatformInfos.isMobile || kIsWeb ? customImageResizer : null, + customImageResizer: PlatformInfos.isMobile || kIsWeb + ? customImageResizer + : null, defaultNetworkRequestTimeout: const Duration(minutes: 30), enableDehydratedDevices: true, - shareKeysWith: ShareKeysWith.values - .singleWhereOrNull((share) => share.name == shareKeysWith) ?? + shareKeysWith: + ShareKeysWith.values.singleWhereOrNull( + (share) => share.name == shareKeysWith, + ) ?? ShareKeysWith.all, convertLinebreaksInFormatting: false, - onSoftLogout: - enableSoftLogout ? (client) => client.refreshAccessToken() : null, + onSoftLogout: enableSoftLogout + ? (client) => client.refreshAccessToken() + : null, // #Pangea shouldReplaceRoomLastEvent: (_, event) { return event.content.tryGet(ModelKey.transcription) == null && @@ -175,10 +184,7 @@ abstract class ClientManager { static void sendInitNotification(String title, String body) async { if (kIsWeb) { - html.Notification( - title, - body: body, - ); + html.Notification(title, body: body); return; } if (Platform.isLinux) { @@ -186,9 +192,7 @@ abstract class ClientManager { title, body: body, appName: AppSettings.applicationName.value, - hints: [ - NotificationHint.soundName('message-new-instant'), - ], + hints: [NotificationHint.soundName('message-new-instant')], ); return; } diff --git a/lib/utils/custom_http_client.dart b/lib/utils/custom_http_client.dart index b0a3dcb28..66b1dcad2 100644 --- a/lib/utils/custom_http_client.dart +++ b/lib/utils/custom_http_client.dart @@ -33,8 +33,8 @@ class CustomHttpClient { } static http.Client createHTTPClient() => retry.RetryClient( - PlatformInfos.isAndroid - ? IOClient(customHttpClient(ISRG_X1)) - : http.Client(), - ); + PlatformInfos.isAndroid + ? IOClient(customHttpClient(ISRG_X1)) + : http.Client(), + ); } diff --git a/lib/utils/custom_image_resizer.dart b/lib/utils/custom_image_resizer.dart index 3431bfc6f..b25ecbbff 100644 --- a/lib/utils/custom_image_resizer.dart +++ b/lib/utils/custom_image_resizer.dart @@ -55,7 +55,8 @@ Future customImageResizer( // scale down image for blurhashing to speed it up final (blurW, blurH) = _scaleToBox(width, height, boxSize: 100); final blurhashImg = nativeImg.resample( - blurW, blurH, + blurW, + blurH, // nearest is unsupported... native.Transform.bilinear, ); @@ -73,8 +74,11 @@ Future customImageResizer( if (width > max || height > max) { (width, height) = _scaleToBox(width, height, boxSize: max); - final scaledImg = - nativeImg.resample(width, height, native.Transform.lanczos); + final scaledImg = nativeImg.resample( + width, + height, + native.Transform.lanczos, + ); nativeImg.free(); nativeImg = scaledImg; } diff --git a/lib/utils/custom_scroll_behaviour.dart b/lib/utils/custom_scroll_behaviour.dart index ba25e9564..32baa332c 100644 --- a/lib/utils/custom_scroll_behaviour.dart +++ b/lib/utils/custom_scroll_behaviour.dart @@ -4,7 +4,7 @@ import 'package:flutter/material.dart'; class CustomScrollBehavior extends MaterialScrollBehavior { @override Set get dragDevices => { - PointerDeviceKind.touch, - PointerDeviceKind.trackpad, - }; + PointerDeviceKind.touch, + PointerDeviceKind.trackpad, + }; } diff --git a/lib/utils/date_time_extension.dart b/lib/utils/date_time_extension.dart index ece0a5c49..508f13e29 100644 --- a/lib/utils/date_time_extension.dart +++ b/lib/utils/date_time_extension.dart @@ -42,7 +42,8 @@ extension DateTimeExtension on DateTime { final sameDay = sameYear && now.month == month && now.day == day; - final sameWeek = sameYear && + final sameWeek = + sameYear && !sameDay && now.millisecondsSinceEpoch - millisecondsSinceEpoch < 1000 * 60 * 60 * 24 * 7; @@ -50,14 +51,17 @@ extension DateTimeExtension on DateTime { if (sameDay) { return localizedTimeOfDay(context); } else if (sameWeek) { - return DateFormat.E(Localizations.localeOf(context).languageCode) - .format(this); + return DateFormat.E( + Localizations.localeOf(context).languageCode, + ).format(this); } else if (sameYear) { - return DateFormat.MMMd(Localizations.localeOf(context).languageCode) - .format(this); + return DateFormat.MMMd( + Localizations.localeOf(context).languageCode, + ).format(this); } - return DateFormat.yMMMd(Localizations.localeOf(context).languageCode) - .format(this); + return DateFormat.yMMMd( + Localizations.localeOf(context).languageCode, + ).format(this); } /// If the DateTime is today, this returns [localizedTimeOfDay()], if not it also diff --git a/lib/utils/error_reporter.dart b/lib/utils/error_reporter.dart index 15d5c1097..bb402a5ad 100644 --- a/lib/utils/error_reporter.dart +++ b/lib/utils/error_reporter.dart @@ -64,10 +64,7 @@ class ErrorReporter { // child: SingleChildScrollView( // child: Text( // text, - // style: const TextStyle( - // fontSize: 14, - // fontFamily: 'RobotoMono', - // ), + // style: const TextStyle(fontSize: 14, fontFamily: 'RobotoMono'), // ), // ), // ), @@ -77,9 +74,7 @@ class ErrorReporter { // child: Text(L10n.of(context).close), // ), // AdaptiveDialogAction( - // onPressed: () => Clipboard.setData( - // ClipboardData(text: text), - // ), + // onPressed: () => Clipboard.setData(ClipboardData(text: text)), // child: Text(L10n.of(context).copy), // ), // AdaptiveDialogAction( diff --git a/lib/utils/event_checkbox_extension.dart b/lib/utils/event_checkbox_extension.dart index cf3832ba6..61e20c408 100644 --- a/lib/utils/event_checkbox_extension.dart +++ b/lib/utils/event_checkbox_extension.dart @@ -6,18 +6,17 @@ extension EventCheckboxRoomExtension on Room { String eventId, int checkboxId, { String? txid, - }) => - sendEvent( - { - 'm.relates_to': { - 'rel_type': relationshipType, - 'event_id': eventId, - 'checkbox_id': checkboxId, - }, - }, - type: EventTypes.Reaction, - txid: txid, - ); + }) => sendEvent( + { + 'm.relates_to': { + 'rel_type': relationshipType, + 'event_id': eventId, + 'checkbox_id': checkboxId, + }, + }, + type: EventTypes.Reaction, + txid: txid, + ); } extension EventCheckboxExtension on Event { diff --git a/lib/utils/feedback_dialog.dart b/lib/utils/feedback_dialog.dart index 36b0f0072..dbb06b362 100644 --- a/lib/utils/feedback_dialog.dart +++ b/lib/utils/feedback_dialog.dart @@ -24,10 +24,7 @@ Future showFeedbackDialog( child: Column( mainAxisSize: MainAxisSize.min, children: [ - const BotFace( - width: 60, - expression: BotExpression.addled, - ), + const BotFace(width: 60, expression: BotExpression.addled), const SizedBox(height: 10), Text(L10n.of(context).reportContentIssueDescription), const SizedBox(height: 10), @@ -35,9 +32,7 @@ Future showFeedbackDialog( padding: const EdgeInsets.all(8.0), decoration: BoxDecoration( borderRadius: BorderRadius.circular(8.0), - border: Border.all( - color: AppConfig.warning, - ), + border: Border.all(color: AppConfig.warning), ), child: offendingContent, ), diff --git a/lib/utils/fluffy_share.dart b/lib/utils/fluffy_share.dart index 17756a030..ea09cbfba 100644 --- a/lib/utils/fluffy_share.dart +++ b/lib/utils/fluffy_share.dart @@ -24,12 +24,10 @@ abstract class FluffyShare { ); return; } - await Clipboard.setData( - ClipboardData(text: text), - ); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text(L10n.of(context).copiedToClipboard)), - ); + await Clipboard.setData(ClipboardData(text: text)); + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text(L10n.of(context).copiedToClipboard))); return; } diff --git a/lib/utils/init_with_restore.dart b/lib/utils/init_with_restore.dart index feb95e003..71cc7f8b4 100644 --- a/lib/utils/init_with_restore.dart +++ b/lib/utils/init_with_restore.dart @@ -31,22 +31,22 @@ class SessionBackup { SessionBackup.fromJson(jsonDecode(json)); factory SessionBackup.fromJson(Map json) => SessionBackup( - olmAccount: json['olm_account'], - accessToken: json['access_token'], - userId: json['user_id'], - homeserver: json['homeserver'], - deviceId: json['device_id'], - deviceName: json['device_name'], - ); + olmAccount: json['olm_account'], + accessToken: json['access_token'], + userId: json['user_id'], + homeserver: json['homeserver'], + deviceId: json['device_id'], + deviceName: json['device_name'], + ); Map toJson() => { - 'olm_account': olmAccount, - 'access_token': accessToken, - 'user_id': userId, - 'homeserver': homeserver, - 'device_id': deviceId, - if (deviceName != null) 'device_name': deviceName, - }; + 'olm_account': olmAccount, + 'access_token': accessToken, + 'user_id': userId, + 'homeserver': homeserver, + 'device_id': deviceId, + if (deviceName != null) 'device_name': deviceName, + }; @override String toString() => jsonEncode(toJson()); @@ -82,7 +82,8 @@ extension InitWithRestoreExtension on Client { final homeserver = this.homeserver?.toString(); final deviceId = deviceID; final userId = userID; - final hasBackup = accessToken != null && + final hasBackup = + accessToken != null && homeserver != null && deviceId != null && userId != null; diff --git a/lib/utils/localized_exception_extension.dart b/lib/utils/localized_exception_extension.dart index e1fdea9cf..b9fe247cc 100644 --- a/lib/utils/localized_exception_extension.dart +++ b/lib/utils/localized_exception_extension.dart @@ -23,8 +23,8 @@ extension LocalizedExceptionExtension on Object { final numString = round < 10 ? num.toStringAsFixed(2) : round < 100 - ? num.toStringAsFixed(1) - : round.toString(); + ? num.toStringAsFixed(1) + : round.toString(); return '$numString ${'kMGTPEZY'[i - 1]}B'; } @@ -47,9 +47,9 @@ extension LocalizedExceptionExtension on Object { // Pangea# if (this is FileTooBigMatrixException) { final exception = this as FileTooBigMatrixException; - return L10n.of(context).fileIsTooBigForServer( - _formatFileSize(exception.maxFileSize), - ); + return L10n.of( + context, + ).fileIsTooBigForServer(_formatFileSize(exception.maxFileSize)); } if (this is OtherPartyCanNotReceiveMessages) { return L10n.of(context).otherPartyNotLoggedIn; diff --git a/lib/utils/markdown_context_builder.dart b/lib/utils/markdown_context_builder.dart index 9404d3504..18b5d5117 100644 --- a/lib/utils/markdown_context_builder.dart +++ b/lib/utils/markdown_context_builder.dart @@ -64,8 +64,10 @@ Widget markdownContextBuilder( if (start == -1) start = 0; final end = selection.end; - final fullLineSelection = - TextSelection(baseOffset: start, extentOffset: end); + final fullLineSelection = TextSelection( + baseOffset: start, + extentOffset: end, + ); const checkBox = '- [ ]'; @@ -78,8 +80,11 @@ Widget markdownContextBuilder( : '$checkBox $line', ) .join('\n'); - controller.text = - controller.text.replaceRange(start, end, replacedRange); + controller.text = controller.text.replaceRange( + start, + end, + replacedRange, + ); ContextMenuController.removeAny(); }, ), diff --git a/lib/utils/matrix_sdk_extensions/device_extension.dart b/lib/utils/matrix_sdk_extensions/device_extension.dart index 55f3ebfc9..3872309ca 100644 --- a/lib/utils/matrix_sdk_extensions/device_extension.dart +++ b/lib/utils/matrix_sdk_extensions/device_extension.dart @@ -22,8 +22,13 @@ IconData _getIconFromName(String displayname) { }.any((s) => name.contains(s))) { return Icons.web_outlined; } - if ({'desktop', 'windows', 'macos', 'linux', 'ubuntu'} - .any((s) => name.contains(s))) { + if ({ + 'desktop', + 'windows', + 'macos', + 'linux', + 'ubuntu', + }.any((s) => name.contains(s))) { return Icons.desktop_mac_outlined; } return Icons.device_unknown_outlined; diff --git a/lib/utils/matrix_sdk_extensions/event_extension.dart b/lib/utils/matrix_sdk_extensions/event_extension.dart index 046df2598..c078bb909 100644 --- a/lib/utils/matrix_sdk_extensions/event_extension.dart +++ b/lib/utils/matrix_sdk_extensions/event_extension.dart @@ -15,8 +15,9 @@ extension LocalizedBody on Event { showFutureLoadingDialog( context: context, futureWithProgress: (onProgress) { - final fileSize = - infoMap['size'] is int ? infoMap['size'] as int : null; + final fileSize = infoMap['size'] is int + ? infoMap['size'] as int + : null; return downloadAndDecryptAttachment( onDownloadProgress: fileSize == null ? null @@ -47,8 +48,11 @@ extension LocalizedBody on Event { thumbnailInfoMap['size'] < room.client.database.maxFileSize; bool get showThumbnail => - [MessageTypes.Image, MessageTypes.Sticker, MessageTypes.Video] - .contains(messageType) && + [ + MessageTypes.Image, + MessageTypes.Sticker, + MessageTypes.Video, + ].contains(messageType) && (kIsWeb || isAttachmentSmallEnough || isThumbnailSmallEnough || diff --git a/lib/utils/matrix_sdk_extensions/filtered_timeline_extension.dart b/lib/utils/matrix_sdk_extensions/filtered_timeline_extension.dart index cb0a3f99b..dc8b89584 100644 --- a/lib/utils/matrix_sdk_extensions/filtered_timeline_extension.dart +++ b/lib/utils/matrix_sdk_extensions/filtered_timeline_extension.dart @@ -10,33 +10,32 @@ extension VisibleInGuiExtension on List { List filterByVisibleInGui({ String? exceptionEventId, String? threadId, - }) => - where( - (event) { - if (threadId != null && - event.relationshipType != RelationshipTypes.reaction) { - if ((event.relationshipType != RelationshipTypes.thread || - event.relationshipEventId != threadId) && - event.eventId != threadId) { - return false; - } - } else if (event.relationshipType == RelationshipTypes.thread) { - return false; - } - // #Pangea - // return event.isVisibleInGui || event.eventId == exceptionEventId; - return (event.isVisibleInGui || event.eventId == exceptionEventId) && - event.isVisibleInPangeaGui; - // Pangea# - }, - ).toList(); + }) => where((event) { + if (threadId != null && + event.relationshipType != RelationshipTypes.reaction) { + if ((event.relationshipType != RelationshipTypes.thread || + event.relationshipEventId != threadId) && + event.eventId != threadId) { + return false; + } + } else if (event.relationshipType == RelationshipTypes.thread) { + return false; + } + // #Pangea + // return event.isVisibleInGui || event.eventId == exceptionEventId; + return (event.isVisibleInGui || event.eventId == exceptionEventId) && + event.isVisibleInPangeaGui; + // Pangea# + }).toList(); } extension IsStateExtension on Event { bool get isVisibleInGui => // always filter out edit and reaction relationships - !{RelationshipTypes.edit, RelationshipTypes.reaction} - .contains(relationshipType) && + !{ + RelationshipTypes.edit, + RelationshipTypes.reaction, + }.contains(relationshipType) && // always filter out m.key.* and other known but unimportant events !isKnownHiddenStates && // event types to hide: redaction and reaction events @@ -56,23 +55,21 @@ extension IsStateExtension on Event { // Pangea# bool get isState => !{ - EventTypes.Message, - EventTypes.Sticker, - EventTypes.Encrypted, - }.contains(type); + EventTypes.Message, + EventTypes.Sticker, + EventTypes.Encrypted, + }.contains(type); bool get isCollapsedState => !{ - EventTypes.Message, - EventTypes.Sticker, - EventTypes.Encrypted, - EventTypes.RoomCreate, - EventTypes.RoomTombstone, - }.contains(type); + EventTypes.Message, + EventTypes.Sticker, + EventTypes.Encrypted, + EventTypes.RoomCreate, + EventTypes.RoomTombstone, + }.contains(type); bool get isKnownHiddenStates => - { - PollEventContent.responseType, - }.contains(type) || + {PollEventContent.responseType}.contains(type) || type.startsWith('m.key.verification.'); // #Pangea diff --git a/lib/utils/matrix_sdk_extensions/flutter_matrix_dart_sdk_database/builder.dart b/lib/utils/matrix_sdk_extensions/flutter_matrix_dart_sdk_database/builder.dart index 95e7eaa00..8a850d212 100644 --- a/lib/utils/matrix_sdk_extensions/flutter_matrix_dart_sdk_database/builder.dart +++ b/lib/utils/matrix_sdk_extensions/flutter_matrix_dart_sdk_database/builder.dart @@ -34,13 +34,10 @@ Future flutterMatrixSdkDatabaseBuilder(String clientName) async { Logs().wtf('Unable to construct database!', e, s); try { + // Send error notification: // #Pangea - // // Send error notification: // final l10n = await lookupL10n(PlatformDispatcher.instance.locale); - // ClientManager.sendInitNotification( - // l10n.initAppError, - // e.toString(), - // ); + // ClientManager.sendInitNotification(l10n.initAppError, e.toString()); // Pangea# } catch (e, s) { Logs().e('Unable to send error notification', e, s); @@ -48,22 +45,22 @@ Future flutterMatrixSdkDatabaseBuilder(String clientName) async { // Try to delete database so that it can created again on next init: database?.delete().catchError( - // #Pangea - (err, s) { - ErrorHandler.logError( - e: e, - s: s, - data: {}, - m: "Failed to delete matrix database after failed construction.", - ); - } - // (e, s) => Logs().wtf( - // 'Unable to delete database, after failed construction', - // e, - // s, - // ), - // Pangea# + // #Pangea + (err, s) { + ErrorHandler.logError( + e: e, + s: s, + data: {}, + m: "Failed to delete matrix database after failed construction.", ); + }, + // (e, s) => Logs().wtf( + // 'Unable to delete database, after failed construction', + // e, + // s, + // ), + // Pangea# + ); // Delete database file: if (!kIsWeb) { @@ -100,8 +97,9 @@ Future _constructDatabase(String clientName) async { // fix dlopen for old Android await applyWorkaroundToOpenSqlCipherOnOldAndroidVersions(); // import the SQLite / SQLCipher shared objects / dynamic libraries - final factory = - createDatabaseFactoryFfi(ffiInit: SQfLiteEncryptionHelper.ffiInit); + final factory = createDatabaseFactoryFfi( + ffiInit: SQfLiteEncryptionHelper.ffiInit, + ); // #Pangea Sentry.addBreadcrumb(Breadcrumb(message: 'Database path: $path')); @@ -117,11 +115,7 @@ Future _constructDatabase(String clientName) async { // to manage SQLite encryption final helper = cipher == null ? null - : SQfLiteEncryptionHelper( - factory: factory, - path: path, - cipher: cipher, - ); + : SQfLiteEncryptionHelper(factory: factory, path: path, cipher: cipher); // #Pangea Sentry.addBreadcrumb(Breadcrumb(message: 'Database cipher helper: $helper')); // Pangea# diff --git a/lib/utils/matrix_sdk_extensions/flutter_matrix_dart_sdk_database/cipher.dart b/lib/utils/matrix_sdk_extensions/flutter_matrix_dart_sdk_database/cipher.dart index 70f8d8072..b890ef8ea 100644 --- a/lib/utils/matrix_sdk_extensions/flutter_matrix_dart_sdk_database/cipher.dart +++ b/lib/utils/matrix_sdk_extensions/flutter_matrix_dart_sdk_database/cipher.dart @@ -39,10 +39,7 @@ Future getDatabaseCipher() async { final list = Uint8List(32); list.setAll(0, Iterable.generate(list.length, (i) => rng.nextInt(256))); final newPassword = base64UrlEncode(list); - await secureStorage.write( - key: _passwordStorageKey, - value: newPassword, - ); + await secureStorage.write(key: _passwordStorageKey, value: newPassword); } // workaround for if we just wrote to the key and it still doesn't exist password = await secureStorage.read(key: _passwordStorageKey); diff --git a/lib/utils/matrix_sdk_extensions/matrix_file_extension.dart b/lib/utils/matrix_sdk_extensions/matrix_file_extension.dart index 09e5d5ded..dffea0c63 100644 --- a/lib/utils/matrix_sdk_extensions/matrix_file_extension.dart +++ b/lib/utils/matrix_sdk_extensions/matrix_file_extension.dart @@ -39,8 +39,9 @@ extension MatrixFileExtension on MatrixFile { await SharePlus.instance.share( ShareParams( files: [XFile.fromData(bytes, name: name, mimeType: mimeType)], - sharePositionOrigin: - box == null ? null : box.localToGlobal(Offset.zero) & box.size, + sharePositionOrigin: box == null + ? null + : box.localToGlobal(Offset.zero) & box.size, ), ); return; diff --git a/lib/utils/matrix_sdk_extensions/matrix_locals.dart b/lib/utils/matrix_sdk_extensions/matrix_locals.dart index 1d3fba848..d910e1792 100644 --- a/lib/utils/matrix_sdk_extensions/matrix_locals.dart +++ b/lib/utils/matrix_sdk_extensions/matrix_locals.dart @@ -356,13 +356,15 @@ class MatrixLocals extends MatrixLocalizations { String get cancelledSend => l10n.sendCanceled; @override - String voiceMessage(String senderName, Duration? duration) => - l10n.sentVoiceMessage( - senderName, - duration == null - ? '' - : '${duration.inMinutes.toString().padLeft(2, '0')}:${(duration.inSeconds % 60).toString().padLeft(2, '0')}', - ); + String voiceMessage( + String senderName, + Duration? duration, + ) => l10n.sentVoiceMessage( + senderName, + duration == null + ? '' + : '${duration.inMinutes.toString().padLeft(2, '0')}:${(duration.inSeconds % 60).toString().padLeft(2, '0')}', + ); @override String get refreshingLastEvent => l10n.loadingPleaseWait; diff --git a/lib/utils/notification_background_handler.dart b/lib/utils/notification_background_handler.dart index 1a694615a..eaaeb7c67 100644 --- a/lib/utils/notification_background_handler.dart +++ b/lib/utils/notification_background_handler.dart @@ -21,19 +21,20 @@ bool _vodInitialized = false; extension NotificationResponseJson on NotificationResponse { String toJsonString() => jsonEncode({ - 'type': notificationResponseType.name, - 'id': id, - 'actionId': actionId, - 'input': input, - 'payload': payload, - 'data': data, - }); + 'type': notificationResponseType.name, + 'id': id, + 'actionId': actionId, + 'input': input, + 'payload': payload, + 'data': data, + }); static NotificationResponse fromJsonString(String jsonString) { final json = jsonDecode(jsonString) as Map; return NotificationResponse( - notificationResponseType: NotificationResponseType.values - .singleWhere((t) => t.name == json['type']), + notificationResponseType: NotificationResponseType.values.singleWhere( + (t) => t.name == json['type'], + ), id: json['id'] as int?, actionId: json['actionId'] as String?, input: json['input'] as String?, @@ -55,8 +56,9 @@ Future waitForPushIsolateDone() async { void notificationTapBackground( NotificationResponse notificationResponse, ) async { - final sendPort = - IsolateNameServer.lookupPortByName(AppConfig.mainIsolatePortName); + final sendPort = IsolateNameServer.lookupPortByName( + AppConfig.mainIsolatePortName, + ); if (sendPort != null) { sendPort.send(notificationResponse.toJsonString()); Logs().i('Notification tap sent to main isolate!'); @@ -80,8 +82,7 @@ void notificationTapBackground( final client = (await ClientManager.getClients( initialize: false, store: store, - )) - .first; + )).first; await client.abortSync(); await client.init( waitForFirstSync: false, @@ -111,8 +112,9 @@ Future notificationTap( 'Notification action handler started', notificationResponse.notificationResponseType.name, ); - final payload = - FluffyChatPushPayload.fromString(notificationResponse.payload ?? ''); + final payload = FluffyChatPushPayload.fromString( + notificationResponse.payload ?? '', + ); switch (notificationResponse.notificationResponseType) { case NotificationResponseType.selectedNotification: final roomId = payload.roomId; @@ -182,16 +184,16 @@ Future notificationTap( final avatarFile = avatar == null ? null : await client - .downloadMxcCached( - avatar, - thumbnailMethod: ThumbnailMethod.crop, - width: notificationAvatarDimension, - height: notificationAvatarDimension, - animated: false, - isThumbnail: true, - rounded: true, - ) - .timeout(const Duration(seconds: 3)); + .downloadMxcCached( + avatar, + thumbnailMethod: ThumbnailMethod.crop, + width: notificationAvatarDimension, + height: notificationAvatarDimension, + animated: false, + isThumbnail: true, + rounded: true, + ) + .timeout(const Duration(seconds: 3)); final messagingStyleInformation = await AndroidFlutterLocalNotificationsPlugin() .getActiveNotificationMessagingStyle(room.id.hashCode); diff --git a/lib/utils/platform_infos.dart b/lib/utils/platform_infos.dart index e80af37e6..619d3f9b9 100644 --- a/lib/utils/platform_infos.dart +++ b/lib/utils/platform_infos.dart @@ -120,5 +120,6 @@ abstract class PlatformInfos { } return null; } -// Pangea# + + // Pangea# } diff --git a/lib/utils/push_helper.dart b/lib/utils/push_helper.dart index 30d92a3df..d8ff412a9 100644 --- a/lib/utils/push_helper.dart +++ b/lib/utils/push_helper.dart @@ -102,8 +102,7 @@ Future _tryPushHelper( client ??= (await ClientManager.getClients( initialize: false, store: await AppSettings.init(), - )) - .first; + )).first; final event = await client.getEventByPushNotification( notification, storeInDatabase: false, @@ -118,8 +117,8 @@ Future _tryPushHelper( // Make sure client is fully loaded and synced before dismiss notifications: await client.roomsLoading; await client.oneShotSync(); - final activeNotifications = - await flutterLocalNotificationsPlugin.getActiveNotifications(); + final activeNotifications = await flutterLocalNotificationsPlugin + .getActiveNotifications(); for (final activeNotification in activeNotifications) { final room = client.rooms.singleWhereOrNull( (room) => room.id.hashCode == activeNotification.id, @@ -184,16 +183,16 @@ Future _tryPushHelper( roomAvatarFile = avatar == null ? null : await client - .downloadMxcCached( - avatar, - thumbnailMethod: ThumbnailMethod.crop, - width: notificationAvatarDimension, - height: notificationAvatarDimension, - animated: false, - isThumbnail: true, - rounded: true, - ) - .timeout(const Duration(seconds: 3)); + .downloadMxcCached( + avatar, + thumbnailMethod: ThumbnailMethod.crop, + width: notificationAvatarDimension, + height: notificationAvatarDimension, + animated: false, + isThumbnail: true, + rounded: true, + ) + .timeout(const Duration(seconds: 3)); } catch (e, s) { Logs().e('Unable to get avatar picture', e, s); // #Pangea @@ -204,18 +203,18 @@ Future _tryPushHelper( senderAvatarFile = event.room.isDirectChat ? roomAvatarFile : senderAvatar == null - ? null - : await client - .downloadMxcCached( - senderAvatar, - thumbnailMethod: ThumbnailMethod.crop, - width: notificationAvatarDimension, - height: notificationAvatarDimension, - animated: false, - isThumbnail: true, - rounded: true, - ) - .timeout(const Duration(seconds: 3)); + ? null + : await client + .downloadMxcCached( + senderAvatar, + thumbnailMethod: ThumbnailMethod.crop, + width: notificationAvatarDimension, + height: notificationAvatarDimension, + animated: false, + isThumbnail: true, + rounded: true, + ) + .timeout(const Duration(seconds: 3)); } catch (e, s) { Logs().e('Unable to get avatar picture', e, s); } @@ -240,14 +239,15 @@ Future _tryPushHelper( final messagingStyleInformation = PlatformInfos.isAndroid ? await AndroidFlutterLocalNotificationsPlugin() - .getActiveNotificationMessagingStyle(id) + .getActiveNotificationMessagingStyle(id) : null; messagingStyleInformation?.messages?.add(newMessage); final roomName = event.room.getLocalizedDisplayname(MatrixLocals(l10n)); - final notificationGroupId = - event.room.isDirectChat ? 'directChats' : 'groupChats'; + final notificationGroupId = event.room.isDirectChat + ? 'directChats' + : 'groupChats'; // #Pangea // final groupName = event.room.isDirectChat ? l10n.directChats : l10n.groups; final groupName = event.room.isDirectChat ? l10n.directChats : l10n.chats; @@ -265,11 +265,13 @@ Future _tryPushHelper( await flutterLocalNotificationsPlugin .resolvePlatformSpecificImplementation< - AndroidFlutterLocalNotificationsPlugin>() + AndroidFlutterLocalNotificationsPlugin + >() ?.createNotificationChannelGroup(messageRooms); await flutterLocalNotificationsPlugin .resolvePlatformSpecificImplementation< - AndroidFlutterLocalNotificationsPlugin>() + AndroidFlutterLocalNotificationsPlugin + >() ?.createNotificationChannel(roomsChannel); final androidPlatformChannelSpecifics = AndroidNotificationDetails( @@ -278,7 +280,8 @@ Future _tryPushHelper( number: notification.counts?.unread, category: AndroidNotificationCategory.message, shortcutId: event.room.id, - styleInformation: messagingStyleInformation ?? + styleInformation: + messagingStyleInformation ?? MessagingStyleInformation( Person( name: senderName, @@ -310,9 +313,7 @@ Future _tryPushHelper( FluffyChatNotificationActions.reply.name, l10n.reply, inputs: [ - AndroidNotificationActionInput( - label: l10n.writeAMessage, - ), + AndroidNotificationActionInput(label: l10n.writeAMessage), ], cancelNotification: false, allowGeneratedReplies: true, @@ -360,9 +361,11 @@ Future _tryPushHelper( body, platformChannelSpecifics, // #Pangea - // payload: - // FluffyChatPushPayload(client.clientName, event.room.id, event.eventId) - // .toString(), + // payload: FluffyChatPushPayload( + // client.clientName, + // event.room.id, + // event.eventId, + // ).toString(), payload: payload, // Pangea# ); diff --git a/lib/utils/resize_video.dart b/lib/utils/resize_video.dart index 99a4c6b0a..ae249818e 100644 --- a/lib/utils/resize_video.dart +++ b/lib/utils/resize_video.dart @@ -39,10 +39,7 @@ extension ResizeImage on XFile { try { final bytes = await VideoCompress.getByteThumbnail(path); if (bytes == null) return null; - return MatrixImageFile( - bytes: bytes, - name: name, - ); + return MatrixImageFile(bytes: bytes, name: name); } catch (e, s) { Logs().w('Error while compressing video', e, s); } diff --git a/lib/utils/room_status_extension.dart b/lib/utils/room_status_extension.dart index 7c978064b..3021a3147 100644 --- a/lib/utils/room_status_extension.dart +++ b/lib/utils/room_status_extension.dart @@ -19,8 +19,9 @@ extension RoomStatusExtension on Room { } else if (typingUsers.length == 1) { typingText = L10n.of(context).isTyping; if (typingUsers.first.id != directChatMatrixID) { - typingText = - L10n.of(context).userIsTyping(typingUsers.first.calcDisplayname()); + typingText = L10n.of( + context, + ).userIsTyping(typingUsers.first.calcDisplayname()); } } else if (typingUsers.length == 2) { typingText = L10n.of(context).userAndUserAreTyping( diff --git a/lib/utils/show_scaffold_dialog.dart b/lib/utils/show_scaffold_dialog.dart index 9a0a0c610..7e552f90d 100644 --- a/lib/utils/show_scaffold_dialog.dart +++ b/lib/utils/show_scaffold_dialog.dart @@ -10,28 +10,25 @@ Future showScaffoldDialog({ double maxWidth = 480, double maxHeight = 720, required Widget Function(BuildContext context) builder, -}) => - showDialog( - context: context, - useSafeArea: false, - builder: FluffyThemes.isColumnMode(context) - ? (context) => Center( - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular( - AppConfig.borderRadius, - ), - color: containerColor ?? - Theme.of(context).scaffoldBackgroundColor, - ), - clipBehavior: Clip.hardEdge, - margin: const EdgeInsets.all(16), - constraints: BoxConstraints( - maxWidth: maxWidth, - maxHeight: maxHeight, - ), - child: builder(context), - ), - ) - : builder, - ); +}) => showDialog( + context: context, + useSafeArea: false, + builder: FluffyThemes.isColumnMode(context) + ? (context) => Center( + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(AppConfig.borderRadius), + color: + containerColor ?? Theme.of(context).scaffoldBackgroundColor, + ), + clipBehavior: Clip.hardEdge, + margin: const EdgeInsets.all(16), + constraints: BoxConstraints( + maxWidth: maxWidth, + maxHeight: maxHeight, + ), + child: builder(context), + ), + ) + : builder, +); diff --git a/lib/utils/sync_status_localization.dart b/lib/utils/sync_status_localization.dart index 6d3a10311..c48e71252 100644 --- a/lib/utils/sync_status_localization.dart +++ b/lib/utils/sync_status_localization.dart @@ -12,8 +12,9 @@ extension SyncStatusLocalization on SyncStatusUpdate { case SyncStatus.waitingForResponse: return L10n.of(context).waitingForServer; case SyncStatus.error: - return ((error?.exception ?? Object()) as Object) - .toLocalizedString(context); + return ((error?.exception ?? Object()) as Object).toLocalizedString( + context, + ); case SyncStatus.processing: case SyncStatus.cleaningUp: case SyncStatus.finished: diff --git a/lib/utils/uia_request_manager.dart b/lib/utils/uia_request_manager.dart index a119353d1..e15fdbf67 100644 --- a/lib/utils/uia_request_manager.dart +++ b/lib/utils/uia_request_manager.dart @@ -16,7 +16,7 @@ extension UiaRequestManager on MatrixState { final l10n = L10n.of(context); final navigatorContext = FluffyChatApp.router.routerDelegate.navigatorKey.currentContext ?? - context; + context; try { if (uiaRequest.state != UiaRequestState.waitForUser || uiaRequest.nextStages.isEmpty) { @@ -27,7 +27,8 @@ extension UiaRequestManager on MatrixState { Logs().d('Uia Request Stage: $stage'); switch (stage) { case AuthenticationTypes.password: - final input = cachedPassword ?? + final input = + cachedPassword ?? (await showTextInputDialog( context: navigatorContext, title: l10n.pleaseEnterYourPassword, @@ -90,9 +91,7 @@ extension UiaRequestManager on MatrixState { ?.tryGet('url'); final fallbackUrl = client.homeserver!.replace( path: '/_matrix/client/v3/auth/$stage/fallback/web', - queryParameters: { - 'session': uiaRequest.session, - }, + queryParameters: {'session': uiaRequest.session}, ); final url = stageUrl != null ? (Uri.tryParse(stageUrl) ?? fallbackUrl) @@ -109,8 +108,9 @@ extension UiaRequestManager on MatrixState { launchUrl(url, mode: LaunchMode.inAppBrowserView); final completer = Completer(); - final listener = - AppLifecycleListener(onResume: () => completer.complete()); + final listener = AppLifecycleListener( + onResume: () => completer.complete(), + ); await completer.future; listener.dispose(); diff --git a/lib/utils/url_launcher.dart b/lib/utils/url_launcher.dart index 00ef99abc..eb41ae102 100644 --- a/lib/utils/url_launcher.dart +++ b/lib/utils/url_launcher.dart @@ -99,13 +99,16 @@ class UrlLauncher { // okay, we have either an http or an https URI. // As some platforms have issues with opening unicode URLs, we are going to help // them out by punycode-encoding them for them ourself. - final newHost = uri.host.split('.').map((hostPartEncoded) { - final hostPart = Uri.decodeComponent(hostPartEncoded); - final hostPartPunycode = punycodeEncode(hostPart); - return hostPartPunycode != '$hostPart-' - ? 'xn--$hostPartPunycode' - : hostPart; - }).join('.'); + final newHost = uri.host + .split('.') + .map((hostPartEncoded) { + final hostPart = Uri.decodeComponent(hostPartEncoded); + final hostPartPunycode = punycodeEncode(hostPart); + return hostPartPunycode != '$hostPart-' + ? 'xn--$hostPartPunycode' + : hostPart; + }) + .join('.'); // Force LaunchMode.externalApplication, otherwise url_launcher will default // to opening links in a webview on mobile platforms. launchUrlString( @@ -117,17 +120,17 @@ class UrlLauncher { void openMatrixToUrl() async { final matrix = Matrix.of(context); final url = this.url!.replaceFirst( - AppConfig.deepLinkPrefix, - AppConfig.inviteLinkPrefix, - ); + AppConfig.deepLinkPrefix, + AppConfig.inviteLinkPrefix, + ); // The identifier might be a matrix.to url and needs escaping. Or, it might have multiple // identifiers (room id & event id), or it might also have a query part. // All this needs parsing. - final identityParts = url.parseIdentifierIntoParts() ?? + final identityParts = + url.parseIdentifierIntoParts() ?? Uri.tryParse(url)?.host.parseIdentifierIntoParts() ?? - Uri.tryParse(url) - ?.pathSegments + Uri.tryParse(url)?.pathSegments .lastWhereOrNull((_) => true) ?.parseIdentifierIntoParts(); if (identityParts == null) { @@ -138,7 +141,8 @@ class UrlLauncher { // we got a room! Let's open that one final roomIdOrAlias = identityParts.primaryIdentifier; final event = identityParts.secondaryIdentifier; - var room = matrix.client.getRoomByAlias(roomIdOrAlias) ?? + var room = + matrix.client.getRoomByAlias(roomIdOrAlias) ?? matrix.client.getRoomById(roomIdOrAlias); var roomId = room?.id; // we make the servers a set and later on convert to a list, so that we can easily @@ -171,10 +175,7 @@ class UrlLauncher { // we have the room, so....just open it if (event != null) { context.go( - '/${Uri( - pathSegments: ['rooms', room.id], - queryParameters: {'event': event}, - )}', + '/${Uri(pathSegments: ['rooms', room.id], queryParameters: {'event': event})}', ); } else { context.go('/rooms/${room.id}'); @@ -184,9 +185,8 @@ class UrlLauncher { // #Pangea // await showAdaptiveDialog( // context: context, - // builder: (c) => PublicRoomDialog( - // roomAlias: identityParts.primaryIdentifier, - // ), + // builder: (c) => + // PublicRoomDialog(roomAlias: identityParts.primaryIdentifier), // ); await PublicRoomBottomSheet.show( context: context, @@ -231,12 +231,11 @@ class UrlLauncher { var noProfileWarning = false; final profileResult = await showFutureLoadingDialog( context: context, - future: () => matrix.client.getProfileFromUserId(userId).catchError( - (_) { - noProfileWarning = true; - return Profile(userId: userId); - }, - ), + future: () => + matrix.client.getProfileFromUserId(userId).catchError((_) { + noProfileWarning = true; + return Profile(userId: userId); + }), ); await UserDialog.show( context: context, diff --git a/lib/utils/voip/video_renderer.dart b/lib/utils/voip/video_renderer.dart index afdd9be2e..935b3984c 100644 --- a/lib/utils/voip/video_renderer.dart +++ b/lib/utils/voip/video_renderer.dart @@ -45,8 +45,9 @@ class _VideoRendererState extends State { @override void initState() { - _streamChangeSubscription = - widget.stream?.onStreamChanged.stream.listen((stream) { + _streamChangeSubscription = widget.stream?.onStreamChanged.stream.listen(( + stream, + ) { setState(() { _renderer?.srcObject = stream; }); diff --git a/lib/utils/voip_plugin.dart b/lib/utils/voip_plugin.dart index c5120d604..adef19dd6 100644 --- a/lib/utils/voip_plugin.dart +++ b/lib/utils/voip_plugin.dart @@ -33,13 +33,15 @@ class VoipPlugin with WidgetsBindingObserver implements WebRTCDelegate { @override void didChangeAppLifecycleState(AppLifecycleState? state) { - background = (state == AppLifecycleState.detached || + background = + (state == AppLifecycleState.detached || state == AppLifecycleState.paused); } void addCallingOverlay(String callId, CallSession call) { - final context = - kIsWeb ? ChatList.contextForVoip! : this.context; // web is weird + final context = kIsWeb + ? ChatList.contextForVoip! + : this.context; // web is weird if (overlayEntry != null) { Logs().e('[VOIP] addCallingOverlay: The call session already exists?'); @@ -85,8 +87,7 @@ class VoipPlugin with WidgetsBindingObserver implements WebRTCDelegate { Future createPeerConnection( Map configuration, [ Map constraints = const {}, - ]) => - webrtc_impl.createPeerConnection(configuration, constraints); + ]) => webrtc_impl.createPeerConnection(configuration, constraints); Future get hasCallingAccount async => false; diff --git a/lib/widgets/adaptive_dialogs/adaptive_dialog_action.dart b/lib/widgets/adaptive_dialogs/adaptive_dialog_action.dart index 4a1929dd1..40fc3f96d 100644 --- a/lib/widgets/adaptive_dialogs/adaptive_dialog_action.dart +++ b/lib/widgets/adaptive_dialogs/adaptive_dialog_action.dart @@ -49,7 +49,8 @@ class AdaptiveDialogAction extends StatelessWidget { child: ElevatedButton( style: ElevatedButton.styleFrom( shape: RoundedRectangleBorder( - borderRadius: borderRadius ?? + borderRadius: + borderRadius ?? BorderRadius.circular(AppConfig.borderRadius), ), backgroundColor: autofocus diff --git a/lib/widgets/adaptive_dialogs/dialog_text_field.dart b/lib/widgets/adaptive_dialogs/dialog_text_field.dart index 7838da05f..aaae9038f 100644 --- a/lib/widgets/adaptive_dialogs/dialog_text_field.dart +++ b/lib/widgets/adaptive_dialogs/dialog_text_field.dart @@ -98,10 +98,7 @@ class DialogTextField extends StatelessWidget { if (errorText != null) Text( errorText, - style: TextStyle( - fontSize: 11, - color: theme.colorScheme.error, - ), + style: TextStyle(fontSize: 11, color: theme.colorScheme.error), textAlign: TextAlign.left, ), ], diff --git a/lib/widgets/adaptive_dialogs/public_room_dialog.dart b/lib/widgets/adaptive_dialogs/public_room_dialog.dart index 6b11d45c9..7fee87bfb 100644 --- a/lib/widgets/adaptive_dialogs/public_room_dialog.dart +++ b/lib/widgets/adaptive_dialogs/public_room_dialog.dart @@ -37,10 +37,7 @@ class PublicRoomDialog extends StatelessWidget { } final roomId = chunk != null && knock ? await client.knockRoom(chunk.roomId, via: via) - : await client.joinRoom( - roomAlias ?? chunk!.roomId, - via: via, - ); + : await client.joinRoom(roomAlias ?? chunk!.roomId, via: via); if (!knock && client.getRoomById(roomId) == null) { await client.waitForRoomInSync(roomId); @@ -78,11 +75,9 @@ class PublicRoomDialog extends StatelessWidget { final chunk = this.chunk; if (chunk != null) return chunk; final query = await Matrix.of(context).client.queryPublicRooms( - server: roomAlias!.domain, - filter: PublicRoomQueryFilter( - genericSearchTerm: roomAlias, - ), - ); + server: roomAlias!.domain, + filter: PublicRoomQueryFilter(genericSearchTerm: roomAlias), + ); if (!query.chunk.any(_testRoom)) { throw (L10n.of(context).noRoomsFound); } @@ -115,8 +110,8 @@ class PublicRoomDialog extends StatelessWidget { return SingleChildScrollView( child: Column( spacing: 8, - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisSize: .min, + crossAxisAlignment: .stretch, children: [ if (roomLink != null) HoverBuilder( @@ -125,9 +120,7 @@ class PublicRoomDialog extends StatelessWidget { cursor: SystemMouseCursors.click, child: GestureDetector( onTap: () { - Clipboard.setData( - ClipboardData(text: roomLink), - ); + Clipboard.setData(ClipboardData(text: roomLink)); setState(() { copied = true; }); @@ -137,8 +130,9 @@ class PublicRoomDialog extends StatelessWidget { children: [ WidgetSpan( child: Padding( - padding: - const EdgeInsets.only(right: 4.0), + padding: const EdgeInsets.only( + right: 4.0, + ), child: AnimatedScale( duration: FluffyThemes.animationDuration, @@ -146,8 +140,8 @@ class PublicRoomDialog extends StatelessWidget { scale: hovered ? 1.33 : copied - ? 1.25 - : 1.0, + ? 1.25 + : 1.0, child: Icon( copied ? Icons.check_circle @@ -160,8 +154,9 @@ class PublicRoomDialog extends StatelessWidget { ), TextSpan(text: roomLink), ], - style: theme.textTheme.bodyMedium - ?.copyWith(fontSize: 10), + style: theme.textTheme.bodyMedium?.copyWith( + fontSize: 10, + ), ), textAlign: TextAlign.center, ), @@ -176,25 +171,26 @@ class PublicRoomDialog extends StatelessWidget { size: Avatar.defaultSize * 2, onTap: avatar != null ? () => showDialog( - context: context, - builder: (_) => MxcImageViewer(avatar), - ) + context: context, + builder: (_) => MxcImageViewer(avatar), + ) : null, ), ), if (profile?.numJoinedMembers != null) Text( - L10n.of(context).countParticipants( - profile?.numJoinedMembers ?? 0, - ), + L10n.of( + context, + ).countParticipants(profile?.numJoinedMembers ?? 0), style: const TextStyle(fontSize: 10), textAlign: TextAlign.center, ), if (topic != null && topic.isNotEmpty) SelectableLinkify( text: topic, - textScaleFactor: - MediaQuery.textScalerOf(context).scale(1), + textScaleFactor: MediaQuery.textScalerOf( + context, + ).scale(1), textAlign: TextAlign.center, options: const LinkifyOptions(humanize: false), linkStyle: TextStyle( @@ -221,8 +217,8 @@ class PublicRoomDialog extends StatelessWidget { Matrix.of(context).client.getRoomById(chunk!.roomId) == null ? L10n.of(context).knock : chunk?.roomType == 'm.space' - ? L10n.of(context).joinSpace - : L10n.of(context).joinRoom, + ? L10n.of(context).joinSpace + : L10n.of(context).joinRoom, ), ), AdaptiveDialogAction( diff --git a/lib/widgets/adaptive_dialogs/show_modal_action_popup.dart b/lib/widgets/adaptive_dialogs/show_modal_action_popup.dart index 47db330f1..f99e69353 100644 --- a/lib/widgets/adaptive_dialogs/show_modal_action_popup.dart +++ b/lib/widgets/adaptive_dialogs/show_modal_action_popup.dart @@ -32,10 +32,7 @@ Future showModalActionPopup({ ListTile( title: title == null ? null - : Text( - title, - style: theme.textTheme.labelSmall, - ), + : Text(title, style: theme.textTheme.labelSmall), subtitle: message == null ? null : Text(message), ), const Divider(height: 1), @@ -49,8 +46,9 @@ Future showModalActionPopup({ style: action.isDestructive ? TextStyle( color: theme.colorScheme.error, - fontWeight: - action.isDefaultAction ? FontWeight.bold : null, + fontWeight: action.isDefaultAction + ? FontWeight.bold + : null, ) : null, ), diff --git a/lib/widgets/adaptive_dialogs/show_ok_cancel_alert_dialog.dart b/lib/widgets/adaptive_dialogs/show_ok_cancel_alert_dialog.dart index 542bdb7a0..3b6c72684 100644 --- a/lib/widgets/adaptive_dialogs/show_ok_cancel_alert_dialog.dart +++ b/lib/widgets/adaptive_dialogs/show_ok_cancel_alert_dialog.dart @@ -16,50 +16,49 @@ Future showOkCancelAlertDialog({ String? cancelLabel, bool isDestructive = false, bool useRootNavigator = true, -}) => - showAdaptiveDialog( - context: context, - useRootNavigator: useRootNavigator, - builder: (context) => AlertDialog.adaptive( - title: ConstrainedBox( - constraints: const BoxConstraints(maxWidth: 256), - child: Text(title), - ), - content: ConstrainedBox( - constraints: const BoxConstraints(maxWidth: 256), - child: message == null - ? null - : SelectableLinkify( - text: message, - textScaleFactor: MediaQuery.textScalerOf(context).scale(1), - linkStyle: TextStyle( - color: Theme.of(context).colorScheme.primary, - decorationColor: Theme.of(context).colorScheme.primary, - ), - options: const LinkifyOptions(humanize: false), - onOpen: (url) => UrlLauncher(context, url.url).launchUrl(), - ), - ), - actions: [ - AdaptiveDialogAction( - onPressed: () => Navigator.of(context) - .pop(OkCancelResult.cancel), - child: Text(cancelLabel ?? L10n.of(context).cancel), - ), - AdaptiveDialogAction( - onPressed: () => - Navigator.of(context).pop(OkCancelResult.ok), - autofocus: true, - child: Text( - okLabel ?? L10n.of(context).ok, - style: isDestructive - ? TextStyle(color: Theme.of(context).colorScheme.error) - : null, +}) => showAdaptiveDialog( + context: context, + useRootNavigator: useRootNavigator, + builder: (context) => AlertDialog.adaptive( + title: ConstrainedBox( + constraints: const BoxConstraints(maxWidth: 256), + child: Text(title), + ), + content: ConstrainedBox( + constraints: const BoxConstraints(maxWidth: 256), + child: message == null + ? null + : SelectableLinkify( + text: message, + textScaleFactor: MediaQuery.textScalerOf(context).scale(1), + linkStyle: TextStyle( + color: Theme.of(context).colorScheme.primary, + decorationColor: Theme.of(context).colorScheme.primary, + ), + options: const LinkifyOptions(humanize: false), + onOpen: (url) => UrlLauncher(context, url.url).launchUrl(), ), - ), - ], + ), + actions: [ + AdaptiveDialogAction( + onPressed: () => + Navigator.of(context).pop(OkCancelResult.cancel), + child: Text(cancelLabel ?? L10n.of(context).cancel), ), - ); + AdaptiveDialogAction( + onPressed: () => + Navigator.of(context).pop(OkCancelResult.ok), + autofocus: true, + child: Text( + okLabel ?? L10n.of(context).ok, + style: isDestructive + ? TextStyle(color: Theme.of(context).colorScheme.error) + : null, + ), + ), + ], + ), +); Future showOkAlertDialog({ required BuildContext context, @@ -67,37 +66,36 @@ Future showOkAlertDialog({ String? message, String? okLabel, bool useRootNavigator = true, -}) => - showAdaptiveDialog( - context: context, - useRootNavigator: useRootNavigator, - builder: (context) => AlertDialog.adaptive( - title: ConstrainedBox( - constraints: const BoxConstraints(maxWidth: 256), - child: Text(title), - ), - content: ConstrainedBox( - constraints: const BoxConstraints(maxWidth: 256), - child: message == null - ? null - : SelectableLinkify( - text: message, - textScaleFactor: MediaQuery.textScalerOf(context).scale(1), - linkStyle: TextStyle( - color: Theme.of(context).colorScheme.primary, - decorationColor: Theme.of(context).colorScheme.primary, - ), - options: const LinkifyOptions(humanize: false), - onOpen: (url) => UrlLauncher(context, url.url).launchUrl(), - ), - ), - actions: [ - AdaptiveDialogAction( - onPressed: () => - Navigator.of(context).pop(OkCancelResult.ok), - autofocus: true, - child: Text(okLabel ?? L10n.of(context).close), - ), - ], +}) => showAdaptiveDialog( + context: context, + useRootNavigator: useRootNavigator, + builder: (context) => AlertDialog.adaptive( + title: ConstrainedBox( + constraints: const BoxConstraints(maxWidth: 256), + child: Text(title), + ), + content: ConstrainedBox( + constraints: const BoxConstraints(maxWidth: 256), + child: message == null + ? null + : SelectableLinkify( + text: message, + textScaleFactor: MediaQuery.textScalerOf(context).scale(1), + linkStyle: TextStyle( + color: Theme.of(context).colorScheme.primary, + decorationColor: Theme.of(context).colorScheme.primary, + ), + options: const LinkifyOptions(humanize: false), + onOpen: (url) => UrlLauncher(context, url.url).launchUrl(), + ), + ), + actions: [ + AdaptiveDialogAction( + onPressed: () => + Navigator.of(context).pop(OkCancelResult.ok), + autofocus: true, + child: Text(okLabel ?? L10n.of(context).close), ), - ); + ], + ), +); diff --git a/lib/widgets/adaptive_dialogs/show_text_input_dialog.dart b/lib/widgets/adaptive_dialogs/show_text_input_dialog.dart index cba2d7247..4ac5b871b 100644 --- a/lib/widgets/adaptive_dialogs/show_text_input_dialog.dart +++ b/lib/widgets/adaptive_dialogs/show_text_input_dialog.dart @@ -45,7 +45,7 @@ Future showTextInputDialog({ content: ConstrainedBox( constraints: const BoxConstraints(maxWidth: 256), child: Column( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ if (message != null) SelectableLinkify( diff --git a/lib/widgets/adaptive_dialogs/user_dialog.dart b/lib/widgets/adaptive_dialogs/user_dialog.dart index 119dfc5a5..8f8cb753a 100644 --- a/lib/widgets/adaptive_dialogs/user_dialog.dart +++ b/lib/widgets/adaptive_dialogs/user_dialog.dart @@ -21,15 +21,12 @@ class UserDialog extends StatelessWidget { required BuildContext context, required Profile profile, bool noProfileWarning = false, - }) => - showAdaptiveDialog( - context: context, - barrierDismissible: true, - builder: (context) => UserDialog( - profile, - noProfileWarning: noProfileWarning, - ), - ); + }) => showAdaptiveDialog( + context: context, + barrierDismissible: true, + builder: (context) => + UserDialog(profile, noProfileWarning: noProfileWarning), + ); final Profile profile; final bool noProfileWarning; @@ -40,7 +37,8 @@ class UserDialog extends StatelessWidget { Widget build(BuildContext context) { final client = Matrix.of(context).client; final dmRoomId = client.getDirectChatFromUserId(profile.userId); - final displayname = profile.displayName ?? + final displayname = + profile.displayName ?? profile.userId.localpart ?? L10n.of(context).user; var copied = false; @@ -65,15 +63,15 @@ class UserDialog extends StatelessWidget { final presenceText = presence.currentlyActive == true ? L10n.of(context).currentlyActive : lastActiveTimestamp != null - ? L10n.of(context).lastActiveAgo( - lastActiveTimestamp.localizedTimeShort(context), - ) - : null; + ? L10n.of(context).lastActiveAgo( + lastActiveTimestamp.localizedTimeShort(context), + ) + : null; return SingleChildScrollView( child: Column( spacing: 8, - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisSize: .min, + crossAxisAlignment: .stretch, children: [ Center( child: Avatar( @@ -82,9 +80,9 @@ class UserDialog extends StatelessWidget { size: Avatar.defaultSize * 2, onTap: avatar != null ? () => showDialog( - context: context, - builder: (_) => MxcImageViewer(avatar), - ) + context: context, + builder: (_) => MxcImageViewer(avatar), + ) : null, // #Pangea userId: profile.userId, @@ -116,8 +114,8 @@ class UserDialog extends StatelessWidget { scale: hovered ? 1.33 : copied - ? 1.25 - : 1.0, + ? 1.25 + : 1.0, child: Icon( copied ? Icons.check_circle @@ -130,8 +128,9 @@ class UserDialog extends StatelessWidget { ), TextSpan(text: profile.userId), ], - style: theme.textTheme.bodyMedium - ?.copyWith(fontSize: 10), + style: theme.textTheme.bodyMedium?.copyWith( + fontSize: 10, + ), ), textAlign: TextAlign.center, ), @@ -149,8 +148,9 @@ class UserDialog extends StatelessWidget { // if (statusMsg != null) // SelectableLinkify( // text: statusMsg, - // textScaleFactor: - // MediaQuery.textScalerOf(context).scale(1), + // textScaleFactor: MediaQuery.textScalerOf( + // context, + // ).scale(1), // textAlign: TextAlign.center, // options: const LinkifyOptions(humanize: false), // linkStyle: TextStyle( @@ -165,9 +165,7 @@ class UserDialog extends StatelessWidget { padding: const EdgeInsets.all(4.0), child: Row( mainAxisAlignment: MainAxisAlignment.center, - children: [ - LevelDisplayName(userId: profile.userId), - ], + children: [LevelDisplayName(userId: profile.userId)], ), ), // Pangea# diff --git a/lib/widgets/app_lock.dart b/lib/widgets/app_lock.dart index ff379c5d8..a8b933011 100644 --- a/lib/widgets/app_lock.dart +++ b/lib/widgets/app_lock.dart @@ -82,8 +82,8 @@ class AppLock extends State with WidgetsBindingObserver { } void showLockScreen() => setState(() { - _isLocked = true; - }); + _isLocked = true; + }); Future pauseWhile(Future future) async { _paused = true; @@ -94,20 +94,15 @@ class AppLock extends State with WidgetsBindingObserver { } } - static AppLock of(BuildContext context) => Provider.of( - context, - listen: false, - ); + static AppLock of(BuildContext context) => + Provider.of(context, listen: false); @override Widget build(BuildContext context) => Provider( - create: (_) => this, - child: Stack( - fit: StackFit.expand, - children: [ - widget.child, - if (isLocked) const LockScreen(), - ], - ), - ); + create: (_) => this, + child: Stack( + fit: StackFit.expand, + children: [widget.child, if (isLocked) const LockScreen()], + ), + ); } diff --git a/lib/widgets/avatar.dart b/lib/widgets/avatar.dart index 995a15b9a..7e1975a1c 100644 --- a/lib/widgets/avatar.dart +++ b/lib/widgets/avatar.dart @@ -62,10 +62,12 @@ class Avatar extends StatelessWidget { final theme = Theme.of(context); final name = this.name; - final fallbackLetters = - name == null || name.isEmpty ? '@' : name.substring(0, 1); + final fallbackLetters = name == null || name.isEmpty + ? '@' + : name.substring(0, 1); - final noPic = mxContent == null || + final noPic = + mxContent == null || mxContent.toString().isEmpty || mxContent.toString() == 'null'; final borderRadius = this.borderRadius ?? BorderRadius.circular(size / 2); @@ -93,55 +95,54 @@ class Avatar extends StatelessWidget { ) // #Pangea : !(mxContent.toString().startsWith('mxc://')) - ? ImageByUrl( - imageUrl: mxContent, - width: size, - replacement: Center( - child: Icon( - icon ?? Icons.person_2, - color: theme.colorScheme.tertiary, - size: size / 1.5, - ), - ), - borderRadius: borderRadius, - ) - // Pangea# - : MxcImage( - // Pangea# - client: client, - borderRadius: borderRadius, - key: ValueKey(mxContent.toString()), - cacheKey: '${mxContent}_$size', - uri: mxContent, - fit: BoxFit.cover, - width: size, - height: size, - placeholder: (_) => noPic - ? Container( - decoration: BoxDecoration( - color: - backgroundColor ?? name?.lightColorAvatar, - ), - alignment: Alignment.center, - child: Text( - fallbackLetters, - textAlign: TextAlign.center, - style: TextStyle( - fontFamily: 'RobotoMono', - color: textColor ?? Colors.white, - fontWeight: FontWeight.bold, - fontSize: (size / 2.5).roundToDouble(), - ), - ), - ) - : Center( - child: Icon( - Icons.person_2, - color: theme.colorScheme.tertiary, - size: size / 1.5, - ), - ), + ? ImageByUrl( + imageUrl: mxContent, + width: size, + replacement: Center( + child: Icon( + icon ?? Icons.person_2, + color: theme.colorScheme.tertiary, + size: size / 1.5, ), + ), + borderRadius: borderRadius, + ) + // Pangea# + : MxcImage( + // Pangea# + client: client, + borderRadius: borderRadius, + key: ValueKey(mxContent.toString()), + cacheKey: '${mxContent}_$size', + uri: mxContent, + fit: BoxFit.cover, + width: size, + height: size, + placeholder: (_) => noPic + ? Container( + decoration: BoxDecoration( + color: backgroundColor ?? name?.lightColorAvatar, + ), + alignment: Alignment.center, + child: Text( + fallbackLetters, + textAlign: TextAlign.center, + style: TextStyle( + fontFamily: 'RobotoMono', + color: textColor ?? Colors.white, + fontWeight: FontWeight.bold, + fontSize: (size / 2.5).roundToDouble(), + ), + ), + ) + : Center( + child: Icon( + Icons.person_2, + color: theme.colorScheme.tertiary, + size: size / 1.5, + ), + ), + ), ), ), // #Pangea @@ -166,8 +167,8 @@ class Avatar extends StatelessWidget { final dotColor = presence.presence.isOnline ? Colors.green : presence.presence.isUnavailable - ? Colors.orange - : Colors.grey; + ? Colors.orange + : Colors.grey; return Positioned( // #Pangea // bottom: -3, @@ -212,10 +213,7 @@ class Avatar extends StatelessWidget { if (onTap == null) return container; return MouseRegion( cursor: SystemMouseCursors.click, - child: GestureDetector( - onTap: onTap, - child: container, - ), + child: GestureDetector(onTap: onTap, child: container), ); } } diff --git a/lib/widgets/avatar_page_header.dart b/lib/widgets/avatar_page_header.dart index e00eca90e..bff0d3881 100644 --- a/lib/widgets/avatar_page_header.dart +++ b/lib/widgets/avatar_page_header.dart @@ -25,8 +25,8 @@ class AvatarPageHeader extends StatelessWidget { child: ConstrainedBox( constraints: const BoxConstraints(maxWidth: FluffyThemes.columnWidth), child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.center, + mainAxisSize: .min, + crossAxisAlignment: .center, spacing: 8.0, children: [ Stack( @@ -58,7 +58,7 @@ class AvatarPageHeader extends StatelessWidget { child: LayoutBuilder( builder: (context, constraints) { return Row( - mainAxisAlignment: MainAxisAlignment.center, + mainAxisAlignment: .center, children: [ ConstrainedBox( constraints: BoxConstraints( @@ -87,7 +87,7 @@ class AvatarPageHeader extends StatelessWidget { ), ), child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, + mainAxisAlignment: .spaceEvenly, children: iconButtons, ), ), diff --git a/lib/widgets/blur_hash.dart b/lib/widgets/blur_hash.dart index d4ad1dd47..a7fc4fac0 100644 --- a/lib/widgets/blur_hash.dart +++ b/lib/widgets/blur_hash.dart @@ -25,9 +25,7 @@ class BlurHash extends StatefulWidget { class _BlurHashState extends State { Uint8List? _data; - static Future getBlurhashData( - BlurhashData blurhashData, - ) async { + static Future getBlurhashData(BlurhashData blurhashData) async { final blurhash = b.BlurHash.decode(blurhashData.hsh); final img = blurhash.toImage(blurhashData.w, blurhashData.h); return Uint8List.fromList(image.encodePng(img)); @@ -46,11 +44,7 @@ class _BlurHashState extends State { return _data ??= await compute( getBlurhashData, - BlurhashData( - hsh: widget.blurhash, - w: width, - h: height, - ), + BlurhashData(hsh: widget.blurhash, w: width, h: height), ); } @@ -84,21 +78,10 @@ class BlurhashData { final int w; final int h; - const BlurhashData({ - required this.hsh, - required this.w, - required this.h, - }); + const BlurhashData({required this.hsh, required this.w, required this.h}); - factory BlurhashData.fromJson(Map json) => BlurhashData( - hsh: json['hsh'], - w: json['w'], - h: json['h'], - ); + factory BlurhashData.fromJson(Map json) => + BlurhashData(hsh: json['hsh'], w: json['w'], h: json['h']); - Map toJson() => { - 'hsh': hsh, - 'w': w, - 'h': h, - }; + Map toJson() => {'hsh': hsh, 'w': w, 'h': h}; } diff --git a/lib/widgets/chat_settings_popup_menu.dart b/lib/widgets/chat_settings_popup_menu.dart index b41bbdfc5..eb2ee71db 100644 --- a/lib/widgets/chat_settings_popup_menu.dart +++ b/lib/widgets/chat_settings_popup_menu.dart @@ -36,10 +36,7 @@ class ChatSettingsPopupMenuState extends State { @override Widget build(BuildContext context) { - notificationChangeSub ??= Matrix.of(context) - .client - .onSync - .stream + notificationChangeSub ??= Matrix.of(context).client.onSync.stream .where( (syncUpdate) => syncUpdate.accountData?.any( @@ -47,9 +44,7 @@ class ChatSettingsPopupMenuState extends State { ) ?? false, ) - .listen( - (u) => setState(() {}), - ); + .listen((u) => setState(() {})); return Stack( alignment: Alignment.center, children: [ diff --git a/lib/widgets/config_viewer.dart b/lib/widgets/config_viewer.dart index b0537317c..c4c23a338 100644 --- a/lib/widgets/config_viewer.dart +++ b/lib/widgets/config_viewer.dart @@ -53,9 +53,7 @@ class _ConfigViewerState extends State { return Scaffold( appBar: AppBar( title: const Text('Advanced configurations'), - leading: BackButton( - onPressed: () => context.go('/'), - ), + leading: BackButton(onPressed: () => context.go('/')), ), body: Column( children: [ @@ -65,9 +63,7 @@ class _ConfigViewerState extends State { color: theme.colorScheme.errorContainer, child: Text( 'Changing configs by hand is untested! Use without any warranty!', - style: TextStyle( - color: theme.colorScheme.onErrorContainer, - ), + style: TextStyle(color: theme.colorScheme.onErrorContainer), ), ), Expanded( diff --git a/lib/widgets/error_widget.dart b/lib/widgets/error_widget.dart index 3bbab55e6..16637e01f 100644 --- a/lib/widgets/error_widget.dart +++ b/lib/widgets/error_widget.dart @@ -25,10 +25,10 @@ class _FluffyChatErrorWidgetState extends State { // related sentry issue: https://pangea-chat.sentry.io/issues/5970490357 if (!context.mounted) return; // Pangea# - ErrorReporter(context, 'Error Widget').onErrorCallback( - widget.details.exception, - widget.details.stack, - ); + ErrorReporter( + context, + 'Error Widget', + ).onErrorCallback(widget.details.exception, widget.details.stack); }); } diff --git a/lib/widgets/fluffy_chat_app.dart b/lib/widgets/fluffy_chat_app.dart index c89916511..ce498d17a 100644 --- a/lib/widgets/fluffy_chat_app.dart +++ b/lib/widgets/fluffy_chat_app.dart @@ -42,9 +42,7 @@ class FluffyChatApp extends StatelessWidget { static final GoRouter router = GoRouter( routes: AppRoutes.routes, // #Pangea - observers: [ - GoogleAnalytics.getAnalyticsObserver(), - ], + observers: [GoogleAnalytics.getAnalyticsObserver()], // Pangea# debugLogDiagnostics: true, ); @@ -56,8 +54,11 @@ class FluffyChatApp extends StatelessWidget { title: AppSettings.applicationName.value, themeMode: themeMode, theme: FluffyThemes.buildTheme(context, Brightness.light, primaryColor), - darkTheme: - FluffyThemes.buildTheme(context, Brightness.dark, primaryColor), + darkTheme: FluffyThemes.buildTheme( + context, + Brightness.dark, + primaryColor, + ), scrollBehavior: CustomScrollBehavior(), // #Pangea locale: Provider.of(context).locale, diff --git a/lib/widgets/future_loading_dialog.dart b/lib/widgets/future_loading_dialog.dart index a5ac91272..e9575364a 100644 --- a/lib/widgets/future_loading_dialog.dart +++ b/lib/widgets/future_loading_dialog.dart @@ -66,10 +66,7 @@ Future> showFutureLoadingDialog({ ), ); return result ?? - Result.error( - Exception('FutureDialog canceled'), - StackTrace.current, - ); + Result.error(Exception('FutureDialog canceled'), StackTrace.current); } class LoadingDialog extends StatefulWidget { @@ -177,7 +174,7 @@ class LoadingDialogState extends State { content: ConstrainedBox( constraints: const BoxConstraints(maxWidth: 256), child: Row( - crossAxisAlignment: CrossAxisAlignment.center, + crossAxisAlignment: .center, children: [ // #Pangea // if (exception == null) ...[ @@ -186,9 +183,7 @@ class LoadingDialogState extends State { StreamBuilder( stream: widget.onProgressStream, builder: (context, snapshot) => - CircularProgressIndicator.adaptive( - value: snapshot.data, - ), + CircularProgressIndicator.adaptive(value: snapshot.data), ), const SizedBox(width: 20), ], @@ -213,47 +208,41 @@ class LoadingDialogState extends State { // ? null // : [ // AdaptiveDialogAction( - // onPressed: () => Navigator.of(context).pop>( - // Result.error( - // exception, - // stackTrace, - // ), - // ), + // onPressed: () => Navigator.of( + // context, + // ).pop>(Result.error(exception, stackTrace)), // child: Text(widget.backLabel ?? L10n.of(context).close), // ), // ], actions: _successMessage != null ? [ AdaptiveDialogAction( - onPressed: () => Navigator.of(context).pop>( - Result.value(_result as T), - ), + onPressed: () => Navigator.of( + context, + ).pop>(Result.value(_result as T)), child: Text(L10n.of(context).close), ), ] : exception == null - ? widget.onDismiss != null - ? [ - AdaptiveDialogAction( - onPressed: () { - widget.onDismiss!(); - Navigator.of(context).pop(); - }, - child: Text(L10n.of(context).cancel), - ), - ] - : null - : [ - AdaptiveDialogAction( - onPressed: () => Navigator.of(context).pop>( - Result.error( - exception, - stackTrace, - ), + ? widget.onDismiss != null + ? [ + AdaptiveDialogAction( + onPressed: () { + widget.onDismiss!(); + Navigator.of(context).pop(); + }, + child: Text(L10n.of(context).cancel), ), - child: Text(widget.backLabel ?? L10n.of(context).close), - ), - ], + ] + : null + : [ + AdaptiveDialogAction( + onPressed: () => Navigator.of( + context, + ).pop>(Result.error(exception, stackTrace)), + child: Text(widget.backLabel ?? L10n.of(context).close), + ), + ], // Pangea# ); } diff --git a/lib/widgets/layouts/login_scaffold.dart b/lib/widgets/layouts/login_scaffold.dart index 9060eace4..fe07af723 100644 --- a/lib/widgets/layouts/login_scaffold.dart +++ b/lib/widgets/layouts/login_scaffold.dart @@ -96,7 +96,7 @@ class LoginScaffold extends StatelessWidget { ), ), ), - const _PrivacyButtons(mainAxisAlignment: MainAxisAlignment.center), + const _PrivacyButtons(mainAxisAlignment: .center), ], ), ); @@ -120,32 +120,20 @@ class _PrivacyButtons extends StatelessWidget { children: [ TextButton( onPressed: () => launchUrlString(AppConfig.website), - child: Text( - L10n.of(context).website, - style: shadowTextStyle, - ), + child: Text(L10n.of(context).website, style: shadowTextStyle), ), TextButton( onPressed: () => launchUrlString(AppConfig.supportUrl), - child: Text( - L10n.of(context).help, - style: shadowTextStyle, - ), + child: Text(L10n.of(context).help, style: shadowTextStyle), ), TextButton( onPressed: () => launchUrl(AppConfig.privacyUrl), - child: Text( - L10n.of(context).privacy, - style: shadowTextStyle, - ), + child: Text(L10n.of(context).privacy, style: shadowTextStyle), ), // #Pangea // TextButton( // onPressed: () => PlatformInfos.showDialog(context), - // child: Text( - // L10n.of(context).about, - // style: shadowTextStyle, - // ), + // child: Text(L10n.of(context).about, style: shadowTextStyle), // ), // Pangea# ], diff --git a/lib/widgets/layouts/max_width_body.dart b/lib/widgets/layouts/max_width_body.dart index 0a8631cc8..b75272a3d 100644 --- a/lib/widgets/layouts/max_width_body.dart +++ b/lib/widgets/layouts/max_width_body.dart @@ -47,22 +47,21 @@ class MaxWidthBody extends StatelessWidget { // constraints: const BoxConstraints( // maxWidth: FluffyThemes.columnWidth * 1.5, // ), - constraints: BoxConstraints( - maxWidth: maxWidth, - ), + constraints: BoxConstraints(maxWidth: maxWidth), // Pangea# child: Material( shape: RoundedRectangleBorder( - borderRadius: - BorderRadius.circular(AppConfig.borderRadius), + borderRadius: BorderRadius.circular( + AppConfig.borderRadius, + ), + // #Pangea + // side: BorderSide(color: theme.dividerColor), side: BorderSide( - // #Pangea - // color: theme.dividerColor, color: showBorder ? theme.dividerColor : Colors.transparent, - // Pangea# ), + // Pangea# ), clipBehavior: Clip.hardEdge, child: Padding( diff --git a/lib/widgets/layouts/two_column_layout.dart b/lib/widgets/layouts/two_column_layout.dart index c9ad03897..13fcd477a 100644 --- a/lib/widgets/layouts/two_column_layout.dart +++ b/lib/widgets/layouts/two_column_layout.dart @@ -31,9 +31,10 @@ class TwoColumnLayout extends StatelessWidget { final spaceID = state.pathParameters['spaceid']; if (roomID == null && spaceID == null) { - showNavRail = !["newcourse", ":construct"].any( - (p) => state.fullPath?.contains(p) ?? false, - ); + showNavRail = ![ + "newcourse", + ":construct", + ].any((p) => state.fullPath?.contains(p) ?? false); } else if (roomID == null) { showNavRail = state.fullPath?.endsWith(':spaceid') == true; } @@ -41,7 +42,7 @@ class TwoColumnLayout extends StatelessWidget { final columnWidth = (showNavRail ? (FluffyThemes.navRailWidth + 1.0) : 0.0) + - (isColumnMode ? (FluffyThemes.columnWidth + 1.0) : 0.0); + (isColumnMode ? (FluffyThemes.columnWidth + 1.0) : 0.0); // Pangea# return ScaffoldMessenger( child: Scaffold( @@ -56,16 +57,7 @@ class TwoColumnLayout extends StatelessWidget { left: columnWidth, child: ClipRRect(child: sideView), ), - SpaceNavigationColumn( - state: state, - showNavRail: showNavRail, - ), - // Container( - // clipBehavior: Clip.antiAlias, - // decoration: const BoxDecoration(), - // width: FluffyThemes.columnWidth + FluffyThemes.navRailWidth, - // child: mainView, - // ), + SpaceNavigationColumn(state: state, showNavRail: showNavRail), // Container(width: 1.0, color: theme.dividerColor), // Expanded(child: ClipRRect(child: sideView)), // Pangea# diff --git a/lib/widgets/local_notifications_extension.dart b/lib/widgets/local_notifications_extension.dart index ee9faf464..f18b5885c 100644 --- a/lib/widgets/local_notifications_extension.dart +++ b/lib/widgets/local_notifications_extension.dart @@ -35,11 +35,13 @@ extension LocalNotificationsExtension on MatrixState { } } - final title = - event.room.getLocalizedDisplayname(MatrixLocals(L10n.of(context))); + final title = event.room.getLocalizedDisplayname( + MatrixLocals(L10n.of(context)), + ); final body = await event.calcLocalizedBody( MatrixLocals(L10n.of(context)), - withSenderNamePrefix: !event.room.isDirectChat || + withSenderNamePrefix: + !event.room.isDirectChat || event.room.lastEvent?.senderId == client.userID, plaintextBody: true, hideReply: true, @@ -71,13 +73,13 @@ extension LocalNotificationsExtension on MatrixState { Logs().d('Unable to pre-download avatar for web notification', e, s); } - thumbnailUri = - await event.senderFromMemoryOrFallback.avatarUrl?.getThumbnailUri( - client, - width: size, - height: size, - method: thumbnailMethod, - ); + thumbnailUri = await event.senderFromMemoryOrFallback.avatarUrl + ?.getThumbnailUri( + client, + width: size, + height: size, + method: thumbnailMethod, + ); } // #Pangea @@ -141,8 +143,9 @@ extension LocalNotificationsExtension on MatrixState { hints: hints, ); notification.action.then((actionStr) { - var action = DesktopNotificationActions.values - .singleWhereOrNull((a) => a.name == actionStr); + var action = DesktopNotificationActions.values.singleWhereOrNull( + (a) => a.name == actionStr, + ); if (action == null && actionStr == "default") { action = DesktopNotificationActions.openChat; } @@ -191,15 +194,10 @@ extension LocalNotificationsExtension on MatrixState { notifPermissionNotifier.value = notifPermissionNotifier.value + 1; } catch (e, s) { final permission = await notificationsEnabled; - ErrorHandler.logError( - e: e, - s: s, - data: { - 'permission': permission, - }, - ); + ErrorHandler.logError(e: e, s: s, data: {'permission': permission}); } } + // Pangea# } diff --git a/lib/widgets/lock_screen.dart b/lib/widgets/lock_screen.dart index ab31e5edb..ea4bcf8c2 100644 --- a/lib/widgets/lock_screen.dart +++ b/lib/widgets/lock_screen.dart @@ -79,10 +79,7 @@ class _LockScreenState extends State { shrinkWrap: true, children: [ Center( - child: Image.asset( - 'assets/info-logo.png', - width: 256, - ), + child: Image.asset('assets/info-logo.png', width: 256), ), TextField( controller: _textEditingController, @@ -95,9 +92,7 @@ class _LockScreenState extends State { onChanged: tryUnlock, onSubmitted: tryUnlock, style: const TextStyle(fontSize: 40), - inputFormatters: [ - LengthLimitingTextInputFormatter(4), - ], + inputFormatters: [LengthLimitingTextInputFormatter(4)], decoration: InputDecoration( errorText: _errorText, hintText: '****', diff --git a/lib/widgets/log_view.dart b/lib/widgets/log_view.dart index 0779af6e6..402e64064 100644 --- a/lib/widgets/log_view.dart +++ b/lib/widgets/log_view.dart @@ -15,17 +15,14 @@ class LogViewerState extends State { double fontSize = 14; @override Widget build(BuildContext context) { - final outputEvents = Logs() - .outputEvents + final outputEvents = Logs().outputEvents .where((e) => e.level.index <= logLevel.index) .toList(); return Scaffold( backgroundColor: Colors.black, appBar: AppBar( title: Text(logLevel.toString()), - leading: BackButton( - onPressed: () => context.go('/'), - ), + leading: BackButton(onPressed: () => context.go('/')), actions: [ IconButton( icon: const Icon(Icons.zoom_in_outlined), @@ -55,9 +52,7 @@ class LogViewerState extends State { scrollDirection: Axis.horizontal, child: SelectableText( outputEvents[i].toDisplayString(), - style: TextStyle( - color: outputEvents[i].color, - ), + style: TextStyle(color: outputEvents[i].color), ), ), ), diff --git a/lib/widgets/matrix.dart b/lib/widgets/matrix.dart index 4fe1b17cf..6886fcbd5 100644 --- a/lib/widgets/matrix.dart +++ b/lib/widgets/matrix.dart @@ -90,15 +90,17 @@ class MatrixState extends State with WidgetsBindingObserver { Client get client { if (_activeClient < 0 || _activeClient >= widget.clients.length) { // #Pangea - currentBundle!.first!.homeserver = - Uri.parse("https://${AppConfig.defaultHomeserver}"); + currentBundle!.first!.homeserver = Uri.parse( + "https://${AppConfig.defaultHomeserver}", + ); // Pangea# return currentBundle!.first!; } // #Pangea - widget.clients[_activeClient].homeserver = - Uri.parse("https://${AppConfig.defaultHomeserver}"); + widget.clients[_activeClient].homeserver = Uri.parse( + "https://${AppConfig.defaultHomeserver}", + ); // Pangea# return widget.clients[_activeClient]; } @@ -157,10 +159,7 @@ class MatrixState extends State with WidgetsBindingObserver { } resBundles[bundle.name] ??= []; resBundles[bundle.name]!.add( - _AccountBundleWithClient( - client: widget.clients[i], - bundle: bundle, - ), + _AccountBundleWithClient(client: widget.clients[i], bundle: bundle), ); } } @@ -169,12 +168,13 @@ class MatrixState extends State with WidgetsBindingObserver { (a, b) => a.bundle!.priority == null ? 1 : b.bundle!.priority == null - ? -1 - : a.bundle!.priority!.compareTo(b.bundle!.priority!), + ? -1 + : a.bundle!.priority!.compareTo(b.bundle!.priority!), ); } - return resBundles - .map((k, v) => MapEntry(k, v.map((vv) => vv.client).toList())); + return resBundles.map( + (k, v) => MapEntry(k, v.map((vv) => vv.client).toList()), + ); } bool get hasComplexBundles => accountBundles.values.any((v) => v.length > 1); @@ -188,48 +188,49 @@ class MatrixState extends State with WidgetsBindingObserver { if (widget.clients.isNotEmpty && !client.isLogged()) { return client; } - final candidate = - _loginClientCandidate ??= await ClientManager.createClient( - '${AppSettings.applicationName.value}-${DateTime.now().millisecondsSinceEpoch}', - store, - ) - ..onLoginStateChanged - .stream + final candidate = _loginClientCandidate ??= + await ClientManager.createClient( + '${AppSettings.applicationName.value}-${DateTime.now().millisecondsSinceEpoch}', + store, + ) + ..onLoginStateChanged.stream .where((l) => l == LoginState.loggedIn) .first .then((_) async { - // #Pangea - MatrixState.pangeaController.handleLoginStateChange( - LoginState.loggedIn, - _loginClientCandidate!.userID, - context, - ); - // Pangea# - if (!widget.clients.contains(_loginClientCandidate)) { - widget.clients.add(_loginClientCandidate!); - } - ClientManager.addClientNameToStore( - _loginClientCandidate!.clientName, - store, - ); - _registerSubs(_loginClientCandidate!.clientName); - _loginClientCandidate = null; - // #Pangea - // FluffyChatApp.router.go('/backup'); - final isL2Set = await pangeaController.userController.isUserL2Set; - FluffyChatApp.router.go( - isL2Set ? '/rooms' : '/registration/create', - ); - // Pangea# - }); + // #Pangea + MatrixState.pangeaController.handleLoginStateChange( + LoginState.loggedIn, + _loginClientCandidate!.userID, + context, + ); + // Pangea# + if (!widget.clients.contains(_loginClientCandidate)) { + widget.clients.add(_loginClientCandidate!); + } + ClientManager.addClientNameToStore( + _loginClientCandidate!.clientName, + store, + ); + _registerSubs(_loginClientCandidate!.clientName); + _loginClientCandidate = null; + // #Pangea + // FluffyChatApp.router.go('/backup'); + final isL2Set = + await pangeaController.userController.isUserL2Set; + FluffyChatApp.router.go( + isL2Set ? '/rooms' : '/registration/create', + ); + // Pangea# + }); // #Pangea candidate.homeserver = Uri.parse("https://${AppConfig.defaultHomeserver}"); // This listener is not set for the new login client until the user is logged in, // but if the user tries to sign up without this listener set, the signup UIA request // will hang. So set the listener here. - onUiaRequest[candidate.clientName] ??= - candidate.onUiaRequest.stream.listen(uiaRequestHandler); + onUiaRequest[candidate.clientName] ??= candidate.onUiaRequest.stream.listen( + uiaRequestHandler, + ); // Pangea# if (widget.clients.isEmpty) widget.clients.add(candidate); return candidate; @@ -272,8 +273,9 @@ class MatrixState extends State with WidgetsBindingObserver { // Pangea# } - final linuxNotifications = - PlatformInfos.isLinux ? NotificationsClient() : null; + final linuxNotifications = PlatformInfos.isLinux + ? NotificationsClient() + : null; final Map linuxNotificationIds = {}; @override @@ -283,12 +285,8 @@ class MatrixState extends State with WidgetsBindingObserver { initMatrix(); // #Pangea Sentry.configureScope( - (scope) => scope.setUser( - SentryUser( - id: client.userID, - name: client.userID, - ), - ), + (scope) => + scope.setUser(SentryUser(id: client.userID, name: client.userID)), ); pangeaController = PangeaController(matrixState: this); WidgetsBinding.instance.addPostFrameCallback((_) { @@ -328,7 +326,7 @@ class MatrixState extends State with WidgetsBindingObserver { await showOkAlertDialog( context: FluffyChatApp.router.routerDelegate.navigatorKey.currentContext ?? - context, + context, title: L10n.of(context).screenSizeWarning, ); _lastShownPopupHeight = MediaQuery.heightOf(context); @@ -339,11 +337,11 @@ class MatrixState extends State with WidgetsBindingObserver { Future _setLanguageListener() async { await pangeaController.userController.initialize(); _languageListener?.cancel(); - _languageListener = - pangeaController.userController.languageStream.stream.listen((update) { - _setAppLanguage(); - analyticsDataService.updateService.onUpdateLanguages(update); - }); + _languageListener = pangeaController.userController.languageStream.stream + .listen((update) { + _setAppLanguage(); + analyticsDataService.updateService.onUpdateLanguages(update); + }); } void _setAppLanguage() { @@ -353,11 +351,7 @@ class MatrixState extends State with WidgetsBindingObserver { ); } catch (e, s) { Logs().e('Error setting app language', e); - ErrorHandler.logError( - e: e, - s: s, - data: {}, - ); + ErrorHandler.logError(e: e, s: s, data: {}); } } // Pangea# @@ -370,8 +364,9 @@ class MatrixState extends State with WidgetsBindingObserver { ); return; } - onRoomKeyRequestSub[name] ??= - c.onRoomKeyRequest.stream.listen((RoomKeyRequest request) async { + onRoomKeyRequestSub[name] ??= c.onRoomKeyRequest.stream.listen(( + RoomKeyRequest request, + ) async { if (widget.clients.any( ((cl) => cl.userID == request.requestingDevice.userId && @@ -385,24 +380,27 @@ class MatrixState extends State with WidgetsBindingObserver { }); onKeyVerificationRequestSub[name] ??= c.onKeyVerificationRequest.stream .listen((KeyVerification request) async { - var hidPopup = false; - request.onUpdate = () { - if (!hidPopup && - {KeyVerificationState.done, KeyVerificationState.error} - .contains(request.state)) { - FluffyChatApp.router.pop('dialog'); - } - hidPopup = true; - }; - request.onUpdate = null; - hidPopup = true; - await KeyVerificationDialog(request: request).show( - FluffyChatApp.router.routerDelegate.navigatorKey.currentContext ?? - context, - ); - }); - onLoginStateChanged[name] ??= - c.onLoginStateChanged.stream.listen((state) async { + var hidPopup = false; + request.onUpdate = () { + if (!hidPopup && + { + KeyVerificationState.done, + KeyVerificationState.error, + }.contains(request.state)) { + FluffyChatApp.router.pop('dialog'); + } + hidPopup = true; + }; + request.onUpdate = null; + hidPopup = true; + await KeyVerificationDialog(request: request).show( + FluffyChatApp.router.routerDelegate.navigatorKey.currentContext ?? + context, + ); + }); + onLoginStateChanged[name] ??= c.onLoginStateChanged.stream.listen(( + state, + ) async { // #Pangea MatrixState.pangeaController.handleLoginStateChange( state, @@ -424,9 +422,7 @@ class MatrixState extends State with WidgetsBindingObserver { FluffyChatApp.router.routerDelegate.navigatorKey.currentContext ?? context, ).showSnackBar( - SnackBar( - content: Text(L10n.of(context).oneClientLoggedOut), - ), + SnackBar(content: Text(L10n.of(context).oneClientLoggedOut)), ); if (state != LoginState.loggedIn) { @@ -434,16 +430,15 @@ class MatrixState extends State with WidgetsBindingObserver { } } else { // #Pangea + // FluffyChatApp.router.go( + // state == LoginState.loggedIn ? '/backup' : '/home', + // ); if (state == LoginState.loggedIn) { final isL2Set = await pangeaController.userController.isUserL2Set; - FluffyChatApp.router.go( - isL2Set ? '/rooms' : '/registration/create', - ); + FluffyChatApp.router.go(isL2Set ? '/rooms' : '/registration/create'); } else { FluffyChatApp.router.go('/home'); } - // FluffyChatApp.router - // .go(state == LoginState.loggedIn ? '/backup' : '/home'); // Pangea# } }); @@ -451,8 +446,9 @@ class MatrixState extends State with WidgetsBindingObserver { if (PlatformInfos.isWeb || PlatformInfos.isLinux) { c.onSync.stream.first.then((s) { html.Notification.requestPermission(); - onNotification[name] ??= - c.onNotification.stream.listen(showLocalNotification); + onNotification[name] ??= c.onNotification.stream.listen( + showLocalNotification, + ); }); } // #Pangea @@ -492,13 +488,18 @@ class MatrixState extends State with WidgetsBindingObserver { this, onFcmError: (errorMsg, {Uri? link}) async { final result = await showOkCancelAlertDialog( - context: FluffyChatApp - .router.routerDelegate.navigatorKey.currentContext ?? + context: + FluffyChatApp + .router + .routerDelegate + .navigatorKey + .currentContext ?? context, title: L10n.of(context).pushNotificationsNotAvailable, message: errorMsg, - okLabel: - link == null ? L10n.of(context).ok : L10n.of(context).learnMore, + okLabel: link == null + ? L10n.of(context).ok + : L10n.of(context).learnMore, cancelLabel: L10n.of(context).doNotShowAgain, ); if (result == OkCancelResult.ok && link != null) { @@ -527,11 +528,13 @@ class MatrixState extends State with WidgetsBindingObserver { @override void didChangeAppLifecycleState(AppLifecycleState state) { - final foreground = state != AppLifecycleState.inactive && + final foreground = + state != AppLifecycleState.inactive && state != AppLifecycleState.paused; for (final client in widget.clients) { - client.syncPresence = - state == AppLifecycleState.resumed ? null : PresenceType.unavailable; + client.syncPresence = state == AppLifecycleState.resumed + ? null + : PresenceType.unavailable; if (PlatformInfos.isMobile) { client.backgroundSync = foreground; client.requestHistoryOnLimitedTimeline = !foreground; @@ -564,10 +567,7 @@ class MatrixState extends State with WidgetsBindingObserver { @override Widget build(BuildContext context) { - return Provider( - create: (_) => this, - child: widget.child, - ); + return Provider(create: (_) => this, child: widget.child); } Future dehydrateAction(BuildContext context) async { @@ -587,9 +587,7 @@ class MatrixState extends State with WidgetsBindingObserver { final export = result.result; if (export == null) return; - final exportBytes = Uint8List.fromList( - const Utf8Codec().encode(export), - ); + final exportBytes = Uint8List.fromList(const Utf8Codec().encode(export)); final exportFileName = 'fluffychat-export-${DateFormat(DateFormat.YEAR_MONTH_DAY).format(DateTime.now())}.fluffybackup'; @@ -602,13 +600,15 @@ class MatrixState extends State with WidgetsBindingObserver { Future _processIncomingUris(Uri? uri) async { if (uri == null || uri.fragment.isEmpty) return; - final path = - uri.fragment.startsWith('/') ? uri.fragment : '/${uri.fragment}'; + final path = uri.fragment.startsWith('/') + ? uri.fragment + : '/${uri.fragment}'; WidgetsBinding.instance.addPostFrameCallback((_) { FluffyChatApp.router.go(path); }); } + // Pangea# } diff --git a/lib/widgets/member_actions_popup_menu_button.dart b/lib/widgets/member_actions_popup_menu_button.dart index 75376e351..0a30f6371 100644 --- a/lib/widgets/member_actions_popup_menu_button.dart +++ b/lib/widgets/member_actions_popup_menu_button.dart @@ -31,9 +31,9 @@ void showMemberActionsPopupMenu({ // #Pangea // final overlay = Overlay.of(context).context.findRenderObject() as RenderBox; - final overlay = Overlay.of(context, rootOverlay: true) - .context - .findRenderObject() as RenderBox; + final overlay = + Overlay.of(context, rootOverlay: true).context.findRenderObject() + as RenderBox; // Pangea# final button = context.findRenderObject() as RenderBox; @@ -69,8 +69,8 @@ void showMemberActionsPopupMenu({ presenceBackgroundColor: theme.colorScheme.surfaceContainer, ), Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: .min, + crossAxisAlignment: .start, children: [ ConstrainedBox( constraints: const BoxConstraints(maxWidth: 128), @@ -97,9 +97,7 @@ void showMemberActionsPopupMenu({ padding: const EdgeInsets.all(4.0), child: Row( mainAxisAlignment: MainAxisAlignment.center, - children: [ - LevelDisplayName(userId: user.id), - ], + children: [LevelDisplayName(userId: user.id)], ), ), // Pangea# @@ -111,10 +109,7 @@ void showMemberActionsPopupMenu({ if (user.id == BotName.byEnvironment && room != null && room.isRoomAdmin) PopupMenuItem( enabled: false, - padding: const EdgeInsets.only( - left: 12.0, - right: 12.0, - ), + padding: const EdgeInsets.only(left: 12.0, right: 12.0), child: BotChatSettingsDialog(room: room), ), const PopupMenuDivider(), @@ -165,16 +160,16 @@ void showMemberActionsPopupMenu({ const Icon(Icons.admin_panel_settings_outlined), const SizedBox(width: 18), Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: .min, + crossAxisAlignment: .start, children: [ Text(L10n.of(context).chatPermissions), Text( user.powerLevel < 50 ? L10n.of(context).userLevel(user.powerLevel) : user.powerLevel < 100 - ? L10n.of(context).moderatorLevel(user.powerLevel) - : L10n.of(context).adminLevel(user.powerLevel), + ? L10n.of(context).moderatorLevel(user.powerLevel) + : L10n.of(context).adminLevel(user.powerLevel), style: const TextStyle(fontSize: 10), ), ], @@ -291,7 +286,8 @@ void showMemberActionsPopupMenu({ cancelLabel: L10n.of(context).no, // #Pangea // message: L10n.of(context).kickUserDescription, - message: user.id == BotName.byEnvironment && + message: + user.id == BotName.byEnvironment && !user.room.isSpace && !user.room.isDirectChat ? L10n.of(context).kickBotWarning @@ -333,10 +329,7 @@ void showMemberActionsPopupMenu({ // final result = await showFutureLoadingDialog( // context: context, - // future: () => user.room.client.reportUser( - // user.id, - // reason, - // ), + // future: () => user.room.client.reportUser(user.id, reason), // ); // if (result.error != null) return; // ScaffoldMessenger.of(context).showSnackBar( @@ -347,10 +340,8 @@ void showMemberActionsPopupMenu({ final router = GoRouter.of(context); final roomIdResult = await showFutureLoadingDialog( context: context, - future: () => user.room.client.startDirectChat( - user.id, - enableEncryption: false, - ), + future: () => + user.room.client.startDirectChat(user.id, enableEncryption: false), ); final roomId = roomIdResult.result; if (roomId == null) return; diff --git a/lib/widgets/mxc_image.dart b/lib/widgets/mxc_image.dart index f2d7ae76a..b8a7cbc70 100644 --- a/lib/widgets/mxc_image.dart +++ b/lib/widgets/mxc_image.dart @@ -200,11 +200,8 @@ class _MxcImageState extends State { // #Pangea // : placeholder(context), : _error != null - ? SizedBox( - width: widget.width, - height: widget.height, - ) - : placeholder(context), + ? SizedBox(width: widget.width, height: widget.height) + : placeholder(context), // Pangea# ); } diff --git a/lib/widgets/navigation_rail.dart b/lib/widgets/navigation_rail.dart index fc2ee8381..4b891123b 100644 --- a/lib/widgets/navigation_rail.dart +++ b/lib/widgets/navigation_rail.dart @@ -47,12 +47,9 @@ class SpacesNavigationRail extends StatelessWidget { @override Widget build(BuildContext context) { final client = Matrix.of(context).client; - final isSettings = GoRouter.of(context) - .routeInformationProvider - .value - .uri - .path - .startsWith('/rooms/settings'); + final isSettings = GoRouter.of( + context, + ).routeInformationProvider.value.uri.path.startsWith('/rooms/settings'); // #Pangea final isAnalytics = path?.contains('analytics') ?? false; final isCourse = path?.contains('course') ?? false; @@ -66,15 +63,14 @@ class SpacesNavigationRail extends StatelessWidget { child: SafeArea( child: StreamBuilder( // Pangea# - key: ValueKey( - client.userID.toString(), - ), + key: ValueKey(client.userID.toString()), stream: client.onSync.stream .where((s) => s.hasRoomUpdate) .rateLimit(const Duration(seconds: 1)), builder: (context, _) { - final allSpaces = - client.rooms.where((room) => room.isSpace).toList(); + final allSpaces = client.rooms + .where((room) => room.isSpace) + .toList(); // #Pangea // return SizedBox( @@ -131,9 +127,11 @@ class SpacesNavigationRail extends StatelessWidget { borderRadius: BorderRadius.circular(99), child: Avatar( mxContent: snapshot.data?.avatarUrl, - name: snapshot.data?.displayName ?? + name: + snapshot.data?.displayName ?? client.userID!.localpart, - size: width - + size: + width - (isColumnMode ? 32.0 : 24.0), ), ), @@ -153,7 +151,8 @@ class SpacesNavigationRail extends StatelessWidget { return NaviRailItem( // #Pangea // isSelected: activeSpaceId == null && !isSettings, - isSelected: activeSpaceId == null && + isSelected: + activeSpaceId == null && !isSettings && !isAnalytics && !isCourse, @@ -205,12 +204,12 @@ class SpacesNavigationRail extends StatelessWidget { width: width - (isColumnMode ? 32.0 : 24.0), height: width - (isColumnMode ? 32.0 : 24.0), color: isCourse - ? Theme.of(context) - .colorScheme - .primaryContainer - : Theme.of(context) - .colorScheme - .surfaceContainerHigh, + ? Theme.of( + context, + ).colorScheme.primaryContainer + : Theme.of( + context, + ).colorScheme.surfaceContainerHigh, child: const Icon(Icons.add), ), ), @@ -220,12 +219,13 @@ class SpacesNavigationRail extends StatelessWidget { ); } final space = allSpaces[i]; - final displayname = - allSpaces[i].getLocalizedDisplayname( - MatrixLocals(L10n.of(context)), - ); - final spaceChildrenIds = - space.spaceChildren.map((c) => c.roomId).toSet(); + final displayname = allSpaces[i] + .getLocalizedDisplayname( + MatrixLocals(L10n.of(context)), + ); + final spaceChildrenIds = space.spaceChildren + .map((c) => c.roomId) + .toSet(); return NaviRailItem( toolTip: displayname, isSelected: activeSpaceId == space.id, @@ -237,10 +237,7 @@ class SpacesNavigationRail extends StatelessWidget { collapse(); final room = client.getRoomById(allSpaces[i].id); if (room != null) { - chatListHandleSpaceTap( - context, - room, - ); + chatListHandleSpaceTap(context, room); } else { context.go( "/rooms/spaces/${allSpaces[i].id}/details", @@ -276,10 +273,7 @@ class SpacesNavigationRail extends StatelessWidget { color: Theme.of(context).colorScheme.onPrimary, size: 16, ), - position: b.BadgePosition.topEnd( - top: -5, - end: -7, - ), + position: b.BadgePosition.topEnd(top: -5, end: -7), child: ClipPath( clipper: MapClipper(), child: Avatar( diff --git a/lib/widgets/permission_slider_dialog.dart b/lib/widgets/permission_slider_dialog.dart index e7e33b56f..0fdc1432e 100644 --- a/lib/widgets/permission_slider_dialog.dart +++ b/lib/widgets/permission_slider_dialog.dart @@ -18,8 +18,8 @@ Future showPermissionChooser( content: ConstrainedBox( constraints: const BoxConstraints(maxWidth: 256, maxHeight: 256), child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisSize: .min, + crossAxisAlignment: .stretch, spacing: 12.0, children: [ Text(L10n.of(context).setPermissionsLevelDescription), diff --git a/lib/widgets/profile_bottom_sheet.dart b/lib/widgets/profile_bottom_sheet.dart index 40afa25ba..440e8d870 100644 --- a/lib/widgets/profile_bottom_sheet.dart +++ b/lib/widgets/profile_bottom_sheet.dart @@ -65,10 +65,7 @@ class ProfileBottomSheet extends StatelessWidget { profile?.displayName ?? userId.localpart ?? userId, style: const TextStyle(fontSize: 18), ), - Text( - userId, - style: const TextStyle(fontSize: 12), - ), + Text(userId, style: const TextStyle(fontSize: 12)), ], ), // Pangea# diff --git a/lib/widgets/qr_code_viewer.dart b/lib/widgets/qr_code_viewer.dart index 374cfc212..eb1cc378d 100644 --- a/lib/widgets/qr_code_viewer.dart +++ b/lib/widgets/qr_code_viewer.dart @@ -14,10 +14,7 @@ import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_file_extension.dar import 'package:fluffychat/widgets/future_loading_dialog.dart'; import '../config/themes.dart'; -Future showQrCodeViewer( - BuildContext context, - String content, -) => +Future showQrCodeViewer(BuildContext context, String content) => showDialog( context: context, builder: (context) => QrCodeViewer(content: content), @@ -36,11 +33,7 @@ class QrCodeViewer extends StatelessWidget { // final inviteLink = 'https://matrix.to/#/$content'; final inviteLink = '${Environment.frontendURL}/#/rooms/$content'; // Pangea# - final image = QRImage( - inviteLink, - size: 256, - radius: 1, - ).generate(); + final image = QRImage(inviteLink, size: 256, radius: 1).generate(); return compute(encodePng, image); }, ); @@ -80,10 +73,7 @@ class QrCodeViewer extends StatelessWidget { backgroundColor: Colors.black.withAlpha(128), ), icon: Icon(Icons.adaptive.share_outlined), - onPressed: () => FluffyShare.share( - inviteLink, - context, - ), + onPressed: () => FluffyShare.share(inviteLink, context), color: Colors.white, tooltip: L10n.of(context).share, ), @@ -109,11 +99,12 @@ class QrCodeViewer extends StatelessWidget { borderRadius: BorderRadius.circular(AppConfig.borderRadius), ), child: Column( - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ ConstrainedBox( - constraints: - const BoxConstraints(maxWidth: FluffyThemes.columnWidth), + constraints: const BoxConstraints( + maxWidth: FluffyThemes.columnWidth, + ), child: PrettyQrView.data( data: inviteLink, decoration: PrettyQrDecoration( diff --git a/lib/widgets/share_scaffold_dialog.dart b/lib/widgets/share_scaffold_dialog.dart index 070d30def..dab24a933 100644 --- a/lib/widgets/share_scaffold_dialog.dart +++ b/lib/widgets/share_scaffold_dialog.dart @@ -65,9 +65,7 @@ class _ShareScaffoldDialogState extends State { @override Widget build(BuildContext context) { final theme = Theme.of(context); - final rooms = Matrix.of(context) - .client - .rooms + final rooms = Matrix.of(context).client.rooms .where( (room) => room.canSendDefaultMessages && @@ -142,8 +140,9 @@ class _ShareScaffoldDialogState extends State { ), controlAffinity: ListTileControlAffinity.trailing, shape: RoundedRectangleBorder( - borderRadius: - BorderRadius.circular(AppConfig.borderRadius), + borderRadius: BorderRadius.circular( + AppConfig.borderRadius, + ), ), secondary: Avatar( mxContent: room.avatar, diff --git a/lib/widgets/theme_builder.dart b/lib/widgets/theme_builder.dart index b526aadfd..669c88913 100644 --- a/lib/widgets/theme_builder.dart +++ b/lib/widgets/theme_builder.dart @@ -12,7 +12,8 @@ class ThemeBuilder extends StatefulWidget { BuildContext context, ThemeMode themeMode, Color? primaryColor, - ) builder; + ) + builder; final String themeModeSettingsKey; final String primaryColorSettingsKey; @@ -38,28 +39,26 @@ class ThemeController extends State { Color? get primaryColor => _primaryColor; static ThemeController of(BuildContext context) => - Provider.of( - context, - listen: false, - ); + Provider.of(context, listen: false); void _loadData(dynamic _) async { - final preferences = - _sharedPreferences ??= await SharedPreferences.getInstance(); + final preferences = _sharedPreferences ??= + await SharedPreferences.getInstance(); final rawThemeMode = preferences.getString(widget.themeModeSettingsKey); final rawColor = preferences.getInt(widget.primaryColorSettingsKey); setState(() { - _themeMode = ThemeMode.values - .singleWhereOrNull((value) => value.name == rawThemeMode); + _themeMode = ThemeMode.values.singleWhereOrNull( + (value) => value.name == rawThemeMode, + ); _primaryColor = rawColor == null ? null : Color(rawColor); }); } Future setThemeMode(ThemeMode newThemeMode) async { - final preferences = - _sharedPreferences ??= await SharedPreferences.getInstance(); + final preferences = _sharedPreferences ??= + await SharedPreferences.getInstance(); await preferences.setString(widget.themeModeSettingsKey, newThemeMode.name); setState(() { _themeMode = newThemeMode; @@ -67,8 +66,8 @@ class ThemeController extends State { } Future setPrimaryColor(Color? newPrimaryColor) async { - final preferences = - _sharedPreferences ??= await SharedPreferences.getInstance(); + final preferences = _sharedPreferences ??= + await SharedPreferences.getInstance(); if (newPrimaryColor == null) { await preferences.remove(widget.primaryColorSettingsKey); } else { @@ -93,11 +92,8 @@ class ThemeController extends State { return Provider( create: (_) => this, child: DynamicColorBuilder( - builder: (light, _) => widget.builder( - context, - themeMode, - primaryColor ?? light?.primary, - ), + builder: (light, _) => + widget.builder(context, themeMode, primaryColor ?? light?.primary), ), ); } diff --git a/lib/widgets/unread_rooms_badge.dart b/lib/widgets/unread_rooms_badge.dart index 4e93e1acc..746933171 100644 --- a/lib/widgets/unread_rooms_badge.dart +++ b/lib/widgets/unread_rooms_badge.dart @@ -23,10 +23,9 @@ class UnreadRoomsBadge extends StatelessWidget { Widget build(BuildContext context) { final theme = Theme.of(context); - final unreadCount = Matrix.of(context) - .client - .rooms - // #Pangea + // #Pangea + // final unreadCount = Matrix.of(context).client.rooms + final unreadCount = Matrix.of(context).client.rooms .where((r) => !r.isHiddenRoom && !r.isSpace) // Pangea# .where(filter) @@ -39,18 +38,12 @@ class UnreadRoomsBadge extends StatelessWidget { // Pangea# badgeColor: theme.colorScheme.primary, elevation: 4, - borderSide: BorderSide( - color: theme.colorScheme.surface, - width: 2, - ), + borderSide: BorderSide(color: theme.colorScheme.surface, width: 2), ), // #Pangea // badgeContent: Text( // unreadCount.toString(), - // style: TextStyle( - // color: theme.colorScheme.onPrimary, - // fontSize: 12, - // ), + // style: TextStyle(color: theme.colorScheme.onPrimary, fontSize: 12), // ), badgeContent: SizedBox( width: 15, @@ -61,10 +54,7 @@ class UnreadRoomsBadge extends StatelessWidget { unreadCount < 100 ? unreadCount.toString() : L10n.of(context).unreadPlus, - style: TextStyle( - color: theme.colorScheme.onPrimary, - fontSize: 12, - ), + style: TextStyle(color: theme.colorScheme.onPrimary, fontSize: 12), ), ), ), diff --git a/pubspec.lock b/pubspec.lock index 9df46cf1d..3b66d1ed9 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -2843,5 +2843,5 @@ packages: source: hosted version: "3.1.3" sdks: - dart: ">=3.9.0 <4.0.0" + dart: ">=3.10.0 <4.0.0" flutter: ">=3.35.0" diff --git a/pubspec.yaml b/pubspec.yaml index 3ab765b8f..287f09756 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -9,7 +9,7 @@ publish_to: none version: 4.1.16+6 environment: - sdk: ">=3.0.0 <4.0.0" + sdk: ">=3.10.0 <4.0.0" dependencies: animations: ^2.1.1 diff --git a/test/command_hint_test.dart b/test/command_hint_test.dart index 68812be5f..84f558635 100644 --- a/test/command_hint_test.dart +++ b/test/command_hint_test.dart @@ -8,8 +8,7 @@ import 'utils/test_client.dart'; void main() async { test('Check for missing /command hints', () async { final translated = - jsonDecode(File('lib/l10n/intl_en.arb').readAsStringSync()) - .keys + jsonDecode(File('lib/l10n/intl_en.arb').readAsStringSync()).keys .where((String k) => k.startsWith('commandHint_')) .map((k) => k.replaceFirst('commandHint_', '')); final commands = (await prepareTestClient()).commands.keys; diff --git a/test/pangea/choreo_record_test.dart b/test/pangea/choreo_record_test.dart index cd8ee065e..4c6c215f9 100644 --- a/test/pangea/choreo_record_test.dart +++ b/test/pangea/choreo_record_test.dart @@ -14,9 +14,7 @@ void main() async { editedText: editedText, ); - assert( - edits.offset == 1 && edits.length == 3 && edits.insert == "erri", - ); + assert(edits.offset == 1 && edits.length == 3 && edits.insert == "erri"); }); test("Test that data saved via ChoreoEdit can be accurately retrieved", () { @@ -30,9 +28,7 @@ void main() async { final String retrieved = edits.editedText(originalText); - assert( - retrieved == editedText, - ); + assert(retrieved == editedText); }); test("Test that addRecord and lastText work correctly", () { diff --git a/test/pangea/text_normalization_test.dart b/test/pangea/text_normalization_test.dart index b8aef771a..1eac52ac8 100644 --- a/test/pangea/text_normalization_test.dart +++ b/test/pangea/text_normalization_test.dart @@ -339,8 +339,10 @@ void main() { final expected = testCase['expected']!; test('Test ${i + 1}: "$input" should normalize to "$expected"', () { - final actual = - normalizeString(input, 'en'); // Default to English for tests + final actual = normalizeString( + input, + 'en', + ); // Default to English for tests expect( actual, equals(expected),