diff --git a/lib/config/app_config.dart b/lib/config/app_config.dart index 28441da6..dc8df452 100644 --- a/lib/config/app_config.dart +++ b/lib/config/app_config.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'dart:ui'; import 'package:matrix/matrix.dart'; diff --git a/lib/config/app_emojis.dart b/lib/config/app_emojis.dart index 18323af5..3c38e2fa 100644 --- a/lib/config/app_emojis.dart +++ b/lib/config/app_emojis.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - abstract class AppEmojis { static const List emojis = [ '👍', diff --git a/lib/config/routes.dart b/lib/config/routes.dart index b6a456f2..279df9f1 100644 --- a/lib/config/routes.dart +++ b/lib/config/routes.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'package:flutter/material.dart'; import 'package:vrouter/vrouter.dart'; diff --git a/lib/config/setting_keys.dart b/lib/config/setting_keys.dart index 160f229d..e003ed8d 100644 --- a/lib/config/setting_keys.dart +++ b/lib/config/setting_keys.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - abstract class SettingKeys { static const String jitsiInstance = 'chat.fluffy.jitsi_instance'; static const String wallpaper = 'chat.fluffy.wallpaper'; diff --git a/lib/config/themes.dart b/lib/config/themes.dart index 5913bb0b..31e8e1cb 100644 --- a/lib/config/themes.dart +++ b/lib/config/themes.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; diff --git a/lib/main.dart b/lib/main.dart index 730dd2cd..e5456c2b 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,5 +1,3 @@ -// @dart=2.11 - import 'dart:async'; import 'package:flutter/foundation.dart'; @@ -67,14 +65,14 @@ void main() async { } class FluffyChatApp extends StatefulWidget { - final Widget testWidget; + final Widget? testWidget; final List clients; - final Map queryParameters; + final Map? queryParameters; const FluffyChatApp({ - Key key, + Key? key, this.testWidget, - @required this.clients, + required this.clients, this.queryParameters, }) : super(key: key); @@ -88,9 +86,9 @@ class FluffyChatApp extends StatefulWidget { } class _FluffyChatAppState extends State { - GlobalKey _router; - bool columnMode; - String _initialUrl; + GlobalKey? _router; + bool? columnMode; + String? _initialUrl; @override void initState() { @@ -133,15 +131,12 @@ class _FluffyChatAppState extends State { localizationsDelegates: L10n.localizationsDelegates, supportedLocales: L10n.supportedLocales, initialUrl: _initialUrl ?? '/', - locale: kIsWeb - ? Locale(html.window.navigator.language.split('-').first) - : null, routes: AppRoutes(columnMode ?? false).routes, builder: (context, child) { - LoadingDialog.defaultTitle = L10n.of(context).loadingPleaseWait; - LoadingDialog.defaultBackLabel = L10n.of(context).close; + LoadingDialog.defaultTitle = L10n.of(context)!.loadingPleaseWait; + LoadingDialog.defaultBackLabel = L10n.of(context)!.close; LoadingDialog.defaultOnError = - (e) => (e as Object).toLocalizedString(context); + (e) => (e as Object?)!.toLocalizedString(context); WidgetsBinding.instance?.addPostFrameCallback((_) { SystemChrome.setSystemUIOverlayStyle( SystemUiOverlayStyle( diff --git a/lib/pages/add_story/add_story.dart b/lib/pages/add_story/add_story.dart index 6a58c3de..037175af 100644 --- a/lib/pages/add_story/add_story.dart +++ b/lib/pages/add_story/add_story.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'dart:io'; import 'package:flutter/material.dart'; diff --git a/lib/pages/add_story/add_story_view.dart b/lib/pages/add_story/add_story_view.dart index bb2d7ba3..f6bad492 100644 --- a/lib/pages/add_story/add_story_view.dart +++ b/lib/pages/add_story/add_story_view.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; diff --git a/lib/pages/add_story/invite_story_page.dart b/lib/pages/add_story/invite_story_page.dart index 4327c0f4..76ad006b 100644 --- a/lib/pages/add_story/invite_story_page.dart +++ b/lib/pages/add_story/invite_story_page.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'package:flutter/material.dart'; import 'package:adaptive_dialog/adaptive_dialog.dart'; diff --git a/lib/pages/archive/archive.dart b/lib/pages/archive/archive.dart index 4df1f352..4872c294 100644 --- a/lib/pages/archive/archive.dart +++ b/lib/pages/archive/archive.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'package:flutter/material.dart'; import 'package:adaptive_dialog/adaptive_dialog.dart'; diff --git a/lib/pages/archive/archive_view.dart b/lib/pages/archive/archive_view.dart index d1c64e1a..ea429547 100644 --- a/lib/pages/archive/archive_view.dart +++ b/lib/pages/archive/archive_view.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; diff --git a/lib/pages/bootstrap/bootstrap_dialog.dart b/lib/pages/bootstrap/bootstrap_dialog.dart index 5dac5627..f974bb2c 100644 --- a/lib/pages/bootstrap/bootstrap_dialog.dart +++ b/lib/pages/bootstrap/bootstrap_dialog.dart @@ -18,12 +18,12 @@ class BootstrapDialog extends StatefulWidget { final bool wipe; final Client client; const BootstrapDialog({ - Key key, + Key? key, this.wipe = false, - @required this.client, + required this.client, }) : super(key: key); - Future show(BuildContext context) => PlatformInfos.isCupertinoStyle + Future show(BuildContext context) => PlatformInfos.isCupertinoStyle ? showCupertinoDialog( context: context, builder: (context) => this, @@ -45,18 +45,18 @@ class _BootstrapDialogState extends State { final TextEditingController _recoveryKeyTextEditingController = TextEditingController(); - Bootstrap bootstrap; + late Bootstrap bootstrap; - String _recoveryKeyInputError; + String? _recoveryKeyInputError; bool _recoveryKeyInputLoading = false; - String titleText; + String? titleText; bool _recoveryKeyStored = false; bool _recoveryKeyCopied = false; - bool _wipe; + bool? _wipe; @override void initState() { @@ -68,8 +68,8 @@ class _BootstrapDialogState extends State { _wipe = wipe; titleText = null; _recoveryKeyStored = false; - bootstrap = widget.client.encryption - .bootstrap(onUpdate: () => setState(() => null)); + bootstrap = + widget.client.encryption!.bootstrap(onUpdate: () => setState(() {})); } @override @@ -79,12 +79,12 @@ class _BootstrapDialogState extends State { Widget body = PlatformInfos.isCupertinoStyle ? const CupertinoActivityIndicator() : const LinearProgressIndicator(); - titleText = L10n.of(context).loadingPleaseWait; + titleText = L10n.of(context)!.loadingPleaseWait; if (bootstrap.newSsssKey?.recoveryKey != null && _recoveryKeyStored == false) { - final key = bootstrap.newSsssKey.recoveryKey; - titleText = L10n.of(context).securityKey; + final key = bootstrap.newSsssKey!.recoveryKey; + titleText = L10n.of(context)!.securityKey; return Scaffold( appBar: AppBar( centerTitle: true, @@ -92,7 +92,7 @@ class _BootstrapDialogState extends State { icon: const Icon(Icons.close), onPressed: Navigator.of(context).pop, ), - title: Text(L10n.of(context).securityKey), + title: Text(L10n.of(context)!.securityKey), ), body: Center( child: ConstrainedBox( @@ -102,7 +102,7 @@ class _BootstrapDialogState extends State { padding: const EdgeInsets.all(16.0), children: [ Text( - L10n.of(context).chatBackupDescription, + L10n.of(context)!.chatBackupDescription, textAlign: TextAlign.center, style: const TextStyle( fontSize: 16, @@ -119,9 +119,9 @@ class _BootstrapDialogState extends State { const SizedBox(height: 16), ElevatedButton.icon( icon: const Icon(Icons.save_alt_outlined), - label: Text(L10n.of(context).saveTheSecurityKeyNow), + label: Text(L10n.of(context)!.saveTheSecurityKeyNow), onPressed: () { - Share.share(key); + Share.share(key!); setState(() => _recoveryKeyCopied = true); }, ), @@ -132,7 +132,7 @@ class _BootstrapDialogState extends State { onPrimary: Theme.of(context).primaryColor, ), icon: const Icon(Icons.check_outlined), - label: Text(L10n.of(context).next), + label: Text(L10n.of(context)!.next), onPressed: _recoveryKeyCopied ? () => setState(() => _recoveryKeyStored = true) : null, @@ -147,27 +147,27 @@ class _BootstrapDialogState extends State { case BootstrapState.loading: break; case BootstrapState.askWipeSsss: - WidgetsBinding.instance.addPostFrameCallback( - (_) => bootstrap.wipeSsss(_wipe), + WidgetsBinding.instance!.addPostFrameCallback( + (_) => bootstrap.wipeSsss(_wipe!), ); break; case BootstrapState.askBadSsss: - WidgetsBinding.instance.addPostFrameCallback( + WidgetsBinding.instance!.addPostFrameCallback( (_) => bootstrap.ignoreBadSecrets(true), ); break; case BootstrapState.askUseExistingSsss: - WidgetsBinding.instance.addPostFrameCallback( - (_) => bootstrap.useExistingSsss(!_wipe), + WidgetsBinding.instance!.addPostFrameCallback( + (_) => bootstrap.useExistingSsss(!_wipe!), ); break; case BootstrapState.askUnlockSsss: - WidgetsBinding.instance.addPostFrameCallback( + WidgetsBinding.instance!.addPostFrameCallback( (_) => bootstrap.unlockedSsss(), ); break; case BootstrapState.askNewSsss: - WidgetsBinding.instance.addPostFrameCallback( + WidgetsBinding.instance!.addPostFrameCallback( (_) => bootstrap.newSsss(), ); break; @@ -180,7 +180,7 @@ class _BootstrapDialogState extends State { icon: const Icon(Icons.close), onPressed: Navigator.of(context).pop, ), - title: Text(L10n.of(context).pleaseEnterSecurityKey), + title: Text(L10n.of(context)!.pleaseEnterSecurityKey), ), body: Center( child: ConstrainedBox( @@ -190,7 +190,7 @@ class _BootstrapDialogState extends State { padding: const EdgeInsets.all(16.0), children: [ Text( - L10n.of(context).pleaseEnterSecurityKeyDescription, + L10n.of(context)!.pleaseEnterSecurityKeyDescription, textAlign: TextAlign.center, style: const TextStyle( fontSize: 16, @@ -209,7 +209,7 @@ class _BootstrapDialogState extends State { controller: _recoveryKeyTextEditingController, decoration: InputDecoration( hintText: 'Abc123 Def456', - labelText: L10n.of(context).securityKey, + labelText: L10n.of(context)!.securityKey, errorText: _recoveryKeyInputError, ), ), @@ -218,7 +218,7 @@ class _BootstrapDialogState extends State { icon: _recoveryKeyInputLoading ? const CircularProgressIndicator.adaptive() : const Icon(Icons.lock_open_outlined), - label: Text(L10n.of(context).unlockChatBackup), + label: Text(L10n.of(context)!.unlockChatBackup), onPressed: _recoveryKeyInputLoading ? null : () async { @@ -229,11 +229,12 @@ class _BootstrapDialogState extends State { try { final key = _recoveryKeyTextEditingController.text; - await bootstrap.newSsssKey.unlock( + await bootstrap.newSsssKey!.unlock( keyOrPassphrase: key, ); Logs().d('SSSS unlocked'); - await bootstrap.client.encryption.crossSigning + await bootstrap + .client.encryption!.crossSigning .selfSign( keyOrPassphrase: key, ); @@ -242,7 +243,7 @@ class _BootstrapDialogState extends State { } catch (e, s) { Logs().w('Unable to unlock SSSS', e, s); setState(() => _recoveryKeyInputError = - L10n.of(context).oopsSomethingWentWrong); + L10n.of(context)!.oopsSomethingWentWrong); } finally { setState( () => _recoveryKeyInputLoading = false); @@ -253,7 +254,7 @@ class _BootstrapDialogState extends State { const Expanded(child: Divider()), Padding( padding: const EdgeInsets.all(12.0), - child: Text(L10n.of(context).or), + child: Text(L10n.of(context)!.or), ), const Expanded(child: Divider()), ]), @@ -264,18 +265,18 @@ class _BootstrapDialogState extends State { onPrimary: Theme.of(context).primaryColor, ), icon: const Icon(Icons.cast_connected_outlined), - label: Text(L10n.of(context).transferFromAnotherDevice), + label: Text(L10n.of(context)!.transferFromAnotherDevice), onPressed: _recoveryKeyInputLoading ? null : () async { final req = await showFutureLoadingDialog( context: context, - future: () => widget - .client.userDeviceKeys[widget.client.userID] + future: () => widget.client + .userDeviceKeys[widget.client.userID!]! .startVerification(), ); if (req.error != null) return; - await KeyVerificationDialog(request: req.result) + await KeyVerificationDialog(request: req.result!) .show(context); Navigator.of(context, rootNavigator: false).pop(); }, @@ -287,7 +288,7 @@ class _BootstrapDialogState extends State { onPrimary: Colors.red, ), icon: const Icon(Icons.delete_outlined), - label: Text(L10n.of(context).securityKeyLost), + label: Text(L10n.of(context)!.securityKeyLost), onPressed: _recoveryKeyInputLoading ? null : () async { @@ -295,10 +296,10 @@ class _BootstrapDialogState extends State { await showOkCancelAlertDialog( useRootNavigator: false, context: context, - title: L10n.of(context).securityKeyLost, - message: L10n.of(context).wipeChatBackup, - okLabel: L10n.of(context).ok, - cancelLabel: L10n.of(context).cancel, + title: L10n.of(context)!.securityKeyLost, + message: L10n.of(context)!.wipeChatBackup, + okLabel: L10n.of(context)!.ok, + cancelLabel: L10n.of(context)!.cancel, isDestructiveAction: true, )) { setState(() => _createBootstrap(true)); @@ -311,12 +312,12 @@ class _BootstrapDialogState extends State { ), ); case BootstrapState.askWipeCrossSigning: - WidgetsBinding.instance.addPostFrameCallback( - (_) => bootstrap.wipeCrossSigning(_wipe), + WidgetsBinding.instance!.addPostFrameCallback( + (_) => bootstrap.wipeCrossSigning(_wipe!), ); break; case BootstrapState.askSetupCrossSigning: - WidgetsBinding.instance.addPostFrameCallback( + WidgetsBinding.instance!.addPostFrameCallback( (_) => bootstrap.askSetupCrossSigning( setupMasterKey: true, setupSelfSigningKey: true, @@ -325,36 +326,36 @@ class _BootstrapDialogState extends State { ); break; case BootstrapState.askWipeOnlineKeyBackup: - WidgetsBinding.instance.addPostFrameCallback( - (_) => bootstrap.wipeOnlineKeyBackup(_wipe), + WidgetsBinding.instance!.addPostFrameCallback( + (_) => bootstrap.wipeOnlineKeyBackup(_wipe!), ); break; case BootstrapState.askSetupOnlineKeyBackup: - WidgetsBinding.instance.addPostFrameCallback( + WidgetsBinding.instance!.addPostFrameCallback( (_) => bootstrap.askSetupOnlineKeyBackup(true), ); break; case BootstrapState.error: - titleText = L10n.of(context).oopsSomethingWentWrong; + titleText = L10n.of(context)!.oopsSomethingWentWrong; body = const Icon(Icons.error_outline, color: Colors.red, size: 40); buttons.add(AdaptiveFlatButton( - label: L10n.of(context).close, + label: L10n.of(context)!.close, onPressed: () => Navigator.of(context, rootNavigator: false).pop(false), )); break; case BootstrapState.done: - titleText = L10n.of(context).everythingReady; + titleText = L10n.of(context)!.everythingReady; body = Column( mainAxisSize: MainAxisSize.min, children: [ Image.asset('assets/backup.png', fit: BoxFit.contain), - Text(L10n.of(context).yourChatBackupHasBeenSetUp), + Text(L10n.of(context)!.yourChatBackupHasBeenSetUp), ], ); buttons.add(AdaptiveFlatButton( - label: L10n.of(context).close, + label: L10n.of(context)!.close, onPressed: () => Navigator.of(context, rootNavigator: false).pop(false), )); @@ -362,7 +363,7 @@ class _BootstrapDialogState extends State { } } - final title = Text(titleText); + final title = Text(titleText!); if (PlatformInfos.isCupertinoStyle) { return CupertinoAlertDialog( title: title, diff --git a/lib/pages/chat/chat.dart b/lib/pages/chat/chat.dart index 35180518..b76a4194 100644 --- a/lib/pages/chat/chat.dart +++ b/lib/pages/chat/chat.dart @@ -34,31 +34,31 @@ import 'send_location_dialog.dart'; import 'sticker_picker_dialog.dart'; class Chat extends StatefulWidget { - final Widget sideView; + final Widget? sideView; - const Chat({Key key, this.sideView}) : super(key: key); + const Chat({Key? key, this.sideView}) : super(key: key); @override ChatController createState() => ChatController(); } class ChatController extends State { - Room room; + Room? room; - Client sendingClient; + Client? sendingClient; - Timeline timeline; + Timeline? timeline; - MatrixState matrix; + MatrixState? matrix; - String get roomId => context.vRouter.pathParameters['roomid']; + String? get roomId => context.vRouter.pathParameters['roomid']; final AutoScrollController scrollController = AutoScrollController(); FocusNode inputFocus = FocusNode(); - Timer typingCoolDown; - Timer typingTimeout; + Timer? typingCoolDown; + Timer? typingTimeout; bool currentlyTyping = false; bool dragging = false; @@ -76,7 +76,7 @@ class ChatController extends State { bytes: bytes, name: xfile.name, ).detectFileType, - room: room, + room: room!, ), ); } @@ -96,13 +96,13 @@ class ChatController extends State { List selectedEvents = []; - List filteredEvents; + late List filteredEvents; final Set unfolded = {}; - Event replyEvent; + Event? replyEvent; - Event editEvent; + Event? editEvent; bool showScrollDownButton = false; @@ -115,8 +115,8 @@ class ChatController extends State { String pendingText = ''; bool get canLoadMore => - timeline.events.isEmpty || - timeline.events.last.type != EventTypes.RoomCreate; + timeline!.events.isEmpty || + timeline!.events.last.type != EventTypes.RoomCreate; bool showEmojiPicker = false; @@ -126,7 +126,7 @@ class ChatController extends State { final success = await showFutureLoadingDialog( context: context, - future: () => room.sendEvent({ + future: () => room!.sendEvent({ 'msgtype': Matrix.callNamespace, 'body': url, })); @@ -137,12 +137,12 @@ class ChatController extends State { void requestHistory() async { if (canLoadMore) { try { - await timeline.requestHistory(historyCount: _loadHistoryCount); + await timeline!.requestHistory(historyCount: _loadHistoryCount); } catch (err) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( - (err as Object).toLocalizedString(context), + (err).toLocalizedString(context), ), ), ); @@ -157,8 +157,8 @@ class ChatController extends State { } if (scrollController.position.pixels == scrollController.position.maxScrollExtent && - timeline.events.isNotEmpty && - timeline.events[timeline.events.length - 1].type != + timeline!.events.isNotEmpty && + timeline!.events[timeline!.events.length - 1].type != EventTypes.RoomCreate) { requestHistory(); } @@ -180,7 +180,7 @@ class ChatController extends State { if (!mounted) return; setState( () { - filteredEvents = timeline.getFilteredEvents(unfolded: unfolded); + filteredEvents = timeline!.getFilteredEvents(unfolded: unfolded); }, ); } @@ -192,22 +192,22 @@ class ChatController extends State { unfolded.add(filteredEvents[i].eventId); i++; } - filteredEvents = timeline.getFilteredEvents(unfolded: unfolded); + filteredEvents = timeline!.getFilteredEvents(unfolded: unfolded); }); } Future getTimeline() async { if (timeline == null) { - timeline = await room.getTimeline(onUpdate: updateView); - if (timeline.events.isNotEmpty) { + timeline = await room!.getTimeline(onUpdate: updateView); + if (timeline!.events.isNotEmpty) { // ignore: unawaited_futures - if (room.markedUnread) room.markUnread(false); + if (room!.markedUnread) room!.markUnread(false); } // when the scroll controller is attached we want to scroll to an event id, if specified // and update the scroll controller...which will trigger a request history, if the // "load more" button is visible on the screen - SchedulerBinding.instance.addPostFrameCallback((_) async { + SchedulerBinding.instance!.addPostFrameCallback((_) async { if (mounted) { final event = VRouter.of(context).queryParameters['event']; if (event != null) { @@ -217,16 +217,15 @@ class ChatController extends State { } }); } - filteredEvents = timeline.getFilteredEvents(unfolded: unfolded); - timeline.requestKeys(); - if (room.notificationCount != null && - room.notificationCount > 0 && + filteredEvents = timeline!.getFilteredEvents(unfolded: unfolded); + timeline!.requestKeys(); + if (room!.notificationCount > 0 && timeline != null && - timeline.events.isNotEmpty && + timeline!.events.isNotEmpty && Matrix.of(context).webHasFocus) { // ignore: unawaited_futures - timeline.setReadMarker(); - room.client.updateIosBadge(); + timeline!.setReadMarker(); + room!.client.updateIosBadge(); } return true; } @@ -240,13 +239,13 @@ class ChatController extends State { TextEditingController sendController = TextEditingController(); - void setSendingClient(Client c) { + void setSendingClient(Client? c) { // first cancle 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); + room!.setTyping(false); currentlyTyping = false; } // then set the new sending client @@ -263,22 +262,22 @@ class ChatController extends State { final commandMatch = RegExp(r'^\/(\w+)').firstMatch(sendController.text); if (commandMatch != null && - !room.client.commands.keys.contains(commandMatch[1].toLowerCase())) { - final l10n = L10n.of(context); + !room!.client.commands.keys.contains(commandMatch[1]!.toLowerCase())) { + final l10n = L10n.of(context)!; final dialogResult = await showOkCancelAlertDialog( context: context, useRootNavigator: false, title: l10n.commandInvalid, - message: l10n.commandMissing(commandMatch[0]), + message: l10n.commandMissing(commandMatch[0]!), okLabel: l10n.sendAsText, cancelLabel: l10n.cancel, ); - if (dialogResult == null || dialogResult == OkCancelResult.cancel) return; + if (dialogResult == OkCancelResult.cancel) return; parseCommands = false; } // ignore: unawaited_futures - room.sendTextEvent(sendController.text, + room!.sendTextEvent(sendController.text, inReplyTo: replyEvent, editEventId: editEvent?.eventId, parseCommands: parseCommands); @@ -298,16 +297,16 @@ class ChatController extends State { void sendFileAction() async { final result = await FilePickerCross.importFromStorage(type: FileTypeCross.any); - if (result == null) return; + if (result.fileName == null) return; await showDialog( context: context, useRootNavigator: false, builder: (c) => SendFileDialog( file: MatrixFile( bytes: result.toUint8List(), - name: result.fileName, + name: result.fileName!, ).detectFileType, - room: room, + room: room!, ), ); } @@ -315,16 +314,16 @@ class ChatController extends State { void sendImageAction() async { final result = await FilePickerCross.importFromStorage(type: FileTypeCross.image); - if (result == null) return; + if (result.fileName == null) return; await showDialog( context: context, useRootNavigator: false, builder: (c) => SendFileDialog( file: MatrixImageFile( bytes: result.toUint8List(), - name: result.fileName, + name: result.fileName!, ), - room: room, + room: room!, ), ); } @@ -343,7 +342,7 @@ class ChatController extends State { bytes: bytes, name: file.path, ), - room: room, + room: room!, ), ); } @@ -362,7 +361,7 @@ class ChatController extends State { bytes: bytes, name: file.path, ), - room: room, + room: room!, ), ); } @@ -371,7 +370,7 @@ class ChatController extends State { final sticker = await showModalBottomSheet( context: context, useRootNavigator: false, - builder: (c) => StickerPickerDialog(room: room), + builder: (c) => StickerPickerDialog(room: room!), ); if (sticker == null) return; final eventContent = { @@ -382,7 +381,7 @@ class ChatController extends State { // send the sticker await showFutureLoadingDialog( context: context, - future: () => room.sendEvent( + future: () => room!.sendEvent( eventContent, type: EventTypes.Sticker, ), @@ -405,7 +404,7 @@ class ChatController extends State { await showFutureLoadingDialog( context: context, future: () => - room.sendFileEvent(file, inReplyTo: replyEvent, extraContent: { + room!.sendFileEvent(file, inReplyTo: replyEvent, extraContent: { 'info': { ...file.info, 'duration': result.duration, @@ -426,7 +425,7 @@ class ChatController extends State { await showDialog( context: context, useRootNavigator: false, - builder: (c) => SendLocationDialog(room: room), + builder: (c) => SendLocationDialog(room: room!), ); } @@ -434,13 +433,13 @@ class ChatController extends State { var copyString = ''; if (selectedEvents.length == 1) { return selectedEvents.first - .getDisplayEvent(timeline) - .getLocalizedBody(MatrixLocals(L10n.of(context))); + .getDisplayEvent(timeline!) + .getLocalizedBody(MatrixLocals(L10n.of(context)!)); } for (final event in selectedEvents) { if (copyString.isNotEmpty) copyString += '\n\n'; - copyString += event.getDisplayEvent(timeline).getLocalizedBody( - MatrixLocals(L10n.of(context)), + copyString += event.getDisplayEvent(timeline!).getLocalizedBody( + MatrixLocals(L10n.of(context)!), withSenderNamePrefix: true); } return copyString; @@ -458,37 +457,37 @@ class ChatController extends State { final event = selectedEvents.single; final score = await showConfirmationDialog( context: context, - title: L10n.of(context).reportMessage, - message: L10n.of(context).howOffensiveIsThisContent, - cancelLabel: L10n.of(context).cancel, - okLabel: L10n.of(context).ok, + title: L10n.of(context)!.reportMessage, + message: L10n.of(context)!.howOffensiveIsThisContent, + cancelLabel: L10n.of(context)!.cancel, + okLabel: L10n.of(context)!.ok, actions: [ AlertDialogAction( key: -100, - label: L10n.of(context).extremeOffensive, + label: L10n.of(context)!.extremeOffensive, ), AlertDialogAction( key: -50, - label: L10n.of(context).offensive, + label: L10n.of(context)!.offensive, ), AlertDialogAction( key: 0, - label: L10n.of(context).inoffensive, + label: L10n.of(context)!.inoffensive, ), ]); if (score == null) return; final reason = await showTextInputDialog( useRootNavigator: false, context: context, - title: L10n.of(context).whyDoYouWantToReportThis, - okLabel: L10n.of(context).ok, - cancelLabel: L10n.of(context).cancel, - textFields: [DialogTextField(hintText: L10n.of(context).reason)]); + title: L10n.of(context)!.whyDoYouWantToReportThis, + okLabel: L10n.of(context)!.ok, + cancelLabel: L10n.of(context)!.cancel, + textFields: [DialogTextField(hintText: L10n.of(context)!.reason)]); if (reason == null || reason.single.isEmpty) return; final result = await showFutureLoadingDialog( context: context, future: () => Matrix.of(context).client.reportContent( - event.roomId, + event.roomId!, event.eventId, reason: reason.single, score: score, @@ -500,16 +499,16 @@ class ChatController extends State { selectedEvents.clear(); }); ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text(L10n.of(context).contentHasBeenReported))); + SnackBar(content: Text(L10n.of(context)!.contentHasBeenReported))); } void redactEventsAction() async { final confirmed = await showOkCancelAlertDialog( useRootNavigator: false, context: context, - title: L10n.of(context).messageWillBeRemovedWarning, - okLabel: L10n.of(context).remove, - cancelLabel: L10n.of(context).cancel, + title: L10n.of(context)!.messageWillBeRemovedWarning, + okLabel: L10n.of(context)!.remove, + cancelLabel: L10n.of(context)!.cancel, ) == OkCancelResult.ok; if (!confirmed) return; @@ -522,12 +521,12 @@ class ChatController extends State { await event.redactEvent(); } else { final client = currentRoomBundle.firstWhere( - (cl) => selectedEvents.first.senderId == cl.userID, + (cl) => selectedEvents.first.senderId == cl!.userID, orElse: () => null); if (client == null) { return; } - final room = client.getRoomById(roomId); + final room = client.getRoomById(roomId!)!; await Event.fromJson(event.toJson(), room).redactEvent(); } } else { @@ -541,17 +540,17 @@ class ChatController extends State { }); } - List get currentRoomBundle { - final clients = matrix.currentBundle; - clients.removeWhere((c) => c.getRoomById(roomId) == null); + List get currentRoomBundle { + final clients = matrix!.currentBundle!; + clients.removeWhere((c) => c!.getRoomById(roomId!) == null); return clients; } bool get canRedactSelectedEvents { - final clients = matrix.currentBundle; + final clients = matrix!.currentBundle; for (final event in selectedEvents) { if (event.canRedact == false && - !(clients.any((cl) => event.senderId == cl.userID))) return false; + !(clients!.any((cl) => event.senderId == cl!.userID))) return false; } return true; } @@ -561,7 +560,7 @@ class ChatController extends State { return false; } return currentRoomBundle - .any((cl) => selectedEvents.first.senderId == cl.userID); + .any((cl) => selectedEvents.first.senderId == cl!.userID); } void forwardEventsAction() async { @@ -583,7 +582,7 @@ class ChatController extends State { event.sendAgain(); } final allEditEvents = event - .aggregatedEvents(timeline, RelationshipTypes.edit) + .aggregatedEvents(timeline!, RelationshipTypes.edit) .where((e) => e.status.isError); for (final e in allEditEvents) { e.sendAgain(); @@ -591,7 +590,7 @@ class ChatController extends State { setState(() => selectedEvents.clear()); } - void replyAction({Event replyTo}) { + void replyAction({Event? replyTo}) { setState(() { replyEvent = replyTo ?? selectedEvents.first; selectedEvents.clear(); @@ -609,7 +608,7 @@ class ChatController extends State { future: () async { // okay, we first have to fetch if the event is in the room try { - final event = await timeline.getEventById(eventId); + final event = await timeline!.getEventById(eventId); if (event == null) { // event is null...meaning something is off return; @@ -628,7 +627,7 @@ class ChatController extends State { return; } try { - await timeline.requestHistory(historyCount: _loadHistoryCount); + await timeline!.requestHistory(historyCount: _loadHistoryCount); } catch (err) { if (err is TimeoutException) { // loading the history timed out...so let's do nothing @@ -662,7 +661,7 @@ class ChatController extends State { return sendEmojiAction(emoji.emoji); } - Iterable _allReactionEvents; + late Iterable _allReactionEvents; void cancelEmojiPicker() => setState(() => showEmojiPicker = false); @@ -671,13 +670,13 @@ class ChatController extends State { setState(() => showEmojiPicker = true); } - void sendEmojiAction(String emoji) async { + void sendEmojiAction(String? emoji) async { final events = List.from(selectedEvents); setState(() => selectedEvents.clear()); for (final event in events) { - await room.sendReaction( + await room!.sendReaction( event.eventId, - emoji, + emoji!, ); } } @@ -695,7 +694,7 @@ class ChatController extends State { void editSelectedEventAction() { final client = currentRoomBundle.firstWhere( - (cl) => selectedEvents.first.senderId == cl.userID, + (cl) => selectedEvents.first.senderId == cl!.userID, orElse: () => null); if (client == null) { return; @@ -704,9 +703,9 @@ class ChatController extends State { setState(() { pendingText = sendController.text; editEvent = selectedEvents.first; - inputText = sendController.text = editEvent - .getDisplayEvent(timeline) - .getLocalizedBody(MatrixLocals(L10n.of(context)), + inputText = sendController.text = editEvent! + .getDisplayEvent(timeline!) + .getLocalizedBody(MatrixLocals(L10n.of(context)!), withSenderNamePrefix: false, hideReply: true); selectedEvents.clear(); }); @@ -718,29 +717,29 @@ class ChatController extends State { await showOkCancelAlertDialog( useRootNavigator: false, context: context, - title: L10n.of(context).goToTheNewRoom, - message: room - .getState(EventTypes.RoomTombstone) + title: L10n.of(context)!.goToTheNewRoom, + message: room! + .getState(EventTypes.RoomTombstone)! .parsedTombstoneContent .body, - okLabel: L10n.of(context).ok, - cancelLabel: L10n.of(context).cancel, + okLabel: L10n.of(context)!.ok, + cancelLabel: L10n.of(context)!.cancel, )) { return; } final result = await showFutureLoadingDialog( context: context, - future: () => room.client.joinRoom(room - .getState(EventTypes.RoomTombstone) + future: () => room!.client.joinRoom(room! + .getState(EventTypes.RoomTombstone)! .parsedTombstoneContent .replacementRoom), ); await showFutureLoadingDialog( context: context, - future: room.leave, + future: room!.leave, ); if (result.error == null) { - VRouter.of(context).toSegments(['rooms', result.result]); + VRouter.of(context).toSegments(['rooms', result.result!]); } } @@ -761,12 +760,12 @@ class ChatController extends State { } } - int findChildIndexCallback(Key key, Map thisEventsKeyMap) { + int? findChildIndexCallback(Key key, Map thisEventsKeyMap) { // this method is called very often. As such, it has to be optimized for speed. if (key is! ValueKey) { return null; } - final eventId = (key as ValueKey).value; + final eventId = key.value; if (eventId is! String) { return null; } @@ -809,11 +808,11 @@ class ChatController extends State { } void onInputBarChanged(String text) { - if (text.endsWith(' ') && matrix.hasComplexBundles) { + if (text.endsWith(' ') && matrix!.hasComplexBundles) { final clients = currentRoomBundle; for (final client in clients) { - final prefix = client.sendPrefix; - if ((prefix?.isNotEmpty ?? false) && + final prefix = client!.sendPrefix; + if ((prefix.isNotEmpty) && text.toLowerCase() == '${prefix.toLowerCase()} ') { setSendingClient(client); setState(() { @@ -828,7 +827,7 @@ class ChatController extends State { typingCoolDown = Timer(const Duration(seconds: 2), () { typingCoolDown = null; currentlyTyping = false; - room.setTyping(false); + room!.setTyping(false); }); typingTimeout ??= Timer(const Duration(seconds: 30), () { typingTimeout = null; @@ -836,12 +835,13 @@ class ChatController extends State { }); if (!currentlyTyping) { currentlyTyping = true; - room.setTyping(true, timeout: const Duration(seconds: 30).inMilliseconds); + room! + .setTyping(true, timeout: const Duration(seconds: 30).inMilliseconds); } setState(() => inputText = text); } - void showEventInfo([Event event]) => + void showEventInfo([Event? event]) => (event ?? selectedEvents.single).showInfoDialog(context); void cancelReplyEventAction() => setState(() { diff --git a/lib/pages/chat/chat_app_bar_title.dart b/lib/pages/chat/chat_app_bar_title.dart index 7d3dcec5..cfc469d4 100644 --- a/lib/pages/chat/chat_app_bar_title.dart +++ b/lib/pages/chat/chat_app_bar_title.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; @@ -19,41 +17,42 @@ class ChatAppBarTitle extends StatelessWidget { @override Widget build(BuildContext context) { + final room = controller.room; + if (room == null) { + return Container(); + } if (controller.selectedEvents.isNotEmpty) { return Text(controller.selectedEvents.length.toString()); } - final directChatMatrixID = controller.room.directChatMatrixID; + final directChatMatrixID = room.directChatMatrixID; return ListTile( leading: Avatar( - mxContent: controller.room.avatar, - name: controller.room.displayname, + mxContent: room.avatar, + name: room.displayname, ), contentPadding: EdgeInsets.zero, onTap: directChatMatrixID != null ? () => showModalBottomSheet( context: context, builder: (c) => UserBottomSheet( - user: controller.room.getUserByMXIDSync(directChatMatrixID), + user: room.getUserByMXIDSync(directChatMatrixID), outerContext: context, onMention: () => controller.sendController.text += - '${controller.room.getUserByMXIDSync(directChatMatrixID).mention} ', + '${room.getUserByMXIDSync(directChatMatrixID).mention} ', ), ) - : () => VRouter.of(context) - .toSegments(['rooms', controller.room.id, 'details']), - title: Text( - controller.room - .getLocalizedDisplayname(MatrixLocals(L10n.of(context)!)), + : () => VRouter.of(context).toSegments(['rooms', room.id, 'details']), + title: Text(room.getLocalizedDisplayname(MatrixLocals(L10n.of(context)!)), maxLines: 1), subtitle: StreamBuilder( stream: Matrix.of(context) .client .onPresence .stream - .where((p) => p.senderId == controller.room.directChatMatrixID) + .where((p) => p.senderId == room.directChatMatrixID) .rateLimit(const Duration(seconds: 1)), builder: (context, snapshot) => Text( - controller.room.getLocalizedStatus(context), + room.getLocalizedStatus(context), maxLines: 1, //overflow: TextOverflow.ellipsis, ), diff --git a/lib/pages/chat/chat_emoji_picker.dart b/lib/pages/chat/chat_emoji_picker.dart index 5a777032..6d5ffd31 100644 --- a/lib/pages/chat/chat_emoji_picker.dart +++ b/lib/pages/chat/chat_emoji_picker.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'package:flutter/material.dart'; import 'package:emoji_picker_flutter/emoji_picker_flutter.dart'; diff --git a/lib/pages/chat/chat_input_row.dart b/lib/pages/chat/chat_input_row.dart index 62c751ef..2671e45b 100644 --- a/lib/pages/chat/chat_input_row.dart +++ b/lib/pages/chat/chat_input_row.dart @@ -13,7 +13,7 @@ import 'input_bar.dart'; class ChatInputRow extends StatelessWidget { final ChatController controller; - const ChatInputRow(this.controller, {Key key}) : super(key: key); + const ChatInputRow(this.controller, {Key? key}) : super(key: key); @override Widget build(BuildContext context) { @@ -30,14 +30,14 @@ class ChatInputRow extends StatelessWidget { child: Row( children: [ const Icon(Icons.keyboard_arrow_left_outlined), - Text(L10n.of(context).forward), + Text(L10n.of(context)!.forward), ], ), ), ), controller.selectedEvents.length == 1 ? controller.selectedEvents.first - .getDisplayEvent(controller.timeline) + .getDisplayEvent(controller.timeline!) .status .isSent ? SizedBox( @@ -46,7 +46,7 @@ class ChatInputRow extends StatelessWidget { onPressed: controller.replyAction, child: Row( children: [ - Text(L10n.of(context).reply), + Text(L10n.of(context)!.reply), const Icon(Icons.keyboard_arrow_right), ], ), @@ -58,7 +58,7 @@ class ChatInputRow extends StatelessWidget { onPressed: controller.sendAgainAction, child: Row( children: [ - Text(L10n.of(context).tryToSendAgain), + Text(L10n.of(context)!.tryToSendAgain), const SizedBox(width: 4), const Icon(Icons.send_outlined, size: 16), ], @@ -88,7 +88,7 @@ class ChatInputRow extends StatelessWidget { foregroundColor: Colors.white, child: Icon(Icons.video_call_outlined), ), - title: Text(L10n.of(context).videoCall), + title: Text(L10n.of(context)!.videoCall), contentPadding: const EdgeInsets.all(0), ), ), @@ -100,7 +100,7 @@ class ChatInputRow extends StatelessWidget { foregroundColor: Colors.white, child: Icon(Icons.attachment_outlined), ), - title: Text(L10n.of(context).sendFile), + title: Text(L10n.of(context)!.sendFile), contentPadding: const EdgeInsets.all(0), ), ), @@ -112,7 +112,7 @@ class ChatInputRow extends StatelessWidget { foregroundColor: Colors.white, child: Icon(Icons.image_outlined), ), - title: Text(L10n.of(context).sendImage), + title: Text(L10n.of(context)!.sendImage), contentPadding: const EdgeInsets.all(0), ), ), @@ -125,7 +125,7 @@ class ChatInputRow extends StatelessWidget { foregroundColor: Colors.white, child: Icon(Icons.camera_alt_outlined), ), - title: Text(L10n.of(context).openCamera), + title: Text(L10n.of(context)!.openCamera), contentPadding: const EdgeInsets.all(0), ), ), @@ -138,11 +138,11 @@ class ChatInputRow extends StatelessWidget { foregroundColor: Colors.white, child: Icon(Icons.videocam_outlined), ), - title: Text(L10n.of(context).openVideoCamera), + title: Text(L10n.of(context)!.openVideoCamera), contentPadding: const EdgeInsets.all(0), ), ), - if (controller.room + if (controller.room! .getImagePacks(ImagePackUsage.sticker) .isNotEmpty) PopupMenuItem( @@ -153,7 +153,7 @@ class ChatInputRow extends StatelessWidget { foregroundColor: Colors.white, child: Icon(Icons.emoji_emotions_outlined), ), - title: Text(L10n.of(context).sendSticker), + title: Text(L10n.of(context)!.sendSticker), contentPadding: const EdgeInsets.all(0), ), ), @@ -166,7 +166,7 @@ class ChatInputRow extends StatelessWidget { foregroundColor: Colors.white, child: Icon(Icons.gps_fixed_outlined), ), - title: Text(L10n.of(context).shareLocation), + title: Text(L10n.of(context)!.shareLocation), contentPadding: const EdgeInsets.all(0), ), ), @@ -176,11 +176,11 @@ class ChatInputRow extends StatelessWidget { Container( height: 56, alignment: Alignment.center, - child: EncryptionButton(controller.room), + child: EncryptionButton(controller.room!), ), - if (controller.matrix.isMultiAccount && - controller.matrix.hasComplexBundles && - controller.matrix.currentBundle.length > 1) + if (controller.matrix!.isMultiAccount && + controller.matrix!.hasComplexBundles && + controller.matrix!.currentBundle!.length > 1) Container( height: 56, alignment: Alignment.center, @@ -190,7 +190,7 @@ class ChatInputRow extends StatelessWidget { child: Padding( padding: const EdgeInsets.symmetric(vertical: 4.0), child: InputBar( - room: controller.room, + room: controller.room!, minLines: 1, maxLines: 8, autofocus: !PlatformInfos.isMobile, @@ -201,7 +201,7 @@ class ChatInputRow extends StatelessWidget { focusNode: controller.inputFocus, controller: controller.sendController, decoration: InputDecoration( - hintText: L10n.of(context).writeAMessage, + hintText: L10n.of(context)!.writeAMessage, hintMaxLines: 1, border: InputBorder.none, enabledBorder: InputBorder.none, @@ -216,7 +216,7 @@ class ChatInputRow extends StatelessWidget { height: 56, alignment: Alignment.center, child: IconButton( - tooltip: L10n.of(context).voiceMessage, + tooltip: L10n.of(context)!.voiceMessage, icon: const Icon(Icons.mic_none_outlined), onPressed: controller.voiceMessageAction, ), @@ -228,7 +228,7 @@ class ChatInputRow extends StatelessWidget { child: IconButton( icon: const Icon(Icons.send_outlined), onPressed: controller.send, - tooltip: L10n.of(context).send, + tooltip: L10n.of(context)!.send, ), ), ], @@ -239,11 +239,11 @@ class ChatInputRow extends StatelessWidget { class _ChatAccountPicker extends StatelessWidget { final ChatController controller; - const _ChatAccountPicker(this.controller, {Key key}) : super(key: key); + const _ChatAccountPicker(this.controller, {Key? key}) : super(key: key); void _popupMenuButtonSelected(String mxid) { - final client = controller.matrix.currentBundle - .firstWhere((cl) => cl.userID == mxid, orElse: () => null); + final client = controller.matrix!.currentBundle! + .firstWhere((cl) => cl!.userID == mxid, orElse: () => null); if (client == null) { Logs().w('Attempted to switch to a non-existing client $mxid'); return; @@ -258,23 +258,23 @@ class _ChatAccountPicker extends StatelessWidget { return Padding( padding: const EdgeInsets.all(8.0), child: FutureBuilder( - future: controller.sendingClient.ownProfile, + future: controller.sendingClient!.ownProfile, builder: (context, snapshot) => PopupMenuButton( onSelected: _popupMenuButtonSelected, itemBuilder: (BuildContext context) => clients .map((client) => PopupMenuItem( - value: client.userID, + value: client!.userID, child: FutureBuilder( future: client.ownProfile, builder: (context, snapshot) => ListTile( leading: Avatar( mxContent: snapshot.data?.avatarUrl, name: snapshot.data?.displayName ?? - client.userID.localpart, + client.userID!.localpart, size: 20, ), title: - Text(snapshot.data?.displayName ?? client.userID), + Text(snapshot.data?.displayName ?? client.userID!), contentPadding: const EdgeInsets.all(0), ), ), @@ -283,7 +283,7 @@ class _ChatAccountPicker extends StatelessWidget { child: Avatar( mxContent: snapshot.data?.avatarUrl, name: snapshot.data?.displayName ?? - controller.matrix.client.userID.localpart, + controller.matrix!.client.userID!.localpart, size: 20, ), ), diff --git a/lib/pages/chat/chat_view.dart b/lib/pages/chat/chat_view.dart index 09347c57..9b548063 100644 --- a/lib/pages/chat/chat_view.dart +++ b/lib/pages/chat/chat_view.dart @@ -34,31 +34,31 @@ enum _EventContextAction { info, report } class ChatView extends StatelessWidget { final ChatController controller; - const ChatView(this.controller, {Key key}) : super(key: key); + const ChatView(this.controller, {Key? key}) : super(key: key); List _appBarActions(BuildContext context) => controller.selectMode ? [ if (controller.canEditSelectedEvents) IconButton( icon: const Icon(Icons.edit_outlined), - tooltip: L10n.of(context).edit, + tooltip: L10n.of(context)!.edit, onPressed: controller.editSelectedEventAction, ), IconButton( icon: const Icon(Icons.copy_outlined), - tooltip: L10n.of(context).copy, + tooltip: L10n.of(context)!.copy, onPressed: controller.copyEventsAction, ), if (controller.canSaveSelectedEvent) IconButton( icon: Icon(Icons.adaptive.share), - tooltip: L10n.of(context).share, + tooltip: L10n.of(context)!.share, onPressed: controller.saveSelectedEvent, ), if (controller.canRedactSelectedEvents) IconButton( icon: const Icon(Icons.delete_outlined), - tooltip: L10n.of(context).redactMessage, + tooltip: L10n.of(context)!.redactMessage, onPressed: controller.redactEventsAction, ), if (controller.selectedEvents.length == 1) @@ -82,7 +82,7 @@ class ChatView extends StatelessWidget { children: [ const Icon(Icons.info_outlined), const SizedBox(width: 12), - Text(L10n.of(context).messageInfo), + Text(L10n.of(context)!.messageInfo), ], ), ), @@ -96,7 +96,7 @@ class ChatView extends StatelessWidget { color: Colors.red, ), const SizedBox(width: 12), - Text(L10n.of(context).reportMessage), + Text(L10n.of(context)!.reportMessage), ], ), ), @@ -104,29 +104,30 @@ class ChatView extends StatelessWidget { ), ] : [ - ChatSettingsPopupMenu(controller.room, !controller.room.isDirectChat), + ChatSettingsPopupMenu( + controller.room!, !controller.room!.isDirectChat), ]; @override Widget build(BuildContext context) { controller.matrix ??= Matrix.of(context); - final client = controller.matrix.client; + final client = controller.matrix!.client; controller.sendingClient ??= client; - controller.room = controller.sendingClient.getRoomById(controller.roomId); + controller.room = controller.sendingClient!.getRoomById(controller.roomId!); if (controller.room == null) { return Scaffold( appBar: AppBar( - title: Text(L10n.of(context).oopsSomethingWentWrong), + title: Text(L10n.of(context)!.oopsSomethingWentWrong), ), body: Center( - child: Text(L10n.of(context).youAreNoLongerParticipatingInThisChat), + child: Text(L10n.of(context)!.youAreNoLongerParticipatingInThisChat), ), ); } - if (controller.room.membership == Membership.invite) { + if (controller.room!.membership == Membership.invite) { showFutureLoadingDialog( - context: context, future: () => controller.room.join()); + context: context, future: () => controller.room!.join()); } final bottomSheetPadding = FluffyThemes.isColumnMode(context) ? 16.0 : 8.0; final horizontalPadding = FluffyThemes.isColumnMode(context) ? 8.0 : 0.0; @@ -139,7 +140,7 @@ class ChatView extends StatelessWidget { } }, child: StreamBuilder( - stream: controller.room.onUpdate.stream + stream: controller.room!.onUpdate.stream .rateLimit(const Duration(milliseconds: 250)), builder: (context, snapshot) => Scaffold( appBar: AppBar( @@ -152,10 +153,10 @@ class ChatView extends StatelessWidget { ? IconButton( icon: const Icon(Icons.close), onPressed: controller.clearSelectedEvents, - tooltip: L10n.of(context).close, + tooltip: L10n.of(context)!.close, color: Theme.of(context).colorScheme.primary, ) - : UnreadBadgeBackButton(roomId: controller.roomId), + : UnreadBadgeBackButton(roomId: controller.roomId!), titleSpacing: 0, title: ChatAppBarTitle(controller), actions: _appBarActions(context), @@ -167,7 +168,7 @@ class ChatView extends StatelessWidget { child: FloatingActionButton( onPressed: controller.scrollDown, foregroundColor: - Theme.of(context).textTheme.bodyText2.color, + Theme.of(context).textTheme.bodyText2!.color, backgroundColor: Theme.of(context).scaffoldBackgroundColor, mini: true, child: Icon(Icons.arrow_downward_outlined, @@ -184,7 +185,7 @@ class ChatView extends StatelessWidget { children: [ if (Matrix.of(context).wallpaper != null) Image.file( - Matrix.of(context).wallpaper, + Matrix.of(context).wallpaper!, width: double.infinity, height: double.infinity, fit: BoxFit.cover, @@ -240,7 +241,7 @@ class ChatView extends StatelessWidget { controller.filteredEvents.length + 1 ? controller - .timeline.isRequestingHistory + .timeline!.isRequestingHistory ? const Center( child: CircularProgressIndicator @@ -259,7 +260,7 @@ class ChatView extends StatelessWidget { onPressed: controller .requestHistory, child: Text( - L10n.of(context) + L10n.of(context)! .loadMore), ), ) @@ -337,7 +338,7 @@ class ChatView extends StatelessWidget { selected: controller .selectedEvents .any((e) => e.eventId == controller.filteredEvents[i - 1].eventId), - timeline: controller.timeline, + timeline: controller.timeline!, nextEvent: i < controller.filteredEvents.length ? controller.filteredEvents[i] : null), ), ); @@ -352,8 +353,8 @@ class ChatView extends StatelessWidget { }, )), ), - if (controller.room.canSendDefaultMessages && - controller.room.membership == Membership.join) + if (controller.room!.canSendDefaultMessages && + controller.room!.membership == Membership.join) Container( margin: EdgeInsets.only( bottom: bottomSheetPadding, diff --git a/lib/pages/chat/command_hints.dart b/lib/pages/chat/command_hints.dart index 3dc82430..617c4f80 100644 --- a/lib/pages/chat/command_hints.dart +++ b/lib/pages/chat/command_hints.dart @@ -1,4 +1,3 @@ -//@dart=2.12 // This file is auto-generated using scripts/generate_command_hints_glue.sh. import 'package:flutter_gen/gen_l10n/l10n.dart'; diff --git a/lib/pages/chat/encryption_button.dart b/lib/pages/chat/encryption_button.dart index 30653817..89fe0b6e 100644 --- a/lib/pages/chat/encryption_button.dart +++ b/lib/pages/chat/encryption_button.dart @@ -12,13 +12,13 @@ import '../../widgets/matrix.dart'; class EncryptionButton extends StatefulWidget { final Room room; - const EncryptionButton(this.room, {Key key}) : super(key: key); + const EncryptionButton(this.room, {Key? key}) : super(key: key); @override _EncryptionButtonState createState() => _EncryptionButtonState(); } class _EncryptionButtonState extends State { - StreamSubscription _onSyncSub; + StreamSubscription? _onSyncSub; void _enableEncryptionAction() async { if (widget.room.encrypted) { @@ -29,20 +29,20 @@ class _EncryptionButtonState extends State { await showOkAlertDialog( useRootNavigator: false, context: context, - okLabel: L10n.of(context).ok, - message: L10n.of(context).noEncryptionForPublicRooms, + okLabel: L10n.of(context)!.ok, + message: L10n.of(context)!.noEncryptionForPublicRooms, ); return; } if (await showOkCancelAlertDialog( useRootNavigator: false, context: context, - title: L10n.of(context).enableEncryption, + title: L10n.of(context)!.enableEncryption, message: widget.room.client.encryptionEnabled - ? L10n.of(context).enableEncryptionWarning - : L10n.of(context).needPantalaimonWarning, - okLabel: L10n.of(context).yes, - cancelLabel: L10n.of(context).cancel, + ? L10n.of(context)!.enableEncryptionWarning + : L10n.of(context)!.needPantalaimonWarning, + okLabel: L10n.of(context)!.yes, + cancelLabel: L10n.of(context)!.cancel, ) == OkCancelResult.ok) { await showFutureLoadingDialog( @@ -50,7 +50,7 @@ class _EncryptionButtonState extends State { future: () => widget.room.enableEncryption(), ); // we want to enable the lock icon - setState(() => null); + setState(() {}); } } @@ -68,22 +68,22 @@ class _EncryptionButtonState extends State { .onSync .stream .where((s) => s.deviceLists != null) - .listen((s) => setState(() => null)); + .listen((s) => setState(() {})); } return FutureBuilder>( future: widget.room.encrypted ? widget.room.requestParticipants() : null, builder: (BuildContext context, snapshot) { - Color color; + Color? color; if (widget.room.encrypted && snapshot.hasData) { - final users = snapshot.data; + final users = snapshot.data!; users.removeWhere((u) => !{Membership.invite, Membership.join}.contains(u.membership) || !widget.room.client.userDeviceKeys.containsKey(u.id)); var allUsersValid = true; var oneUserInvalid = false; for (final u in users) { - final status = widget.room.client.userDeviceKeys[u.id].verified; + final status = widget.room.client.userDeviceKeys[u.id]!.verified; if (status != UserVerifiedStatus.verified) { allUsersValid = false; } @@ -99,8 +99,8 @@ class _EncryptionButtonState extends State { } return IconButton( tooltip: widget.room.encrypted - ? L10n.of(context).encrypted - : L10n.of(context).encryptionNotEnabled, + ? L10n.of(context)!.encrypted + : L10n.of(context)!.encryptionNotEnabled, icon: Icon( widget.room.encrypted ? Icons.lock_outlined diff --git a/lib/pages/chat/event_info_dialog.dart b/lib/pages/chat/event_info_dialog.dart index 679c34d4..ce9be4d8 100644 --- a/lib/pages/chat/event_info_dialog.dart +++ b/lib/pages/chat/event_info_dialog.dart @@ -13,7 +13,7 @@ extension EventInfoDialogExtension on Event { void showInfoDialog(BuildContext context) => showModalBottomSheet( context: context, builder: (context) => - EventInfoDialog(l10n: L10n.of(context), event: this), + EventInfoDialog(l10n: L10n.of(context)!, event: this), ); } @@ -21,9 +21,9 @@ class EventInfoDialog extends StatelessWidget { final Event event; final L10n l10n; const EventInfoDialog({ - @required this.event, - @required this.l10n, - Key key, + required this.event, + required this.l10n, + Key? key, }) : super(key: key); String get prettyJson { @@ -37,11 +37,11 @@ class EventInfoDialog extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: Text(L10n.of(context).messageInfo), + title: Text(L10n.of(context)!.messageInfo), leading: IconButton( icon: const Icon(Icons.arrow_downward_outlined), onPressed: Navigator.of(context, rootNavigator: false).pop, - tooltip: L10n.of(context).close, + tooltip: L10n.of(context)!.close, ), ), body: ListView( @@ -51,19 +51,19 @@ class EventInfoDialog extends StatelessWidget { mxContent: event.sender.avatarUrl, name: event.sender.calcDisplayname(), ), - title: Text(L10n.of(context).sender), + title: Text(L10n.of(context)!.sender), subtitle: Text('${event.sender.calcDisplayname()} [${event.senderId}]'), ), ListTile( - title: Text(L10n.of(context).time), + title: Text(L10n.of(context)!.time), subtitle: Text(event.originServerTs.localizedTime(context)), ), ListTile( - title: Text(L10n.of(context).messageType), + title: Text(L10n.of(context)!.messageType), subtitle: Text(event.humanreadableType), ), - ListTile(title: Text('${L10n.of(context).sourceCode}:')), + ListTile(title: Text('${L10n.of(context)!.sourceCode}:')), Padding( padding: const EdgeInsets.all(12.0), child: Material( diff --git a/lib/pages/chat/events/audio_player.dart b/lib/pages/chat/events/audio_player.dart index 44693285..aa3cd536 100644 --- a/lib/pages/chat/events/audio_player.dart +++ b/lib/pages/chat/events/audio_player.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'dart:async'; import 'dart:io'; diff --git a/lib/pages/chat/events/html_message.dart b/lib/pages/chat/events/html_message.dart index 4e2f3613..f5b84e6c 100644 --- a/lib/pages/chat/events/html_message.dart +++ b/lib/pages/chat/events/html_message.dart @@ -13,17 +13,17 @@ import '../../../utils/url_launcher.dart'; class HtmlMessage extends StatelessWidget { final String html; - final int maxLines; + final int? maxLines; final Room room; - final TextStyle defaultTextStyle; - final TextStyle linkStyle; - final double emoteSize; + final TextStyle? defaultTextStyle; + final TextStyle? linkStyle; + final double? emoteSize; const HtmlMessage({ - Key key, - this.html, + Key? key, + required this.html, this.maxLines, - this.room, + required this.room, this.defaultTextStyle, this.linkStyle, this.emoteSize, @@ -52,7 +52,7 @@ class HtmlMessage extends StatelessWidget { defaultTextStyle: defaultTextStyle, emoteSize: emoteSize, linkStyle: linkStyle ?? - themeData.textTheme.bodyText2.copyWith( + themeData.textTheme.bodyText2!.copyWith( color: themeData.colorScheme.secondary, decoration: TextDecoration.underline, ), @@ -60,11 +60,11 @@ class HtmlMessage extends StatelessWidget { maxLines: maxLines, onLinkTap: (url) => UrlLauncher(context, url).launchUrl(), onPillTap: (url) => UrlLauncher(context, url).launchUrl(), - getMxcUrl: (String mxc, double width, double height, - {bool animated = false}) { + getMxcUrl: (String mxc, double? width, double? height, + {bool? animated = false}) { final ratio = MediaQuery.of(context).devicePixelRatio; return Uri.parse(mxc) - ?.getThumbnail( + .getThumbnail( matrix.client, width: (width ?? 800) * ratio, height: (height ?? 800) * ratio, @@ -92,9 +92,6 @@ class HtmlMessage extends StatelessWidget { return await matrix.store.getItem('${SettingKeys.codeLanguage}.$key'); }, getPillInfo: (String url) async { - if (room == null) { - return null; - } final identityParts = url.parseIdentifierIntoParts(); final identifier = identityParts?.primaryIdentifier; if (identifier == null) { @@ -108,13 +105,10 @@ class HtmlMessage extends StatelessWidget { } // there might still be a profile... final profile = await room.client.getProfileFromUserId(identifier); - if (profile != null) { - return { - 'displayname': profile.displayName, - 'avatar_url': profile.avatarUrl.toString(), - }; - } - return null; + return { + 'displayname': profile.displayName, + 'avatar_url': profile.avatarUrl.toString(), + }; } if (identifier.sigil == '#') { // we have an alias pill @@ -128,7 +122,7 @@ class HtmlMessage extends StatelessWidget { // we have a room! return { 'displayname': - r.getLocalizedDisplayname(MatrixLocals(L10n.of(context))), + r.getLocalizedDisplayname(MatrixLocals(L10n.of(context)!)), 'avatar_url': r.getState('m.room.avatar')?.content['url'], }; } @@ -143,12 +137,12 @@ class HtmlMessage extends StatelessWidget { } return { 'displayname': - r.getLocalizedDisplayname(MatrixLocals(L10n.of(context))), + r.getLocalizedDisplayname(MatrixLocals(L10n.of(context)!)), 'avatar_url': r.getState('m.room.avatar')?.content['url'], }; } return null; - }, + } as Future> Function(String)?, ); } } diff --git a/lib/pages/chat/events/image_bubble.dart b/lib/pages/chat/events/image_bubble.dart index 9b20e722..0943a476 100644 --- a/lib/pages/chat/events/image_bubble.dart +++ b/lib/pages/chat/events/image_bubble.dart @@ -19,13 +19,13 @@ class ImageBubble extends StatefulWidget { final bool tapToView; final BoxFit fit; final bool maxSize; - final Color backgroundColor; + final Color? backgroundColor; final bool thumbnailOnly; final bool animated; final double width; final double height; - final void Function() onLoaded; - final void Function() onTap; + final void Function()? onLoaded; + final void Function()? onTap; const ImageBubble( this.event, { @@ -39,7 +39,7 @@ class ImageBubble extends StatefulWidget { this.height = 300, this.animated = false, this.onTap, - Key key, + Key? key, }) : super(key: key); @override @@ -48,17 +48,17 @@ class ImageBubble extends StatefulWidget { class _ImageBubbleState extends State { // for plaintext: holds the http URL for the thumbnail - String thumbnailUrl; + String? thumbnailUrl; // for plaintext. holds the http URL for the thumbnial, without the animated flag - String thumbnailUrlNoAnimated; + String? thumbnailUrlNoAnimated; // for plaintext: holds the http URL of the original - String attachmentUrl; - MatrixFile _file; - MatrixFile _thumbnail; + String? attachmentUrl; + MatrixFile? _file; + MatrixFile? _thumbnail; bool _requestedThumbnailOnFailure = false; // In case we have animated = false, this will hold the first frame so that we make // sure that things are never animated - Widget _firstFrame; + Widget? _firstFrame; // the mimetypes that we know how to render, from the flutter Image widget final _knownMimetypes = { @@ -82,8 +82,8 @@ class _ImageBubbleState extends State { ? widget.event.thumbnailMimetype.toLowerCase() : widget.event.attachmentMimetype.toLowerCase(); - MatrixFile get _displayFile => _file ?? _thumbnail; - String get displayUrl => widget.thumbnailOnly ? thumbnailUrl : attachmentUrl; + MatrixFile? get _displayFile => _file ?? _thumbnail; + String? get displayUrl => widget.thumbnailOnly ? thumbnailUrl : attachmentUrl; dynamic _error; @@ -91,14 +91,14 @@ class _ImageBubbleState extends State { try { final res = await widget.event .downloadAndDecryptAttachmentCached(getThumbnail: getThumbnail); - WidgetsBinding.instance.addPostFrameCallback((_) { + WidgetsBinding.instance!.addPostFrameCallback((_) { if (getThumbnail) { if (mounted) { setState(() => _thumbnail = res); } } else { if (widget.onLoaded != null) { - widget.onLoaded(); + widget.onLoaded!(); } if (mounted) { setState(() => _file = res); @@ -106,7 +106,7 @@ class _ImageBubbleState extends State { } }); } catch (err) { - WidgetsBinding.instance.addPostFrameCallback((_) { + WidgetsBinding.instance!.addPostFrameCallback((_) { if (mounted) { setState(() => _error = err); } @@ -114,7 +114,7 @@ class _ImageBubbleState extends State { } } - Widget frameBuilder(_, Widget child, int frame, __) { + Widget frameBuilder(_, Widget child, int? frame, __) { // as servers might return animated gifs as thumbnails and we want them to *not* play // animated, we'll have to store the first frame in a variable and display that instead if (widget.animated) { @@ -135,12 +135,14 @@ class _ImageBubbleState extends State { key: ValueKey(key), fit: widget.fit, ), - network: (String url) => SvgPicture.network( - url, - key: ValueKey(url), - placeholderBuilder: (context) => getPlaceholderWidget(), - fit: widget.fit, - ), + network: (String? url) => url == null + ? Container() + : SvgPicture.network( + url, + key: ValueKey(url), + placeholderBuilder: (context) => getPlaceholderWidget(), + fit: widget.fit, + ), ); _contentRenderers['image/lottie+json'] = _ImageBubbleContentRenderer( memory: (Uint8List bytes, String key) => Lottie.memory( @@ -151,14 +153,16 @@ class _ImageBubbleState extends State { getErrorWidget(context, error), animate: widget.animated, ), - network: (String url) => Lottie.network( - url, - key: ValueKey(url), - fit: widget.fit, - errorBuilder: (context, error, stacktrace) => - getErrorWidget(context, error), - animate: widget.animated, - ), + network: (String? url) => url == null + ? Container() + : Lottie.network( + url, + key: ValueKey(url), + fit: widget.fit, + errorBuilder: (context, error, stacktrace) => + getErrorWidget(context, error), + animate: widget.animated, + ), ); // add all the custom content renderer mimetypes to the known mimetypes set @@ -203,7 +207,7 @@ class _ImageBubbleState extends State { OutlinedButton.icon( style: OutlinedButton.styleFrom( backgroundColor: Theme.of(context).scaffoldBackgroundColor, - primary: Theme.of(context).textTheme.bodyText1.color, + primary: Theme.of(context).textTheme.bodyText1!.color, ), icon: const Icon(Icons.download_outlined), onPressed: () => widget.event.saveFile(context), @@ -215,7 +219,7 @@ class _ImageBubbleState extends State { ), ), const SizedBox(height: 8), - if (widget.event.sizeString != null) Text(widget.event.sizeString), + if (widget.event.sizeString != null) Text(widget.event.sizeString!), const SizedBox(height: 8), Text((error ?? _error).toString()), ], @@ -223,8 +227,8 @@ class _ImageBubbleState extends State { ); } - Widget getPlaceholderWidget({Widget child}) { - Widget blurhash; + Widget getPlaceholderWidget({Widget? child}) { + Widget? blurhash; if (widget.event.infoMap['xyz.amorgan.blurhash'] is String) { final ratio = widget.event.infoMap['w'] is int && widget.event.infoMap['h'] is int @@ -265,16 +269,16 @@ class _ImageBubbleState extends State { : widget.event.thumbnailMxcUrl.toString(); final mimetype = getMimetype(!isOriginal); if (_contentRenderers.containsKey(mimetype)) { - return _contentRenderers[mimetype].memory(_displayFile.bytes, key); + return _contentRenderers[mimetype]!.memory!(_displayFile!.bytes, key); } else { return Image.memory( - _displayFile.bytes, + _displayFile!.bytes, key: ValueKey(key), fit: widget.fit, errorBuilder: (context, error, stacktrace) { if (widget.event.hasThumbnail && !_requestedThumbnailOnFailure) { _requestedThumbnailOnFailure = true; - WidgetsBinding.instance.addPostFrameCallback((_) { + WidgetsBinding.instance!.addPostFrameCallback((_) { setState(() { _file = null; _requestFile(getThumbnail: true); @@ -299,12 +303,12 @@ class _ImageBubbleState extends State { final mimetype = getMimetype(_requestedThumbnailOnFailure); if (displayUrl == attachmentUrl && _contentRenderers.containsKey(mimetype)) { - return _contentRenderers[mimetype].network(displayUrl); + return _contentRenderers[mimetype]!.network!(displayUrl); } else { return CachedNetworkImage( // as we change the url on-error we need a key so that the widget actually updates key: ValueKey(displayUrl), - imageUrl: displayUrl, + imageUrl: displayUrl!, placeholder: (context, url) { if (!widget.thumbnailOnly && displayUrl != thumbnailUrl && @@ -313,7 +317,7 @@ class _ImageBubbleState extends State { return FutureBuilder( future: (() async { return await DefaultCacheManager() - .getFileFromCache(thumbnailUrl) != + .getFileFromCache(thumbnailUrl!) != null; })(), builder: (BuildContext context, AsyncSnapshot snapshot) { @@ -321,8 +325,8 @@ class _ImageBubbleState extends State { return getPlaceholderWidget(); } final effectiveUrl = snapshot.data == true - ? thumbnailUrl - : thumbnailUrlNoAnimated; + ? thumbnailUrl! + : thumbnailUrlNoAnimated!; return CachedNetworkImage( key: ValueKey(effectiveUrl), imageUrl: effectiveUrl, @@ -348,7 +352,7 @@ class _ImageBubbleState extends State { // the image failed to load but the event has a thumbnail attached....so we can // try to load this one! _requestedThumbnailOnFailure = true; - WidgetsBinding.instance.addPostFrameCallback((_) { + WidgetsBinding.instance!.addPostFrameCallback((_) { setState(() { thumbnailUrl = widget.event .getAttachmentUrl( @@ -382,11 +386,11 @@ class _ImageBubbleState extends State { OutlinedButton( style: OutlinedButton.styleFrom( backgroundColor: Theme.of(context).scaffoldBackgroundColor, - primary: Theme.of(context).textTheme.bodyText1.color, + primary: Theme.of(context).textTheme.bodyText1!.color, ), onPressed: () => onTap(context), child: Text( - L10n.of(context).tapToShowImage, + L10n.of(context)!.tapToShowImage, overflow: TextOverflow.fade, softWrap: false, maxLines: 1, @@ -394,7 +398,7 @@ class _ImageBubbleState extends State { ), if (widget.event.sizeString != null) ...[ const SizedBox(height: 8), - Text(widget.event.sizeString), + Text(widget.event.sizeString!), ] ], )); @@ -451,7 +455,7 @@ class _ImageBubbleState extends State { void onTap(BuildContext context) { if (widget.onTap != null) { - widget.onTap(); + widget.onTap!(); return; } if (!widget.tapToView) return; @@ -476,8 +480,8 @@ class _ImageBubbleState extends State { } class _ImageBubbleContentRenderer { - final Widget Function(Uint8List, String) memory; - final Widget Function(String) network; + final Widget Function(Uint8List, String)? memory; + final Widget Function(String?)? network; _ImageBubbleContentRenderer({this.memory, this.network}); } diff --git a/lib/pages/chat/events/map_bubble.dart b/lib/pages/chat/events/map_bubble.dart index 47aede77..b889a40f 100644 --- a/lib/pages/chat/events/map_bubble.dart +++ b/lib/pages/chat/events/map_bubble.dart @@ -11,13 +11,13 @@ class MapBubble extends StatelessWidget { final double height; final double radius; const MapBubble({ - this.latitude, - this.longitude, + required this.latitude, + required this.longitude, this.zoom = 14.0, this.width = 400, this.height = 400, this.radius = 10.0, - Key key, + Key? key, }) : super(key: key); @override diff --git a/lib/pages/chat/events/message.dart b/lib/pages/chat/events/message.dart index e04dc21d..03cb6664 100644 --- a/lib/pages/chat/events/message.dart +++ b/lib/pages/chat/events/message.dart @@ -16,14 +16,14 @@ import 'verification_request_content.dart'; class Message extends StatelessWidget { final Event event; - final Event nextEvent; - final void Function(Event) onSelect; - final void Function(Event) onAvatarTab; - final void Function(Event) onInfoTab; - final void Function(String) scrollToEventId; + final Event? nextEvent; + final void Function(Event)? onSelect; + final void Function(Event)? onAvatarTab; + final void Function(Event)? onInfoTab; + final void Function(String)? scrollToEventId; final void Function(String) unfold; - final bool longPressSelect; - final bool selected; + final bool? longPressSelect; + final bool? selected; final Timeline timeline; const Message(this.event, @@ -33,10 +33,10 @@ class Message extends StatelessWidget { this.onInfoTab, this.onAvatarTab, this.scrollToEventId, - @required this.unfold, + required this.unfold, this.selected, - this.timeline, - Key key}) + required this.timeline, + Key? key}) : super(key: key); /// Indicates wheither the user may use a mouse instead @@ -61,14 +61,14 @@ class Message extends StatelessWidget { var color = Theme.of(context).appBarTheme.backgroundColor; final displayTime = event.type == EventTypes.RoomCreate || nextEvent == null || - !event.originServerTs.sameEnvironment(nextEvent.originServerTs); + !event.originServerTs.sameEnvironment(nextEvent!.originServerTs); final sameSender = nextEvent != null && [ EventTypes.Message, EventTypes.Sticker, EventTypes.Encrypted, - ].contains(nextEvent.type) - ? nextEvent.sender.id == event.sender.id && !displayTime + ].contains(nextEvent!.type) + ? nextEvent!.sender.id == event.sender.id && !displayTime : false; final textColor = ownMessage ? Colors.white @@ -119,7 +119,7 @@ class Message extends StatelessWidget { : Avatar( mxContent: event.sender.avatarUrl, name: event.sender.calcDisplayname(), - onTap: () => onAvatarTab(event), + onTap: () => onAvatarTab!(event), ), Expanded( child: Column( @@ -152,10 +152,11 @@ class Message extends StatelessWidget { clipBehavior: Clip.antiAlias, child: InkWell( onHover: (b) => useMouse = true, - onTap: !useMouse && longPressSelect - ? () => null - : () => onSelect(event), - onLongPress: !longPressSelect ? null : () => onSelect(event), + onTap: !useMouse && longPressSelect! + ? () {} + : () => onSelect!(event), + onLongPress: + !longPressSelect! ? null : () => onSelect!(event), borderRadius: borderRadius, child: Container( decoration: BoxDecoration( @@ -175,13 +176,13 @@ class Message extends StatelessWidget { children: [ if (event.relationshipType == RelationshipTypes.reply) - FutureBuilder( + FutureBuilder( future: event.getReplyEvent(timeline), builder: (BuildContext context, snapshot) { final replyEvent = snapshot.hasData - ? snapshot.data + ? snapshot.data! : Event( - eventId: event.relationshipEventId, + eventId: event.relationshipEventId!, content: { 'msgtype': 'm.text', 'body': '...' @@ -195,7 +196,7 @@ class Message extends StatelessWidget { return InkWell( onTap: () { if (scrollToEventId != null) { - scrollToEventId(replyEvent.eventId); + scrollToEventId!(replyEvent.eventId); } }, child: AbsorbPointer( @@ -300,7 +301,7 @@ class Message extends StatelessWidget { return Center( child: Container( - color: selected + color: selected! ? Theme.of(context).primaryColor.withAlpha(100) : Theme.of(context).primaryColor.withAlpha(0), constraints: diff --git a/lib/pages/chat/events/message_content.dart b/lib/pages/chat/events/message_content.dart index 1bc68348..29de72fa 100644 --- a/lib/pages/chat/events/message_content.dart +++ b/lib/pages/chat/events/message_content.dart @@ -22,10 +22,10 @@ import 'sticker.dart'; class MessageContent extends StatelessWidget { final Event event; - final Color textColor; - final void Function(Event) onInfoTab; + final Color? textColor; + final void Function(Event)? onInfoTab; - const MessageContent(this.event, {this.onInfoTab, Key key, this.textColor}) + const MessageContent(this.event, {this.onInfoTab, Key? key, this.textColor}) : super(key: key); void _verifyOrRequestKey(BuildContext context) async { @@ -33,15 +33,15 @@ class MessageContent extends StatelessWidget { ScaffoldMessenger.of(context).showSnackBar(SnackBar( content: Text( event.type == EventTypes.Encrypted - ? L10n.of(context).needPantalaimonWarning + ? L10n.of(context)!.needPantalaimonWarning : event.getLocalizedBody( - MatrixLocals(L10n.of(context)), + MatrixLocals(L10n.of(context)!), ), ))); return; } final client = Matrix.of(context).client; - if (client.isUnknownSession && client.encryption.crossSigning.enabled) { + if (client.isUnknownSession && client.encryption!.crossSigning.enabled) { await BootstrapDialog( client: Matrix.of(context).client, ).show(context); @@ -55,7 +55,7 @@ class MessageContent extends StatelessWidget { ); if (success.error == null) { ScaffoldMessenger.of(context).showSnackBar(SnackBar( - content: Text(L10n.of(context).requestToReadOlderMessages))); + content: Text(L10n.of(context)!.requestToReadOlderMessages))); } } } @@ -83,17 +83,17 @@ class MessageContent extends StatelessWidget { if (PlatformInfos.isMobile) { return AudioPlayerWidget( event, - color: textColor, + color: textColor!, ); } - return MessageDownloadContent(event, textColor); + return MessageDownloadContent(event, textColor!); case MessageTypes.Video: if (PlatformInfos.isMobile || PlatformInfos.isWeb) { return EventVideoPlayer(event); } - return MessageDownloadContent(event, textColor); + return MessageDownloadContent(event, textColor!); case MessageTypes.File: - return MessageDownloadContent(event, textColor); + return MessageDownloadContent(event, textColor!); case MessageTypes.Text: case MessageTypes.Notice: @@ -115,7 +115,7 @@ class MessageContent extends StatelessWidget { fontSize: bigEmotes ? fontSize * 3 : fontSize, ), linkStyle: TextStyle( - color: textColor.withAlpha(150), + color: textColor!.withAlpha(150), fontSize: bigEmotes ? fontSize * 3 : fontSize, decoration: TextDecoration.underline, ), @@ -131,14 +131,12 @@ class MessageContent extends StatelessWidget { textColor: buttonTextColor, onPressed: () => _verifyOrRequestKey(context), icon: const Icon(Icons.lock_outline), - label: L10n.of(context).encrypted, + label: L10n.of(context)!.encrypted, ); case MessageTypes.Location: final geoUri = - Uri.tryParse(event.content.tryGet('geo_uri')); - if (geoUri != null && - geoUri.scheme == 'geo' && - geoUri.path != null) { + Uri.tryParse(event.content.tryGet('geo_uri')!); + if (geoUri != null && geoUri.scheme == 'geo') { final latlong = geoUri.path .split(';') .first @@ -152,8 +150,8 @@ class MessageContent extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ MapBubble( - latitude: latlong.first, - longitude: latlong.last, + latitude: latlong.first!, + longitude: latlong.last!, ), const SizedBox(height: 6), OutlinedButton.icon( @@ -161,7 +159,7 @@ class MessageContent extends StatelessWidget { onPressed: UrlLauncher(context, geoUri.toString()).launchUrl, label: Text( - L10n.of(context).openInMaps, + L10n.of(context)!.openInMaps, style: TextStyle(color: textColor), ), ), @@ -177,24 +175,24 @@ class MessageContent extends StatelessWidget { return _ButtonContent( onPressed: () => launch(event.body), icon: const Icon(Icons.phone_outlined, color: Colors.green), - label: L10n.of(context).videoCall, + label: L10n.of(context)!.videoCall, textColor: buttonTextColor, ); } if (event.redacted) { return _ButtonContent( - label: L10n.of(context) + label: L10n.of(context)! .redactedAnEvent(event.sender.calcDisplayname()), icon: const Icon(Icons.delete_outlined), textColor: buttonTextColor, - onPressed: () => onInfoTab(event), + onPressed: () => onInfoTab!(event), ); } final bigEmotes = event.onlyEmotes && event.numberEmotes > 0 && event.numberEmotes <= 10; return LinkText( - text: event.getLocalizedBody(MatrixLocals(L10n.of(context)), + text: event.getLocalizedBody(MatrixLocals(L10n.of(context)!), hideReply: true), textStyle: TextStyle( color: textColor, @@ -202,24 +200,22 @@ class MessageContent extends StatelessWidget { decoration: event.redacted ? TextDecoration.lineThrough : null, ), linkStyle: TextStyle( - color: textColor.withAlpha(150), + color: textColor!.withAlpha(150), fontSize: bigEmotes ? fontSize * 3 : fontSize, decoration: TextDecoration.underline, ), onLinkTap: (url) => UrlLauncher(context, url).launchUrl(), ); } - break; default: return _ButtonContent( - label: L10n.of(context) + label: L10n.of(context)! .userSentUnknownEvent(event.sender.calcDisplayname(), event.type), icon: const Icon(Icons.info_outlined), textColor: buttonTextColor, - onPressed: () => onInfoTab(event), + onPressed: () => onInfoTab!(event), ); } - return Container(); // else flutter analyze complains } } @@ -227,14 +223,14 @@ class _ButtonContent extends StatelessWidget { final void Function() onPressed; final String label; final Icon icon; - final Color textColor; + final Color? textColor; const _ButtonContent({ - @required this.label, - @required this.icon, - @required this.textColor, - @required this.onPressed, - Key key, + required this.label, + required this.icon, + required this.textColor, + required this.onPressed, + Key? key, }) : super(key: key); @override diff --git a/lib/pages/chat/events/message_download_content.dart b/lib/pages/chat/events/message_download_content.dart index 470793e2..970b92db 100644 --- a/lib/pages/chat/events/message_download_content.dart +++ b/lib/pages/chat/events/message_download_content.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'package:flutter/material.dart'; import 'package:matrix/matrix.dart'; diff --git a/lib/pages/chat/events/message_reactions.dart b/lib/pages/chat/events/message_reactions.dart index a2a3e065..8c44d758 100644 --- a/lib/pages/chat/events/message_reactions.dart +++ b/lib/pages/chat/events/message_reactions.dart @@ -2,6 +2,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:cached_network_image/cached_network_image.dart'; +import 'package:collection/collection.dart' show IterableExtension; import 'package:future_loading_dialog/future_loading_dialog.dart'; import 'package:matrix/matrix.dart'; @@ -14,14 +15,14 @@ class MessageReactions extends StatelessWidget { final Event event; final Timeline timeline; - const MessageReactions(this.event, this.timeline, {Key key}) + const MessageReactions(this.event, this.timeline, {Key? key}) : super(key: key); @override Widget build(BuildContext context) { final allReactionEvents = event.aggregatedEvents(timeline, RelationshipTypes.reaction); - final reactionMap = {}; + final reactionMap = {}; final client = Matrix.of(context).client; for (final e in allReactionEvents) { @@ -35,9 +36,9 @@ class MessageReactions extends StatelessWidget { reactors: [], ); } - reactionMap[key].count++; - reactionMap[key].reactors.add(e.sender); - reactionMap[key].reacted |= e.senderId == e.room.client.userID; + reactionMap[key]!.count++; + reactionMap[key]!.reactors!.add(e.sender); + reactionMap[key]!.reacted |= e.senderId == e.room.client.userID; } } @@ -52,11 +53,9 @@ class MessageReactions extends StatelessWidget { reacted: r.reacted, onTap: () { if (r.reacted) { - final evt = allReactionEvents.firstWhere( - (e) => - e.senderId == e.room.client.userID && - e.content['m.relates_to']['key'] == r.key, - orElse: () => null); + final evt = allReactionEvents.firstWhereOrNull((e) => + e.senderId == e.room.client.userID && + e.content['m.relates_to']['key'] == r.key); if (evt != null) { showFutureLoadingDialog( context: context, @@ -67,7 +66,7 @@ class MessageReactions extends StatelessWidget { showFutureLoadingDialog( context: context, future: () => - event.room.sendReaction(event.eventId, r.key)); + event.room.sendReaction(event.eventId, r.key!)); } }, onLongPress: () async => await _AdaptableReactorsDialog( @@ -91,11 +90,11 @@ class MessageReactions extends StatelessWidget { } class _Reaction extends StatelessWidget { - final String reactionKey; - final int count; - final bool reacted; - final void Function() onTap; - final void Function() onLongPress; + final String? reactionKey; + final int? count; + final bool? reacted; + final void Function()? onTap; + final void Function()? onLongPress; const _Reaction({ this.reactionKey, @@ -113,11 +112,11 @@ class _Reaction extends StatelessWidget { final color = Theme.of(context).scaffoldBackgroundColor; final fontSize = DefaultTextStyle.of(context).style.fontSize; Widget content; - if (reactionKey.startsWith('mxc://')) { - final src = Uri.parse(reactionKey)?.getThumbnail( + if (reactionKey!.startsWith('mxc://')) { + final src = Uri.parse(reactionKey!).getThumbnail( Matrix.of(context).client, width: 9999, - height: fontSize * MediaQuery.of(context).devicePixelRatio, + height: fontSize! * MediaQuery.of(context).devicePixelRatio, method: ThumbnailMethod.scale, ); content = Row( @@ -136,7 +135,7 @@ class _Reaction extends StatelessWidget { ], ); } else { - var renderKey = Characters(reactionKey); + var renderKey = Characters(reactionKey!); if (renderKey.length > 10) { renderKey = renderKey.getRange(0, 9) + Characters('…'); } @@ -147,13 +146,13 @@ class _Reaction extends StatelessWidget { )); } return InkWell( - onTap: () => onTap != null ? onTap() : null, - onLongPress: () => onLongPress != null ? onLongPress() : null, + onTap: () => onTap != null ? onTap!() : null, + onLongPress: () => onLongPress != null ? onLongPress!() : null, borderRadius: BorderRadius.circular(AppConfig.borderRadius), child: Container( decoration: BoxDecoration( color: color, - border: reacted + border: reacted! ? Border.all( width: 1, color: Theme.of(context).primaryColor, @@ -169,25 +168,30 @@ class _Reaction extends StatelessWidget { } class _ReactionEntry { - String key; + String? key; int count; bool reacted; - List reactors; + List? reactors; - _ReactionEntry({this.key, this.count, this.reacted, this.reactors}); + _ReactionEntry({ + this.key, + required this.count, + required this.reacted, + this.reactors, + }); } class _AdaptableReactorsDialog extends StatelessWidget { - final Client client; - final _ReactionEntry reactionEntry; + final Client? client; + final _ReactionEntry? reactionEntry; const _AdaptableReactorsDialog({ - Key key, + Key? key, this.client, this.reactionEntry, }) : super(key: key); - Future show(BuildContext context) => PlatformInfos.isCupertinoStyle + Future show(BuildContext context) => PlatformInfos.isCupertinoStyle ? showCupertinoDialog( context: context, builder: (context) => this, @@ -209,20 +213,20 @@ class _AdaptableReactorsDialog extends StatelessWidget { runSpacing: 4.0, alignment: WrapAlignment.center, children: [ - for (var reactor in reactionEntry.reactors) + for (var reactor in reactionEntry!.reactors!) Chip( avatar: Avatar( mxContent: reactor.avatarUrl, name: reactor.displayName, client: client, ), - label: Text(reactor.displayName), + label: Text(reactor.displayName!), ), ], ), ); - final title = Center(child: Text(reactionEntry.key)); + final title = Center(child: Text(reactionEntry!.key!)); return PlatformInfos.isCupertinoStyle ? CupertinoAlertDialog( diff --git a/lib/pages/chat/events/reply_content.dart b/lib/pages/chat/events/reply_content.dart index a6d935f0..026e24fe 100644 --- a/lib/pages/chat/events/reply_content.dart +++ b/lib/pages/chat/events/reply_content.dart @@ -10,21 +10,23 @@ import 'html_message.dart'; class ReplyContent extends StatelessWidget { final Event replyEvent; final bool lightText; - final Timeline timeline; + final Timeline? timeline; - const ReplyContent(this.replyEvent, - {this.lightText = false, Key key, this.timeline}) - : super(key: key); + const ReplyContent( + this.replyEvent, { + this.lightText = false, + Key? key, + this.timeline, + }) : super(key: key); @override Widget build(BuildContext context) { Widget replyBody; - final displayEvent = replyEvent != null && timeline != null - ? replyEvent.getDisplayEvent(timeline) - : replyEvent; + final timeline = this.timeline; + final displayEvent = + timeline != null ? replyEvent.getDisplayEvent(timeline) : replyEvent; final fontSize = AppConfig.messageFontSize * AppConfig.fontSizeFactor; - if (displayEvent != null && - AppConfig.renderHtml && + if (AppConfig.renderHtml && [EventTypes.Message, EventTypes.Encrypted] .contains(displayEvent.type) && [MessageTypes.Text, MessageTypes.Notice, MessageTypes.Emote] @@ -32,16 +34,16 @@ class ReplyContent extends StatelessWidget { !displayEvent.redacted && displayEvent.content['format'] == 'org.matrix.custom.html' && displayEvent.content['formatted_body'] is String) { - String html = displayEvent.content['formatted_body']; + String? html = displayEvent.content['formatted_body']; if (displayEvent.messageType == MessageTypes.Emote) { html = '* $html'; } replyBody = HtmlMessage( - html: html, + html: html!, defaultTextStyle: TextStyle( color: lightText ? Colors.white - : Theme.of(context).textTheme.bodyText2.color, + : Theme.of(context).textTheme.bodyText2!.color, fontSize: fontSize, ), maxLines: 1, @@ -50,18 +52,17 @@ class ReplyContent extends StatelessWidget { ); } else { replyBody = Text( - displayEvent?.getLocalizedBody( - MatrixLocals(L10n.of(context)), - withSenderNamePrefix: false, - hideReply: true, - ) ?? - '', + displayEvent.getLocalizedBody( + MatrixLocals(L10n.of(context)!), + withSenderNamePrefix: false, + hideReply: true, + ), overflow: TextOverflow.ellipsis, maxLines: 1, style: TextStyle( color: lightText ? Colors.white - : Theme.of(context).textTheme.bodyText2.color, + : Theme.of(context).textTheme.bodyText2!.color, fontSize: fontSize, ), ); @@ -81,7 +82,7 @@ class ReplyContent extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.center, children: [ Text( - (displayEvent?.sender?.calcDisplayname() ?? '') + ':', + displayEvent.sender.calcDisplayname() + ':', maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle( diff --git a/lib/pages/chat/events/state_message.dart b/lib/pages/chat/events/state_message.dart index 70cf2146..c10537ad 100644 --- a/lib/pages/chat/events/state_message.dart +++ b/lib/pages/chat/events/state_message.dart @@ -9,16 +9,16 @@ import '../../../config/app_config.dart'; class StateMessage extends StatelessWidget { final Event event; final void Function(String) unfold; - const StateMessage(this.event, {@required this.unfold, Key key}) + const StateMessage(this.event, {required this.unfold, Key? key}) : super(key: key); @override Widget build(BuildContext context) { - if (event.unsigned['im.fluffychat.collapsed_state_event'] == true) { + if (event.unsigned!['im.fluffychat.collapsed_state_event'] == true) { return Container(); } final int counter = - event.unsigned['im.fluffychat.collapsed_state_event_count'] ?? 0; + event.unsigned!['im.fluffychat.collapsed_state_event_count'] ?? 0; return Padding( padding: const EdgeInsets.symmetric( horizontal: 8.0, @@ -40,18 +40,18 @@ class StateMessage extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ Text( - event.getLocalizedBody(MatrixLocals(L10n.of(context))), + event.getLocalizedBody(MatrixLocals(L10n.of(context)!)), textAlign: TextAlign.center, style: TextStyle( fontSize: 14 * AppConfig.fontSizeFactor, - color: Theme.of(context).textTheme.bodyText2.color, + color: Theme.of(context).textTheme.bodyText2!.color, decoration: event.redacted ? TextDecoration.lineThrough : null, ), ), if (counter != 0) Text( - L10n.of(context).moreEvents(counter), + L10n.of(context)!.moreEvents(counter), style: TextStyle( fontWeight: FontWeight.bold, fontSize: 14 * AppConfig.fontSizeFactor, diff --git a/lib/pages/chat/events/sticker.dart b/lib/pages/chat/events/sticker.dart index 8be80cf8..4e1618e6 100644 --- a/lib/pages/chat/events/sticker.dart +++ b/lib/pages/chat/events/sticker.dart @@ -10,14 +10,14 @@ import 'image_bubble.dart'; class Sticker extends StatefulWidget { final Event event; - const Sticker(this.event, {Key key}) : super(key: key); + const Sticker(this.event, {Key? key}) : super(key: key); @override _StickerState createState() => _StickerState(); } class _StickerState extends State { - bool animated; + bool? animated; @override Widget build(BuildContext context) { @@ -31,7 +31,7 @@ class _StickerState extends State { showOkAlertDialog( context: context, message: widget.event.body, - okLabel: L10n.of(context).ok, + okLabel: L10n.of(context)!.ok, ); }, animated: animated ?? AppConfig.autoplayImages, diff --git a/lib/pages/chat/events/verification_request_content.dart b/lib/pages/chat/events/verification_request_content.dart index 4d912e68..423e418d 100644 --- a/lib/pages/chat/events/verification_request_content.dart +++ b/lib/pages/chat/events/verification_request_content.dart @@ -9,7 +9,8 @@ class VerificationRequestContent extends StatelessWidget { final Event event; final Timeline timeline; - const VerificationRequestContent({this.event, this.timeline, Key key}) + const VerificationRequestContent( + {required this.event, required this.timeline, Key? key}) : super(key: key); @override @@ -50,10 +51,10 @@ class VerificationRequestContent extends StatelessWidget { Text(canceled ? 'Error ${cancel.first.content.tryGet('code')}: ${cancel.first.content.tryGet('reason')}' : (fullyDone - ? L10n.of(context).verifySuccess + ? L10n.of(context)!.verifySuccess : (started - ? L10n.of(context).loadingPleaseWait - : L10n.of(context).newVerificationRequest))) + ? L10n.of(context)!.loadingPleaseWait + : L10n.of(context)!.newVerificationRequest))) ], ), ), diff --git a/lib/pages/chat/events/video_player.dart b/lib/pages/chat/events/video_player.dart index dcadf78e..9cbcb9bc 100644 --- a/lib/pages/chat/events/video_player.dart +++ b/lib/pages/chat/events/video_player.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'dart:io'; import 'package:flutter/foundation.dart'; diff --git a/lib/pages/chat/input_bar.dart b/lib/pages/chat/input_bar.dart index 1942265b..a465673a 100644 --- a/lib/pages/chat/input_bar.dart +++ b/lib/pages/chat/input_bar.dart @@ -15,19 +15,19 @@ import 'command_hints.dart'; class InputBar extends StatelessWidget { final Room room; - final int minLines; - final int maxLines; - final TextInputType keyboardType; - final TextInputAction textInputAction; - final ValueChanged onSubmitted; - final FocusNode focusNode; - final TextEditingController controller; - final InputDecoration decoration; - final ValueChanged onChanged; - final bool autofocus; + final int? minLines; + final int? maxLines; + final TextInputType? keyboardType; + final TextInputAction? textInputAction; + final ValueChanged? onSubmitted; + final FocusNode? focusNode; + final TextEditingController? controller; + final InputDecoration? decoration; + final ValueChanged? onChanged; + final bool? autofocus; const InputBar({ - this.room, + required this.room, this.minLines, this.maxLines, this.keyboardType, @@ -38,22 +38,23 @@ class InputBar extends StatelessWidget { this.onChanged, this.autofocus, this.textInputAction, - Key key, + Key? key, }) : super(key: key); - List> getSuggestions(String text) { - if (controller.selection.baseOffset != controller.selection.extentOffset || - controller.selection.baseOffset < 0) { + List> getSuggestions(String text) { + if (controller!.selection.baseOffset != + controller!.selection.extentOffset || + controller!.selection.baseOffset < 0) { return []; // no entries if there is selected text } final searchText = - controller.text.substring(0, controller.selection.baseOffset); - final ret = >[]; + controller!.text.substring(0, controller!.selection.baseOffset); + final List> ret = >[]; const maxResults = 30; final commandMatch = RegExp(r'^\/([\w]*)$').firstMatch(searchText); if (commandMatch != null) { - final commandSearch = commandMatch[1].toLowerCase(); + final commandSearch = commandMatch[1]!.toLowerCase(); for (final command in room.client.commands.keys) { if (command.contains(commandSearch)) { ret.add({ @@ -69,7 +70,7 @@ class InputBar extends StatelessWidget { RegExp(r'(?:\s|^):(?:([-\w]+)~)?([-\w]+)$').firstMatch(searchText); if (emojiMatch != null) { final packSearch = emojiMatch[1]; - final emoteSearch = emojiMatch[2].toLowerCase(); + final emoteSearch = emojiMatch[2]!.toLowerCase(); final emotePacks = room.getImagePacks(ImagePackUsage.emoticon); if (packSearch == null || packSearch.isEmpty) { for (final pack in emotePacks.entries) { @@ -93,16 +94,16 @@ class InputBar extends StatelessWidget { } } } else if (emotePacks[packSearch] != null) { - for (final emote in emotePacks[packSearch].images.entries) { + for (final emote in emotePacks[packSearch]!.images.entries) { if (emote.key.toLowerCase().contains(emoteSearch)) { ret.add({ 'type': 'emote', 'name': emote.key, 'pack': packSearch, 'pack_avatar_url': - emotePacks[packSearch].pack.avatarUrl?.toString(), + emotePacks[packSearch]!.pack.avatarUrl?.toString(), 'pack_display_name': - emotePacks[packSearch].pack.displayName ?? packSearch, + emotePacks[packSearch]!.pack.displayName ?? packSearch, 'mxc': emote.value.url.toString(), }); } @@ -114,11 +115,11 @@ class InputBar extends StatelessWidget { } final userMatch = RegExp(r'(?:\s|^)@([-\w]+)$').firstMatch(searchText); if (userMatch != null) { - final userSearch = userMatch[1].toLowerCase(); + final userSearch = userMatch[1]!.toLowerCase(); for (final user in room.getParticipants()) { if ((user.displayName != null && - (user.displayName.toLowerCase().contains(userSearch) || - slugify(user.displayName.toLowerCase()) + (user.displayName!.toLowerCase().contains(userSearch) || + slugify(user.displayName!.toLowerCase()) .contains(userSearch))) || user.id.split(':')[0].toLowerCase().contains(userSearch)) { ret.add({ @@ -136,7 +137,7 @@ class InputBar extends StatelessWidget { } final roomMatch = RegExp(r'(?:\s|^)#([-\w]+)$').firstMatch(searchText); if (roomMatch != null) { - final roomSearch = roomMatch[1].toLowerCase(); + final roomSearch = roomMatch[1]!.toLowerCase(); for (final r in room.client.rooms) { if (r.getState(EventTypes.RoomTombstone) != null) { continue; // we don't care about tombstoned rooms @@ -155,12 +156,10 @@ class InputBar extends StatelessWidget { .split(':')[0] .toLowerCase() .contains(roomSearch))))) || - (r.name != null && r.name.toLowerCase().contains(roomSearch))) { + (r.name.toLowerCase().contains(roomSearch))) { ret.add({ 'type': 'room', - 'mxid': (r.canonicalAlias != null && r.canonicalAlias.isNotEmpty) - ? r.canonicalAlias - : r.id, + 'mxid': (r.canonicalAlias.isNotEmpty) ? r.canonicalAlias : r.id, 'displayname': r.displayname, 'avatar_url': r.avatar?.toString(), }); @@ -175,14 +174,14 @@ class InputBar extends StatelessWidget { Widget buildSuggestion( BuildContext context, - Map suggestion, - Client client, + Map suggestion, + Client? client, ) { const size = 30.0; const padding = EdgeInsets.all(4.0); if (suggestion['type'] == 'command') { - final command = suggestion['name']; - final hint = commandHint(L10n.of(context), command); + final command = suggestion['name']!; + final hint = commandHint(L10n.of(context)!, command); return Tooltip( message: hint, waitDuration: const Duration(days: 1), // don't show on hover @@ -206,7 +205,7 @@ class InputBar extends StatelessWidget { } if (suggestion['type'] == 'emote') { final ratio = MediaQuery.of(context).devicePixelRatio; - final url = Uri.parse(suggestion['mxc'] ?? '')?.getThumbnail( + final url = Uri.parse(suggestion['mxc'] ?? '').getThumbnail( room.client, width: size * ratio, height: size * ratio, @@ -224,7 +223,7 @@ class InputBar extends StatelessWidget { height: size, ), const SizedBox(width: 6), - Text(suggestion['name']), + Text(suggestion['name']!), Expanded( child: Align( alignment: Alignment.centerRight, @@ -239,7 +238,7 @@ class InputBar extends StatelessWidget { size: size * 0.9, client: client, ) - : Text(suggestion['pack_display_name']), + : Text(suggestion['pack_display_name']!), ), ), ), @@ -262,7 +261,7 @@ class InputBar extends StatelessWidget { client: client, ), const SizedBox(width: 6), - Text(suggestion['displayname'] ?? suggestion['mxid']), + Text(suggestion['displayname'] ?? suggestion['mxid']!), ], ), ); @@ -270,16 +269,16 @@ class InputBar extends StatelessWidget { return Container(); } - void insertSuggestion(_, Map suggestion) { + void insertSuggestion(_, Map suggestion) { final replaceText = - controller.text.substring(0, controller.selection.baseOffset); + controller!.text.substring(0, controller!.selection.baseOffset); var startText = ''; - final afterText = replaceText == controller.text + final afterText = replaceText == controller!.text ? '' - : controller.text.substring(controller.selection.baseOffset + 1); + : controller!.text.substring(controller!.selection.baseOffset + 1); var insertText = ''; if (suggestion['type'] == 'command') { - insertText = suggestion['name'] + ' '; + insertText = suggestion['name']! + ' '; startText = replaceText.replaceAllMapped( RegExp(r'^(\/[\w]*)$'), (Match m) => '/' + insertText, @@ -304,29 +303,29 @@ class InputBar extends StatelessWidget { break; } } - insertText = ':${isUnique ? '' : insertPack + '~'}$insertEmote: '; + insertText = ':${isUnique ? '' : insertPack! + '~'}$insertEmote: '; startText = replaceText.replaceAllMapped( RegExp(r'(\s|^)(:(?:[-\w]+~)?[-\w]+)$'), (Match m) => '${m[1]}$insertText', ); } if (suggestion['type'] == 'user') { - insertText = suggestion['mention'] + ' '; + insertText = suggestion['mention']! + ' '; startText = replaceText.replaceAllMapped( RegExp(r'(\s|^)(@[-\w]+)$'), (Match m) => '${m[1]}$insertText', ); } if (suggestion['type'] == 'room') { - insertText = suggestion['mxid'] + ' '; + insertText = suggestion['mxid']! + ' '; startText = replaceText.replaceAllMapped( RegExp(r'(\s|^)(#[-\w]+)$'), (Match m) => '${m[1]}$insertText', ); } if (insertText.isNotEmpty && startText.isNotEmpty) { - controller.text = startText + afterText; - controller.selection = TextSelection( + controller!.text = startText + afterText; + controller!.selection = TextSelection( baseOffset: startText.length, extentOffset: startText.length, ); @@ -351,13 +350,13 @@ class InputBar extends StatelessWidget { ? {} : { NewLineIntent: CallbackAction(onInvoke: (i) { - final val = controller.value; + final val = controller!.value; final selection = val.selection.start; final messageWithoutNewLine = - controller.text.substring(0, val.selection.start) + + controller!.text.substring(0, val.selection.start) + '\n' + - controller.text.substring(val.selection.end); - controller.value = TextEditingValue( + controller!.text.substring(val.selection.end); + controller!.value = TextEditingValue( text: messageWithoutNewLine, selection: TextSelection.fromPosition( TextPosition(offset: selection + 1), @@ -366,11 +365,11 @@ class InputBar extends StatelessWidget { return null; }), SubmitLineIntent: CallbackAction(onInvoke: (i) { - onSubmitted(controller.text); + onSubmitted!(controller!.text); return null; }), }, - child: TypeAheadField>( + child: TypeAheadField>( direction: AxisDirection.up, hideOnEmpty: true, hideOnLoading: true, @@ -381,31 +380,31 @@ class InputBar extends StatelessWidget { textFieldConfiguration: TextFieldConfiguration( minLines: minLines, maxLines: maxLines, - keyboardType: keyboardType, + keyboardType: keyboardType!, textInputAction: textInputAction, - autofocus: autofocus, + autofocus: autofocus!, onSubmitted: (text) { // fix for library for now // it sets the types for the callback incorrectly - onSubmitted(text); + onSubmitted!(text); }, //focusNode: focusNode, controller: controller, - decoration: decoration, + decoration: decoration!, focusNode: focusNode, onChanged: (text) { // fix for the library for now // it sets the types for the callback incorrectly - onChanged(text); + onChanged!(text); }, textCapitalization: TextCapitalization.sentences, ), suggestionsCallback: getSuggestions, itemBuilder: (c, s) => buildSuggestion(c, s, Matrix.of(context).client), - onSuggestionSelected: (Map suggestion) => + onSuggestionSelected: (Map suggestion) => insertSuggestion(context, suggestion), - errorBuilder: (BuildContext context, Object error) => Container(), + errorBuilder: (BuildContext context, Object? error) => Container(), loadingBuilder: (BuildContext context) => Container(), // fix loading briefly flickering a dark box noItemsFoundBuilder: (BuildContext context) => diff --git a/lib/pages/chat/reactions_picker.dart b/lib/pages/chat/reactions_picker.dart index de023a7d..b43edb36 100644 --- a/lib/pages/chat/reactions_picker.dart +++ b/lib/pages/chat/reactions_picker.dart @@ -8,14 +8,14 @@ import 'package:fluffychat/pages/chat/chat.dart'; class ReactionsPicker extends StatelessWidget { final ChatController controller; - const ReactionsPicker(this.controller, {Key key}) : super(key: key); + const ReactionsPicker(this.controller, {Key? key}) : super(key: key); @override Widget build(BuildContext context) { if (controller.showEmojiPicker) return Container(); final display = controller.editEvent == null && controller.replyEvent == null && - controller.room.canSendDefaultMessages && + controller.room!.canSendDefaultMessages && controller.selectedEvents.isNotEmpty; return AnimatedContainer( duration: const Duration(milliseconds: 300), @@ -28,8 +28,9 @@ class ReactionsPicker extends StatelessWidget { } final emojis = List.from(AppEmojis.emojis); final allReactionEvents = controller.selectedEvents.first - .aggregatedEvents(controller.timeline, RelationshipTypes.reaction) - ?.where((event) => + .aggregatedEvents( + controller.timeline!, RelationshipTypes.reaction) + .where((event) => event.senderId == event.room.client.userID && event.type == 'm.reaction'); diff --git a/lib/pages/chat/recording_dialog.dart b/lib/pages/chat/recording_dialog.dart index 098cebf1..26cfefeb 100644 --- a/lib/pages/chat/recording_dialog.dart +++ b/lib/pages/chat/recording_dialog.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'dart:async'; import 'package:flutter/cupertino.dart'; diff --git a/lib/pages/chat/reply_display.dart b/lib/pages/chat/reply_display.dart index 4d0a09f8..29068d51 100644 --- a/lib/pages/chat/reply_display.dart +++ b/lib/pages/chat/reply_display.dart @@ -9,7 +9,7 @@ import 'events/reply_content.dart'; class ReplyDisplay extends StatelessWidget { final ChatController controller; - const ReplyDisplay(this.controller, {Key key}) : super(key: key); + const ReplyDisplay(this.controller, {Key? key}) : super(key: key); @override Widget build(BuildContext context) { @@ -23,16 +23,16 @@ class ReplyDisplay extends StatelessWidget { child: Row( children: [ IconButton( - tooltip: L10n.of(context).close, + tooltip: L10n.of(context)!.close, icon: const Icon(Icons.close), onPressed: controller.cancelReplyEventAction, ), Expanded( child: controller.replyEvent != null - ? ReplyContent(controller.replyEvent, - timeline: controller.timeline) + ? ReplyContent(controller.replyEvent!, + timeline: controller.timeline!) : _EditContent(controller.editEvent - ?.getDisplayEvent(controller.timeline)), + ?.getDisplayEvent(controller.timeline!)), ), ], ), @@ -42,7 +42,7 @@ class ReplyDisplay extends StatelessWidget { } class _EditContent extends StatelessWidget { - final Event event; + final Event? event; const _EditContent(this.event); @@ -60,7 +60,7 @@ class _EditContent extends StatelessWidget { Container(width: 15.0), Text( event?.getLocalizedBody( - MatrixLocals(L10n.of(context)), + MatrixLocals(L10n.of(context)!), withSenderNamePrefix: false, hideReply: true, ) ?? @@ -68,7 +68,7 @@ class _EditContent extends StatelessWidget { overflow: TextOverflow.ellipsis, maxLines: 1, style: TextStyle( - color: Theme.of(context).textTheme.bodyText2.color, + color: Theme.of(context).textTheme.bodyText2!.color, ), ), ], diff --git a/lib/pages/chat/seen_by_row.dart b/lib/pages/chat/seen_by_row.dart index 50c2650b..2a3ac52a 100644 --- a/lib/pages/chat/seen_by_row.dart +++ b/lib/pages/chat/seen_by_row.dart @@ -8,12 +8,12 @@ import 'package:fluffychat/widgets/matrix.dart'; class SeenByRow extends StatelessWidget { final ChatController controller; - const SeenByRow(this.controller, {Key key}) : super(key: key); + const SeenByRow(this.controller, {Key? key}) : super(key: key); @override Widget build(BuildContext context) { - final seenByUsers = controller.room.getSeenByUsers( - controller.timeline, + final seenByUsers = controller.room!.getSeenByUsers( + controller.timeline!, controller.filteredEvents, controller.unfolded, ); diff --git a/lib/pages/chat/send_file_dialog.dart b/lib/pages/chat/send_file_dialog.dart index 272210b3..ae7e403f 100644 --- a/lib/pages/chat/send_file_dialog.dart +++ b/lib/pages/chat/send_file_dialog.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; diff --git a/lib/pages/chat/send_location_dialog.dart b/lib/pages/chat/send_location_dialog.dart index 5abd36b2..4c82eaaa 100644 --- a/lib/pages/chat/send_location_dialog.dart +++ b/lib/pages/chat/send_location_dialog.dart @@ -15,8 +15,8 @@ class SendLocationDialog extends StatefulWidget { final Room room; const SendLocationDialog({ - this.room, - Key key, + required this.room, + Key? key, }) : super(key: key); @override @@ -27,8 +27,8 @@ class _SendLocationDialogState extends State { bool disabled = false; bool denied = false; bool isSending = false; - Position position; - Error error; + Position? position; + Object? error; @override void initState() { @@ -75,9 +75,9 @@ class _SendLocationDialogState extends State { void sendAction() async { setState(() => isSending = true); final body = - 'https://www.openstreetmap.org/?mlat=${position.latitude}&mlon=${position.longitude}#map=16/${position.latitude}/${position.longitude}'; + 'https://www.openstreetmap.org/?mlat=${position!.latitude}&mlon=${position!.longitude}#map=16/${position!.latitude}/${position!.longitude}'; final uri = - 'geo:${position.latitude},${position.longitude};u=${position.accuracy}'; + 'geo:${position!.latitude},${position!.longitude};u=${position!.accuracy}'; await showFutureLoadingDialog( context: context, future: () => widget.room.sendLocation(body, uri), @@ -90,16 +90,16 @@ class _SendLocationDialogState extends State { Widget contentWidget; if (position != null) { contentWidget = MapBubble( - latitude: position.latitude, - longitude: position.longitude, + latitude: position!.latitude, + longitude: position!.longitude, ); } else if (disabled) { - contentWidget = Text(L10n.of(context).locationDisabledNotice); + contentWidget = Text(L10n.of(context)!.locationDisabledNotice); } else if (denied) { - contentWidget = Text(L10n.of(context).locationPermissionDeniedNotice); + contentWidget = Text(L10n.of(context)!.locationPermissionDeniedNotice); } else if (error != null) { contentWidget = - Text(L10n.of(context).errorObtainingLocation(error.toString())); + Text(L10n.of(context)!.errorObtainingLocation(error.toString())); } else { contentWidget = Row( mainAxisSize: MainAxisSize.min, @@ -107,38 +107,38 @@ class _SendLocationDialogState extends State { children: [ const CupertinoActivityIndicator(), const SizedBox(width: 12), - Text(L10n.of(context).obtainingLocation), + Text(L10n.of(context)!.obtainingLocation), ], ); } if (PlatformInfos.isCupertinoStyle) { return CupertinoAlertDialog( - title: Text(L10n.of(context).shareLocation), + title: Text(L10n.of(context)!.shareLocation), content: contentWidget, actions: [ CupertinoDialogAction( onPressed: Navigator.of(context, rootNavigator: false).pop, - child: Text(L10n.of(context).cancel), + child: Text(L10n.of(context)!.cancel), ), CupertinoDialogAction( onPressed: isSending ? null : sendAction, - child: Text(L10n.of(context).send), + child: Text(L10n.of(context)!.send), ), ], ); } return AlertDialog( - title: Text(L10n.of(context).shareLocation), + title: Text(L10n.of(context)!.shareLocation), content: contentWidget, actions: [ TextButton( onPressed: Navigator.of(context, rootNavigator: false).pop, - child: Text(L10n.of(context).cancel), + child: Text(L10n.of(context)!.cancel), ), if (position != null) TextButton( onPressed: isSending ? null : sendAction, - child: Text(L10n.of(context).send), + child: Text(L10n.of(context)!.send), ), ], ); diff --git a/lib/pages/chat/sticker_picker_dialog.dart b/lib/pages/chat/sticker_picker_dialog.dart index 6f1feea4..9b8a2573 100644 --- a/lib/pages/chat/sticker_picker_dialog.dart +++ b/lib/pages/chat/sticker_picker_dialog.dart @@ -10,14 +10,14 @@ import 'events/image_bubble.dart'; class StickerPickerDialog extends StatefulWidget { final Room room; - const StickerPickerDialog({this.room, Key key}) : super(key: key); + const StickerPickerDialog({required this.room, Key? key}) : super(key: key); @override StickerPickerDialogState createState() => StickerPickerDialogState(); } class StickerPickerDialogState extends State { - String searchFilter; + String? searchFilter; @override Widget build(BuildContext context) { @@ -26,14 +26,14 @@ class StickerPickerDialogState extends State { // ignore: prefer_function_declarations_over_variables final _packBuilder = (BuildContext context, int packIndex) { - final pack = stickerPacks[packSlugs[packIndex]]; + final pack = stickerPacks[packSlugs[packIndex]]!; final filteredImagePackImageEntried = pack.images.entries.toList(); if (searchFilter?.isNotEmpty ?? false) { filteredImagePackImageEntried.removeWhere((e) => - !(e.key.toLowerCase().contains(searchFilter.toLowerCase()) || + !(e.key.toLowerCase().contains(searchFilter!.toLowerCase()) || (e.value.body ?.toLowerCase() - ?.contains(searchFilter.toLowerCase()) ?? + .contains(searchFilter!.toLowerCase()) ?? false))); } final imageKeys = @@ -62,7 +62,7 @@ class StickerPickerDialogState extends State { shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemBuilder: (BuildContext context, int imageIndex) { - final image = pack.images[imageKeys[imageIndex]]; + final image = pack.images[imageKeys[imageIndex]]!; final fakeEvent = Event.fromJson({ 'type': EventTypes.Sticker, 'content': { @@ -116,7 +116,7 @@ class StickerPickerDialogState extends State { ), title: DefaultAppBarSearchField( autofocus: false, - hintText: L10n.of(context).search, + hintText: L10n.of(context)!.search, suffix: const Icon(Icons.search_outlined), onChanged: (s) => setState(() => searchFilter = s), ), diff --git a/lib/pages/chat/tombstone_display.dart b/lib/pages/chat/tombstone_display.dart index a627b9c4..4bd0821d 100644 --- a/lib/pages/chat/tombstone_display.dart +++ b/lib/pages/chat/tombstone_display.dart @@ -7,11 +7,11 @@ import 'chat.dart'; class TombstoneDisplay extends StatelessWidget { final ChatController controller; - const TombstoneDisplay(this.controller, {Key key}) : super(key: key); + const TombstoneDisplay(this.controller, {Key? key}) : super(key: key); @override Widget build(BuildContext context) { - if (controller.room.getState(EventTypes.RoomTombstone) == null) { + if (controller.room!.getState(EventTypes.RoomTombstone) == null) { return Container(); } return SizedBox( @@ -26,14 +26,14 @@ class TombstoneDisplay extends StatelessWidget { child: const Icon(Icons.upgrade_outlined), ), title: Text( - controller.room - .getState(EventTypes.RoomTombstone) + controller.room! + .getState(EventTypes.RoomTombstone)! .parsedTombstoneContent .body, maxLines: 1, overflow: TextOverflow.ellipsis, ), - subtitle: Text(L10n.of(context).goToTheNewRoom), + subtitle: Text(L10n.of(context)!.goToTheNewRoom), onTap: controller.goToNewRoomAction, ), ), diff --git a/lib/pages/chat/typing_indicators.dart b/lib/pages/chat/typing_indicators.dart index f63a1479..1466040f 100644 --- a/lib/pages/chat/typing_indicators.dart +++ b/lib/pages/chat/typing_indicators.dart @@ -8,11 +8,11 @@ import 'package:fluffychat/widgets/matrix.dart'; class TypingIndicators extends StatelessWidget { final ChatController controller; - const TypingIndicators(this.controller, {Key key}) : super(key: key); + const TypingIndicators(this.controller, {Key? key}) : super(key: key); @override Widget build(BuildContext context) { - final typingUsers = controller.room.typingUsers + final typingUsers = controller.room!.typingUsers ..removeWhere((u) => u.stateKey == Matrix.of(context).client.userID); const topPadding = 20.0; const bottomPadding = 4.0; diff --git a/lib/pages/chat_details/chat_details.dart b/lib/pages/chat_details/chat_details.dart index 2566cf4d..650b627c 100644 --- a/lib/pages/chat_details/chat_details.dart +++ b/lib/pages/chat_details/chat_details.dart @@ -18,34 +18,34 @@ import 'package:fluffychat/widgets/matrix.dart'; enum AliasActions { copy, delete, setCanonical } class ChatDetails extends StatefulWidget { - const ChatDetails({Key key}) : super(key: key); + const ChatDetails({Key? key}) : super(key: key); @override ChatDetailsController createState() => ChatDetailsController(); } class ChatDetailsController extends State { - List members; + List? members; bool displaySettings = false; void toggleDisplaySettings() => setState(() => displaySettings = !displaySettings); - String get roomId => VRouter.of(context).pathParameters['roomid']; + String? get roomId => VRouter.of(context).pathParameters['roomid']; void setDisplaynameAction() async { - final room = Matrix.of(context).client.getRoomById(roomId); + final room = Matrix.of(context).client.getRoomById(roomId!)!; final input = await showTextInputDialog( useRootNavigator: false, context: context, - title: L10n.of(context).changeTheNameOfTheGroup, - okLabel: L10n.of(context).ok, - cancelLabel: L10n.of(context).cancel, + title: L10n.of(context)!.changeTheNameOfTheGroup, + okLabel: L10n.of(context)!.ok, + cancelLabel: L10n.of(context)!.cancel, textFields: [ DialogTextField( initialText: room.getLocalizedDisplayname( MatrixLocals( - L10n.of(context), + L10n.of(context)!, ), ), ) @@ -58,12 +58,12 @@ class ChatDetailsController extends State { ); if (success.error == null) { ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text(L10n.of(context).displaynameHasBeenChanged))); + SnackBar(content: Text(L10n.of(context)!.displaynameHasBeenChanged))); } } void editAliases() async { - final room = Matrix.of(context).client.getRoomById(roomId); + final room = Matrix.of(context).client.getRoomById(roomId!); // The current endpoint doesnt seem to be implemented in Synapse. This may // change in the future and then we just need to switch to this api call: @@ -76,7 +76,7 @@ class ChatDetailsController extends State { // While this is not working we use the unstable api: final aliases = await showFutureLoadingDialog( context: context, - future: () => room.client + future: () => room!.client .request( RequestType.GET, '/client/unstable/org.matrix.msc2432/rooms/${Uri.encodeComponent(room.id)}/aliases', @@ -86,21 +86,21 @@ class ChatDetailsController extends State { // Switch to the stable api once it is implemented. if (aliases.error != null) return; - final adminMode = room.canSendEvent('m.room.canonical_alias'); - if (aliases.result.isEmpty && (room.canonicalAlias?.isNotEmpty ?? false)) { - aliases.result.add(room.canonicalAlias); + final adminMode = room!.canSendEvent('m.room.canonical_alias'); + if (aliases.result!.isEmpty && (room.canonicalAlias.isNotEmpty)) { + aliases.result!.add(room.canonicalAlias); } - if (aliases.result.isEmpty && adminMode) { + if (aliases.result!.isEmpty && adminMode) { return setAliasAction(); } final select = await showConfirmationDialog( useRootNavigator: false, context: context, - title: L10n.of(context).editRoomAliases, + title: L10n.of(context)!.editRoomAliases, actions: [ if (adminMode) - AlertDialogAction(label: L10n.of(context).create, key: 'new'), - ...aliases.result + AlertDialogAction(label: L10n.of(context)!.create, key: 'new'), + ...aliases.result! .map((alias) => AlertDialogAction(key: alias, label: alias)) .toList(), ], @@ -114,29 +114,30 @@ class ChatDetailsController extends State { title: select, actions: [ AlertDialogAction( - label: L10n.of(context).copyToClipboard, + label: L10n.of(context)!.copyToClipboard, key: AliasActions.copy, isDefaultAction: true, ), if (adminMode) ...{ AlertDialogAction( - label: L10n.of(context).setAsCanonicalAlias, + label: L10n.of(context)!.setAsCanonicalAlias, key: AliasActions.setCanonical, isDestructiveAction: true, ), AlertDialogAction( - label: L10n.of(context).delete, + label: L10n.of(context)!.delete, key: AliasActions.delete, isDestructiveAction: true, ), }, ], ); + if (option == null) return; switch (option) { case AliasActions.copy: await Clipboard.setData(ClipboardData(text: select)); ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text(L10n.of(context).copiedToClipboard)), + SnackBar(content: Text(L10n.of(context)!.copiedToClipboard)), ); break; case AliasActions.delete: @@ -162,21 +163,21 @@ class ChatDetailsController extends State { } void setAliasAction() async { - final room = Matrix.of(context).client.getRoomById(roomId); - final domain = room.client.userID.domain; + final room = Matrix.of(context).client.getRoomById(roomId!)!; + final domain = room.client.userID!.domain; final input = await showTextInputDialog( useRootNavigator: false, context: context, - title: L10n.of(context).setInvitationLink, - okLabel: L10n.of(context).ok, - cancelLabel: L10n.of(context).cancel, + title: L10n.of(context)!.setInvitationLink, + okLabel: L10n.of(context)!.ok, + cancelLabel: L10n.of(context)!.cancel, textFields: [ DialogTextField( prefixText: '#', suffixText: domain, - hintText: L10n.of(context).alias, - initialText: room.canonicalAlias?.localpart, + hintText: L10n.of(context)!.alias, + initialText: room.canonicalAlias.localpart, ) ], ); @@ -184,21 +185,21 @@ class ChatDetailsController extends State { await showFutureLoadingDialog( context: context, future: () => - room.client.setRoomAlias('#' + input.single + ':' + domain, room.id), + room.client.setRoomAlias('#' + input.single + ':' + domain!, room.id), ); } void setTopicAction() async { - final room = Matrix.of(context).client.getRoomById(roomId); + final room = Matrix.of(context).client.getRoomById(roomId!)!; final input = await showTextInputDialog( useRootNavigator: false, context: context, - title: L10n.of(context).setGroupDescription, - okLabel: L10n.of(context).ok, - cancelLabel: L10n.of(context).cancel, + title: L10n.of(context)!.setGroupDescription, + okLabel: L10n.of(context)!.ok, + cancelLabel: L10n.of(context)!.cancel, textFields: [ DialogTextField( - hintText: L10n.of(context).setGroupDescription, + hintText: L10n.of(context)!.setGroupDescription, initialText: room.topic, minLines: 1, maxLines: 4, @@ -212,7 +213,7 @@ class ChatDetailsController extends State { ); if (success.error == null) { ScaffoldMessenger.of(context).showSnackBar(SnackBar( - content: Text(L10n.of(context).groupDescriptionHasBeenChanged))); + content: Text(L10n.of(context)!.groupDescriptionHasBeenChanged))); } } @@ -220,7 +221,7 @@ class ChatDetailsController extends State { context: context, future: () => Matrix.of(context) .client - .getRoomById(roomId) + .getRoomById(roomId!)! .setGuestAccess(guestAccess), ); @@ -229,7 +230,7 @@ class ChatDetailsController extends State { context: context, future: () => Matrix.of(context) .client - .getRoomById(roomId) + .getRoomById(roomId!)! .setHistoryVisibility(historyVisibility), ); @@ -237,12 +238,12 @@ class ChatDetailsController extends State { context: context, future: () => Matrix.of(context) .client - .getRoomById(roomId) + .getRoomById(roomId!)! .setJoinRules(joinRule), ); void goToEmoteSettings() async { - final room = Matrix.of(context).client.getRoomById(roomId); + final room = Matrix.of(context).client.getRoomById(roomId!)!; // okay, we need to test if there are any emote state events other than the default one // if so, we need to be directed to a selection screen for which pack we want to look at // otherwise, we just open the normal one. @@ -256,24 +257,24 @@ class ChatDetailsController extends State { } void setAvatarAction() async { - final room = Matrix.of(context).client.getRoomById(roomId); + final room = Matrix.of(context).client.getRoomById(roomId!); final actions = [ if (PlatformInfos.isMobile) SheetAction( key: AvatarAction.camera, - label: L10n.of(context).openCamera, + label: L10n.of(context)!.openCamera, isDefaultAction: true, icon: Icons.camera_alt_outlined, ), SheetAction( key: AvatarAction.file, - label: L10n.of(context).openGallery, + label: L10n.of(context)!.openGallery, icon: Icons.photo_outlined, ), if (room?.avatar != null) SheetAction( key: AvatarAction.remove, - label: L10n.of(context).delete, + label: L10n.of(context)!.delete, isDestructiveAction: true, icon: Icons.delete_outlined, ), @@ -282,14 +283,14 @@ class ChatDetailsController extends State { ? actions.single : await showModalActionSheet( context: context, - title: L10n.of(context).editRoomAvatar, + title: L10n.of(context)!.editRoomAvatar, actions: actions, ); if (action == null) return; if (action == AvatarAction.remove) { await showFutureLoadingDialog( context: context, - future: () => room.setAvatar(null), + future: () => room!.setAvatar(null), ); return; } @@ -309,22 +310,22 @@ class ChatDetailsController extends State { } else { final result = await FilePickerCross.importFromStorage(type: FileTypeCross.image); - if (result == null) return; + if (result.fileName == null) return; file = MatrixFile( bytes: result.toUint8List(), - name: result.fileName, + name: result.fileName!, ); } await showFutureLoadingDialog( context: context, - future: () => room.setAvatar(file), + future: () => room!.setAvatar(file), ); } void requestMoreMembersAction() async { - final room = Matrix.of(context).client.getRoomById(roomId); + final room = Matrix.of(context).client.getRoomById(roomId!); final participants = await showFutureLoadingDialog( - context: context, future: () => room.requestParticipants()); + context: context, future: () => room!.requestParticipants()); if (participants.error == null) { setState(() => members = participants.result); } @@ -334,7 +335,8 @@ class ChatDetailsController extends State { @override Widget build(BuildContext context) { - members ??= Matrix.of(context).client.getRoomById(roomId).getParticipants(); + members ??= + Matrix.of(context).client.getRoomById(roomId!)!.getParticipants(); return SizedBox( width: fixedWidth, child: ChatDetailsView(this), diff --git a/lib/pages/chat_details/chat_details_view.dart b/lib/pages/chat_details/chat_details_view.dart index ca15a4f7..3953e024 100644 --- a/lib/pages/chat_details/chat_details_view.dart +++ b/lib/pages/chat_details/chat_details_view.dart @@ -20,28 +20,28 @@ import '../../utils/url_launcher.dart'; class ChatDetailsView extends StatelessWidget { final ChatDetailsController controller; - const ChatDetailsView(this.controller, {Key key}) : super(key: key); + const ChatDetailsView(this.controller, {Key? key}) : super(key: key); @override Widget build(BuildContext context) { - final room = Matrix.of(context).client.getRoomById(controller.roomId); + final room = Matrix.of(context).client.getRoomById(controller.roomId!); if (room == null) { return Scaffold( appBar: AppBar( - title: Text(L10n.of(context).oopsSomethingWentWrong), + title: Text(L10n.of(context)!.oopsSomethingWentWrong), ), body: Center( - child: Text(L10n.of(context).youAreNoLongerParticipatingInThisChat), + child: Text(L10n.of(context)!.youAreNoLongerParticipatingInThisChat), ), ); } - controller.members.removeWhere((u) => u.membership == Membership.leave); - final actualMembersCount = (room.summary?.mInvitedMemberCount ?? 0) + - (room.summary?.mJoinedMemberCount ?? 0); + controller.members!.removeWhere((u) => u.membership == Membership.leave); + final actualMembersCount = (room.summary.mInvitedMemberCount ?? 0) + + (room.summary.mJoinedMemberCount ?? 0); final canRequestMoreMembers = - controller.members.length < actualMembersCount; - final iconColor = Theme.of(context).textTheme.bodyText1.color; + controller.members!.length < actualMembersCount; + final iconColor = Theme.of(context).textTheme.bodyText1!.color; return StreamBuilder( stream: room.onUpdate.stream, builder: (context, snapshot) { @@ -56,16 +56,16 @@ class ChatDetailsView extends StatelessWidget { VRouter.of(context).path.startsWith('/spaces/') ? VRouter.of(context).pop() : VRouter.of(context) - .toSegments(['rooms', controller.roomId]), + .toSegments(['rooms', controller.roomId!]), ), elevation: Theme.of(context).appBarTheme.elevation, expandedHeight: 300.0, floating: true, pinned: true, actions: [ - if (room.canonicalAlias?.isNotEmpty ?? false) + if (room.canonicalAlias.isNotEmpty) IconButton( - tooltip: L10n.of(context).share, + tooltip: L10n.of(context)!.share, icon: Icon(Icons.adaptive.share_outlined), onPressed: () => FluffyShare.share( AppConfig.inviteLinkPrefix + room.canonicalAlias, @@ -75,16 +75,17 @@ class ChatDetailsView extends StatelessWidget { ], title: Text( room.getLocalizedDisplayname( - MatrixLocals(L10n.of(context))), + MatrixLocals(L10n.of(context)!)), style: TextStyle( color: Theme.of(context) .appBarTheme - .titleTextStyle + .titleTextStyle! .color)), backgroundColor: Theme.of(context).appBarTheme.backgroundColor, flexibleSpace: FlexibleSpaceBar( - background: ContentBanner(room.avatar, + background: ContentBanner( + mxContent: room.avatar, onEdit: room.canSendEvent('m.room.avatar') ? controller.setAvatarAction : null), @@ -93,7 +94,7 @@ class ChatDetailsView extends StatelessWidget { ], body: MaxWidthBody( child: ListView.builder( - itemCount: controller.members.length + + itemCount: controller.members!.length + 1 + (canRequestMoreMembers ? 1 : 0), itemBuilder: (BuildContext context, int i) => i == 0 @@ -111,15 +112,15 @@ class ChatDetailsView extends StatelessWidget { ) : null, title: Text( - '${L10n.of(context).groupDescription}:', + '${L10n.of(context)!.groupDescription}:', style: TextStyle( color: Theme.of(context) .colorScheme .secondary, fontWeight: FontWeight.bold)), subtitle: LinkText( - text: room.topic?.isEmpty ?? true - ? L10n.of(context).addGroupDescription + text: room.topic.isEmpty + ? L10n.of(context)!.addGroupDescription : room.topic, linkStyle: const TextStyle(color: Colors.blueAccent), @@ -127,7 +128,7 @@ class ChatDetailsView extends StatelessWidget { fontSize: 14, color: Theme.of(context) .textTheme - .bodyText2 + .bodyText2! .color, ), onLinkTap: (url) => @@ -141,7 +142,7 @@ class ChatDetailsView extends StatelessWidget { const Divider(height: 1), ListTile( title: Text( - L10n.of(context).settings, + L10n.of(context)!.settings, style: TextStyle( color: Theme.of(context).colorScheme.secondary, @@ -163,10 +164,10 @@ class ChatDetailsView extends StatelessWidget { child: const Icon( Icons.people_outline_outlined), ), - title: Text( - L10n.of(context).changeTheNameOfTheGroup), + title: Text(L10n.of(context)! + .changeTheNameOfTheGroup), subtitle: Text(room.getLocalizedDisplayname( - MatrixLocals(L10n.of(context)))), + MatrixLocals(L10n.of(context)!))), onTap: controller.setDisplaynameAction, ), if (room.joinRules == JoinRules.public) @@ -178,11 +179,12 @@ class ChatDetailsView extends StatelessWidget { child: const Icon(Icons.link_outlined), ), onTap: controller.editAliases, - title: Text(L10n.of(context).editRoomAliases), + title: + Text(L10n.of(context)!.editRoomAliases), subtitle: Text( - (room.canonicalAlias?.isNotEmpty ?? false) + (room.canonicalAlias.isNotEmpty) ? room.canonicalAlias - : L10n.of(context).none), + : L10n.of(context)!.none), ), ListTile( leading: CircleAvatar( @@ -192,9 +194,9 @@ class ChatDetailsView extends StatelessWidget { child: const Icon( Icons.insert_emoticon_outlined), ), - title: Text(L10n.of(context).emoteSettings), + title: Text(L10n.of(context)!.emoteSettings), subtitle: - Text(L10n.of(context).setCustomEmotes), + Text(L10n.of(context)!.setCustomEmotes), onTap: controller.goToEmoteSettings, ), PopupMenuButton( @@ -206,14 +208,14 @@ class ChatDetailsView extends StatelessWidget { value: JoinRules.public, child: Text(JoinRules.public .getLocalizedString( - MatrixLocals(L10n.of(context)))), + MatrixLocals(L10n.of(context)!))), ), if (room.canChangeJoinRules) PopupMenuItem( value: JoinRules.invite, child: Text(JoinRules.invite .getLocalizedString( - MatrixLocals(L10n.of(context)))), + MatrixLocals(L10n.of(context)!))), ), ], child: ListTile( @@ -222,11 +224,11 @@ class ChatDetailsView extends StatelessWidget { .scaffoldBackgroundColor, foregroundColor: iconColor, child: const Icon(Icons.shield_outlined)), - title: Text(L10n.of(context) + title: Text(L10n.of(context)! .whoIsAllowedToJoinThisGroup), subtitle: Text( - room.joinRules.getLocalizedString( - MatrixLocals(L10n.of(context))), + room.joinRules!.getLocalizedString( + MatrixLocals(L10n.of(context)!)), ), ), ), @@ -240,21 +242,21 @@ class ChatDetailsView extends StatelessWidget { value: HistoryVisibility.invited, child: Text(HistoryVisibility.invited .getLocalizedString( - MatrixLocals(L10n.of(context)))), + MatrixLocals(L10n.of(context)!))), ), if (room.canChangeHistoryVisibility) PopupMenuItem( value: HistoryVisibility.joined, child: Text(HistoryVisibility.joined .getLocalizedString( - MatrixLocals(L10n.of(context)))), + MatrixLocals(L10n.of(context)!))), ), if (room.canChangeHistoryVisibility) PopupMenuItem( value: HistoryVisibility.shared, child: Text(HistoryVisibility.shared .getLocalizedString( - MatrixLocals(L10n.of(context)))), + MatrixLocals(L10n.of(context)!))), ), if (room.canChangeHistoryVisibility) PopupMenuItem( @@ -262,7 +264,7 @@ class ChatDetailsView extends StatelessWidget { child: Text(HistoryVisibility .worldReadable .getLocalizedString( - MatrixLocals(L10n.of(context)))), + MatrixLocals(L10n.of(context)!))), ), ], child: ListTile( @@ -273,12 +275,11 @@ class ChatDetailsView extends StatelessWidget { child: const Icon(Icons.visibility_outlined), ), - title: Text(L10n.of(context) + title: Text(L10n.of(context)! .visibilityOfTheChatHistory), subtitle: Text( - room.historyVisibility.getLocalizedString( - MatrixLocals(L10n.of(context))) ?? - '', + room.historyVisibility!.getLocalizedString( + MatrixLocals(L10n.of(context)!)), ), ), ), @@ -293,7 +294,7 @@ class ChatDetailsView extends StatelessWidget { child: Text( GuestAccess.canJoin .getLocalizedString(MatrixLocals( - L10n.of(context))), + L10n.of(context)!)), ), ), if (room.canChangeGuestAccess) @@ -302,7 +303,7 @@ class ChatDetailsView extends StatelessWidget { child: Text( GuestAccess.forbidden .getLocalizedString(MatrixLocals( - L10n.of(context))), + L10n.of(context)!)), ), ), ], @@ -314,19 +315,19 @@ class ChatDetailsView extends StatelessWidget { child: const Icon( Icons.person_add_alt_1_outlined), ), - title: Text(L10n.of(context) + title: Text(L10n.of(context)! .areGuestsAllowedToJoin), subtitle: Text( room.guestAccess.getLocalizedString( - MatrixLocals(L10n.of(context))), + MatrixLocals(L10n.of(context)!)), ), ), ), ListTile( title: - Text(L10n.of(context).editChatPermissions), + Text(L10n.of(context)!.editChatPermissions), subtitle: Text( - L10n.of(context).whoCanPerformWhichAction), + L10n.of(context)!.whoCanPerformWhichAction), leading: CircleAvatar( backgroundColor: Theme.of(context).scaffoldBackgroundColor, @@ -342,9 +343,9 @@ class ChatDetailsView extends StatelessWidget { ListTile( title: Text( actualMembersCount > 1 - ? L10n.of(context).countParticipants( + ? L10n.of(context)!.countParticipants( actualMembersCount.toString()) - : L10n.of(context).emptyChat, + : L10n.of(context)!.emptyChat, style: TextStyle( color: Theme.of(context).colorScheme.secondary, @@ -354,7 +355,8 @@ class ChatDetailsView extends StatelessWidget { ), room.canInvite ? ListTile( - title: Text(L10n.of(context).inviteContact), + title: + Text(L10n.of(context)!.inviteContact), leading: CircleAvatar( backgroundColor: Theme.of(context).primaryColor, @@ -368,13 +370,13 @@ class ChatDetailsView extends StatelessWidget { : Container(), ], ) - : i < controller.members.length + 1 - ? ParticipantListItem(controller.members[i - 1]) + : i < controller.members!.length + 1 + ? ParticipantListItem(controller.members![i - 1]) : ListTile( - title: Text(L10n.of(context) + title: Text(L10n.of(context)! .loadCountMoreParticipants( (actualMembersCount - - controller.members.length) + controller.members!.length) .toString())), leading: CircleAvatar( backgroundColor: diff --git a/lib/pages/chat_details/participant_list_item.dart b/lib/pages/chat_details/participant_list_item.dart index bbaf3b50..20499b1d 100644 --- a/lib/pages/chat_details/participant_list_item.dart +++ b/lib/pages/chat_details/participant_list_item.dart @@ -9,20 +9,20 @@ import '../user_bottom_sheet/user_bottom_sheet.dart'; class ParticipantListItem extends StatelessWidget { final User user; - const ParticipantListItem(this.user, {Key key}) : super(key: key); + const ParticipantListItem(this.user, {Key? key}) : super(key: key); @override Widget build(BuildContext context) { final membershipBatch = { Membership.join: '', - Membership.ban: L10n.of(context).banned, - Membership.invite: L10n.of(context).invited, - Membership.leave: L10n.of(context).leftTheChat, + Membership.ban: L10n.of(context)!.banned, + Membership.invite: L10n.of(context)!.invited, + Membership.leave: L10n.of(context)!.leftTheChat, }; final permissionBatch = user.powerLevel == 100 - ? L10n.of(context).admin + ? L10n.of(context)!.admin : user.powerLevel >= 50 - ? L10n.of(context).moderator + ? L10n.of(context)!.moderator : ''; return Opacity( @@ -49,7 +49,7 @@ class ParticipantListItem extends StatelessWidget { ), child: Center(child: Text(permissionBatch)), ), - membershipBatch[user.membership].isEmpty + membershipBatch[user.membership]!.isEmpty ? Container() : Container( padding: const EdgeInsets.all(4), @@ -59,7 +59,7 @@ class ParticipantListItem extends StatelessWidget { borderRadius: BorderRadius.circular(8), ), child: - Center(child: Text(membershipBatch[user.membership])), + Center(child: Text(membershipBatch[user.membership]!)), ), ], ), diff --git a/lib/pages/chat_encryption_settings/chat_encryption_settings.dart b/lib/pages/chat_encryption_settings/chat_encryption_settings.dart index d70f9e83..5892cf9b 100644 --- a/lib/pages/chat_encryption_settings/chat_encryption_settings.dart +++ b/lib/pages/chat_encryption_settings/chat_encryption_settings.dart @@ -9,7 +9,7 @@ import 'package:fluffychat/widgets/matrix.dart'; import '../key_verification/key_verification_dialog.dart'; class ChatEncryptionSettings extends StatefulWidget { - const ChatEncryptionSettings({Key key}) : super(key: key); + const ChatEncryptionSettings({Key? key}) : super(key: key); @override ChatEncryptionSettingsController createState() => @@ -17,7 +17,7 @@ class ChatEncryptionSettings extends StatefulWidget { } class ChatEncryptionSettingsController extends State { - String get roomId => VRouter.of(context).pathParameters['roomid']; + String? get roomId => VRouter.of(context).pathParameters['roomid']; Future unblock(DeviceKeys key) async { if (key.blocked) { @@ -27,14 +27,14 @@ class ChatEncryptionSettingsController extends State { Future onSelected( BuildContext context, String action, DeviceKeys key) async { - final room = Matrix.of(context).client.getRoomById(roomId); + final room = Matrix.of(context).client.getRoomById(roomId!); switch (action) { case 'verify': await unblock(key); final req = key.startVerification(); req.onUpdate = () { if (req.state == KeyVerificationState.done) { - setState(() => null); + setState(() {}); } }; await KeyVerificationDialog(request: req).show(context); @@ -42,10 +42,10 @@ class ChatEncryptionSettingsController extends State { case 'verify_user': await unblock(key); final req = - await room.client.userDeviceKeys[key.userId].startVerification(); + await room!.client.userDeviceKeys[key.userId]!.startVerification(); req.onUpdate = () { if (req.state == KeyVerificationState.done) { - setState(() => null); + setState(() {}); } }; await KeyVerificationDialog(request: req).show(context); @@ -55,11 +55,11 @@ class ChatEncryptionSettingsController extends State { await key.setVerified(false); } await key.setBlocked(true); - setState(() => null); + setState(() {}); break; case 'unblock': await unblock(key); - setState(() => null); + setState(() {}); break; } } 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 37f18c03..8da5698a 100644 --- a/lib/pages/chat_encryption_settings/chat_encryption_settings_view.dart +++ b/lib/pages/chat_encryption_settings/chat_encryption_settings_view.dart @@ -13,21 +13,21 @@ import '../../utils/matrix_sdk_extensions.dart/device_extension.dart'; class ChatEncryptionSettingsView extends StatelessWidget { final ChatEncryptionSettingsController controller; - const ChatEncryptionSettingsView(this.controller, {Key key}) + const ChatEncryptionSettingsView(this.controller, {Key? key}) : super(key: key); @override Widget build(BuildContext context) { - final room = Matrix.of(context).client.getRoomById(controller.roomId); + final room = Matrix.of(context).client.getRoomById(controller.roomId!)!; return Scaffold( appBar: AppBar( leading: IconButton( icon: const Icon(Icons.close_outlined), onPressed: () => - VRouter.of(context).toSegments(['rooms', controller.roomId]), + VRouter.of(context).toSegments(['rooms', controller.roomId!]), ), - title: Text(L10n.of(context).tapOnDeviceToVerify), + title: Text(L10n.of(context)!.tapOnDeviceToVerify), elevation: 0, ), body: MaxWidthBody( @@ -36,7 +36,7 @@ class ChatEncryptionSettingsView extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ ListTile( - title: Text(L10n.of(context).deviceVerifyDescription), + title: Text(L10n.of(context)!.deviceVerifyDescription), leading: CircleAvatar( backgroundColor: Theme.of(context).secondaryHeaderColor, foregroundColor: Theme.of(context).colorScheme.secondary, @@ -52,7 +52,7 @@ class ChatEncryptionSettingsView extends StatelessWidget { builder: (BuildContext context, snapshot) { if (snapshot.hasError) { return Center( - child: Text(L10n.of(context).oopsSomethingWentWrong + + child: Text(L10n.of(context)!.oopsSomethingWentWrong + ': ' + snapshot.error.toString()), ); @@ -62,7 +62,7 @@ class ChatEncryptionSettingsView extends StatelessWidget { child: CircularProgressIndicator.adaptive( strokeWidth: 2)); } - final deviceKeys = snapshot.data; + final deviceKeys = snapshot.data!; return ListView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), @@ -75,18 +75,18 @@ class ChatEncryptionSettingsView extends StatelessWidget { deviceKeys[i - 1].userId) ...{ const Divider(height: 1, thickness: 1), PopupMenuButton( - onSelected: (action) => controller.onSelected( - context, action, deviceKeys[i]), + onSelected: (dynamic action) => controller + .onSelected(context, action, deviceKeys[i]), itemBuilder: (c) { final items = >[]; if (room .client - .userDeviceKeys[deviceKeys[i].userId] + .userDeviceKeys[deviceKeys[i].userId]! .verified == UserVerifiedStatus.unknown) { items.add(PopupMenuItem( value: 'verify_user', - child: Text(L10n.of(context).verifyUser), + child: Text(L10n.of(context)!.verifyUser), )); } return items; @@ -114,8 +114,8 @@ class ChatEncryptionSettingsView extends StatelessWidget { ), }, PopupMenuButton( - onSelected: (action) => controller.onSelected( - context, action, deviceKeys[i]), + onSelected: (dynamic action) => controller + .onSelected(context, action, deviceKeys[i]), itemBuilder: (c) { final items = >[]; if (deviceKeys[i].blocked || @@ -125,19 +125,20 @@ class ChatEncryptionSettingsView extends StatelessWidget { room.client.userID ? 'verify' : 'verify_user', - child: Text(L10n.of(context).verifyStart), + child: Text(L10n.of(context)!.verifyStart), )); } if (deviceKeys[i].blocked) { items.add(PopupMenuItem( value: 'unblock', - child: Text(L10n.of(context).unblockDevice), + child: + Text(L10n.of(context)!.unblockDevice), )); } if (!deviceKeys[i].blocked) { items.add(PopupMenuItem( value: 'block', - child: Text(L10n.of(context).blockDevice), + child: Text(L10n.of(context)!.blockDevice), )); } return items; @@ -156,17 +157,17 @@ class ChatEncryptionSettingsView extends StatelessWidget { subtitle: Row( children: [ Text( - deviceKeys[i].deviceId, + deviceKeys[i].deviceId!, style: const TextStyle( fontWeight: FontWeight.w300), ), const Spacer(), Text( deviceKeys[i].blocked - ? L10n.of(context).blocked + ? L10n.of(context)!.blocked : deviceKeys[i].verified - ? L10n.of(context).verified - : L10n.of(context).unverified, + ? L10n.of(context)!.verified + : L10n.of(context)!.unverified, style: TextStyle( fontSize: 14, color: deviceKeys[i].color, diff --git a/lib/pages/chat_list/chat_list.dart b/lib/pages/chat_list/chat_list.dart index b94d5ef8..f5518b89 100644 --- a/lib/pages/chat_list/chat_list.dart +++ b/lib/pages/chat_list/chat_list.dart @@ -34,25 +34,28 @@ enum PopupMenuAction { } class ChatList extends StatefulWidget { - const ChatList({Key key}) : super(key: key); + const ChatList({Key? key}) : super(key: key); @override ChatListController createState() => ChatListController(); } class ChatListController extends State { - StreamSubscription _intentDataStreamSubscription; + StreamSubscription? _intentDataStreamSubscription; - StreamSubscription _intentFileStreamSubscription; + StreamSubscription? _intentFileStreamSubscription; - StreamSubscription _intentUriStreamSubscription; + StreamSubscription? _intentUriStreamSubscription; - String _activeSpaceId; + String? _activeSpaceId; + + String? get activeSpaceId { + final id = _activeSpaceId; + return id != null && Matrix.of(context).client.getRoomById(id) == null + ? null + : _activeSpaceId; + } - String get activeSpaceId => - Matrix.of(context).client.getRoomById(_activeSpaceId) == null - ? null - : _activeSpaceId; final ScrollController scrollController = ScrollController(); bool scrolledToTop = true; @@ -69,12 +72,12 @@ class ChatListController extends State { } } - void setActiveSpaceId(BuildContext context, String spaceId) { + void setActiveSpaceId(BuildContext context, String? spaceId) { setState(() => _activeSpaceId = spaceId); } void editSpace(BuildContext context, String spaceId) async { - await Matrix.of(context).client.getRoomById(spaceId).postLoad(); + await Matrix.of(context).client.getRoomById(spaceId)!.postLoad(); VRouter.of(context).toSegments(['spaces', spaceId]); } @@ -82,7 +85,7 @@ class ChatListController extends State { Matrix.of(context).client.rooms.where((r) => r.isSpace).toList(); final selectedRoomIds = {}; - bool crossSigningCached; + bool? crossSigningCached; bool showChatBackupBanner = false; void firstRunBootstrapAction() async { @@ -96,7 +99,7 @@ class ChatListController extends State { VRouter.of(context).to('/rooms'); } - String get activeChat => VRouter.of(context).pathParameters['roomid']; + String? get activeChat => VRouter.of(context).pathParameters['roomid']; SelectMode get selectMode => Matrix.of(context).shareContent != null ? SelectMode.share @@ -105,7 +108,7 @@ class ChatListController extends State { : SelectMode.select; void _processIncomingSharedFiles(List files) { - if (files?.isEmpty ?? true) return; + if (files.isEmpty) return; VRouter.of(context).to('/rooms'); final file = File(files.first.path); @@ -118,7 +121,7 @@ class ChatListController extends State { }; } - void _processIncomingSharedText(String text) { + void _processIncomingSharedText(String? text) { if (text == null) return; VRouter.of(context).to('/rooms'); if (text.toLowerCase().startsWith(AppConfig.deepLinkPrefix) || @@ -133,10 +136,10 @@ class ChatListController extends State { }; } - void _processIncomingUris(String text) async { + void _processIncomingUris(String? text) async { if (text == null) return; VRouter.of(context).to('/rooms'); - WidgetsBinding.instance.addPostFrameCallback((_) { + WidgetsBinding.instance!.addPostFrameCallback((_) { UrlLauncher(context, text).openMatrixToUrl(); }); } @@ -180,10 +183,10 @@ class ChatListController extends State { await Matrix.of(context).client.accountDataLoading; await Matrix.of(context).client.userDeviceKeysLoading; final crossSigning = - await Matrix.of(context).client.encryption?.crossSigning?.isCached() ?? + await Matrix.of(context).client.encryption?.crossSigning.isCached() ?? false; final needsBootstrap = - Matrix.of(context).client.encryption?.crossSigning?.enabled == false || + Matrix.of(context).client.encryption?.crossSigning.enabled == false || crossSigning == false; final isUnknownSession = Matrix.of(context).client.isUnknownSession; if (needsBootstrap || isUnknownSession) { @@ -206,23 +209,21 @@ class ChatListController extends State { if (room.isSpace && room.membership == Membership.join && !room.isUnread) { return false; } - if (room.getState(EventTypes.RoomCreate)?.content?.tryGet('type') == + if (room.getState(EventTypes.RoomCreate)?.content.tryGet('type') == ClientStoriesExtension.storiesRoomType) { return false; } if (activeSpaceId != null) { - final space = Matrix.of(context).client.getRoomById(activeSpaceId); - if (space.spaceChildren?.any((child) => child.roomId == room.id) ?? - false) { + final space = Matrix.of(context).client.getRoomById(activeSpaceId!)!; + if (space.spaceChildren.any((child) => child.roomId == room.id)) { return true; } - if (room.spaceParents?.any((parent) => parent.roomId == activeSpaceId) ?? - false) { + if (room.spaceParents.any((parent) => parent.roomId == activeSpaceId)) { return true; } if (room.isDirectChat && - room.summary?.mHeroes != null && - room.summary.mHeroes.any((userId) { + room.summary.mHeroes != null && + room.summary.mHeroes!.any((userId) { final user = space.getState(EventTypes.RoomMember, userId)?.asUser; return user != null && user.membership == Membership.join; })) { @@ -246,9 +247,9 @@ class ChatListController extends State { final markUnread = anySelectedRoomNotMarkedUnread; final client = Matrix.of(context).client; for (final roomId in selectedRoomIds) { - final room = client.getRoomById(roomId); + final room = client.getRoomById(roomId)!; if (room.markedUnread == markUnread) continue; - await client.getRoomById(roomId).markUnread(markUnread); + await client.getRoomById(roomId)!.markUnread(markUnread); } }, ); @@ -262,9 +263,9 @@ class ChatListController extends State { final makeFavorite = anySelectedRoomNotFavorite; final client = Matrix.of(context).client; for (final roomId in selectedRoomIds) { - final room = client.getRoomById(roomId); + final room = client.getRoomById(roomId)!; if (room.isFavourite == makeFavorite) continue; - await client.getRoomById(roomId).setFavourite(makeFavorite); + await client.getRoomById(roomId)!.setFavourite(makeFavorite); } }, ); @@ -280,9 +281,9 @@ class ChatListController extends State { : PushRuleState.notify; final client = Matrix.of(context).client; for (final roomId in selectedRoomIds) { - final room = client.getRoomById(roomId); + final room = client.getRoomById(roomId)!; if (room.pushRuleState == newState) continue; - await client.getRoomById(roomId).setPushRuleState(newState); + await client.getRoomById(roomId)!.setPushRuleState(newState); } }, ); @@ -293,9 +294,9 @@ class ChatListController extends State { final confirmed = await showOkCancelAlertDialog( useRootNavigator: false, context: context, - title: L10n.of(context).areYouSure, - okLabel: L10n.of(context).yes, - cancelLabel: L10n.of(context).cancel, + title: L10n.of(context)!.areYouSure, + okLabel: L10n.of(context)!.yes, + cancelLabel: L10n.of(context)!.cancel, ) == OkCancelResult.ok; if (!confirmed) return; @@ -303,26 +304,26 @@ class ChatListController extends State { context: context, future: () => _archiveSelectedRooms(), ); - setState(() => null); + setState(() {}); } void setStatus() async { final input = await showTextInputDialog( useRootNavigator: false, context: context, - title: L10n.of(context).setStatus, - okLabel: L10n.of(context).ok, - cancelLabel: L10n.of(context).cancel, + title: L10n.of(context)!.setStatus, + okLabel: L10n.of(context)!.ok, + cancelLabel: L10n.of(context)!.cancel, textFields: [ DialogTextField( - hintText: L10n.of(context).statusExampleMessage, + hintText: L10n.of(context)!.statusExampleMessage, ), ]); if (input == null) return; await showFutureLoadingDialog( context: context, future: () => Matrix.of(context).client.setPresence( - Matrix.of(context).client.userID, + Matrix.of(context).client.userID!, PresenceType.online, statusMsg: input.single, ), @@ -339,7 +340,7 @@ class ChatListController extends State { break; case PopupMenuAction.invite: FluffyShare.share( - L10n.of(context).inviteText(Matrix.of(context).client.userID, + L10n.of(context)!.inviteText(Matrix.of(context).client.userID!, 'https://matrix.to/#/${Matrix.of(context).client.userID}?client=im.fluffychat'), context); break; @@ -360,7 +361,7 @@ class ChatListController extends State { while (selectedRoomIds.isNotEmpty) { final roomId = selectedRoomIds.first; try { - await client.getRoomById(roomId).leave(); + await client.getRoomById(roomId)!.leave(); } finally { toggleSelection(roomId); } @@ -371,36 +372,36 @@ class ChatListController extends State { if (activeSpaceId != null) { final consent = await showOkCancelAlertDialog( context: context, - title: L10n.of(context).removeFromSpace, - message: L10n.of(context).removeFromSpaceDescription, - okLabel: L10n.of(context).remove, - cancelLabel: L10n.of(context).cancel, + title: L10n.of(context)!.removeFromSpace, + message: L10n.of(context)!.removeFromSpaceDescription, + okLabel: L10n.of(context)!.remove, + cancelLabel: L10n.of(context)!.cancel, isDestructiveAction: true, fullyCapitalizedForMaterial: false, ); if (consent != OkCancelResult.ok) return; - final space = Matrix.of(context).client.getRoomById(activeSpaceId); + final space = Matrix.of(context).client.getRoomById(activeSpaceId!); final result = await showFutureLoadingDialog( context: context, future: () async { for (final roomId in selectedRoomIds) { - await space.removeSpaceChild(roomId); + await space!.removeSpaceChild(roomId); } }, ); if (result.error == null) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: Text(L10n.of(context).chatHasBeenRemovedFromThisSpace), + content: Text(L10n.of(context)!.chatHasBeenRemovedFromThisSpace), ), ); } } else { final selectedSpace = await showConfirmationDialog( context: context, - title: L10n.of(context).addToSpace, - message: L10n.of(context).addToSpaceDescription, + title: L10n.of(context)!.addToSpace, + message: L10n.of(context)!.addToSpaceDescription, fullyCapitalizedForMaterial: false, actions: Matrix.of(context) .client @@ -417,7 +418,7 @@ class ChatListController extends State { final result = await showFutureLoadingDialog( context: context, future: () async { - final space = Matrix.of(context).client.getRoomById(selectedSpace); + final space = Matrix.of(context).client.getRoomById(selectedSpace)!; if (space.canSendDefaultStates) { for (final roomId in selectedRoomIds) { await space.setSpaceChild(roomId); @@ -428,7 +429,7 @@ class ChatListController extends State { if (result.error == null) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: Text(L10n.of(context).chatHasBeenAddedToThisSpace), + content: Text(L10n.of(context)!.chatHasBeenAddedToThisSpace), ), ); } @@ -437,13 +438,13 @@ class ChatListController extends State { } bool get anySelectedRoomNotMarkedUnread => selectedRoomIds.any( - (roomId) => !Matrix.of(context).client.getRoomById(roomId).markedUnread); + (roomId) => !Matrix.of(context).client.getRoomById(roomId)!.markedUnread); bool get anySelectedRoomNotFavorite => selectedRoomIds.any( - (roomId) => !Matrix.of(context).client.getRoomById(roomId).isFavourite); + (roomId) => !Matrix.of(context).client.getRoomById(roomId)!.isFavourite); bool get anySelectedRoomNotMuted => selectedRoomIds.any((roomId) => - Matrix.of(context).client.getRoomById(roomId).pushRuleState == + Matrix.of(context).client.getRoomById(roomId)!.pushRuleState == PushRuleState.notify); bool waitForFirstSync = false; @@ -457,10 +458,10 @@ class ChatListController extends State { } // Load space members to display DM rooms if (activeSpaceId != null) { - final space = client.getRoomById(activeSpaceId); + final space = client.getRoomById(activeSpaceId!)!; final localMembers = space.getParticipants().length; - final actualMembersCount = (space.summary?.mInvitedMemberCount ?? 0) + - (space.summary?.mJoinedMemberCount ?? 0); + final actualMembersCount = (space.summary.mInvitedMemberCount ?? 0) + + (space.summary.mJoinedMemberCount ?? 0); if (localMembers < actualMembersCount) { await space.requestParticipants(); } @@ -468,7 +469,7 @@ class ChatListController extends State { setState(() { waitForFirstSync = true; }); - WidgetsBinding.instance.addPostFrameCallback((_) => checkBootstrap()); + WidgetsBinding.instance!.addPostFrameCallback((_) => checkBootstrap()); return; } @@ -481,7 +482,6 @@ class ChatListController extends State { } void setActiveClient(Client client) { - if (client == null) return; VRouter.of(context).to('/rooms'); setState(() { _activeSpaceId = null; @@ -498,30 +498,30 @@ class ChatListController extends State { selectedRoomIds.clear(); Matrix.of(context).activeBundle = bundle; if (!Matrix.of(context) - .currentBundle + .currentBundle! .any((client) => client == Matrix.of(context).client)) { Matrix.of(context) - .setActiveClient(Matrix.of(context).currentBundle.first); + .setActiveClient(Matrix.of(context).currentBundle!.first); } }); } - void editBundlesForAccount(String userId, String activeBundle) async { + void editBundlesForAccount(String? userId, String? activeBundle) async { final client = Matrix.of(context) .widget - .clients[Matrix.of(context).getClientIndexByMatrixId(userId)]; + .clients[Matrix.of(context).getClientIndexByMatrixId(userId!)]; final action = await showConfirmationDialog( context: context, - title: L10n.of(context).editBundlesForAccount, + title: L10n.of(context)!.editBundlesForAccount, actions: [ AlertDialogAction( key: EditBundleAction.addToBundle, - label: L10n.of(context).addToBundle, + label: L10n.of(context)!.addToBundle, ), if (activeBundle != client.userID) AlertDialogAction( key: EditBundleAction.removeFromBundle, - label: L10n.of(context).removeFromBundle, + label: L10n.of(context)!.removeFromBundle, ), ], ); @@ -530,9 +530,9 @@ class ChatListController extends State { case EditBundleAction.addToBundle: final bundle = await showTextInputDialog( context: context, - title: L10n.of(context).bundleName, + title: L10n.of(context)!.bundleName, textFields: [ - DialogTextField(hintText: L10n.of(context).bundleName) + DialogTextField(hintText: L10n.of(context)!.bundleName) ]); if (bundle == null || bundle.isEmpty || bundle.single.isEmpty) return; await showFutureLoadingDialog( @@ -543,7 +543,7 @@ class ChatListController extends State { case EditBundleAction.removeFromBundle: await showFutureLoadingDialog( context: context, - future: () => client.removeFromAccountBundle(activeBundle), + future: () => client.removeFromAccountBundle(activeBundle!), ); } } @@ -552,7 +552,7 @@ class ChatListController extends State { Matrix.of(context).hasComplexBundles && Matrix.of(context).accountBundles.keys.length > 1; - String get secureActiveBundle { + String? get secureActiveBundle { if (Matrix.of(context).activeBundle == null || !Matrix.of(context) .accountBundles @@ -564,7 +564,7 @@ class ChatListController extends State { } void resetActiveBundle() { - WidgetsBinding.instance.addPostFrameCallback((timeStamp) { + WidgetsBinding.instance!.addPostFrameCallback((timeStamp) { setState(() { Matrix.of(context).activeBundle = null; }); diff --git a/lib/pages/chat_list/chat_list_item.dart b/lib/pages/chat_list/chat_list_item.dart index b82210a8..eac9a04a 100644 --- a/lib/pages/chat_list/chat_list_item.dart +++ b/lib/pages/chat_list/chat_list_item.dart @@ -21,9 +21,9 @@ class ChatListItem extends StatelessWidget { final Room room; final bool activeChat; final bool selected; - final Function onForget; - final Function onTap; - final Function onLongPress; + final Function? onForget; + final Function? onTap; + final Function? onLongPress; const ChatListItem( this.room, { @@ -32,11 +32,11 @@ class ChatListItem extends StatelessWidget { this.onTap, this.onLongPress, this.onForget, - Key key, + Key? key, }) : super(key: key); dynamic clickAction(BuildContext context) async { - if (onTap != null) return onTap(); + if (onTap != null) return onTap!(); if (!activeChat) { if (room.membership == Membership.invite && (await showFutureLoadingDialog( @@ -57,7 +57,7 @@ class ChatListItem extends StatelessWidget { if (room.membership == Membership.ban) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: Text(L10n.of(context).youHaveBeenBannedFromThisChat), + content: Text(L10n.of(context)!.youHaveBeenBannedFromThisChat), ), ); return; @@ -66,15 +66,15 @@ class ChatListItem extends StatelessWidget { if (room.membership == Membership.leave) { final action = await showModalActionSheet( context: context, - title: L10n.of(context).archivedRoom, - message: L10n.of(context).thisRoomHasBeenArchived, + title: L10n.of(context)!.archivedRoom, + message: L10n.of(context)!.thisRoomHasBeenArchived, actions: [ SheetAction( - label: L10n.of(context).rejoin, + label: L10n.of(context)!.rejoin, key: ArchivedRoomAction.rejoin, ), SheetAction( - label: L10n.of(context).delete, + label: L10n.of(context)!.delete, key: ArchivedRoomAction.delete, isDestructiveAction: true, ), @@ -97,18 +97,18 @@ class ChatListItem extends StatelessWidget { if (room.membership == Membership.join) { if (Matrix.of(context).shareContent != null) { - if (Matrix.of(context).shareContent['msgtype'] == + if (Matrix.of(context).shareContent!['msgtype'] == 'chat.fluffy.shared_file') { await showDialog( context: context, useRootNavigator: false, builder: (c) => SendFileDialog( - file: Matrix.of(context).shareContent['file'], + file: Matrix.of(context).shareContent!['file'], room: room, ), ); } else { - unawaited(room.sendEvent(Matrix.of(context).shareContent)); + unawaited(room.sendEvent(Matrix.of(context).shareContent!)); } Matrix.of(context).shareContent = null; } @@ -125,16 +125,16 @@ class ChatListItem extends StatelessWidget { future: () => room.forget(), ); if (success.error == null) { - if (onForget != null) onForget(); + if (onForget != null) onForget!(); } - return success; + return; } final confirmed = await showOkCancelAlertDialog( useRootNavigator: false, context: context, - title: L10n.of(context).areYouSure, - okLabel: L10n.of(context).yes, - cancelLabel: L10n.of(context).no, + title: L10n.of(context)!.areYouSure, + okLabel: L10n.of(context)!.yes, + cancelLabel: L10n.of(context)!.no, ); if (confirmed == OkCancelResult.cancel) return; await showFutureLoadingDialog( @@ -160,7 +160,7 @@ class ChatListItem extends StatelessWidget { selectedTileColor: selected ? Theme.of(context).primaryColor.withAlpha(100) : Theme.of(context).secondaryHeaderColor, - onLongPress: onLongPress, + onLongPress: onLongPress as void Function()?, leading: selected ? SizedBox( width: Avatar.defaultSize, @@ -174,13 +174,13 @@ class ChatListItem extends StatelessWidget { : Avatar( mxContent: room.avatar, name: room.displayname, - onTap: onLongPress, + onTap: onLongPress as void Function()?, ), title: Row( children: [ Expanded( child: Text( - room.getLocalizedDisplayname(MatrixLocals(L10n.of(context))), + room.getLocalizedDisplayname(MatrixLocals(L10n.of(context)!)), maxLines: 1, overflow: TextOverflow.ellipsis, softWrap: false, @@ -188,7 +188,7 @@ class ChatListItem extends StatelessWidget { fontWeight: FontWeight.bold, color: unread ? Theme.of(context).colorScheme.secondary - : Theme.of(context).textTheme.bodyText1.color, + : Theme.of(context).textTheme.bodyText1!.color, ), ), ), @@ -218,7 +218,7 @@ class ChatListItem extends StatelessWidget { fontSize: 13, color: unread ? Theme.of(context).colorScheme.secondary - : Theme.of(context).textTheme.bodyText2.color, + : Theme.of(context).textTheme.bodyText2!.color, ), ), ), @@ -229,7 +229,7 @@ class ChatListItem extends StatelessWidget { children: [ if (typingText.isEmpty && ownMessage && - room.lastEvent.status.isSending) ...[ + room.lastEvent!.status.isSending) ...[ const SizedBox( width: 16, height: 16, @@ -261,9 +261,9 @@ class ChatListItem extends StatelessWidget { ) : Text( room.membership == Membership.invite - ? L10n.of(context).youAreInvitedToThisChat + ? L10n.of(context)!.youAreInvitedToThisChat : room.lastEvent?.getLocalizedBody( - MatrixLocals(L10n.of(context)), + MatrixLocals(L10n.of(context)!), hideReply: true, hideEdit: true, plaintextBody: true, @@ -271,14 +271,14 @@ class ChatListItem extends StatelessWidget { room.directChatMatrixID != room.lastEvent?.senderId, ) ?? - L10n.of(context).emptyChat, + L10n.of(context)!.emptyChat, softWrap: false, maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle( color: unread ? Theme.of(context).colorScheme.secondary - : Theme.of(context).textTheme.bodyText2.color, + : Theme.of(context).textTheme.bodyText2!.color, decoration: room.lastEvent?.redacted == true ? TextDecoration.lineThrough : null, diff --git a/lib/pages/chat_list/chat_list_view.dart b/lib/pages/chat_list/chat_list_view.dart index 2c5360c5..2c925794 100644 --- a/lib/pages/chat_list/chat_list_view.dart +++ b/lib/pages/chat_list/chat_list_view.dart @@ -21,11 +21,11 @@ import '../../widgets/matrix.dart'; class ChatListView extends StatelessWidget { final ChatListController controller; - const ChatListView(this.controller, {Key key}) : super(key: key); + const ChatListView(this.controller, {Key? key}) : super(key: key); @override Widget build(BuildContext context) { - return StreamBuilder( + return StreamBuilder( stream: Matrix.of(context).onShareContentChanged.stream, builder: (_, __) { final selectMode = controller.selectMode; @@ -48,7 +48,7 @@ class ChatListView extends StatelessWidget { ? ClientChooserButton(controller) : null : IconButton( - tooltip: L10n.of(context).cancel, + tooltip: L10n.of(context)!.cancel, icon: const Icon(Icons.close_outlined), onPressed: controller.cancelAction, color: Theme.of(context).colorScheme.primary, @@ -60,12 +60,12 @@ class ChatListView extends StatelessWidget { ? [ if (controller.spaces.isNotEmpty) IconButton( - tooltip: L10n.of(context).addToSpace, + tooltip: L10n.of(context)!.addToSpace, icon: const Icon(Icons.group_work_outlined), onPressed: controller.addOrRemoveToSpace, ), IconButton( - tooltip: L10n.of(context).toggleUnread, + tooltip: L10n.of(context)!.toggleUnread, icon: Icon( controller.anySelectedRoomNotMarkedUnread ? Icons.mark_chat_read_outlined @@ -73,7 +73,7 @@ class ChatListView extends StatelessWidget { onPressed: controller.toggleUnread, ), IconButton( - tooltip: L10n.of(context).toggleFavorite, + tooltip: L10n.of(context)!.toggleFavorite, icon: Icon(controller.anySelectedRoomNotFavorite ? Icons.push_pin_outlined : Icons.push_pin), @@ -83,19 +83,19 @@ class ChatListView extends StatelessWidget { icon: Icon(controller.anySelectedRoomNotMuted ? Icons.notifications_off_outlined : Icons.notifications_outlined), - tooltip: L10n.of(context).toggleMuted, + tooltip: L10n.of(context)!.toggleMuted, onPressed: controller.toggleMuted, ), IconButton( icon: const Icon(Icons.delete_outlined), - tooltip: L10n.of(context).archive, + tooltip: L10n.of(context)!.archive, onPressed: controller.archiveAction, ), ] : [ IconButton( icon: const Icon(Icons.search_outlined), - tooltip: L10n.of(context).search, + tooltip: L10n.of(context)!.search, onPressed: () => VRouter.of(context).to('/search'), ), @@ -109,7 +109,7 @@ class ChatListView extends StatelessWidget { children: [ const Icon(Icons.edit_outlined), const SizedBox(width: 12), - Text(L10n.of(context).setStatus), + Text(L10n.of(context)!.setStatus), ], ), ), @@ -120,7 +120,7 @@ class ChatListView extends StatelessWidget { children: [ const Icon(Icons.group_add_outlined), const SizedBox(width: 12), - Text(L10n.of(context).createNewGroup), + Text(L10n.of(context)!.createNewGroup), ], ), ), @@ -131,7 +131,7 @@ class ChatListView extends StatelessWidget { children: [ const Icon(Icons.group_work_outlined), const SizedBox(width: 12), - Text(L10n.of(context).createNewSpace), + Text(L10n.of(context)!.createNewSpace), ], ), ), @@ -142,7 +142,7 @@ class ChatListView extends StatelessWidget { children: [ const Icon(Icons.share_outlined), const SizedBox(width: 12), - Text(L10n.of(context).inviteContact), + Text(L10n.of(context)!.inviteContact), ], ), ), @@ -153,7 +153,7 @@ class ChatListView extends StatelessWidget { children: [ const Icon(Icons.archive_outlined), const SizedBox(width: 12), - Text(L10n.of(context).archive), + Text(L10n.of(context)!.archive), ], ), ), @@ -164,7 +164,7 @@ class ChatListView extends StatelessWidget { children: [ const Icon(Icons.settings_outlined), const SizedBox(width: 12), - Text(L10n.of(context).settings), + Text(L10n.of(context)!.settings), ], ), ), @@ -172,14 +172,14 @@ class ChatListView extends StatelessWidget { ), ], title: Text(selectMode == SelectMode.share - ? L10n.of(context).share + ? L10n.of(context)!.share : selectMode == SelectMode.select ? controller.selectedRoomIds.length.toString() : controller.activeSpaceId == null ? AppConfig.applicationName : Matrix.of(context) .client - .getRoomById(controller.activeSpaceId) + .getRoomById(controller.activeSpaceId!)! .displayname), ), body: Column(children: [ @@ -197,7 +197,7 @@ class ChatListView extends StatelessWidget { fit: BoxFit.contain, width: 44, ), - title: Text(L10n.of(context).setupChatBackupNow), + title: Text(L10n.of(context)!.setupChatBackupNow), trailing: const Icon(Icons.chevron_right_outlined), onTap: controller.firstRunBootstrapAction, ), @@ -211,7 +211,7 @@ class ChatListView extends StatelessWidget { onPressed: () => VRouter.of(context).to('/newprivatechat'), icon: const Icon(CupertinoIcons.chat_bubble), - label: Text(L10n.of(context).newChat), + label: Text(L10n.of(context)!.newChat), ) : null, bottomNavigationBar: Column( @@ -232,7 +232,7 @@ class ChatListView extends StatelessWidget { class _ChatListViewBody extends StatefulWidget { final ChatListController controller; - const _ChatListViewBody(this.controller, {Key key}) : super(key: key); + const _ChatListViewBody(this.controller, {Key? key}) : super(key: key); @override State<_ChatListViewBody> createState() => _ChatListViewBodyState(); @@ -240,12 +240,12 @@ class _ChatListViewBody extends StatefulWidget { class _ChatListViewBodyState extends State<_ChatListViewBody> { // the matrix sync stream - StreamSubscription _subscription; - StreamSubscription _clientSubscription; + late StreamSubscription _subscription; + late StreamSubscription _clientSubscription; // used to check the animation direction - String _lastUserId; - String _lastSpaceId; + String? _lastUserId; + String? _lastSpaceId; @override void initState() { @@ -285,7 +285,7 @@ class _ChatListViewBodyState extends State<_ChatListViewBody> { ), Center( child: Text( - L10n.of(context).startYourFirstChat, + L10n.of(context)!.startYourFirstChat, textAlign: TextAlign.start, style: const TextStyle( color: Colors.grey, @@ -324,9 +324,9 @@ class _ChatListViewBodyState extends State<_ChatListViewBody> { } else { const dummyChatCount = 8; final titleColor = - Theme.of(context).textTheme.bodyText1.color.withAlpha(100); + Theme.of(context).textTheme.bodyText1!.color!.withAlpha(100); final subtitleColor = - Theme.of(context).textTheme.bodyText1.color.withAlpha(50); + Theme.of(context).textTheme.bodyText1!.color!.withAlpha(50); child = ListView.builder( itemCount: dummyChatCount, itemBuilder: (context, i) => Opacity( @@ -336,7 +336,7 @@ class _ChatListViewBodyState extends State<_ChatListViewBody> { backgroundColor: titleColor, child: CircularProgressIndicator( strokeWidth: 1, - color: Theme.of(context).textTheme.bodyText1.color, + color: Theme.of(context).textTheme.bodyText1!.color, ), ), title: Row( @@ -417,11 +417,11 @@ class _ChatListViewBodyState extends State<_ChatListViewBody> { final newClient = Matrix.of(context).client; if (_lastUserId != newClient.userID) { reversed = Matrix.of(context) - .currentBundle - .indexWhere((element) => element.userID == _lastUserId) < + .currentBundle! + .indexWhere((element) => element!.userID == _lastUserId) < Matrix.of(context) - .currentBundle - .indexWhere((element) => element.userID == newClient.userID); + .currentBundle! + .indexWhere((element) => element!.userID == newClient.userID); } // otherwise, the space changed... else { diff --git a/lib/pages/chat_list/client_chooser_button.dart b/lib/pages/chat_list/client_chooser_button.dart index 73717741..7ecce505 100644 --- a/lib/pages/chat_list/client_chooser_button.dart +++ b/lib/pages/chat_list/client_chooser_button.dart @@ -8,20 +8,20 @@ import 'chat_list.dart'; class ClientChooserButton extends StatelessWidget { final ChatListController controller; - const ClientChooserButton(this.controller, {Key key}) : super(key: key); + const ClientChooserButton(this.controller, {Key? key}) : super(key: key); List> _bundleMenuItems(BuildContext context) { final matrix = Matrix.of(context); final bundles = matrix.accountBundles.keys.toList() - ..sort((a, b) => a.isValidMatrixId == b.isValidMatrixId + ..sort((a, b) => a!.isValidMatrixId == b!.isValidMatrixId ? 0 : a.isValidMatrixId && !b.isValidMatrixId ? -1 : 1); return >[ for (final bundle in bundles) ...[ - if (matrix.accountBundles[bundle].length != 1 || - matrix.accountBundles[bundle].single.userID != bundle) + if (matrix.accountBundles[bundle]!.length != 1 || + matrix.accountBundles[bundle]!.single!.userID != bundle) PopupMenuItem( value: null, child: Column( @@ -29,9 +29,9 @@ class ClientChooserButton extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ Text( - bundle, + bundle!, style: TextStyle( - color: Theme.of(context).textTheme.subtitle1.color, + color: Theme.of(context).textTheme.subtitle1!.color, fontSize: 14, ), ), @@ -39,25 +39,26 @@ class ClientChooserButton extends StatelessWidget { ], ), ), - ...matrix.accountBundles[bundle] + ...matrix.accountBundles[bundle]! .map( (client) => PopupMenuItem( value: client, child: FutureBuilder( - future: client.ownProfile, + future: client!.ownProfile, builder: (context, snapshot) => Row( children: [ Avatar( mxContent: snapshot.data?.avatarUrl, name: snapshot.data?.displayName ?? - client.userID.localpart, + client.userID!.localpart, size: 28, fontSize: 12, ), const SizedBox(width: 12), Expanded( child: Text( - snapshot.data?.displayName ?? client.userID.localpart, + snapshot.data?.displayName ?? + client.userID!.localpart!, overflow: TextOverflow.ellipsis, ), ), @@ -86,7 +87,7 @@ class ClientChooserButton extends StatelessWidget { builder: (context, snapshot) => PopupMenuButton( child: Avatar( mxContent: snapshot.data?.avatarUrl, - name: snapshot.data?.displayName ?? matrix.client.userID.localpart, + name: snapshot.data?.displayName ?? matrix.client.userID!.localpart, size: 28, fontSize: 12, ), diff --git a/lib/pages/chat_list/spaces_bottom_bar.dart b/lib/pages/chat_list/spaces_bottom_bar.dart index 81196972..59ea3fb6 100644 --- a/lib/pages/chat_list/spaces_bottom_bar.dart +++ b/lib/pages/chat_list/spaces_bottom_bar.dart @@ -10,7 +10,7 @@ import 'package:fluffychat/widgets/matrix.dart'; class SpacesBottomBar extends StatelessWidget { final ChatListController controller; - const SpacesBottomBar(this.controller, {Key key}) : super(key: key); + const SpacesBottomBar(this.controller, {Key? key}) : super(key: key); @override Widget build(BuildContext context) { @@ -25,8 +25,9 @@ class SpacesBottomBar extends StatelessWidget { child: SafeArea( child: StreamBuilder( stream: Matrix.of(context).client.onSync.stream.where((sync) => - (sync.rooms?.join?.values?.any((r) => - r.state?.any((s) => s.type.startsWith('m.space'))) ?? + (sync.rooms?.join?.values.any((r) => + r.state?.any((s) => s.type.startsWith('m.space')) ?? + false) ?? false) || (sync.rooms?.leave?.isNotEmpty ?? false)), builder: (context, snapshot) { @@ -48,7 +49,7 @@ class SpacesBottomBar extends StatelessWidget { icon: const Icon(CupertinoIcons.chat_bubble_2), activeIcon: const Icon(CupertinoIcons.chat_bubble_2_fill), - title: Text(L10n.of(context).allChats), + title: Text(L10n.of(context)!.allChats), ), ...controller.spaces .map((space) => SalomonBottomBarItem( diff --git a/lib/pages/chat_list/stories_header.dart b/lib/pages/chat_list/stories_header.dart index 2f2b0526..84037263 100644 --- a/lib/pages/chat_list/stories_header.dart +++ b/lib/pages/chat_list/stories_header.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'package:flutter/material.dart'; import 'package:adaptive_dialog/adaptive_dialog.dart'; diff --git a/lib/pages/chat_permissions_settings/chat_permissions_settings.dart b/lib/pages/chat_permissions_settings/chat_permissions_settings.dart index a02d4280..372edc5f 100644 --- a/lib/pages/chat_permissions_settings/chat_permissions_settings.dart +++ b/lib/pages/chat_permissions_settings/chat_permissions_settings.dart @@ -13,7 +13,7 @@ import 'package:fluffychat/widgets/matrix.dart'; import 'package:fluffychat/widgets/permission_slider_dialog.dart'; class ChatPermissionsSettings extends StatefulWidget { - const ChatPermissionsSettings({Key key}) : super(key: key); + const ChatPermissionsSettings({Key? key}) : super(key: key); @override ChatPermissionsSettingsController createState() => @@ -21,13 +21,13 @@ class ChatPermissionsSettings extends StatefulWidget { } class ChatPermissionsSettingsController extends State { - String get roomId => VRouter.of(context).pathParameters['roomid']; + String? get roomId => VRouter.of(context).pathParameters['roomid']; void editPowerLevel(BuildContext context, String key, int currentLevel, - {String category}) async { - final room = Matrix.of(context).client.getRoomById(roomId); + {String? category}) 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; } final newLevel = @@ -35,7 +35,7 @@ class ChatPermissionsSettingsController extends State { .show(context); if (newLevel == null) return; final content = Map.from( - room.getState(EventTypes.RoomPowerLevels).content); + room.getState(EventTypes.RoomPowerLevels)!.content); if (category != null) { if (!content.containsKey(category)) { content[category] = {}; @@ -58,20 +58,20 @@ 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 + (e.rooms?.join?.containsKey(roomId) ?? false) && + (e.rooms!.join![roomId!]?.timeline?.events ?.any((s) => s.type == EventTypes.RoomPowerLevels) ?? false), ); void updateRoomAction(Capabilities capabilities) async { - final room = Matrix.of(context).client.getRoomById(roomId); + final room = Matrix.of(context).client.getRoomById(roomId!)!; final String roomVersion = - room.getState(EventTypes.RoomCreate).content['room_version'] ?? '1'; + room.getState(EventTypes.RoomCreate)!.content['room_version'] ?? '1'; final newVersion = await showConfirmationDialog( context: context, - title: L10n.of(context).replaceRoomWithNewerVersion, - actions: capabilities.mRoomVersions.available.entries + title: L10n.of(context)!.replaceRoomWithNewerVersion, + actions: capabilities.mRoomVersions!.available.entries .where((r) => r.key != roomVersion) .map((version) => AlertDialogAction( key: version.key, @@ -84,15 +84,15 @@ class ChatPermissionsSettingsController extends State { await showOkCancelAlertDialog( useRootNavigator: false, context: context, - okLabel: L10n.of(context).yes, - cancelLabel: L10n.of(context).cancel, - title: L10n.of(context).areYouSure, + okLabel: L10n.of(context)!.yes, + cancelLabel: L10n.of(context)!.cancel, + title: L10n.of(context)!.areYouSure, )) { return; } await showFutureLoadingDialog( context: context, - future: () => room.client.upgradeRoom(roomId, newVersion), + future: () => room.client.upgradeRoom(roomId!, newVersion), ).then((_) => VRouter.of(context).pop()); } 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 94561a28..645d2358 100644 --- a/lib/pages/chat_permissions_settings/chat_permissions_settings_view.dart +++ b/lib/pages/chat_permissions_settings/chat_permissions_settings_view.dart @@ -12,7 +12,7 @@ import 'package:fluffychat/widgets/matrix.dart'; class ChatPermissionsSettingsView extends StatelessWidget { final ChatPermissionsSettingsController controller; - const ChatPermissionsSettingsView(this.controller, {Key key}) + const ChatPermissionsSettingsView(this.controller, {Key? key}) : super(key: key); @override @@ -24,19 +24,24 @@ class ChatPermissionsSettingsView extends StatelessWidget { : IconButton( icon: const Icon(Icons.close_outlined), onPressed: () => VRouter.of(context) - .toSegments(['rooms', controller.roomId]), + .toSegments(['rooms', controller.roomId!]), ), - title: Text(L10n.of(context).editChatPermissions), + title: Text(L10n.of(context)!.editChatPermissions), ), body: MaxWidthBody( withScrolling: true, child: StreamBuilder( stream: controller.onChanged, builder: (context, _) { - final room = - Matrix.of(context).client.getRoomById(controller.roomId); + final roomId = controller.roomId; + final room = roomId == null + ? null + : Matrix.of(context).client.getRoomById(roomId); + if (room == null) { + return Center(child: Text(L10n.of(context)!.noRoomsFound)); + } final powerLevelsContent = Map.from( - room.getState(EventTypes.RoomPowerLevels).content); + room.getState(EventTypes.RoomPowerLevels)!.content); final powerLevels = Map.from(powerLevelsContent) ..removeWhere((k, v) => v is! int); final eventsPowerLevels = @@ -57,7 +62,7 @@ class ChatPermissionsSettingsView extends StatelessWidget { const Divider(thickness: 1), ListTile( title: Text( - L10n.of(context).notifications, + L10n.of(context)!.notifications, style: TextStyle( color: Theme.of(context).primaryColor, fontWeight: FontWeight.bold, @@ -82,23 +87,22 @@ class ChatPermissionsSettingsView extends StatelessWidget { const Divider(thickness: 1), ListTile( title: Text( - L10n.of(context).configureChat, + L10n.of(context)!.configureChat, style: TextStyle( color: Theme.of(context).primaryColor, fontWeight: FontWeight.bold, ), ), ), - if (eventsPowerLevels != null) - for (var entry in eventsPowerLevels.entries) - PermissionsListTile( - permissionKey: entry.key, - category: 'events', - permission: entry.value, - onTap: () => controller.editPowerLevel( - context, entry.key, entry.value, - category: 'events'), - ), + for (var entry in eventsPowerLevels.entries) + PermissionsListTile( + permissionKey: entry.key, + category: 'events', + permission: entry.value, + onTap: () => controller.editPowerLevel( + context, entry.key, entry.value, + category: 'events'), + ), if (room.canSendEvent(EventTypes.RoomTombstone)) ...{ const Divider(thickness: 1), FutureBuilder( @@ -110,15 +114,15 @@ class ChatPermissionsSettingsView extends StatelessWidget { strokeWidth: 2)); } final String roomVersion = room - .getState(EventTypes.RoomCreate) + .getState(EventTypes.RoomCreate)! .content['room_version'] ?? '1'; return ListTile( title: Text( - '${L10n.of(context).roomVersion}: $roomVersion'), + '${L10n.of(context)!.roomVersion}: $roomVersion'), onTap: () => - controller.updateRoomAction(snapshot.data), + controller.updateRoomAction(snapshot.data!), ); }, ), diff --git a/lib/pages/chat_permissions_settings/permission_list_tile.dart b/lib/pages/chat_permissions_settings/permission_list_tile.dart index a7e03161..f16a40d8 100644 --- a/lib/pages/chat_permissions_settings/permission_list_tile.dart +++ b/lib/pages/chat_permissions_settings/permission_list_tile.dart @@ -6,13 +6,13 @@ import 'package:matrix/matrix.dart'; class PermissionsListTile extends StatelessWidget { final String permissionKey; final int permission; - final String category; - final void Function() onTap; + final String? category; + final void Function()? onTap; const PermissionsListTile({ - Key key, - @required this.permissionKey, - @required this.permission, + Key? key, + required this.permissionKey, + required this.permission, this.category, this.onTap, }) : super(key: key); @@ -21,43 +21,43 @@ class PermissionsListTile extends StatelessWidget { if (category == null) { switch (permissionKey) { case 'users_default': - return L10n.of(context).defaultPermissionLevel; + return L10n.of(context)!.defaultPermissionLevel; case 'events_default': - return L10n.of(context).sendMessages; + return L10n.of(context)!.sendMessages; case 'state_default': - return L10n.of(context).configureChat; + return L10n.of(context)!.configureChat; case 'ban': - return L10n.of(context).banFromChat; + return L10n.of(context)!.banFromChat; case 'kick': - return L10n.of(context).kickFromChat; + return L10n.of(context)!.kickFromChat; case 'redact': - return L10n.of(context).deleteMessage; + return L10n.of(context)!.deleteMessage; case 'invite': - return L10n.of(context).inviteContact; + return L10n.of(context)!.inviteContact; } } else if (category == 'notifications') { switch (permissionKey) { case 'rooms': - return L10n.of(context).notifications; + return L10n.of(context)!.notifications; } } else if (category == 'events') { switch (permissionKey) { case EventTypes.RoomName: - return L10n.of(context).changeTheNameOfTheGroup; + return L10n.of(context)!.changeTheNameOfTheGroup; case EventTypes.RoomPowerLevels: - return L10n.of(context).editChatPermissions; + return L10n.of(context)!.editChatPermissions; case EventTypes.HistoryVisibility: - return L10n.of(context).visibilityOfTheChatHistory; + return L10n.of(context)!.visibilityOfTheChatHistory; case EventTypes.RoomCanonicalAlias: - return L10n.of(context).setInvitationLink; + return L10n.of(context)!.setInvitationLink; case EventTypes.RoomAvatar: - return L10n.of(context).editRoomAvatar; + return L10n.of(context)!.editRoomAvatar; case EventTypes.RoomTombstone: - return L10n.of(context).replaceRoomWithNewerVersion; + return L10n.of(context)!.replaceRoomWithNewerVersion; case EventTypes.Encryption: - return L10n.of(context).enableEncryption; + return L10n.of(context)!.enableEncryption; case 'm.room.server_acl': - return L10n.of(context).editBlockedServers; + return L10n.of(context)!.editBlockedServers; } } return permissionKey; @@ -96,9 +96,9 @@ class PermissionsListTile extends StatelessWidget { extension on int { String toLocalizedPowerLevelString(BuildContext context) { return this == 100 - ? L10n.of(context).admin + ? L10n.of(context)!.admin : this >= 50 - ? L10n.of(context).moderator - : L10n.of(context).participant; + ? L10n.of(context)!.moderator + : L10n.of(context)!.participant; } } diff --git a/lib/pages/device_settings/device_settings.dart b/lib/pages/device_settings/device_settings.dart index 5edd6d2b..294e2ed3 100644 --- a/lib/pages/device_settings/device_settings.dart +++ b/lib/pages/device_settings/device_settings.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:adaptive_dialog/adaptive_dialog.dart'; +import 'package:collection/collection.dart' show IterableExtension; import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:future_loading_dialog/future_loading_dialog.dart'; import 'package:matrix/encryption/utils/key_verification.dart'; @@ -11,14 +12,14 @@ import 'package:fluffychat/pages/key_verification/key_verification_dialog.dart'; import '../../widgets/matrix.dart'; class DevicesSettings extends StatefulWidget { - const DevicesSettings({Key key}) : super(key: key); + const DevicesSettings({Key? key}) : super(key: key); @override DevicesSettingsController createState() => DevicesSettingsController(); } class DevicesSettingsController extends State { - List devices; + List? devices; Future loadUserDevices(BuildContext context) async { if (devices != null) return true; devices = await Matrix.of(context).client.getDevices(); @@ -28,15 +29,15 @@ class DevicesSettingsController extends State { void reload() => setState(() => devices = null); bool loadingDeletingDevices = false; - String errorDeletingDevices; + String? errorDeletingDevices; void removeDevicesAction(List devices) async { if (await showOkCancelAlertDialog( useRootNavigator: false, context: context, - title: L10n.of(context).areYouSure, - okLabel: L10n.of(context).yes, - cancelLabel: L10n.of(context).cancel, + title: L10n.of(context)!.areYouSure, + okLabel: L10n.of(context)!.yes, + cancelLabel: L10n.of(context)!.cancel, ) == OkCancelResult.cancel) return; final matrix = Matrix.of(context); @@ -69,9 +70,9 @@ class DevicesSettingsController extends State { final displayName = await showTextInputDialog( useRootNavigator: false, context: context, - title: L10n.of(context).changeDeviceName, - okLabel: L10n.of(context).ok, - cancelLabel: L10n.of(context).cancel, + title: L10n.of(context)!.changeDeviceName, + okLabel: L10n.of(context)!.ok, + cancelLabel: L10n.of(context)!.cancel, textFields: [ DialogTextField( hintText: device.displayName, @@ -93,13 +94,13 @@ class DevicesSettingsController extends State { void verifyDeviceAction(Device device) async { final req = Matrix.of(context) .client - .userDeviceKeys[Matrix.of(context).client.userID] - .deviceKeys[device.deviceId] + .userDeviceKeys[Matrix.of(context).client.userID!]! + .deviceKeys[device.deviceId]! .startVerification(); req.onUpdate = () { if ({KeyVerificationState.error, KeyVerificationState.done} .contains(req.state)) { - setState(() => null); + setState(() {}); } }; await KeyVerificationDialog(request: req).show(context); @@ -108,33 +109,32 @@ class DevicesSettingsController extends State { void blockDeviceAction(Device device) async { final key = Matrix.of(context) .client - .userDeviceKeys[Matrix.of(context).client.userID] - .deviceKeys[device.deviceId]; + .userDeviceKeys[Matrix.of(context).client.userID!]! + .deviceKeys[device.deviceId]!; if (key.directVerified) { await key.setVerified(false); } await key.setBlocked(true); - setState(() => null); + setState(() {}); } void unblockDeviceAction(Device device) async { final key = Matrix.of(context) .client - .userDeviceKeys[Matrix.of(context).client.userID] - .deviceKeys[device.deviceId]; + .userDeviceKeys[Matrix.of(context).client.userID!]! + .deviceKeys[device.deviceId]!; await key.setBlocked(false); - setState(() => null); + setState(() {}); } bool _isOwnDevice(Device userDevice) => userDevice.deviceId == Matrix.of(context).client.deviceID; - Device get thisDevice => devices.firstWhere( + Device? get thisDevice => devices!.firstWhereOrNull( _isOwnDevice, - orElse: () => null, ); - List get notThisDevice => List.from(devices) + List get notThisDevice => List.from(devices!) ..removeWhere(_isOwnDevice) ..sort((a, b) => (b.lastSeenTs ?? 0).compareTo(a.lastSeenTs ?? 0)); diff --git a/lib/pages/device_settings/device_settings_view.dart b/lib/pages/device_settings/device_settings_view.dart index e8506160..9fe1ee47 100644 --- a/lib/pages/device_settings/device_settings_view.dart +++ b/lib/pages/device_settings/device_settings_view.dart @@ -9,14 +9,14 @@ import 'user_device_list_item.dart'; class DevicesSettingsView extends StatelessWidget { final DevicesSettingsController controller; - const DevicesSettingsView(this.controller, {Key key}) : super(key: key); + const DevicesSettingsView(this.controller, {Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( leading: const BackButton(), - title: Text(L10n.of(context).devices), + title: Text(L10n.of(context)!.devices), ), body: MaxWidthBody( child: FutureBuilder( @@ -41,7 +41,7 @@ class DevicesSettingsView extends StatelessWidget { children: [ if (controller.thisDevice != null) UserDeviceListItem( - controller.thisDevice, + controller.thisDevice!, rename: controller.renameDeviceAction, remove: (d) => controller.removeDevicesAction([d]), verify: controller.verifyDeviceAction, @@ -53,7 +53,7 @@ class DevicesSettingsView extends StatelessWidget { ListTile( title: Text( controller.errorDeletingDevices ?? - L10n.of(context).removeAllOtherDevices, + L10n.of(context)!.removeAllOtherDevices, style: const TextStyle(color: Colors.red), ), trailing: controller.loadingDeletingDevices diff --git a/lib/pages/device_settings/user_device_list_item.dart b/lib/pages/device_settings/user_device_list_item.dart index c7f32f17..a741c01c 100644 --- a/lib/pages/device_settings/user_device_list_item.dart +++ b/lib/pages/device_settings/user_device_list_item.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'package:flutter/material.dart'; import 'package:adaptive_dialog/adaptive_dialog.dart'; diff --git a/lib/pages/homeserver_picker/homeserver_picker.dart b/lib/pages/homeserver_picker/homeserver_picker.dart index c55161e5..af392c8f 100644 --- a/lib/pages/homeserver_picker/homeserver_picker.dart +++ b/lib/pages/homeserver_picker/homeserver_picker.dart @@ -21,7 +21,7 @@ import '../../main.dart'; import '../../utils/localized_exception_extension.dart'; class HomeserverPicker extends StatefulWidget { - const HomeserverPicker({Key key}) : super(key: key); + const HomeserverPicker({Key? key}) : super(key: key); @override HomeserverPickerController createState() => HomeserverPickerController(); @@ -32,9 +32,9 @@ class HomeserverPickerController extends State { String domain = AppConfig.defaultHomeserver; final TextEditingController homeserverController = TextEditingController(text: AppConfig.defaultHomeserver); - StreamSubscription _intentDataStreamSubscription; - String error; - Timer _coolDown; + StreamSubscription? _intentDataStreamSubscription; + String? error; + Timer? _coolDown; void setDomain(String domain) { this.domain = domain; @@ -46,7 +46,7 @@ class HomeserverPickerController extends State { } void _loginWithToken(String token) { - if (token?.isEmpty ?? true) return; + if (token.isEmpty) return; showFutureLoadingDialog( context: context, @@ -66,7 +66,7 @@ class HomeserverPickerController extends State { ); } - void _processIncomingUris(String text) async { + void _processIncomingUris(String? text) async { if (text == null || !text.startsWith(AppConfig.appOpenUrlScheme)) return; await browser?.close(); VRouter.of(context).to('/home'); @@ -89,8 +89,8 @@ class HomeserverPickerController extends State { super.initState(); _initReceiveUri(); if (kIsWeb) { - WidgetsBinding.instance.addPostFrameCallback((_) { - final token = Matrix.of(context).widget.queryParameters['loginToken']; + WidgetsBinding.instance!.addPostFrameCallback((_) { + final token = Matrix.of(context).widget.queryParameters!['loginToken']; if (token != null) _loginWithToken(token); }); } @@ -103,7 +103,7 @@ class HomeserverPickerController extends State { _intentDataStreamSubscription?.cancel(); } - String _lastCheckedHomeserver; + String? _lastCheckedHomeserver; /// Starts an analysis of the given homeserver. It uses the current domain and /// makes sure that it is prefixed with https. Then it searches for the @@ -112,7 +112,7 @@ class HomeserverPickerController extends State { Future checkHomeserverAction() async { _coolDown?.cancel(); if (_lastCheckedHomeserver == domain) return; - if (domain.isEmpty) throw L10n.of(context).changeTheHomeserver; + if (domain.isEmpty) throw L10n.of(context)!.changeTheHomeserver; var homeserver = domain; if (!homeserver.startsWith('https://')) { @@ -129,7 +129,7 @@ class HomeserverPickerController extends State { await Matrix.of(context).getLoginClient().checkHomeserver(homeserver); var jitsi = wellKnown?.additionalProperties - ?.tryGet>('im.vector.riot.jitsi') + .tryGet>('im.vector.riot.jitsi') ?.tryGet('preferredDomain'); if (jitsi != null) { if (!jitsi.endsWith('/')) { @@ -150,10 +150,10 @@ class HomeserverPickerController extends State { await Matrix.of(context).getLoginClient().register(); registrationSupported = true; } on MatrixException catch (e) { - registrationSupported = e.requireAdditionalAuthentication ?? false; + registrationSupported = e.requireAdditionalAuthentication; } } catch (e) { - setState(() => error = (e as Object).toLocalizedString(context)); + setState(() => error = (e).toLocalizedString(context)); } finally { _lastCheckedHomeserver = domain; if (mounted) { @@ -162,12 +162,12 @@ class HomeserverPickerController extends State { } } - Map _rawLoginTypes; - bool registrationSupported; + Map? _rawLoginTypes; + bool? registrationSupported; List get identityProviders { if (!ssoLoginSupported) return []; - final rawProviders = _rawLoginTypes.tryGetList('flows').singleWhere( + final rawProviders = _rawLoginTypes!.tryGetList('flows')!.singleWhere( (flow) => flow['type'] == AuthenticationTypes.sso)['identity_providers']; final list = (rawProviders as List) @@ -184,8 +184,8 @@ class HomeserverPickerController extends State { .client .supportedLoginTypes .contains(AuthenticationTypes.password) && - _rawLoginTypes - .tryGetList('flows') + _rawLoginTypes! + .tryGetList('flows')! .any((flow) => flow['type'] == AuthenticationTypes.password); bool get ssoLoginSupported => @@ -193,11 +193,11 @@ class HomeserverPickerController extends State { .client .supportedLoginTypes .contains(AuthenticationTypes.sso) && - _rawLoginTypes - .tryGetList('flows') + _rawLoginTypes! + .tryGetList('flows')! .any((flow) => flow['type'] == AuthenticationTypes.sso); - ChromeSafariBrowser browser; + ChromeSafariBrowser? browser; static const String ssoHomeserverKey = 'sso-homeserver'; @@ -215,7 +215,7 @@ class HomeserverPickerController extends State { '${Matrix.of(context).getLoginClient().homeserver?.toString()}/_matrix/client/r0/login/sso/redirect/${Uri.encodeComponent(id)}?redirectUrl=${Uri.encodeQueryComponent(redirectUrl)}'; if (PlatformInfos.isMobile) { browser ??= ChromeSafariBrowser(); - browser.open(url: Uri.parse(url)); + browser!.open(url: Uri.parse(url)); } else { launch(redirectUrl); } @@ -234,10 +234,10 @@ class HomeserverPickerController extends State { } class IdentityProvider { - final String id; - final String name; - final String icon; - final String brand; + final String? id; + final String? name; + final String? icon; + final String? brand; IdentityProvider({this.id, this.name, this.icon, this.brand}); diff --git a/lib/pages/homeserver_picker/homeserver_picker_view.dart b/lib/pages/homeserver_picker/homeserver_picker_view.dart index bb750e47..c79e84e7 100644 --- a/lib/pages/homeserver_picker/homeserver_picker_view.dart +++ b/lib/pages/homeserver_picker/homeserver_picker_view.dart @@ -17,7 +17,7 @@ import 'homeserver_picker.dart'; class HomeserverPickerView extends StatelessWidget { final HomeserverPickerController controller; - const HomeserverPickerView(this.controller, {Key key}) : super(key: key); + const HomeserverPickerView(this.controller, {Key? key}) : super(key: key); @override Widget build(BuildContext context) { @@ -27,7 +27,7 @@ class HomeserverPickerView extends StatelessWidget { titleSpacing: 8, title: DefaultAppBarSearchField( prefixText: 'https://', - hintText: L10n.of(context).enterYourHomeserver, + hintText: L10n.of(context)!.enterYourHomeserver, searchController: controller.homeserverController, suffix: const Icon(Icons.edit_outlined), padding: EdgeInsets.zero, @@ -36,7 +36,7 @@ class HomeserverPickerView extends StatelessWidget { onSubmit: (_) => controller.checkHomeserverAction(), unfocusOnClear: false, autocorrect: false, - labelText: L10n.of(context).homeserver, + labelText: L10n.of(context)!.homeserver, ), elevation: 0, ), @@ -54,7 +54,7 @@ class HomeserverPickerView extends StatelessWidget { child: Padding( padding: const EdgeInsets.all(12.0), child: Text( - controller.error, + controller.error!, textAlign: TextAlign.center, style: TextStyle( fontSize: 18, @@ -77,7 +77,7 @@ class HomeserverPickerView extends StatelessWidget { const Expanded(child: Divider()), Padding( padding: const EdgeInsets.all(12.0), - child: Text(L10n.of(context).loginWithOneClick), + child: Text(L10n.of(context)!.loginWithOneClick), ), const Expanded(child: Divider()), ]), @@ -88,20 +88,20 @@ class HomeserverPickerView extends StatelessWidget { in controller.identityProviders) _SsoButton( onPressed: () => - controller.ssoLoginAction(identityProvider.id), + controller.ssoLoginAction(identityProvider.id!), identityProvider: identityProvider, ), }, ].toList(), ), if (controller.ssoLoginSupported && - (controller.registrationSupported || + (controller.registrationSupported! || controller.passwordLoginSupported)) Row(children: [ const Expanded(child: Divider()), Padding( padding: const EdgeInsets.all(12.0), - child: Text(L10n.of(context).or), + child: Text(L10n.of(context)!.or), ), const Expanded(child: Divider()), ]), @@ -111,22 +111,22 @@ class HomeserverPickerView extends StatelessWidget { onPressed: () => VRouter.of(context).to('login'), icon: Icon( CupertinoIcons.lock_open_fill, - color: Theme.of(context).textTheme.bodyText1.color, + color: Theme.of(context).textTheme.bodyText1!.color, ), - labelText: L10n.of(context).login, + labelText: L10n.of(context)!.login, ), ), const SizedBox(height: 12), ], - if (controller.registrationSupported) + if (controller.registrationSupported!) Center( child: _LoginButton( onPressed: controller.signUpAction, icon: Icon( CupertinoIcons.person_add, - color: Theme.of(context).textTheme.bodyText1.color, + color: Theme.of(context).textTheme.bodyText1!.color, ), - labelText: L10n.of(context).register, + labelText: L10n.of(context)!.register, ), ), ], @@ -142,7 +142,7 @@ class HomeserverPickerView extends StatelessWidget { TextButton( onPressed: () => launch(AppConfig.privacyUrl), child: Text( - L10n.of(context).privacy, + L10n.of(context)!.privacy, style: const TextStyle( decoration: TextDecoration.underline, color: Colors.blueGrey, @@ -152,7 +152,7 @@ class HomeserverPickerView extends StatelessWidget { TextButton( onPressed: () => PlatformInfos.showDialog(context), child: Text( - L10n.of(context).about, + L10n.of(context)!.about, style: const TextStyle( decoration: TextDecoration.underline, color: Colors.blueGrey, @@ -169,10 +169,10 @@ class HomeserverPickerView extends StatelessWidget { class _SsoButton extends StatelessWidget { final IdentityProvider identityProvider; - final void Function() onPressed; + final void Function()? onPressed; const _SsoButton({ - Key key, - @required this.identityProvider, + Key? key, + required this.identityProvider, this.onPressed, }) : super(key: key); @@ -196,7 +196,7 @@ class _SsoButton extends StatelessWidget { child: identityProvider.icon == null ? const Icon(Icons.web_outlined) : CachedNetworkImage( - imageUrl: Uri.parse(identityProvider.icon) + imageUrl: Uri.parse(identityProvider.icon!) .getDownloadLink( Matrix.of(context).getLoginClient()) .toString(), @@ -209,11 +209,11 @@ class _SsoButton extends StatelessWidget { Text( identityProvider.name ?? identityProvider.brand ?? - L10n.of(context).singlesignon, + L10n.of(context)!.singlesignon, style: TextStyle( fontSize: 12, fontWeight: FontWeight.bold, - color: Theme.of(context).textTheme.subtitle2.color, + color: Theme.of(context).textTheme.subtitle2!.color, ), ), ], @@ -224,11 +224,11 @@ class _SsoButton extends StatelessWidget { } class _LoginButton extends StatelessWidget { - final String labelText; - final Widget icon; - final void Function() onPressed; + final String? labelText; + final Widget? icon; + final void Function()? onPressed; const _LoginButton({ - Key key, + Key? key, this.labelText, this.icon, this.onPressed, @@ -246,11 +246,11 @@ class _LoginButton extends StatelessWidget { ), ), onPressed: onPressed, - icon: icon, + icon: icon!, label: Text( - labelText, + labelText!, style: TextStyle( - color: Theme.of(context).textTheme.bodyText1.color, + color: Theme.of(context).textTheme.bodyText1!.color, ), ), ); diff --git a/lib/pages/image_viewer/image_viewer.dart b/lib/pages/image_viewer/image_viewer.dart index 6c63e22f..d46d3439 100644 --- a/lib/pages/image_viewer/image_viewer.dart +++ b/lib/pages/image_viewer/image_viewer.dart @@ -10,9 +10,9 @@ import '../../utils/matrix_sdk_extensions.dart/event_extension.dart'; class ImageViewer extends StatefulWidget { final Event event; - final void Function() onLoaded; + final void Function()? onLoaded; - const ImageViewer(this.event, {Key key, this.onLoaded}) : super(key: key); + const ImageViewer(this.event, {Key? key, this.onLoaded}) : super(key: key); @override ImageViewerController createState() => ImageViewerController(); diff --git a/lib/pages/image_viewer/image_viewer_view.dart b/lib/pages/image_viewer/image_viewer_view.dart index a2cb9609..da478aa2 100644 --- a/lib/pages/image_viewer/image_viewer_view.dart +++ b/lib/pages/image_viewer/image_viewer_view.dart @@ -8,7 +8,7 @@ import 'image_viewer.dart'; class ImageViewerView extends StatelessWidget { final ImageViewerController controller; - const ImageViewerView(this.controller, {Key key}) : super(key: key); + const ImageViewerView(this.controller, {Key? key}) : super(key: key); @override Widget build(BuildContext context) { @@ -21,7 +21,7 @@ class ImageViewerView extends StatelessWidget { icon: const Icon(Icons.close), onPressed: Navigator.of(context).pop, color: Colors.white, - tooltip: L10n.of(context).close, + tooltip: L10n.of(context)!.close, ), backgroundColor: const Color(0x44000000), actions: [ @@ -29,13 +29,13 @@ class ImageViewerView extends StatelessWidget { icon: const Icon(Icons.reply_outlined), onPressed: controller.forwardAction, color: Colors.white, - tooltip: L10n.of(context).share, + tooltip: L10n.of(context)!.share, ), IconButton( icon: const Icon(Icons.download_outlined), onPressed: controller.saveFileAction, color: Colors.white, - tooltip: L10n.of(context).downloadFile, + tooltip: L10n.of(context)!.downloadFile, ), ], ), diff --git a/lib/pages/invitation_selection/invitation_selection.dart b/lib/pages/invitation_selection/invitation_selection.dart index 9af6d2d2..3b11c79a 100644 --- a/lib/pages/invitation_selection/invitation_selection.dart +++ b/lib/pages/invitation_selection/invitation_selection.dart @@ -12,7 +12,7 @@ import 'package:fluffychat/widgets/matrix.dart'; import '../../utils/localized_exception_extension.dart'; class InvitationSelection extends StatefulWidget { - const InvitationSelection({Key key}) : super(key: key); + const InvitationSelection({Key? key}) : super(key: key); @override InvitationSelectionController createState() => @@ -21,16 +21,16 @@ class InvitationSelection extends StatefulWidget { class InvitationSelectionController extends State { TextEditingController controller = TextEditingController(); - String currentSearchTerm; + late String currentSearchTerm; bool loading = false; List foundProfiles = []; - Timer coolDown; + Timer? coolDown; - String get roomId => VRouter.of(context).pathParameters['roomid']; + String? get roomId => VRouter.of(context).pathParameters['roomid']; Future> getContacts(BuildContext context) async { final client = Matrix.of(context).client; - final room = client.getRoomById(roomId); + final room = client.getRoomById(roomId!)!; final participants = await room.requestParticipants(); participants.removeWhere( (u) => ![Membership.join, Membership.invite].contains(u.membership), @@ -38,7 +38,7 @@ class InvitationSelectionController extends State { final participantsIds = participants.map((p) => p.stateKey).toList(); final contacts = client.rooms .where((r) => r.isDirectChat) - .map((r) => r.getUserByMXIDSync(r.directChatMatrixID)) + .map((r) => r.getUserByMXIDSync(r.directChatMatrixID!)) .toList() ..removeWhere((u) => participantsIds.contains(u.stateKey)); contacts.sort( @@ -50,14 +50,14 @@ class InvitationSelectionController extends State { } void inviteAction(BuildContext context, String id) async { - final room = Matrix.of(context).client.getRoomById(roomId); + final room = Matrix.of(context).client.getRoomById(roomId!); final success = await showFutureLoadingDialog( context: context, - future: () => room.invite(id), + future: () => room!.invite(id), ); if (success.error == null) { ScaffoldMessenger.of(context).showSnackBar(SnackBar( - content: Text(L10n.of(context).contactHasBeenInvitedToTheGroup))); + content: Text(L10n.of(context)!.contactHasBeenInvitedToTheGroup))); } } @@ -84,7 +84,7 @@ class InvitationSelectionController extends State { response = await matrix.client.searchUserDirectory(text, limit: 10); } catch (e) { ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text((e as Object).toLocalizedString(context)))); + SnackBar(content: Text((e).toLocalizedString(context)))); return; } finally { setState(() => loading = false); @@ -99,7 +99,7 @@ class InvitationSelectionController extends State { } final participants = Matrix.of(context) .client - .getRoomById(roomId) + .getRoomById(roomId!)! .getParticipants() .where((user) => [Membership.join, Membership.invite].contains(user.membership)) diff --git a/lib/pages/invitation_selection/invitation_selection_view.dart b/lib/pages/invitation_selection/invitation_selection_view.dart index 41a05735..821f3136 100644 --- a/lib/pages/invitation_selection/invitation_selection_view.dart +++ b/lib/pages/invitation_selection/invitation_selection_view.dart @@ -13,13 +13,12 @@ import 'package:fluffychat/widgets/matrix.dart'; class InvitationSelectionView extends StatelessWidget { final InvitationSelectionController controller; - const InvitationSelectionView(this.controller, {Key key}) : super(key: key); + const InvitationSelectionView(this.controller, {Key? key}) : super(key: key); @override Widget build(BuildContext context) { - final room = Matrix.of(context).client.getRoomById(controller.roomId); - final groupName = - room.name?.isEmpty ?? false ? L10n.of(context).group : room.name; + final room = Matrix.of(context).client.getRoomById(controller.roomId!)!; + final groupName = room.name.isEmpty ? L10n.of(context)!.group : room.name; return Scaffold( appBar: AppBar( leading: VRouter.of(context).path.startsWith('/spaces/') @@ -27,12 +26,12 @@ class InvitationSelectionView extends StatelessWidget { : IconButton( icon: const Icon(Icons.close_outlined), onPressed: () => VRouter.of(context) - .toSegments(['rooms', controller.roomId]), + .toSegments(['rooms', controller.roomId!]), ), titleSpacing: 0, title: DefaultAppBarSearchField( autofocus: true, - hintText: L10n.of(context).inviteContactToGroup(groupName), + hintText: L10n.of(context)!.inviteContactToGroup(groupName), onChanged: controller.searchUserWithCoolDown, ), ), @@ -51,7 +50,7 @@ class InvitationSelectionView extends StatelessWidget { ), title: Text( controller.foundProfiles[i].displayName ?? - controller.foundProfiles[i].userId.localpart, + controller.foundProfiles[i].userId.localpart!, ), subtitle: Text(controller.foundProfiles[i].userId), onTap: () => controller.inviteAction( @@ -66,7 +65,7 @@ class InvitationSelectionView extends StatelessWidget { child: CircularProgressIndicator.adaptive(strokeWidth: 2), ); } - final contacts = snapshot.data; + final contacts = snapshot.data!; return ListView.builder( physics: const NeverScrollableScrollPhysics(), shrinkWrap: true, diff --git a/lib/pages/key_verification/key_verification_dialog.dart b/lib/pages/key_verification/key_verification_dialog.dart index 3f9c8095..53f20b7e 100644 --- a/lib/pages/key_verification/key_verification_dialog.dart +++ b/lib/pages/key_verification/key_verification_dialog.dart @@ -34,8 +34,8 @@ class KeyVerificationDialog extends StatefulWidget { final KeyVerification request; const KeyVerificationDialog({ - Key key, - this.request, + Key? key, + required this.request, }) : super(key: key); @override @@ -43,25 +43,23 @@ class KeyVerificationDialog extends StatefulWidget { } class _KeyVerificationPageState extends State { - void Function() originalOnUpdate; - List sasEmoji; + void Function()? originalOnUpdate; + late final List sasEmoji; @override void initState() { originalOnUpdate = widget.request.onUpdate; widget.request.onUpdate = () { - if (originalOnUpdate != null) { - originalOnUpdate(); - } - setState(() => null); + originalOnUpdate?.call(); + setState(() {}); }; widget.request.client.getProfileFromUserId(widget.request.userId).then((p) { profile = p; - setState(() => null); + setState(() {}); }); rootBundle.loadString('assets/sas-emoji.json').then((e) { sasEmoji = json.decode(e); - setState(() => null); + setState(() {}); }); super.initState(); } @@ -77,12 +75,11 @@ class _KeyVerificationPageState extends State { super.dispose(); } - Profile profile; + Profile? profile; Future checkInput(String input) async { - if (input == null || input.isEmpty) { - return; - } + if (input.isEmpty) return; + final valid = await showFutureLoadingDialog( context: context, future: () async { @@ -101,24 +98,24 @@ class _KeyVerificationPageState extends State { await showOkAlertDialog( useRootNavigator: false, context: context, - message: L10n.of(context).incorrectPassphraseOrKey, + message: L10n.of(context)!.incorrectPassphraseOrKey, ); } } @override Widget build(BuildContext context) { - User user; + User? user; final directChatId = widget.request.client.getDirectChatFromUserId(widget.request.userId); if (directChatId != null) { user = widget.request.client - .getRoomById(directChatId) - ?.getUserByMXIDSync(widget.request.userId); + .getRoomById(directChatId)! + .getUserByMXIDSync(widget.request.userId); } final displayName = - user?.calcDisplayname() ?? widget.request.userId.localpart; - var title = Text(L10n.of(context).verifyTitle); + user?.calcDisplayname() ?? widget.request.userId.localpart!; + var title = Text(L10n.of(context)!.verifyTitle); Widget body; final buttons = []; switch (widget.request.state) { @@ -131,7 +128,7 @@ class _KeyVerificationPageState extends State { child: Column( mainAxisSize: MainAxisSize.min, children: [ - Text(L10n.of(context).askSSSSSign, + Text(L10n.of(context)!.askSSSSSign, style: const TextStyle(fontSize: 20)), Container(height: 10), TextField( @@ -146,7 +143,7 @@ class _KeyVerificationPageState extends State { maxLines: 1, obscureText: true, decoration: InputDecoration( - hintText: L10n.of(context).passphraseOrKey, + hintText: L10n.of(context)!.passphraseOrKey, prefixStyle: TextStyle(color: Theme.of(context).primaryColor), suffixStyle: TextStyle(color: Theme.of(context).primaryColor), border: const OutlineInputBorder(), @@ -156,16 +153,16 @@ class _KeyVerificationPageState extends State { ), ); buttons.add(AdaptiveFlatButton( - label: L10n.of(context).submit, + label: L10n.of(context)!.submit, onPressed: () => checkInput(textEditingController.text), )); buttons.add(AdaptiveFlatButton( - label: L10n.of(context).skip, + label: L10n.of(context)!.skip, onPressed: () => widget.request.openSSSS(skip: true), )); break; case KeyVerificationState.askAccept: - title = Text(L10n.of(context).newVerificationRequest); + title = Text(L10n.of(context)!.newVerificationRequest); body = Column( mainAxisSize: MainAxisSize.min, children: [ @@ -199,19 +196,19 @@ class _KeyVerificationPageState extends State { Image.asset('assets/verification.png', fit: BoxFit.contain), const SizedBox(height: 16), Text( - L10n.of(context).askVerificationRequest(displayName), + L10n.of(context)!.askVerificationRequest(displayName), ) ], ); buttons.add(AdaptiveFlatButton( - label: L10n.of(context).reject, + label: L10n.of(context)!.reject, textColor: Colors.red, onPressed: () => widget.request .rejectVerification() .then((_) => Navigator.of(context, rootNavigator: false).pop()), )); buttons.add(AdaptiveFlatButton( - label: L10n.of(context).accept, + label: L10n.of(context)!.accept, onPressed: () => widget.request.acceptVerification(), )); break; @@ -224,22 +221,22 @@ class _KeyVerificationPageState extends State { const CircularProgressIndicator.adaptive(strokeWidth: 2), const SizedBox(height: 16), Text( - L10n.of(context).waitingPartnerAcceptRequest, + L10n.of(context)!.waitingPartnerAcceptRequest, textAlign: TextAlign.center, ), ], ); final key = widget.request.client.userDeviceKeys[widget.request.userId] - .deviceKeys[widget.request.deviceId]; + ?.deviceKeys[widget.request.deviceId]; if (key != null) { buttons.add(AdaptiveFlatButton( - label: L10n.of(context).verifyManual, + label: L10n.of(context)!.verifyManual, onPressed: () async { final result = await showOkCancelAlertDialog( useRootNavigator: false, context: context, - title: L10n.of(context).verifyManual, - message: key.ed25519Key.beautified, + title: L10n.of(context)!.verifyManual, + message: key.ed25519Key?.beautified ?? 'Key not found', ); if (result == OkCancelResult.ok) { await key.setVerified(true); @@ -257,14 +254,14 @@ class _KeyVerificationPageState extends State { // view for if "emoji" is a present sasType or not? String compareText; if (widget.request.sasTypes.contains('emoji')) { - compareText = L10n.of(context).compareEmojiMatch; + compareText = L10n.of(context)!.compareEmojiMatch; compareWidget = TextSpan( children: widget.request.sasEmojis .map((e) => WidgetSpan(child: _Emoji(e, sasEmoji))) .toList(), ); } else { - compareText = L10n.of(context).compareNumbersMatch; + compareText = L10n.of(context)!.compareNumbersMatch; final numbers = widget.request.sasNumbers; final numbstr = '${numbers[0]}-${numbers[1]}-${numbers[2]}'; compareWidget = @@ -289,18 +286,18 @@ class _KeyVerificationPageState extends State { ); buttons.add(AdaptiveFlatButton( textColor: Colors.red, - label: L10n.of(context).theyDontMatch, + label: L10n.of(context)!.theyDontMatch, onPressed: () => widget.request.rejectSas(), )); buttons.add(AdaptiveFlatButton( - label: L10n.of(context).theyMatch, + label: L10n.of(context)!.theyMatch, onPressed: () => widget.request.acceptSas(), )); break; case KeyVerificationState.waitingSas: final acceptText = widget.request.sasTypes.contains('emoji') - ? L10n.of(context).waitingPartnerEmoji - : L10n.of(context).waitingPartnerNumbers; + ? L10n.of(context)!.waitingPartnerEmoji + : L10n.of(context)!.waitingPartnerNumbers; body = Column( mainAxisSize: MainAxisSize.min, children: [ @@ -321,13 +318,13 @@ class _KeyVerificationPageState extends State { color: Colors.green, size: 200.0), const SizedBox(height: 10), Text( - L10n.of(context).verifySuccess, + L10n.of(context)!.verifySuccess, textAlign: TextAlign.center, ), ], ); buttons.add(AdaptiveFlatButton( - label: L10n.of(context).close, + label: L10n.of(context)!.close, onPressed: () => Navigator.of(context, rootNavigator: false).pop(), )); break; @@ -344,12 +341,11 @@ class _KeyVerificationPageState extends State { ], ); buttons.add(AdaptiveFlatButton( - label: L10n.of(context).close, + label: L10n.of(context)!.close, onPressed: () => Navigator.of(context, rootNavigator: false).pop(), )); break; } - body ??= Text('ERROR: Unknown state ' + widget.request.state.toString()); final content = SingleChildScrollView( scrollDirection: Axis.vertical, child: Column( @@ -377,16 +373,17 @@ class _KeyVerificationPageState extends State { class _Emoji extends StatelessWidget { final KeyVerificationEmoji emoji; - final List sasEmoji; + final List? sasEmoji; const _Emoji(this.emoji, this.sasEmoji); String getLocalizedName() { + final sasEmoji = this.sasEmoji; if (sasEmoji == null) { // asset is still being loaded return emoji.name; } - final translations = Map.from( + final translations = Map.from( sasEmoji[emoji.number]['translated_descriptions']); translations['en'] = emoji.name; for (final locale in window.locales) { @@ -398,7 +395,7 @@ class _Emoji extends StatelessWidget { if (haveLanguage == wantLanguage && (Set.from(haveLocaleParts)..removeAll(wantLocaleParts)).isEmpty && (translations[haveLocale]?.isNotEmpty ?? false)) { - return translations[haveLocale]; + return translations[haveLocale]!; } } } diff --git a/lib/pages/login/login.dart b/lib/pages/login/login.dart index e3f8afde..490418d9 100644 --- a/lib/pages/login/login.dart +++ b/lib/pages/login/login.dart @@ -15,7 +15,7 @@ import '../../utils/platform_infos.dart'; import 'login_view.dart'; class Login extends StatefulWidget { - const Login({Key key}) : super(key: key); + const Login({Key? key}) : super(key: key); @override LoginController createState() => LoginController(); @@ -24,8 +24,8 @@ class Login extends StatefulWidget { class LoginController extends State { final TextEditingController usernameController = TextEditingController(); final TextEditingController passwordController = TextEditingController(); - String usernameError; - String passwordError; + String? usernameError; + String? passwordError; bool loading = false; bool showPassword = false; @@ -34,12 +34,12 @@ class LoginController extends State { void login([_]) async { final matrix = Matrix.of(context); if (usernameController.text.isEmpty) { - setState(() => usernameError = L10n.of(context).pleaseEnterYourUsername); + setState(() => usernameError = L10n.of(context)!.pleaseEnterYourUsername); } else { setState(() => usernameError = null); } if (passwordController.text.isEmpty) { - setState(() => passwordError = L10n.of(context).pleaseEnterYourPassword); + setState(() => passwordError = L10n.of(context)!.pleaseEnterYourPassword); } else { setState(() => passwordError = null); } @@ -85,7 +85,7 @@ class LoginController extends State { if (mounted) setState(() => loading = false); } - Timer _coolDown; + Timer? _coolDown; void checkWellKnownWithCoolDown(String userId) async { _coolDown?.cancel(); @@ -100,14 +100,13 @@ class LoginController extends State { if (!userId.isValidMatrixId) return; try { final oldHomeserver = Matrix.of(context).getLoginClient().homeserver; - var newDomain = Uri.https(userId.domain, ''); + var newDomain = Uri.https(userId.domain!, ''); Matrix.of(context).getLoginClient().homeserver = newDomain; - DiscoveryInformation wellKnownInformation; + DiscoveryInformation? wellKnownInformation; try { wellKnownInformation = await Matrix.of(context).getLoginClient().getWellknown(); - if (wellKnownInformation.mHomeserver?.baseUrl?.toString()?.isNotEmpty ?? - false) { + if (wellKnownInformation.mHomeserver.baseUrl.toString().isNotEmpty) { newDomain = wellKnownInformation.mHomeserver.baseUrl; } } catch (_) { @@ -130,9 +129,10 @@ class LoginController extends State { final dialogResult = await showOkCancelAlertDialog( context: context, useRootNavigator: false, - message: L10n.of(context).noMatrixServer(newDomain, oldHomeserver), - okLabel: L10n.of(context).ok, - cancelLabel: L10n.of(context).cancel, + message: + L10n.of(context)!.noMatrixServer(newDomain, oldHomeserver!), + okLabel: L10n.of(context)!.ok, + cancelLabel: L10n.of(context)!.cancel, ); if (dialogResult == OkCancelResult.ok) { setState(() => usernameError = null); @@ -142,7 +142,7 @@ class LoginController extends State { } } var jitsi = wellKnownInformation?.additionalProperties - ?.tryGet>('im.vector.riot.jitsi') + .tryGet>('im.vector.riot.jitsi') ?.tryGet('preferredDomain'); if (jitsi != null) { if (!jitsi.endsWith('/')) { @@ -168,12 +168,12 @@ class LoginController extends State { final input = await showTextInputDialog( useRootNavigator: false, context: context, - title: L10n.of(context).enterAnEmailAddress, - okLabel: L10n.of(context).ok, - cancelLabel: L10n.of(context).cancel, + title: L10n.of(context)!.enterAnEmailAddress, + okLabel: L10n.of(context)!.ok, + cancelLabel: L10n.of(context)!.cancel, textFields: [ DialogTextField( - hintText: L10n.of(context).enterAnEmailAddress, + hintText: L10n.of(context)!.enterAnEmailAddress, keyboardType: TextInputType.emailAddress, ), ], @@ -194,17 +194,17 @@ class LoginController extends State { final ok = await showOkAlertDialog( useRootNavigator: false, context: context, - title: L10n.of(context).weSentYouAnEmail, - message: L10n.of(context).pleaseClickOnLink, - okLabel: L10n.of(context).iHaveClickedOnLink, + title: L10n.of(context)!.weSentYouAnEmail, + message: L10n.of(context)!.pleaseClickOnLink, + okLabel: L10n.of(context)!.iHaveClickedOnLink, ); - if (ok == null) return; + if (ok != OkCancelResult.ok) return; final password = await showTextInputDialog( useRootNavigator: false, context: context, - title: L10n.of(context).chooseAStrongPassword, - okLabel: L10n.of(context).ok, - cancelLabel: L10n.of(context).cancel, + title: L10n.of(context)!.chooseAStrongPassword, + okLabel: L10n.of(context)!.ok, + cancelLabel: L10n.of(context)!.cancel, textFields: [ const DialogTextField( hintText: '******', @@ -222,7 +222,7 @@ class LoginController extends State { auth: AuthenticationThreePidCreds( type: AuthenticationTypes.emailIdentity, threepidCreds: ThreepidCreds( - sid: response.result.sid, + sid: response.result!.sid, clientSecret: clientSecret, ), ), @@ -230,7 +230,7 @@ class LoginController extends State { ); if (success.error == null) { ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text(L10n.of(context).passwordHasBeenChanged))); + SnackBar(content: Text(L10n.of(context)!.passwordHasBeenChanged))); } } diff --git a/lib/pages/login/login_view.dart b/lib/pages/login/login_view.dart index b8de732b..1b0b44f3 100644 --- a/lib/pages/login/login_view.dart +++ b/lib/pages/login/login_view.dart @@ -9,7 +9,7 @@ import 'login.dart'; class LoginView extends StatelessWidget { final LoginController controller; - const LoginView(this.controller, {Key key}) : super(key: key); + const LoginView(this.controller, {Key? key}) : super(key: key); @override Widget build(BuildContext context) { @@ -19,7 +19,7 @@ class LoginView extends StatelessWidget { leading: controller.loading ? Container() : const BackButton(), elevation: 0, title: Text( - L10n.of(context).logInTo(Matrix.of(context) + L10n.of(context)!.logInTo(Matrix.of(context) .getLoginClient() .homeserver .toString() @@ -42,9 +42,9 @@ class LoginView extends StatelessWidget { controller.loading ? null : [AutofillHints.username], decoration: InputDecoration( prefixIcon: const Icon(Icons.account_box_outlined), - hintText: L10n.of(context).username, + hintText: L10n.of(context)!.username, errorText: controller.usernameError, - labelText: L10n.of(context).username), + labelText: L10n.of(context)!.username), ), ), Padding( @@ -62,13 +62,13 @@ class LoginView extends StatelessWidget { hintText: '****', errorText: controller.passwordError, suffixIcon: IconButton( - tooltip: L10n.of(context).showPassword, + tooltip: L10n.of(context)!.showPassword, icon: Icon(controller.showPassword ? Icons.visibility_off_outlined : Icons.visibility_outlined), onPressed: controller.toggleShowPassword, ), - labelText: L10n.of(context).password, + labelText: L10n.of(context)!.password, ), ), ), @@ -83,7 +83,7 @@ class LoginView extends StatelessWidget { : () => controller.login(context), child: controller.loading ? const LinearProgressIndicator() - : Text(L10n.of(context).login), + : Text(L10n.of(context)!.login), ), ), ), @@ -91,7 +91,7 @@ class LoginView extends StatelessWidget { child: TextButton( onPressed: controller.passwordForgotten, child: Text( - L10n.of(context).passwordForgotten, + L10n.of(context)!.passwordForgotten, style: const TextStyle( color: Colors.blue, decoration: TextDecoration.underline, diff --git a/lib/pages/new_group/new_group.dart b/lib/pages/new_group/new_group.dart index 7b6666f1..d5ae9637 100644 --- a/lib/pages/new_group/new_group.dart +++ b/lib/pages/new_group/new_group.dart @@ -8,7 +8,7 @@ import 'package:fluffychat/pages/new_group/new_group_view.dart'; import 'package:fluffychat/widgets/matrix.dart'; class NewGroup extends StatefulWidget { - const NewGroup({Key key}) : super(key: key); + const NewGroup({Key? key}) : super(key: key); @override NewGroupController createState() => NewGroupController(); @@ -35,7 +35,7 @@ class NewGroupController extends State { }, ); if (roomID.error == null) { - VRouter.of(context).toSegments(['rooms', roomID.result, 'invite']); + VRouter.of(context).toSegments(['rooms', roomID.result!, 'invite']); } } diff --git a/lib/pages/new_group/new_group_view.dart b/lib/pages/new_group/new_group_view.dart index 581a2610..628ab939 100644 --- a/lib/pages/new_group/new_group_view.dart +++ b/lib/pages/new_group/new_group_view.dart @@ -8,13 +8,13 @@ import 'package:fluffychat/widgets/layouts/max_width_body.dart'; class NewGroupView extends StatelessWidget { final NewGroupController controller; - const NewGroupView(this.controller, {Key key}) : super(key: key); + const NewGroupView(this.controller, {Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: Text(L10n.of(context).createNewGroup), + title: Text(L10n.of(context)!.createNewGroup), ), body: MaxWidthBody( child: Column( @@ -29,13 +29,13 @@ class NewGroupView extends StatelessWidget { textInputAction: TextInputAction.go, onSubmitted: controller.submitAction, decoration: InputDecoration( - labelText: L10n.of(context).optionalGroupName, + labelText: L10n.of(context)!.optionalGroupName, prefixIcon: const Icon(Icons.people_outlined), - hintText: L10n.of(context).enterAGroupName), + hintText: L10n.of(context)!.enterAGroupName), ), ), SwitchListTile.adaptive( - title: Text(L10n.of(context).groupIsPublic), + title: Text(L10n.of(context)!.groupIsPublic), value: controller.publicGroup, onChanged: controller.setPublicGroup, ), diff --git a/lib/pages/new_private_chat/new_private_chat.dart b/lib/pages/new_private_chat/new_private_chat.dart index 4cc1e67f..4a01b4e5 100644 --- a/lib/pages/new_private_chat/new_private_chat.dart +++ b/lib/pages/new_private_chat/new_private_chat.dart @@ -11,7 +11,7 @@ import 'package:fluffychat/utils/url_launcher.dart'; import 'package:fluffychat/widgets/matrix.dart'; class NewPrivateChat extends StatefulWidget { - const NewPrivateChat({Key key}) : super(key: key); + const NewPrivateChat({Key? key}) : super(key: key); @override NewPrivateChatController createState() => NewPrivateChatController(); @@ -48,20 +48,20 @@ class NewPrivateChatController extends State { void submitAction([_]) async { controller.text = controller.text.trim(); - if (!formKey.currentState.validate()) return; + if (!formKey.currentState!.validate()) return; UrlLauncher(context, '$prefix${controller.text}').openMatrixToUrl(); } - String validateForm(String value) { - if (value.isEmpty) { - return L10n.of(context).pleaseEnterAMatrixIdentifier; + String? validateForm(String? value) { + if (value!.isEmpty) { + return L10n.of(context)!.pleaseEnterAMatrixIdentifier; } if (!controller.text.isValidMatrixId || !supportedSigils.contains(controller.text.sigil)) { - return L10n.of(context).makeSureTheIdentifierIsValid; + return L10n.of(context)!.makeSureTheIdentifierIsValid; } if (controller.text == Matrix.of(context).client.userID) { - return L10n.of(context).youCannotInviteYourself; + return L10n.of(context)!.youCannotInviteYourself; } return null; } 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 3f79d46e..48c68023 100644 --- a/lib/pages/new_private_chat/new_private_chat_view.dart +++ b/lib/pages/new_private_chat/new_private_chat_view.dart @@ -15,7 +15,7 @@ import 'package:fluffychat/widgets/matrix.dart'; class NewPrivateChatView extends StatelessWidget { final NewPrivateChatController controller; - const NewPrivateChatView(this.controller, {Key key}) : super(key: key); + const NewPrivateChatView(this.controller, {Key? key}) : super(key: key); static const double _qrCodePadding = 8; @@ -24,13 +24,13 @@ class NewPrivateChatView extends StatelessWidget { return Scaffold( appBar: AppBar( leading: const BackButton(), - title: Text(L10n.of(context).newChat), + title: Text(L10n.of(context)!.newChat), backgroundColor: Theme.of(context).scaffoldBackgroundColor, actions: [ TextButton( onPressed: () => VRouter.of(context).to('/newgroup'), child: Text( - L10n.of(context).createNewGroup, + L10n.of(context)!.createNewGroup, style: TextStyle(color: Theme.of(context).colorScheme.secondary), ), ) @@ -67,7 +67,7 @@ class NewPrivateChatView extends StatelessWidget { ), ), ListTile( - subtitle: Text(L10n.of(context).createNewChatExplaination), + subtitle: Text(L10n.of(context)!.createNewChatExplaination), ), Padding( padding: const EdgeInsets.all(12), @@ -81,7 +81,7 @@ class NewPrivateChatView extends StatelessWidget { onFieldSubmitted: controller.submitAction, validator: controller.validateForm, decoration: InputDecoration( - labelText: L10n.of(context).typeInInviteLinkManually, + labelText: L10n.of(context)!.typeInInviteLinkManually, hintText: '@username', prefixText: 'matrix.to/#/', suffixIcon: IconButton( @@ -105,7 +105,7 @@ class NewPrivateChatView extends StatelessWidget { floatingActionButton: PlatformInfos.isMobile && !controller.hideFab ? FloatingActionButton.extended( onPressed: controller.openScannerAction, - label: Text(L10n.of(context).scanQrCode), + label: Text(L10n.of(context)!.scanQrCode), icon: const Icon(Icons.camera_alt_outlined), ) : null, diff --git a/lib/pages/new_private_chat/qr_scanner_modal.dart b/lib/pages/new_private_chat/qr_scanner_modal.dart index ed8f4749..d6fcb6cd 100644 --- a/lib/pages/new_private_chat/qr_scanner_modal.dart +++ b/lib/pages/new_private_chat/qr_scanner_modal.dart @@ -9,7 +9,7 @@ import 'package:qr_code_scanner/qr_code_scanner.dart'; import 'package:fluffychat/utils/url_launcher.dart'; class QrScannerModal extends StatefulWidget { - const QrScannerModal({Key key}) : super(key: key); + const QrScannerModal({Key? key}) : super(key: key); @override _QrScannerModalState createState() => _QrScannerModalState(); @@ -17,15 +17,15 @@ class QrScannerModal extends StatefulWidget { class _QrScannerModalState extends State { final GlobalKey qrKey = GlobalKey(debugLabel: 'QR'); - QRViewController controller; + QRViewController? controller; @override void reassemble() { super.reassemble(); if (Platform.isAndroid) { - controller.pauseCamera(); + controller!.pauseCamera(); } else if (Platform.isIOS) { - controller.resumeCamera(); + controller!.resumeCamera(); } } @@ -36,9 +36,9 @@ class _QrScannerModalState extends State { leading: IconButton( icon: const Icon(Icons.close_outlined), onPressed: Navigator.of(context).pop, - tooltip: L10n.of(context).close, + tooltip: L10n.of(context)!.close, ), - title: Text(L10n.of(context).scanQrCode), + title: Text(L10n.of(context)!.scanQrCode), ), body: Stack( children: [ @@ -59,7 +59,7 @@ class _QrScannerModalState extends State { void _onQRViewCreated(QRViewController controller) { this.controller = controller; - StreamSubscription sub; + late StreamSubscription sub; sub = controller.scannedDataStream.listen((scanData) { sub.cancel(); Navigator.of(context).pop(); diff --git a/lib/pages/new_space/new_space.dart b/lib/pages/new_space/new_space.dart index 0f17d7c7..062b6336 100644 --- a/lib/pages/new_space/new_space.dart +++ b/lib/pages/new_space/new_space.dart @@ -9,7 +9,7 @@ import 'package:fluffychat/pages/new_space/new_space_view.dart'; import 'package:fluffychat/widgets/matrix.dart'; class NewSpace extends StatefulWidget { - const NewSpace({Key key}) : super(key: key); + const NewSpace({Key? key}) : super(key: key); @override NewSpaceController createState() => NewSpaceController(); @@ -38,7 +38,7 @@ class NewSpaceController extends State { ), ); if (roomID.error == null) { - VRouter.of(context).toSegments(['rooms', roomID.result, 'details']); + VRouter.of(context).toSegments(['rooms', roomID.result!, 'details']); } } diff --git a/lib/pages/new_space/new_space_view.dart b/lib/pages/new_space/new_space_view.dart index 17608869..7bbbd1a1 100644 --- a/lib/pages/new_space/new_space_view.dart +++ b/lib/pages/new_space/new_space_view.dart @@ -8,13 +8,13 @@ import 'new_space.dart'; class NewSpaceView extends StatelessWidget { final NewSpaceController controller; - const NewSpaceView(this.controller, {Key key}) : super(key: key); + const NewSpaceView(this.controller, {Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: Text(L10n.of(context).createNewSpace), + title: Text(L10n.of(context)!.createNewSpace), ), body: MaxWidthBody( child: Column( @@ -29,13 +29,13 @@ class NewSpaceView extends StatelessWidget { textInputAction: TextInputAction.go, onSubmitted: controller.submitAction, decoration: InputDecoration( - labelText: L10n.of(context).spaceName, + labelText: L10n.of(context)!.spaceName, prefixIcon: const Icon(Icons.people_outlined), - hintText: L10n.of(context).enterASpacepName), + hintText: L10n.of(context)!.enterASpacepName), ), ), SwitchListTile.adaptive( - title: Text(L10n.of(context).spaceIsPublic), + title: Text(L10n.of(context)!.spaceIsPublic), value: controller.publicGroup, onChanged: controller.setPublicGroup, ), diff --git a/lib/pages/search/search.dart b/lib/pages/search/search.dart index 88edb37f..72fa41e4 100644 --- a/lib/pages/search/search.dart +++ b/lib/pages/search/search.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'dart:async'; import 'package:flutter/material.dart'; @@ -114,7 +112,7 @@ class SearchController extends State { super.initState(); WidgetsBinding.instance?.addPostFrameCallback((_) async { controller.text = VRouter.of(context).queryParameters['query'] ?? ''; - final server = await Store().getItem(_serverStoreNamespace) as String?; + final server = await Store().getItem(_serverStoreNamespace); if (server?.isNotEmpty ?? false) { this.server = server; } diff --git a/lib/pages/search/search_view.dart b/lib/pages/search/search_view.dart index 317b93ac..f586df94 100644 --- a/lib/pages/search/search_view.dart +++ b/lib/pages/search/search_view.dart @@ -17,12 +17,12 @@ import 'search.dart'; class SearchView extends StatelessWidget { final SearchController controller; - const SearchView(this.controller, {Key key}) : super(key: key); + const SearchView(this.controller, {Key? key}) : super(key: key); @override Widget build(BuildContext context) { final server = controller.genericSearchTerm?.isValidMatrixId ?? false - ? controller.genericSearchTerm.domain + ? controller.genericSearchTerm!.domain : controller.server; if (controller.lastServer != server) { controller.lastServer = server; @@ -44,15 +44,22 @@ class SearchView extends StatelessWidget { 'chunk': [], }); }).then((QueryPublicRoomsResponse res) { - if (controller.genericSearchTerm != null && + final genericSearchTerm = controller.genericSearchTerm; + if (genericSearchTerm != null && !res.chunk.any((room) => (room.aliases?.contains(controller.genericSearchTerm) ?? false) || room.canonicalAlias == controller.genericSearchTerm)) { // we have to tack on the original alias - res.chunk.add(PublicRoomsChunk.fromJson({ - 'aliases': [controller.genericSearchTerm], - 'name': controller.genericSearchTerm, - })); + res.chunk.add( + PublicRoomsChunk( + aliases: [genericSearchTerm], + name: genericSearchTerm, + numJoinedMembers: 0, + roomId: '!unknown', + worldReadable: true, + guestCanJoin: true, + ), + ); } return res; }); @@ -68,15 +75,14 @@ class SearchView extends StatelessWidget { const tabCount = 3; return DefaultTabController( length: tabCount, - initialIndex: - controller.controller.text?.startsWith('#') ?? false ? 0 : 1, + initialIndex: controller.controller.text.startsWith('#') ? 0 : 1, child: Scaffold( appBar: AppBar( leading: const BackButton(), titleSpacing: 0, title: DefaultAppBarSearchField( autofocus: true, - hintText: L10n.of(context).search, + hintText: L10n.of(context)!.search, searchController: controller.controller, suffix: const Icon(Icons.search_outlined), onChanged: controller.search, @@ -84,16 +90,16 @@ class SearchView extends StatelessWidget { bottom: TabBar( indicatorColor: Theme.of(context).colorScheme.secondary, labelColor: Theme.of(context).colorScheme.secondary, - unselectedLabelColor: Theme.of(context).textTheme.bodyText1.color, + unselectedLabelColor: Theme.of(context).textTheme.bodyText1!.color, labelStyle: const TextStyle(fontSize: 16), labelPadding: const EdgeInsets.symmetric( horizontal: 8, vertical: 0, ), tabs: [ - Tab(child: Text(L10n.of(context).discover, maxLines: 1)), - Tab(child: Text(L10n.of(context).chats, maxLines: 1)), - Tab(child: Text(L10n.of(context).people, maxLines: 1)), + Tab(child: Text(L10n.of(context)!.discover, maxLines: 1)), + Tab(child: Text(L10n.of(context)!.chats, maxLines: 1)), + Tab(child: Text(L10n.of(context)!.people, maxLines: 1)), ], ), ), @@ -111,7 +117,7 @@ class SearchView extends StatelessWidget { backgroundColor: Theme.of(context).secondaryHeaderColor, child: const Icon(Icons.edit_outlined), ), - title: Text(L10n.of(context).changeTheServer), + title: Text(L10n.of(context)!.changeTheServer), onTap: controller.setServer, ), FutureBuilder( @@ -130,7 +136,7 @@ class SearchView extends StatelessWidget { ), Center( child: Text( - snapshot.error.toLocalizedString(context), + snapshot.error!.toLocalizedString(context), textAlign: TextAlign.center, style: const TextStyle( color: Colors.grey, @@ -146,7 +152,7 @@ class SearchView extends StatelessWidget { child: CircularProgressIndicator.adaptive( strokeWidth: 2)); } - final publicRoomsResponse = snapshot.data; + final publicRoomsResponse = snapshot.data!; if (publicRoomsResponse.chunk.isEmpty) { return Column( mainAxisSize: MainAxisSize.min, @@ -159,7 +165,7 @@ class SearchView extends StatelessWidget { ), Center( child: Text( - L10n.of(context).noPublicRoomsFound, + L10n.of(context)!.noPublicRoomsFound, textAlign: TextAlign.center, style: const TextStyle( color: Colors.grey, @@ -201,7 +207,7 @@ class SearchView extends StatelessWidget { name: publicRoomsResponse.chunk[i].name, ), Text( - publicRoomsResponse.chunk[i].name, + publicRoomsResponse.chunk[i].name!, style: const TextStyle( fontSize: 16, fontWeight: FontWeight.bold, @@ -210,17 +216,16 @@ class SearchView extends StatelessWidget { textAlign: TextAlign.center, ), Text( - L10n.of(context).countParticipants( + L10n.of(context)!.countParticipants( publicRoomsResponse - .chunk[i].numJoinedMembers ?? - 0), + .chunk[i].numJoinedMembers), style: const TextStyle(fontSize: 10.5), maxLines: 1, textAlign: TextAlign.center, ), Text( publicRoomsResponse.chunk[i].topic ?? - L10n.of(context).noDescription, + L10n.of(context)!.noDescription, maxLines: 4, textAlign: TextAlign.center, ), @@ -261,7 +266,7 @@ class SearchView extends StatelessWidget { ); if (roomID.error == null) { VRouter.of(context) - .toSegments(['rooms', roomID.result]); + .toSegments(['rooms', roomID.result!]); } }, leading: Avatar( @@ -271,7 +276,7 @@ class SearchView extends StatelessWidget { ), title: Text( foundProfile.displayName ?? - foundProfile.userId.localpart, + foundProfile.userId.localpart!, style: const TextStyle(), maxLines: 1, ), diff --git a/lib/pages/settings/settings.dart b/lib/pages/settings/settings.dart index e42163f4..56026783 100644 --- a/lib/pages/settings/settings.dart +++ b/lib/pages/settings/settings.dart @@ -14,19 +14,19 @@ import '../../widgets/matrix.dart'; import 'settings_view.dart'; class Settings extends StatefulWidget { - const Settings({Key key}) : super(key: key); + const Settings({Key? key}) : super(key: key); @override SettingsController createState() => SettingsController(); } class SettingsController extends State { - Future crossSigningCachedFuture; - bool crossSigningCached; - Future megolmBackupCachedFuture; - bool megolmBackupCached; - Future profileFuture; - Profile profile; + Future? crossSigningCachedFuture; + bool? crossSigningCached; + Future? megolmBackupCachedFuture; + bool? megolmBackupCached; + Future? profileFuture; + Profile? profile; bool profileUpdated = false; void updateProfile() => setState(() { @@ -39,19 +39,19 @@ class SettingsController extends State { if (PlatformInfos.isMobile) SheetAction( key: AvatarAction.camera, - label: L10n.of(context).openCamera, + label: L10n.of(context)!.openCamera, isDefaultAction: true, icon: Icons.camera_alt_outlined, ), SheetAction( key: AvatarAction.file, - label: L10n.of(context).openGallery, + label: L10n.of(context)!.openGallery, icon: Icons.photo_outlined, ), if (profile?.avatarUrl != null) SheetAction( key: AvatarAction.remove, - label: L10n.of(context).removeYourAvatar, + label: L10n.of(context)!.removeYourAvatar, isDestructiveAction: true, icon: Icons.delete_outlined, ), @@ -60,7 +60,7 @@ class SettingsController extends State { ? actions.single : await showModalActionSheet( context: context, - title: L10n.of(context).changeYourAvatar, + title: L10n.of(context)!.changeYourAvatar, actions: actions, ); if (action == null) return; @@ -91,10 +91,10 @@ class SettingsController extends State { } else { final result = await FilePickerCross.importFromStorage(type: FileTypeCross.image); - if (result == null) return; + if (result.fileName == null) return; file = MatrixFile( bytes: result.toUint8List(), - name: result.fileName, + name: result.fileName!, ); } final success = await showFutureLoadingDialog( @@ -111,7 +111,7 @@ class SettingsController extends State { final client = Matrix.of(context).client; profileFuture ??= client .getProfileFromUserId( - client.userID, + client.userID!, cache: !profileUpdated, getFromRooms: !profileUpdated, ) @@ -121,12 +121,12 @@ class SettingsController extends State { }); if (client.encryption != null) { crossSigningCachedFuture ??= - client.encryption?.crossSigning?.isCached()?.then((c) { + client.encryption?.crossSigning.isCached().then((c) { if (mounted) setState(() => crossSigningCached = c); return c; }); megolmBackupCachedFuture ??= - client.encryption?.keyManager?.isCached()?.then((c) { + client.encryption?.keyManager.isCached().then((c) { if (mounted) setState(() => megolmBackupCached = c); return c; }); diff --git a/lib/pages/settings/settings_view.dart b/lib/pages/settings/settings_view.dart index 00639bad..c2146f4d 100644 --- a/lib/pages/settings/settings_view.dart +++ b/lib/pages/settings/settings_view.dart @@ -13,7 +13,7 @@ import 'settings.dart'; class SettingsView extends StatelessWidget { final SettingsController controller; - const SettingsView(this.controller, {Key key}) : super(key: key); + const SettingsView(this.controller, {Key? key}) : super(key: key); @override Widget build(BuildContext context) { @@ -25,11 +25,11 @@ class SettingsView extends StatelessWidget { expandedHeight: 300.0, floating: true, pinned: true, - title: Text(L10n.of(context).settings), + title: Text(L10n.of(context)!.settings), backgroundColor: Theme.of(context).appBarTheme.backgroundColor, flexibleSpace: FlexibleSpaceBar( background: ContentBanner( - controller.profile?.avatarUrl, + mxContent: controller.profile?.avatarUrl, onEdit: controller.setAvatarAction, defaultIcon: Icons.person_outline_outlined, ), @@ -37,54 +37,54 @@ class SettingsView extends StatelessWidget { ), ], body: ListTileTheme( - iconColor: Theme.of(context).textTheme.bodyText1.color, + iconColor: Theme.of(context).textTheme.bodyText1!.color, child: ListView( children: [ ListTile( leading: const Icon(Icons.format_paint_outlined), - title: Text(L10n.of(context).changeTheme), + title: Text(L10n.of(context)!.changeTheme), onTap: () => VRouter.of(context).to('/settings/style'), ), const Divider(thickness: 1), ListTile( leading: const Icon(Icons.notifications_outlined), - title: Text(L10n.of(context).notifications), + title: Text(L10n.of(context)!.notifications), onTap: () => VRouter.of(context).to('/settings/notifications'), ), ListTile( leading: const Icon(Icons.devices_outlined), - title: Text(L10n.of(context).devices), + title: Text(L10n.of(context)!.devices), onTap: () => VRouter.of(context).to('/settings/devices'), ), ListTile( leading: const Icon(Icons.chat_bubble_outline_outlined), - title: Text(L10n.of(context).chat), + title: Text(L10n.of(context)!.chat), onTap: () => VRouter.of(context).to('/settings/chat'), ), ListTile( leading: const Icon(Icons.account_circle_outlined), - title: Text(L10n.of(context).account), + title: Text(L10n.of(context)!.account), onTap: () => VRouter.of(context).to('/settings/account'), ), ListTile( leading: const Icon(Icons.shield_outlined), - title: Text(L10n.of(context).security), + title: Text(L10n.of(context)!.security), onTap: () => VRouter.of(context).to('/settings/security'), ), const Divider(thickness: 1), ListTile( leading: const Icon(Icons.help_outline_outlined), - title: Text(L10n.of(context).help), + title: Text(L10n.of(context)!.help), onTap: () => launch(AppConfig.supportUrl), ), ListTile( leading: const Icon(Icons.shield_sharp), - title: Text(L10n.of(context).privacy), + title: Text(L10n.of(context)!.privacy), onTap: () => launch(AppConfig.privacyUrl), ), ListTile( leading: const Icon(Icons.info_outline_rounded), - title: Text(L10n.of(context).about), + title: Text(L10n.of(context)!.about), onTap: () => PlatformInfos.showDialog(context), ), ], diff --git a/lib/pages/settings_3pid/settings_3pid.dart b/lib/pages/settings_3pid/settings_3pid.dart index 46afaf60..56a7a8d0 100644 --- a/lib/pages/settings_3pid/settings_3pid.dart +++ b/lib/pages/settings_3pid/settings_3pid.dart @@ -11,7 +11,7 @@ import 'settings_3pid_view.dart'; class Settings3Pid extends StatefulWidget { static int sendAttempt = 0; - const Settings3Pid({Key key}) : super(key: key); + const Settings3Pid({Key? key}) : super(key: key); @override Settings3PidController createState() => Settings3PidController(); @@ -22,12 +22,12 @@ class Settings3PidController extends State { final input = await showTextInputDialog( useRootNavigator: false, context: context, - title: L10n.of(context).enterAnEmailAddress, - okLabel: L10n.of(context).ok, - cancelLabel: L10n.of(context).cancel, + title: L10n.of(context)!.enterAnEmailAddress, + okLabel: L10n.of(context)!.ok, + cancelLabel: L10n.of(context)!.cancel, textFields: [ DialogTextField( - hintText: L10n.of(context).enterAnEmailAddress, + hintText: L10n.of(context)!.enterAnEmailAddress, keyboardType: TextInputType.emailAddress, ), ], @@ -46,17 +46,17 @@ class Settings3PidController extends State { final ok = await showOkAlertDialog( useRootNavigator: false, context: context, - title: L10n.of(context).weSentYouAnEmail, - message: L10n.of(context).pleaseClickOnLink, - okLabel: L10n.of(context).iHaveClickedOnLink, + title: L10n.of(context)!.weSentYouAnEmail, + message: L10n.of(context)!.pleaseClickOnLink, + okLabel: L10n.of(context)!.iHaveClickedOnLink, ); - if (ok == null) return; + if (ok != OkCancelResult.ok) return; final success = await showFutureLoadingDialog( context: context, future: () => Matrix.of(context).client.uiaRequestBackground( (auth) => Matrix.of(context).client.add3PID( clientSecret, - response.result.sid, + response.result!.sid, auth: auth, ), ), @@ -65,15 +65,15 @@ class Settings3PidController extends State { setState(() => request = null); } - Future> request; + Future?>? request; void delete3Pid(ThirdPartyIdentifier identifier) async { if (await showOkCancelAlertDialog( useRootNavigator: false, context: context, - title: L10n.of(context).areYouSure, - okLabel: L10n.of(context).yes, - cancelLabel: L10n.of(context).cancel, + title: L10n.of(context)!.areYouSure, + okLabel: L10n.of(context)!.yes, + cancelLabel: L10n.of(context)!.cancel, ) != OkCancelResult.ok) { return; diff --git a/lib/pages/settings_3pid/settings_3pid_view.dart b/lib/pages/settings_3pid/settings_3pid_view.dart index 544d720a..07ed7a4c 100644 --- a/lib/pages/settings_3pid/settings_3pid_view.dart +++ b/lib/pages/settings_3pid/settings_3pid_view.dart @@ -10,7 +10,7 @@ import 'package:fluffychat/widgets/matrix.dart'; class Settings3PidView extends StatelessWidget { final Settings3PidController controller; - const Settings3PidView(this.controller, {Key key}) : super(key: key); + const Settings3PidView(this.controller, {Key? key}) : super(key: key); @override Widget build(BuildContext context) { @@ -18,20 +18,20 @@ class Settings3PidView extends StatelessWidget { return Scaffold( appBar: AppBar( leading: const BackButton(), - title: Text(L10n.of(context).passwordRecovery), + title: Text(L10n.of(context)!.passwordRecovery), actions: [ IconButton( icon: const Icon(Icons.add_outlined), onPressed: controller.add3PidAction, - tooltip: L10n.of(context).addEmail, + tooltip: L10n.of(context)!.addEmail, ) ], ), body: MaxWidthBody( - child: FutureBuilder>( + child: FutureBuilder?>( future: controller.request, builder: (BuildContext context, - AsyncSnapshot> snapshot) { + AsyncSnapshot?> snapshot) { if (snapshot.hasError) { return Center( child: Text( @@ -44,7 +44,7 @@ class Settings3PidView extends StatelessWidget { return const Center( child: CircularProgressIndicator.adaptive(strokeWidth: 2)); } - final identifier = snapshot.data; + final identifier = snapshot.data!; return Column( children: [ ListTile( @@ -60,8 +60,8 @@ class Settings3PidView extends StatelessWidget { ), title: Text( identifier.isEmpty - ? L10n.of(context).noPasswordRecoveryDescription - : L10n.of(context) + ? L10n.of(context)!.noPasswordRecoveryDescription + : L10n.of(context)! .withTheseAddressesRecoveryDescription, ), ), @@ -77,7 +77,7 @@ class Settings3PidView extends StatelessWidget { child: Icon(identifier[i].iconData)), title: Text(identifier[i].address), trailing: IconButton( - tooltip: L10n.of(context).delete, + tooltip: L10n.of(context)!.delete, icon: const Icon(Icons.delete_forever_outlined), color: Colors.red, onPressed: () => controller.delete3Pid(identifier[i]), @@ -102,6 +102,5 @@ extension on ThirdPartyIdentifier { case ThirdPartyIdentifierMedium.msisdn: return Icons.phone_android_outlined; } - return Icons.device_unknown_outlined; } } diff --git a/lib/pages/settings_account/settings_account.dart b/lib/pages/settings_account/settings_account.dart index ea32f399..3bf2fa5d 100644 --- a/lib/pages/settings_account/settings_account.dart +++ b/lib/pages/settings_account/settings_account.dart @@ -10,15 +10,15 @@ import 'package:fluffychat/pages/settings_account/settings_account_view.dart'; import 'package:fluffychat/widgets/matrix.dart'; class SettingsAccount extends StatefulWidget { - const SettingsAccount({Key key}) : super(key: key); + const SettingsAccount({Key? key}) : super(key: key); @override SettingsAccountController createState() => SettingsAccountController(); } class SettingsAccountController extends State { - Future profileFuture; - Profile profile; + Future? profileFuture; + Profile? profile; bool profileUpdated = false; void updateProfile() => setState(() { @@ -30,13 +30,13 @@ class SettingsAccountController extends State { final input = await showTextInputDialog( useRootNavigator: false, context: context, - title: L10n.of(context).editDisplayname, - okLabel: L10n.of(context).ok, - cancelLabel: L10n.of(context).cancel, + title: L10n.of(context)!.editDisplayname, + okLabel: L10n.of(context)!.ok, + cancelLabel: L10n.of(context)!.cancel, textFields: [ DialogTextField( initialText: profile?.displayName ?? - Matrix.of(context).client.userID.localpart, + Matrix.of(context).client.userID!.localpart, ) ], ); @@ -45,7 +45,7 @@ class SettingsAccountController extends State { final success = await showFutureLoadingDialog( context: context, future: () => - matrix.client.setDisplayName(matrix.client.userID, input.single), + matrix.client.setDisplayName(matrix.client.userID!, input.single), ); if (success.error == null) { updateProfile(); @@ -56,9 +56,9 @@ class SettingsAccountController extends State { if (await showOkCancelAlertDialog( useRootNavigator: false, context: context, - title: L10n.of(context).areYouSureYouWantToLogout, - okLabel: L10n.of(context).yes, - cancelLabel: L10n.of(context).cancel, + title: L10n.of(context)!.areYouSureYouWantToLogout, + okLabel: L10n.of(context)!.yes, + cancelLabel: L10n.of(context)!.cancel, ) == OkCancelResult.cancel) { return; @@ -74,10 +74,10 @@ class SettingsAccountController extends State { if (await showOkCancelAlertDialog( useRootNavigator: false, context: context, - title: L10n.of(context).warning, - message: L10n.of(context).deactivateAccountWarning, - okLabel: L10n.of(context).ok, - cancelLabel: L10n.of(context).cancel, + title: L10n.of(context)!.warning, + message: L10n.of(context)!.deactivateAccountWarning, + okLabel: L10n.of(context)!.ok, + cancelLabel: L10n.of(context)!.cancel, ) == OkCancelResult.cancel) { return; @@ -85,9 +85,9 @@ class SettingsAccountController extends State { if (await showOkCancelAlertDialog( useRootNavigator: false, context: context, - title: L10n.of(context).areYouSure, - okLabel: L10n.of(context).yes, - cancelLabel: L10n.of(context).cancel, + title: L10n.of(context)!.areYouSure, + okLabel: L10n.of(context)!.yes, + cancelLabel: L10n.of(context)!.cancel, ) == OkCancelResult.cancel) { return; @@ -95,9 +95,9 @@ class SettingsAccountController extends State { final input = await showTextInputDialog( useRootNavigator: false, context: context, - title: L10n.of(context).pleaseEnterYourPassword, - okLabel: L10n.of(context).ok, - cancelLabel: L10n.of(context).cancel, + title: L10n.of(context)!.pleaseEnterYourPassword, + okLabel: L10n.of(context)!.ok, + cancelLabel: L10n.of(context)!.cancel, textFields: [ const DialogTextField( obscureText: true, @@ -114,7 +114,7 @@ class SettingsAccountController extends State { auth: AuthenticationPassword( password: input.single, identifier: AuthenticationUserIdentifier( - user: Matrix.of(context).client.userID), + user: Matrix.of(context).client.userID!), ), ), ); @@ -127,7 +127,7 @@ class SettingsAccountController extends State { final client = Matrix.of(context).client; profileFuture ??= client .getProfileFromUserId( - client.userID, + client.userID!, cache: !profileUpdated, getFromRooms: !profileUpdated, ) diff --git a/lib/pages/settings_account/settings_account_view.dart b/lib/pages/settings_account/settings_account_view.dart index ca65a17b..267bc07c 100644 --- a/lib/pages/settings_account/settings_account_view.dart +++ b/lib/pages/settings_account/settings_account_view.dart @@ -10,51 +10,51 @@ import 'settings_account.dart'; class SettingsAccountView extends StatelessWidget { final SettingsAccountController controller; - const SettingsAccountView(this.controller, {Key key}) : super(key: key); + const SettingsAccountView(this.controller, {Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(title: Text(L10n.of(context).account)), + appBar: AppBar(title: Text(L10n.of(context)!.account)), body: ListTileTheme( - iconColor: Theme.of(context).textTheme.bodyText1.color, + iconColor: Theme.of(context).textTheme.bodyText1!.color, child: MaxWidthBody( withScrolling: true, child: Column( children: [ ListTile( - title: Text(L10n.of(context).yourUserId), - subtitle: Text(Matrix.of(context).client.userID), + title: Text(L10n.of(context)!.yourUserId), + subtitle: Text(Matrix.of(context).client.userID!), trailing: const Icon(Icons.copy_outlined), onTap: () => FluffyShare.share( - Matrix.of(context).client.userID, + Matrix.of(context).client.userID!, context, ), ), ListTile( trailing: const Icon(Icons.edit_outlined), - title: Text(L10n.of(context).editDisplayname), + title: Text(L10n.of(context)!.editDisplayname), subtitle: Text(controller.profile?.displayName ?? - Matrix.of(context).client.userID.localpart), + Matrix.of(context).client.userID!.localpart!), onTap: controller.setDisplaynameAction, ), const Divider(height: 1), ListTile( trailing: const Icon(Icons.person_add_outlined), - title: Text(L10n.of(context).addAccount), - subtitle: Text(L10n.of(context).enableMultiAccounts), + title: Text(L10n.of(context)!.addAccount), + subtitle: Text(L10n.of(context)!.enableMultiAccounts), onTap: controller.addAccountAction, ), ListTile( trailing: const Icon(Icons.exit_to_app_outlined), - title: Text(L10n.of(context).logout), + title: Text(L10n.of(context)!.logout), onTap: controller.logoutAction, ), const Divider(height: 1), ListTile( trailing: const Icon(Icons.delete_outlined), title: Text( - L10n.of(context).deleteAccount, + L10n.of(context)!.deleteAccount, style: const TextStyle(color: Colors.red), ), onTap: controller.deleteAccountAction, diff --git a/lib/pages/settings_chat/settings_chat.dart b/lib/pages/settings_chat/settings_chat.dart index 68ff5c7f..7e412d3c 100644 --- a/lib/pages/settings_chat/settings_chat.dart +++ b/lib/pages/settings_chat/settings_chat.dart @@ -9,7 +9,7 @@ import 'package:fluffychat/widgets/matrix.dart'; import 'settings_chat_view.dart'; class SettingsChat extends StatefulWidget { - const SettingsChat({Key key}) : super(key: key); + const SettingsChat({Key? key}) : super(key: key); @override SettingsChatController createState() => SettingsChatController(); @@ -21,9 +21,9 @@ class SettingsChatController extends State { final input = await showTextInputDialog( useRootNavigator: false, context: context, - title: L10n.of(context).editJitsiInstance, - okLabel: L10n.of(context).ok, - cancelLabel: L10n.of(context).cancel, + title: L10n.of(context)!.editJitsiInstance, + okLabel: L10n.of(context)!.ok, + cancelLabel: L10n.of(context)!.cancel, textFields: [ DialogTextField( initialText: AppConfig.jitsiInstance.replaceFirst(prefix, ''), diff --git a/lib/pages/settings_chat/settings_chat_view.dart b/lib/pages/settings_chat/settings_chat_view.dart index 073f6b50..b406e8b8 100644 --- a/lib/pages/settings_chat/settings_chat_view.dart +++ b/lib/pages/settings_chat/settings_chat_view.dart @@ -12,52 +12,52 @@ import 'settings_chat.dart'; class SettingsChatView extends StatelessWidget { final SettingsChatController controller; - const SettingsChatView(this.controller, {Key key}) : super(key: key); + const SettingsChatView(this.controller, {Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(title: Text(L10n.of(context).chat)), + appBar: AppBar(title: Text(L10n.of(context)!.chat)), body: ListTileTheme( - iconColor: Theme.of(context).textTheme.bodyText1.color, + iconColor: Theme.of(context).textTheme.bodyText1!.color, child: MaxWidthBody( withScrolling: true, child: Column( children: [ SettingsSwitchListTile.adaptive( - title: L10n.of(context).renderRichContent, + title: L10n.of(context)!.renderRichContent, onChanged: (b) => AppConfig.renderHtml = b, storeKey: SettingKeys.renderHtml, defaultValue: AppConfig.renderHtml, ), SettingsSwitchListTile.adaptive( - title: L10n.of(context).hideRedactedEvents, + title: L10n.of(context)!.hideRedactedEvents, onChanged: (b) => AppConfig.hideRedactedEvents = b, storeKey: SettingKeys.hideRedactedEvents, defaultValue: AppConfig.hideRedactedEvents, ), SettingsSwitchListTile.adaptive( - title: L10n.of(context).hideUnknownEvents, + title: L10n.of(context)!.hideUnknownEvents, onChanged: (b) => AppConfig.hideUnknownEvents = b, storeKey: SettingKeys.hideUnknownEvents, defaultValue: AppConfig.hideUnknownEvents, ), SettingsSwitchListTile.adaptive( - title: L10n.of(context).autoplayImages, + title: L10n.of(context)!.autoplayImages, onChanged: (b) => AppConfig.autoplayImages = b, storeKey: SettingKeys.autoplayImages, defaultValue: AppConfig.autoplayImages, ), if (PlatformInfos.isMobile) SettingsSwitchListTile.adaptive( - title: L10n.of(context).sendOnEnter, + title: L10n.of(context)!.sendOnEnter, onChanged: (b) => AppConfig.sendOnEnter = b, storeKey: SettingKeys.sendOnEnter, defaultValue: AppConfig.sendOnEnter, ), const Divider(height: 1), ListTile( - title: Text(L10n.of(context).emoteSettings), + title: Text(L10n.of(context)!.emoteSettings), onTap: () => VRouter.of(context).to('emotes'), trailing: const Padding( padding: EdgeInsets.all(16.0), @@ -69,7 +69,7 @@ class SettingsChatView extends StatelessWidget { padding: EdgeInsets.all(16.0), child: Icon(Icons.phone_outlined), ), - title: Text(L10n.of(context).editJitsiInstance), + title: Text(L10n.of(context)!.editJitsiInstance), subtitle: Text(AppConfig.jitsiInstance), onTap: controller.setJitsiInstanceAction, ), diff --git a/lib/pages/settings_emotes/settings_emotes.dart b/lib/pages/settings_emotes/settings_emotes.dart index ba8ad241..c96df15a 100644 --- a/lib/pages/settings_emotes/settings_emotes.dart +++ b/lib/pages/settings_emotes/settings_emotes.dart @@ -12,27 +12,27 @@ import '../../widgets/matrix.dart'; import 'settings_emotes_view.dart'; class EmotesSettings extends StatefulWidget { - const EmotesSettings({Key key}) : super(key: key); + const EmotesSettings({Key? key}) : super(key: key); @override EmotesSettingsController createState() => EmotesSettingsController(); } class EmotesSettingsController extends State { - String get roomId => VRouter.of(context).pathParameters['roomid']; - Room get room => - roomId != null ? Matrix.of(context).client.getRoomById(roomId) : null; - String get stateKey => VRouter.of(context).pathParameters['state_key']; + String? get roomId => VRouter.of(context).pathParameters['roomid']; + Room? get room => + roomId != null ? Matrix.of(context).client.getRoomById(roomId!) : null; + String? get stateKey => VRouter.of(context).pathParameters['state_key']; bool showSave = false; TextEditingController newImageCodeController = TextEditingController(); - ValueNotifier newImageController = - ValueNotifier(null); + ValueNotifier newImageController = + ValueNotifier(null); ImagePackContent _getPack() { final client = Matrix.of(context).client; final event = (room != null - ? room.getState('im.ponies.room_emotes', stateKey ?? '') + ? room!.getState('im.ponies.room_emotes', stateKey ?? '') : client.accountData['im.ponies.user_emotes']) ?? BasicEvent.fromJson({ 'type': 'm.dummy', @@ -42,8 +42,8 @@ class EmotesSettingsController extends State { return BasicEvent.fromJson(event.toJson()).parsedImagePackContent; } - ImagePackContent _pack; - ImagePackContent get pack { + ImagePackContent? _pack; + ImagePackContent? get pack { if (_pack != null) { return _pack; } @@ -60,13 +60,13 @@ class EmotesSettingsController extends State { await showFutureLoadingDialog( context: context, future: () => client.setRoomStateWithKey( - room.id, 'im.ponies.room_emotes', stateKey ?? '', pack.toJson()), + room!.id, 'im.ponies.room_emotes', stateKey ?? '', pack!.toJson()), ); } else { await showFutureLoadingDialog( context: context, future: () => client.setAccountData( - client.userID, 'im.ponies.user_emotes', pack.toJson()), + client.userID!, 'im.ponies.user_emotes', pack!.toJson()), ); } } @@ -82,26 +82,26 @@ class EmotesSettingsController extends State { if (content['rooms'] is! Map) { content['rooms'] = {}; } - if (content['rooms'][room.id] is! Map) { - content['rooms'][room.id] = {}; + if (content['rooms'][room!.id] is! Map) { + content['rooms'][room!.id] = {}; } - if (content['rooms'][room.id][stateKey ?? ''] is! Map) { - content['rooms'][room.id][stateKey ?? ''] = {}; + if (content['rooms'][room!.id][stateKey ?? ''] is! Map) { + content['rooms'][room!.id][stateKey ?? ''] = {}; } - } else if (content['rooms'] is Map && content['rooms'][room.id] is Map) { - content['rooms'][room.id].remove(stateKey ?? ''); + } else if (content['rooms'] is Map && content['rooms'][room!.id] is Map) { + content['rooms'][room!.id].remove(stateKey ?? ''); } // and save await showFutureLoadingDialog( context: context, future: () => client.setAccountData( - client.userID, 'im.ponies.emote_rooms', content), + client.userID!, 'im.ponies.emote_rooms', content), ); - setState(() => null); + setState(() {}); } void removeImageAction(String oldImageCode) => setState(() { - pack.images.remove(oldImageCode); + pack!.images.remove(oldImageCode); showSave = true; }); @@ -111,13 +111,13 @@ class EmotesSettingsController extends State { ImagePackImageContent image, TextEditingController controller, ) { - if (pack.images.keys.any((k) => k == imageCode && k != oldImageCode)) { + if (pack!.images.keys.any((k) => k == imageCode && k != oldImageCode)) { controller.text = oldImageCode; showOkAlertDialog( useRootNavigator: false, context: context, - message: L10n.of(context).emoteExists, - okLabel: L10n.of(context).ok, + message: L10n.of(context)!.emoteExists, + okLabel: L10n.of(context)!.ok, ); return; } @@ -126,29 +126,29 @@ class EmotesSettingsController extends State { showOkAlertDialog( useRootNavigator: false, context: context, - message: L10n.of(context).emoteInvalid, - okLabel: L10n.of(context).ok, + message: L10n.of(context)!.emoteInvalid, + okLabel: L10n.of(context)!.ok, ); return; } setState(() { - pack.images[imageCode] = image; - pack.images.remove(oldImageCode); + pack!.images[imageCode] = image; + pack!.images.remove(oldImageCode); showSave = true; }); } - bool isGloballyActive(Client client) => + bool isGloballyActive(Client? client) => room != null && - client.accountData['im.ponies.emote_rooms']?.content is Map && - client.accountData['im.ponies.emote_rooms'].content['rooms'] is Map && - client.accountData['im.ponies.emote_rooms'].content['rooms'][room.id] + client!.accountData['im.ponies.emote_rooms']?.content is Map && + client.accountData['im.ponies.emote_rooms']!.content['rooms'] is Map && + client.accountData['im.ponies.emote_rooms']!.content['rooms'][room!.id] is Map && - client.accountData['im.ponies.emote_rooms'].content['rooms'][room.id] + client.accountData['im.ponies.emote_rooms']!.content['rooms'][room!.id] [stateKey ?? ''] is Map; bool get readonly => - room == null ? false : !(room.canSendEvent('im.ponies.room_emotes')); + room == null ? false : !(room!.canSendEvent('im.ponies.room_emotes')); void saveAction() async { await _save(context); @@ -158,24 +158,23 @@ class EmotesSettingsController extends State { } void addImageAction() async { - if (newImageCodeController.text == null || - newImageCodeController.text.isEmpty || + if (newImageCodeController.text.isEmpty || newImageController.value == null) { await showOkAlertDialog( useRootNavigator: false, context: context, - message: L10n.of(context).emoteWarnNeedToPick, - okLabel: L10n.of(context).ok, + message: L10n.of(context)!.emoteWarnNeedToPick, + okLabel: L10n.of(context)!.ok, ); return; } final imageCode = newImageCodeController.text; - if (pack.images.containsKey(imageCode)) { + if (pack!.images.containsKey(imageCode)) { await showOkAlertDialog( useRootNavigator: false, context: context, - message: L10n.of(context).emoteExists, - okLabel: L10n.of(context).ok, + message: L10n.of(context)!.emoteExists, + okLabel: L10n.of(context)!.ok, ); return; } @@ -183,12 +182,12 @@ class EmotesSettingsController extends State { await showOkAlertDialog( useRootNavigator: false, context: context, - message: L10n.of(context).emoteInvalid, - okLabel: L10n.of(context).ok, + message: L10n.of(context)!.emoteInvalid, + okLabel: L10n.of(context)!.ok, ); return; } - pack.images[imageCode] = newImageController.value; + pack!.images[imageCode] = newImageController.value!; await _save(context); setState(() { newImageCodeController.text = ''; @@ -198,13 +197,13 @@ class EmotesSettingsController extends State { } void imagePickerAction( - ValueNotifier controller) async { + ValueNotifier controller) async { final result = await FilePickerCross.importFromStorage(type: FileTypeCross.image); - if (result == null) return; + if (result.fileName == null) return; var file = MatrixImageFile( bytes: result.toUint8List(), - name: result.fileName, + name: result.fileName!, ); try { file = await file.resizeImage(calcBlurhash: false); diff --git a/lib/pages/settings_emotes/settings_emotes_view.dart b/lib/pages/settings_emotes/settings_emotes_view.dart index fc167d58..9307faad 100644 --- a/lib/pages/settings_emotes/settings_emotes_view.dart +++ b/lib/pages/settings_emotes/settings_emotes_view.dart @@ -13,16 +13,16 @@ import 'settings_emotes.dart'; class EmotesSettingsView extends StatelessWidget { final EmotesSettingsController controller; - const EmotesSettingsView(this.controller, {Key key}) : super(key: key); + const EmotesSettingsView(this.controller, {Key? key}) : super(key: key); @override Widget build(BuildContext context) { final client = Matrix.of(context).client; - final imageKeys = controller.pack.images.keys.toList(); + final imageKeys = controller.pack!.images.keys.toList(); return Scaffold( appBar: AppBar( leading: const BackButton(), - title: Text(L10n.of(context).emoteSettings), + title: Text(L10n.of(context)!.emoteSettings), ), floatingActionButton: controller.showSave ? FloatingActionButton( @@ -53,7 +53,7 @@ class EmotesSettingsView extends StatelessWidget { minLines: 1, maxLines: 1, decoration: InputDecoration( - hintText: L10n.of(context).emoteShortcode, + hintText: L10n.of(context)!.emoteShortcode, prefixText: ': ', suffixText: ':', prefixStyle: TextStyle( @@ -84,7 +84,7 @@ class EmotesSettingsView extends StatelessWidget { ), if (controller.room != null) SwitchListTile.adaptive( - title: Text(L10n.of(context).enableEmotesGlobally), + title: Text(L10n.of(context)!.enableEmotesGlobally), value: controller.isGloballyActive(client), onChanged: controller.setIsGloballyActive, ), @@ -100,7 +100,7 @@ class EmotesSettingsView extends StatelessWidget { child: Padding( padding: const EdgeInsets.all(16), child: Text( - L10n.of(context).noEmotesFound, + L10n.of(context)!.noEmotesFound, style: const TextStyle(fontSize: 20), ), ), @@ -114,7 +114,7 @@ class EmotesSettingsView extends StatelessWidget { return Container(height: 70); } final imageCode = imageKeys[i]; - final image = controller.pack.images[imageCode]; + final image = controller.pack!.images[imageCode]!; final textEditingController = TextEditingController(); textEditingController.text = imageCode; final useShortCuts = @@ -158,7 +158,7 @@ class EmotesSettingsView extends StatelessWidget { minLines: 1, maxLines: 1, decoration: InputDecoration( - hintText: L10n.of(context).emoteShortcode, + hintText: L10n.of(context)!.emoteShortcode, prefixText: ': ', suffixText: ':', prefixStyle: TextStyle( @@ -217,7 +217,7 @@ class _EmoteImage extends StatelessWidget { Widget build(BuildContext context) { const size = 38.0; final devicePixelRatio = MediaQuery.of(context).devicePixelRatio; - final url = mxc?.getThumbnail( + final url = mxc.getThumbnail( Matrix.of(context).client, width: size * devicePixelRatio, height: size * devicePixelRatio, @@ -233,11 +233,11 @@ class _EmoteImage extends StatelessWidget { } class _ImagePicker extends StatefulWidget { - final ValueNotifier controller; + final ValueNotifier controller; - final void Function(ValueNotifier) onPressed; + final void Function(ValueNotifier) onPressed; - const _ImagePicker({@required this.controller, @required this.onPressed}); + const _ImagePicker({required this.controller, required this.onPressed}); @override _ImagePickerState createState() => _ImagePickerState(); @@ -249,10 +249,10 @@ class _ImagePickerState extends State<_ImagePicker> { if (widget.controller.value == null) { return ElevatedButton( onPressed: () => widget.onPressed(widget.controller), - child: Text(L10n.of(context).pickImage), + child: Text(L10n.of(context)!.pickImage), ); } else { - return _EmoteImage(widget.controller.value.url); + return _EmoteImage(widget.controller.value!.url); } } } diff --git a/lib/pages/settings_ignore_list/settings_ignore_list.dart b/lib/pages/settings_ignore_list/settings_ignore_list.dart index 9d320a94..cf0713aa 100644 --- a/lib/pages/settings_ignore_list/settings_ignore_list.dart +++ b/lib/pages/settings_ignore_list/settings_ignore_list.dart @@ -6,9 +6,9 @@ import '../../widgets/matrix.dart'; import 'settings_ignore_list_view.dart'; class SettingsIgnoreList extends StatefulWidget { - final String initialUserId; + final String? initialUserId; - const SettingsIgnoreList({Key key, this.initialUserId}) : super(key: key); + const SettingsIgnoreList({Key? key, this.initialUserId}) : super(key: key); @override SettingsIgnoreListController createState() => SettingsIgnoreListController(); @@ -21,7 +21,7 @@ class SettingsIgnoreListController extends State { void initState() { super.initState(); if (widget.initialUserId != null) { - controller.text = widget.initialUserId.replaceAll('@', ''); + controller.text = widget.initialUserId!.replaceAll('@', ''); } } 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 07c0692b..05d97f0d 100644 --- a/lib/pages/settings_ignore_list/settings_ignore_list_view.dart +++ b/lib/pages/settings_ignore_list/settings_ignore_list_view.dart @@ -12,7 +12,7 @@ import 'settings_ignore_list.dart'; class SettingsIgnoreListView extends StatelessWidget { final SettingsIgnoreListController controller; - const SettingsIgnoreListView(this.controller, {Key key}) : super(key: key); + const SettingsIgnoreListView(this.controller, {Key? key}) : super(key: key); @override Widget build(BuildContext context) { @@ -20,7 +20,7 @@ class SettingsIgnoreListView extends StatelessWidget { return Scaffold( appBar: AppBar( leading: const BackButton(), - title: Text(L10n.of(context).ignoredUsers), + title: Text(L10n.of(context)!.ignoredUsers), ), body: MaxWidthBody( child: Column( @@ -39,9 +39,9 @@ class SettingsIgnoreListView extends StatelessWidget { border: const OutlineInputBorder(), hintText: 'bad_guy:domain.abc', prefixText: '@', - labelText: L10n.of(context).ignoreUsername, + labelText: L10n.of(context)!.ignoreUsername, suffixIcon: IconButton( - tooltip: L10n.of(context).ignore, + tooltip: L10n.of(context)!.ignore, icon: const Icon(Icons.done_outlined), onPressed: () => controller.ignoreUser(context), ), @@ -49,7 +49,7 @@ class SettingsIgnoreListView extends StatelessWidget { ), const SizedBox(height: 16), Text( - L10n.of(context).ignoreListDescription, + L10n.of(context)!.ignoreListDescription, style: const TextStyle(color: Colors.orange), ), ], @@ -74,7 +74,7 @@ class SettingsIgnoreListView extends StatelessWidget { title: Text( s.data?.displayName ?? client.ignoredUsers[i]), trailing: IconButton( - tooltip: L10n.of(context).delete, + tooltip: L10n.of(context)!.delete, icon: const Icon(Icons.delete_forever_outlined), onPressed: () => showFutureLoadingDialog( context: context, diff --git a/lib/pages/settings_multiple_emotes/settings_multiple_emotes.dart b/lib/pages/settings_multiple_emotes/settings_multiple_emotes.dart index 9584f253..ff15116f 100644 --- a/lib/pages/settings_multiple_emotes/settings_multiple_emotes.dart +++ b/lib/pages/settings_multiple_emotes/settings_multiple_emotes.dart @@ -5,7 +5,7 @@ import 'package:vrouter/vrouter.dart'; import 'settings_multiple_emotes_view.dart'; class MultipleEmotesSettings extends StatefulWidget { - const MultipleEmotesSettings({Key key}) : super(key: key); + const MultipleEmotesSettings({Key? key}) : super(key: key); @override MultipleEmotesSettingsController createState() => @@ -13,7 +13,7 @@ class MultipleEmotesSettings extends StatefulWidget { } class MultipleEmotesSettingsController extends State { - String get roomId => VRouter.of(context).pathParameters['roomid']; + String? get roomId => VRouter.of(context).pathParameters['roomid']; @override Widget build(BuildContext context) => MultipleEmotesSettingsView(this); } diff --git a/lib/pages/settings_multiple_emotes/settings_multiple_emotes_view.dart b/lib/pages/settings_multiple_emotes/settings_multiple_emotes_view.dart index efaf4fde..45652f45 100644 --- a/lib/pages/settings_multiple_emotes/settings_multiple_emotes_view.dart +++ b/lib/pages/settings_multiple_emotes/settings_multiple_emotes_view.dart @@ -10,21 +10,21 @@ import 'package:fluffychat/widgets/matrix.dart'; class MultipleEmotesSettingsView extends StatelessWidget { final MultipleEmotesSettingsController controller; - const MultipleEmotesSettingsView(this.controller, {Key key}) + const MultipleEmotesSettingsView(this.controller, {Key? key}) : super(key: key); @override Widget build(BuildContext context) { - final room = Matrix.of(context).client.getRoomById(controller.roomId); + final room = Matrix.of(context).client.getRoomById(controller.roomId!)!; return Scaffold( appBar: AppBar( leading: const BackButton(), - title: Text(L10n.of(context).emotePacks), + title: Text(L10n.of(context)!.emotePacks), ), body: StreamBuilder( stream: room.onUpdate.stream, builder: (context, snapshot) { - final packs = + final Map packs = room.states['im.ponies.room_emotes'] ?? {}; if (!packs.containsKey('')) { packs[''] = null; @@ -36,7 +36,8 @@ class MultipleEmotesSettingsView extends StatelessWidget { itemCount: keys.length, itemBuilder: (BuildContext context, int i) { final event = packs[keys[i]]; - var packName = keys[i].isNotEmpty ? keys[i] : 'Default Pack'; + String? packName = + keys[i].isNotEmpty ? keys[i] : 'Default Pack'; if (event != null && event.content['pack'] is Map) { if (event.content['pack']['displayname'] is String) { packName = event.content['pack']['displayname']; @@ -45,7 +46,7 @@ class MultipleEmotesSettingsView extends StatelessWidget { } } return ListTile( - title: Text(packName), + title: Text(packName!), onTap: () async { VRouter.of(context).toSegments( ['rooms', room.id, 'details', 'emotes', keys[i]]); diff --git a/lib/pages/settings_notifications/settings_notifications.dart b/lib/pages/settings_notifications/settings_notifications.dart index 56703097..1e677edc 100644 --- a/lib/pages/settings_notifications/settings_notifications.dart +++ b/lib/pages/settings_notifications/settings_notifications.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; +import 'package:collection/collection.dart' show IterableExtension; import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:future_loading_dialog/future_loading_dialog.dart'; @@ -19,38 +20,38 @@ class NotificationSettingsItem { NotificationSettingsItem( PushRuleKind.underride, '.m.rule.room_one_to_one', - (c) => L10n.of(c).directChats, + (c) => L10n.of(c)!.directChats, ), NotificationSettingsItem( PushRuleKind.override, '.m.rule.contains_display_name', - (c) => L10n.of(c).containsDisplayName, + (c) => L10n.of(c)!.containsDisplayName, ), NotificationSettingsItem( PushRuleKind.content, '.m.rule.contains_user_name', - (c) => L10n.of(c).containsUserName, + (c) => L10n.of(c)!.containsUserName, ), NotificationSettingsItem( PushRuleKind.override, '.m.rule.invite_for_me', - (c) => L10n.of(c).inviteForMe, + (c) => L10n.of(c)!.inviteForMe, ), NotificationSettingsItem( PushRuleKind.override, '.m.rule.member_event', - (c) => L10n.of(c).memberChanges, + (c) => L10n.of(c)!.memberChanges, ), NotificationSettingsItem( PushRuleKind.override, '.m.rule.suppress_notices', - (c) => L10n.of(c).botMessages, + (c) => L10n.of(c)!.botMessages, ), ]; } class SettingsNotifications extends StatefulWidget { - const SettingsNotifications({Key key}) : super(key: key); + const SettingsNotifications({Key? key}) : super(key: key); @override SettingsNotificationsController createState() => @@ -71,31 +72,30 @@ class SettingsNotificationsController extends State { return NotificationSetting.open(); } - bool getNotificationSetting(NotificationSettingsItem item) { + bool? getNotificationSetting(NotificationSettingsItem item) { final pushRules = Matrix.of(context).client.globalPushRules; switch (item.type) { case PushRuleKind.content: - return pushRules.content - ?.singleWhere((r) => r.ruleId == item.key, orElse: () => null) + return pushRules!.content + ?.singleWhereOrNull((r) => r.ruleId == item.key) ?.enabled; case PushRuleKind.override: - return pushRules.override - ?.singleWhere((r) => r.ruleId == item.key, orElse: () => null) + return pushRules!.override + ?.singleWhereOrNull((r) => r.ruleId == item.key) ?.enabled; case PushRuleKind.room: - return pushRules.room - ?.singleWhere((r) => r.ruleId == item.key, orElse: () => null) + return pushRules!.room + ?.singleWhereOrNull((r) => r.ruleId == item.key) ?.enabled; case PushRuleKind.sender: - return pushRules.sender - ?.singleWhere((r) => r.ruleId == item.key, orElse: () => null) + return pushRules!.sender + ?.singleWhereOrNull((r) => r.ruleId == item.key) ?.enabled; case PushRuleKind.underride: - return pushRules.underride - ?.singleWhere((r) => r.ruleId == item.key, orElse: () => null) + return pushRules!.underride + ?.singleWhereOrNull((r) => r.ruleId == item.key) ?.enabled; } - return false; } void setNotificationSetting(NotificationSettingsItem item, bool enabled) { diff --git a/lib/pages/settings_notifications/settings_notifications_view.dart b/lib/pages/settings_notifications/settings_notifications_view.dart index 44180f73..d80b0ecf 100644 --- a/lib/pages/settings_notifications/settings_notifications_view.dart +++ b/lib/pages/settings_notifications/settings_notifications_view.dart @@ -15,14 +15,15 @@ import 'settings_notifications.dart'; class SettingsNotificationsView extends StatelessWidget { final SettingsNotificationsController controller; - const SettingsNotificationsView(this.controller, {Key key}) : super(key: key); + const SettingsNotificationsView(this.controller, {Key? key}) + : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( leading: const BackButton(), - title: Text(L10n.of(context).notifications), + title: Text(L10n.of(context)!.notifications), ), body: MaxWidthBody( withScrolling: true, @@ -38,7 +39,7 @@ class SettingsNotificationsView extends StatelessWidget { SwitchListTile.adaptive( value: !Matrix.of(context).client.allPushNotificationsMuted, title: Text( - L10n.of(context).notificationsEnabledForThisAccount), + L10n.of(context)!.notificationsEnabledForThisAccount), onChanged: (_) => showFutureLoadingDialog( context: context, future: () => @@ -52,7 +53,7 @@ class SettingsNotificationsView extends StatelessWidget { if (!Matrix.of(context).client.allPushNotificationsMuted) ...{ if (!kIsWeb && Platform.isAndroid) ListTile( - title: Text(L10n.of(context).soundVibrationLedColor), + title: Text(L10n.of(context)!.soundVibrationLedColor), trailing: CircleAvatar( backgroundColor: Theme.of(context).scaffoldBackgroundColor, @@ -64,7 +65,7 @@ class SettingsNotificationsView extends StatelessWidget { const Divider(thickness: 1), ListTile( title: Text( - L10n.of(context).pushRules, + L10n.of(context)!.pushRules, style: TextStyle( color: Theme.of(context).colorScheme.secondary, fontWeight: FontWeight.bold, @@ -82,20 +83,20 @@ class SettingsNotificationsView extends StatelessWidget { const Divider(thickness: 1), ListTile( title: Text( - L10n.of(context).devices, + L10n.of(context)!.devices, style: TextStyle( color: Theme.of(context).colorScheme.secondary, fontWeight: FontWeight.bold, ), ), ), - FutureBuilder>( + FutureBuilder?>( future: Matrix.of(context).client.getPushers(), builder: (context, snapshot) { if (snapshot.hasError) { Center( child: Text( - snapshot.error.toLocalizedString(context), + snapshot.error!.toLocalizedString(context), ), ); } diff --git a/lib/pages/settings_security/settings_security.dart b/lib/pages/settings_security/settings_security.dart index eb409fbb..a27e42ef 100644 --- a/lib/pages/settings_security/settings_security.dart +++ b/lib/pages/settings_security/settings_security.dart @@ -12,7 +12,7 @@ import '../bootstrap/bootstrap_dialog.dart'; import 'settings_security_view.dart'; class SettingsSecurity extends StatefulWidget { - const SettingsSecurity({Key key}) : super(key: key); + const SettingsSecurity({Key? key}) : super(key: key); @override SettingsSecurityController createState() => SettingsSecurityController(); @@ -23,18 +23,18 @@ class SettingsSecurityController extends State { final input = await showTextInputDialog( useRootNavigator: false, context: context, - title: L10n.of(context).changePassword, - okLabel: L10n.of(context).ok, - cancelLabel: L10n.of(context).cancel, + title: L10n.of(context)!.changePassword, + okLabel: L10n.of(context)!.ok, + cancelLabel: L10n.of(context)!.cancel, textFields: [ DialogTextField( - hintText: L10n.of(context).pleaseEnterYourPassword, + hintText: L10n.of(context)!.pleaseEnterYourPassword, obscureText: true, minLines: 1, maxLines: 1, ), DialogTextField( - hintText: L10n.of(context).chooseAStrongPassword, + hintText: L10n.of(context)!.chooseAStrongPassword, obscureText: true, minLines: 1, maxLines: 1, @@ -50,7 +50,7 @@ class SettingsSecurityController extends State { ); if (success.error == null) { ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text(L10n.of(context).passwordHasBeenChanged))); + SnackBar(content: Text(L10n.of(context)!.passwordHasBeenChanged))); } } @@ -58,21 +58,22 @@ class SettingsSecurityController extends State { final currentLock = await const FlutterSecureStorage().read(key: SettingKeys.appLockKey); if (currentLock?.isNotEmpty ?? false) { - await AppLock.of(context).showLockScreen(); + await AppLock.of(context)!.showLockScreen(); } final newLock = await showTextInputDialog( useRootNavigator: false, context: context, - title: L10n.of(context).pleaseChooseAPasscode, - message: L10n.of(context).pleaseEnter4Digits, - cancelLabel: L10n.of(context).cancel, + title: L10n.of(context)!.pleaseChooseAPasscode, + message: L10n.of(context)!.pleaseEnter4Digits, + cancelLabel: L10n.of(context)!.cancel, textFields: [ DialogTextField( validator: (text) { - if (text.isEmpty || (text.length == 4 && int.tryParse(text) >= 0)) { + if (text!.isEmpty || + (text.length == 4 && int.tryParse(text)! >= 0)) { return null; } - return L10n.of(context).pleaseEnter4Digits; + return L10n.of(context)!.pleaseEnter4Digits; }, keyboardType: TextInputType.number, obscureText: true, @@ -85,9 +86,9 @@ class SettingsSecurityController extends State { await const FlutterSecureStorage() .write(key: SettingKeys.appLockKey, value: newLock.single); if (newLock.single.isEmpty) { - AppLock.of(context).disable(); + AppLock.of(context)!.disable(); } else { - AppLock.of(context).enable(); + AppLock.of(context)!.enable(); } } } diff --git a/lib/pages/settings_security/settings_security_view.dart b/lib/pages/settings_security/settings_security_view.dart index e3a6cd68..ebe9567c 100644 --- a/lib/pages/settings_security/settings_security_view.dart +++ b/lib/pages/settings_security/settings_security_view.dart @@ -12,38 +12,38 @@ import 'settings_security.dart'; class SettingsSecurityView extends StatelessWidget { final SettingsSecurityController controller; - const SettingsSecurityView(this.controller, {Key key}) : super(key: key); + const SettingsSecurityView(this.controller, {Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(title: Text(L10n.of(context).security)), + appBar: AppBar(title: Text(L10n.of(context)!.security)), body: ListTileTheme( - iconColor: Theme.of(context).textTheme.bodyText1.color, + iconColor: Theme.of(context).textTheme.bodyText1!.color, child: MaxWidthBody( withScrolling: true, child: Column( children: [ ListTile( trailing: const Icon(Icons.panorama_fish_eye), - title: Text(L10n.of(context).whoCanSeeMyStories), + title: Text(L10n.of(context)!.whoCanSeeMyStories), onTap: () => VRouter.of(context).to('stories'), ), ListTile( trailing: const Icon(Icons.close), - title: Text(L10n.of(context).ignoredUsers), + title: Text(L10n.of(context)!.ignoredUsers), onTap: () => VRouter.of(context).to('ignorelist'), ), ListTile( trailing: const Icon(Icons.vpn_key_outlined), title: Text( - L10n.of(context).changePassword, + L10n.of(context)!.changePassword, ), onTap: controller.changePasswordAccountAction, ), ListTile( trailing: const Icon(Icons.mail_outlined), - title: Text(L10n.of(context).passwordRecovery), + title: Text(L10n.of(context)!.passwordRecovery), onTap: () => VRouter.of(context).to('3pid'), ), if (Matrix.of(context).client.encryption != null) ...{ @@ -51,30 +51,30 @@ class SettingsSecurityView extends StatelessWidget { if (PlatformInfos.isMobile) ListTile( trailing: const Icon(Icons.lock_outlined), - title: Text(L10n.of(context).appLock), + title: Text(L10n.of(context)!.appLock), onTap: controller.setAppLockAction, ), ListTile( - title: Text(L10n.of(context).yourPublicKey), + title: Text(L10n.of(context)!.yourPublicKey), onTap: () => showOkAlertDialog( useRootNavigator: false, context: context, - title: L10n.of(context).yourPublicKey, + title: L10n.of(context)!.yourPublicKey, message: Matrix.of(context).client.fingerprintKey.beautified, - okLabel: L10n.of(context).ok, + okLabel: L10n.of(context)!.ok, ), trailing: const Icon(Icons.vpn_key_outlined), ), - if (!Matrix.of(context).client.encryption.crossSigning.enabled) + if (!Matrix.of(context).client.encryption!.crossSigning.enabled) ListTile( - title: Text(L10n.of(context).crossSigningEnabled), + title: Text(L10n.of(context)!.crossSigningEnabled), trailing: const Icon(Icons.error, color: Colors.red), onTap: () => controller.showBootstrapDialog(context), ), - if (!Matrix.of(context).client.encryption.keyManager.enabled) + if (!Matrix.of(context).client.encryption!.keyManager.enabled) ListTile( - title: Text(L10n.of(context).onlineKeyBackupEnabled), + title: Text(L10n.of(context)!.onlineKeyBackupEnabled), trailing: const Icon(Icons.error, color: Colors.red), onTap: () => controller.showBootstrapDialog(context), ), @@ -88,19 +88,19 @@ class SettingsSecurityView extends StatelessWidget { future: () async { return (await Matrix.of(context) .client - .encryption + .encryption! .keyManager .isCached()) && (await Matrix.of(context) .client - .encryption + .encryption! .crossSigning .isCached()); }(), builder: (context, snapshot) => snapshot.data == true ? Container() : ListTile( - title: Text(L10n.of(context).keysCached), + title: Text(L10n.of(context)!.keysCached), trailing: const Icon(Icons.error, color: Colors.red), onTap: () => controller.showBootstrapDialog(context), ), diff --git a/lib/pages/settings_stories/settings_stories.dart b/lib/pages/settings_stories/settings_stories.dart index bf2f25f2..a9f666cf 100644 --- a/lib/pages/settings_stories/settings_stories.dart +++ b/lib/pages/settings_stories/settings_stories.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'package:flutter/material.dart'; import 'package:future_loading_dialog/future_loading_dialog.dart'; diff --git a/lib/pages/settings_stories/settings_stories_view.dart b/lib/pages/settings_stories/settings_stories_view.dart index 5e33c096..d502373c 100644 --- a/lib/pages/settings_stories/settings_stories_view.dart +++ b/lib/pages/settings_stories/settings_stories_view.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; diff --git a/lib/pages/settings_style/settings_style.dart b/lib/pages/settings_style/settings_style.dart index 68ac629a..7df7565e 100644 --- a/lib/pages/settings_style/settings_style.dart +++ b/lib/pages/settings_style/settings_style.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'dart:io'; import 'package:flutter/material.dart'; diff --git a/lib/pages/settings_style/settings_style_view.dart b/lib/pages/settings_style/settings_style_view.dart index 3192b333..f0867a1e 100644 --- a/lib/pages/settings_style/settings_style_view.dart +++ b/lib/pages/settings_style/settings_style_view.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'package:flutter/material.dart'; import 'package:adaptive_theme/adaptive_theme.dart'; @@ -19,6 +17,7 @@ class SettingsStyleView extends StatelessWidget { Widget build(BuildContext context) { controller.currentTheme ??= AdaptiveTheme.of(context).mode; const colorPickerSize = 32.0; + final wallpaper = Matrix.of(context).wallpaper; return Scaffold( appBar: AppBar( leading: const BackButton(), @@ -86,10 +85,10 @@ class SettingsStyleView extends StatelessWidget { ), ), ), - if (Matrix.of(context).wallpaper != null) + if (wallpaper != null) ListTile( title: Image.file( - Matrix.of(context).wallpaper, + wallpaper, height: 38, fit: BoxFit.cover, ), diff --git a/lib/pages/sign_up/signup.dart b/lib/pages/sign_up/signup.dart index f4c839b7..a9df0d37 100644 --- a/lib/pages/sign_up/signup.dart +++ b/lib/pages/sign_up/signup.dart @@ -9,7 +9,7 @@ import 'package:fluffychat/widgets/matrix.dart'; import '../../utils/localized_exception_extension.dart'; class SignupPage extends StatefulWidget { - const SignupPage({Key key}) : super(key: key); + const SignupPage({Key? key}) : super(key: key); @override SignupPageController createState() => SignupPageController(); @@ -20,49 +20,49 @@ class SignupPageController extends State { final TextEditingController passwordController = TextEditingController(); final TextEditingController passwordController2 = TextEditingController(); final TextEditingController emailController = TextEditingController(); - String error; + String? error; bool loading = false; bool showPassword = false; void toggleShowPassword() => setState(() => showPassword = !showPassword); - String get domain => VRouter.of(context).queryParameters['domain']; + String? get domain => VRouter.of(context).queryParameters['domain']; final GlobalKey formKey = GlobalKey(); - String usernameTextFieldValidator(String value) { + String? usernameTextFieldValidator(String? value) { usernameController.text = usernameController.text.trim().toLowerCase().replaceAll(' ', '_'); - if (value.isEmpty) { - return L10n.of(context).pleaseChooseAUsername; + if (value!.isEmpty) { + return L10n.of(context)!.pleaseChooseAUsername; } return null; } - String password1TextFieldValidator(String value) { + String? password1TextFieldValidator(String? value) { const minLength = 8; - if (value.isEmpty) { - return L10n.of(context).chooseAStrongPassword; + if (value!.isEmpty) { + return L10n.of(context)!.chooseAStrongPassword; } if (value.length < minLength) { - return L10n.of(context).pleaseChooseAtLeastChars(minLength.toString()); + return L10n.of(context)!.pleaseChooseAtLeastChars(minLength.toString()); } return null; } - String password2TextFieldValidator(String value) { - if (value.isEmpty) { - return L10n.of(context).chooseAStrongPassword; + String? password2TextFieldValidator(String? value) { + if (value!.isEmpty) { + return L10n.of(context)!.chooseAStrongPassword; } if (value != passwordController.text) { - return L10n.of(context).passwordsDoNotMatch; + return L10n.of(context)!.passwordsDoNotMatch; } return null; } - String emailTextFieldValidator(String value) { - if (value.isNotEmpty && !value.contains('@')) { - return L10n.of(context).pleaseEnterValidEmail; + String? emailTextFieldValidator(String? value) { + if (value!.isNotEmpty && !value.contains('@')) { + return L10n.of(context)!.pleaseEnterValidEmail; } return null; } @@ -71,7 +71,7 @@ class SignupPageController extends State { setState(() { error = null; }); - if (!formKey.currentState.validate()) return; + if (!formKey.currentState!.validate()) return; setState(() { loading = true; @@ -99,7 +99,7 @@ class SignupPageController extends State { ), ); } catch (e) { - error = (e as Object).toLocalizedString(context); + error = (e).toLocalizedString(context); } finally { if (mounted) { setState(() => loading = false); diff --git a/lib/pages/sign_up/signup_view.dart b/lib/pages/sign_up/signup_view.dart index 7832e219..4cbd4492 100644 --- a/lib/pages/sign_up/signup_view.dart +++ b/lib/pages/sign_up/signup_view.dart @@ -7,14 +7,14 @@ import 'signup.dart'; class SignupPageView extends StatelessWidget { final SignupPageController controller; - const SignupPageView(this.controller, {Key key}) : super(key: key); + const SignupPageView(this.controller, {Key? key}) : super(key: key); @override Widget build(BuildContext context) { return OnePageCard( child: Scaffold( appBar: AppBar( - title: Text(L10n.of(context).signUp), + title: Text(L10n.of(context)!.signUp), ), body: Form( key: controller.formKey, @@ -31,8 +31,8 @@ class SignupPageView extends StatelessWidget { validator: controller.usernameTextFieldValidator, decoration: InputDecoration( prefixIcon: const Icon(Icons.account_circle_outlined), - hintText: L10n.of(context).username, - labelText: L10n.of(context).username, + hintText: L10n.of(context)!.username, + labelText: L10n.of(context)!.username, prefixText: '@', prefixStyle: const TextStyle(fontWeight: FontWeight.bold), suffixStyle: const TextStyle(fontWeight: FontWeight.w200), @@ -53,13 +53,13 @@ class SignupPageView extends StatelessWidget { prefixIcon: const Icon(Icons.vpn_key_outlined), hintText: '****', suffixIcon: IconButton( - tooltip: L10n.of(context).showPassword, + tooltip: L10n.of(context)!.showPassword, icon: Icon(controller.showPassword ? Icons.visibility_off_outlined : Icons.visibility_outlined), onPressed: controller.toggleShowPassword, ), - labelText: L10n.of(context).password, + labelText: L10n.of(context)!.password, ), ), ), @@ -76,7 +76,7 @@ class SignupPageView extends StatelessWidget { decoration: InputDecoration( prefixIcon: const Icon(Icons.repeat_outlined), hintText: '****', - labelText: L10n.of(context).repeatPassword, + labelText: L10n.of(context)!.repeatPassword, ), ), ), @@ -92,7 +92,7 @@ class SignupPageView extends StatelessWidget { validator: controller.emailTextFieldValidator, decoration: InputDecoration( prefixIcon: const Icon(Icons.mail_outlined), - labelText: L10n.of(context).addEmail, + labelText: L10n.of(context)!.addEmail, hintText: 'email@example.abc', ), ), @@ -103,7 +103,7 @@ class SignupPageView extends StatelessWidget { Padding( padding: const EdgeInsets.symmetric(horizontal: 12), child: Text( - controller.error, + controller.error!, style: const TextStyle(color: Colors.red), textAlign: TextAlign.center, ), @@ -120,7 +120,7 @@ class SignupPageView extends StatelessWidget { onPressed: controller.loading ? null : controller.signup, child: controller.loading ? const LinearProgressIndicator() - : Text(L10n.of(context).signUp), + : Text(L10n.of(context)!.signUp), ), ), ), diff --git a/lib/pages/story/story_page.dart b/lib/pages/story/story_page.dart index 4cfb4d3f..192664e2 100644 --- a/lib/pages/story/story_page.dart +++ b/lib/pages/story/story_page.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'dart:async'; import 'dart:io'; diff --git a/lib/pages/story/story_view.dart b/lib/pages/story/story_view.dart index bdeefdb9..6f68a804 100644 --- a/lib/pages/story/story_view.dart +++ b/lib/pages/story/story_view.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; diff --git a/lib/pages/user_bottom_sheet/user_bottom_sheet.dart b/lib/pages/user_bottom_sheet/user_bottom_sheet.dart index f19be8de..84bdd966 100644 --- a/lib/pages/user_bottom_sheet/user_bottom_sheet.dart +++ b/lib/pages/user_bottom_sheet/user_bottom_sheet.dart @@ -12,13 +12,13 @@ import 'user_bottom_sheet_view.dart'; class UserBottomSheet extends StatefulWidget { final User user; - final Function onMention; + final Function? onMention; final BuildContext outerContext; const UserBottomSheet({ - Key key, - @required this.user, - @required this.outerContext, + Key? key, + required this.user, + required this.outerContext, this.onMention, }) : super(key: key); @@ -33,15 +33,15 @@ class UserBottomSheetController extends State { () async => (await showOkCancelAlertDialog( useRootNavigator: false, context: context, - title: L10n.of(context).areYouSure, - okLabel: L10n.of(context).yes, - cancelLabel: L10n.of(context).no, + title: L10n.of(context)!.areYouSure, + okLabel: L10n.of(context)!.yes, + cancelLabel: L10n.of(context)!.no, ) == OkCancelResult.ok); switch (action) { case 'mention': Navigator.of(context, rootNavigator: false).pop(); - widget.onMention(); + widget.onMention!(); break; case 'ban': if (await _askConfirmation()) { @@ -90,7 +90,7 @@ class UserBottomSheetController extends State { ); if (roomIdResult.error != null) return; VRouter.of(widget.outerContext) - .toSegments(['rooms', roomIdResult.result]); + .toSegments(['rooms', roomIdResult.result!]); Navigator.of(context, rootNavigator: false).pop(); break; case 'ignore': diff --git a/lib/pages/user_bottom_sheet/user_bottom_sheet_view.dart b/lib/pages/user_bottom_sheet/user_bottom_sheet_view.dart index 1a8f234d..4c163432 100644 --- a/lib/pages/user_bottom_sheet/user_bottom_sheet_view.dart +++ b/lib/pages/user_bottom_sheet/user_bottom_sheet_view.dart @@ -15,7 +15,7 @@ import 'user_bottom_sheet.dart'; class UserBottomSheetView extends StatelessWidget { final UserBottomSheetController controller; - const UserBottomSheetView(this.controller, {Key key}) : super(key: key); + const UserBottomSheetView(this.controller, {Key? key}) : super(key: key); @override Widget build(BuildContext context) { @@ -38,7 +38,7 @@ class UserBottomSheetView extends StatelessWidget { leading: IconButton( icon: const Icon(Icons.arrow_downward_outlined), onPressed: Navigator.of(context, rootNavigator: false).pop, - tooltip: L10n.of(context).close, + tooltip: L10n.of(context)!.close, ), title: Text(user.calcDisplayname()), actions: [ @@ -49,7 +49,7 @@ class UserBottomSheetView extends StatelessWidget { PopupMenuItem( value: 'mention', child: _TextWithIcon( - L10n.of(context).mention, + L10n.of(context)!.mention, Icons.alternate_email_outlined, ), ), @@ -57,7 +57,7 @@ class UserBottomSheetView extends StatelessWidget { PopupMenuItem( value: 'message', child: _TextWithIcon( - L10n.of(context).sendAMessage, + L10n.of(context)!.sendAMessage, Icons.send_outlined, ), ), @@ -65,7 +65,7 @@ class UserBottomSheetView extends StatelessWidget { PopupMenuItem( value: 'permission', child: _TextWithIcon( - L10n.of(context).setPermissionsLevel, + L10n.of(context)!.setPermissionsLevel, Icons.edit_attributes_outlined, ), ), @@ -73,7 +73,7 @@ class UserBottomSheetView extends StatelessWidget { PopupMenuItem( value: 'kick', child: _TextWithIcon( - L10n.of(context).kickFromChat, + L10n.of(context)!.kickFromChat, Icons.exit_to_app_outlined, ), ), @@ -81,7 +81,7 @@ class UserBottomSheetView extends StatelessWidget { PopupMenuItem( value: 'ban', child: _TextWithIcon( - L10n.of(context).banFromChat, + L10n.of(context)!.banFromChat, Icons.warning_sharp, ), ) @@ -90,7 +90,7 @@ class UserBottomSheetView extends StatelessWidget { PopupMenuItem( value: 'unban', child: _TextWithIcon( - L10n.of(context).unbanFromChat, + L10n.of(context)!.unbanFromChat, Icons.warning_outlined, ), ), @@ -98,7 +98,7 @@ class UserBottomSheetView extends StatelessWidget { PopupMenuItem( value: 'ignore', child: _TextWithIcon( - L10n.of(context).ignore, + L10n.of(context)!.ignore, Icons.block, ), ), @@ -111,13 +111,13 @@ class UserBottomSheetView extends StatelessWidget { children: [ Expanded( child: ContentBanner( - user.avatarUrl, + mxContent: user.avatarUrl, defaultIcon: Icons.person_outline, client: client, ), ), ListTile( - title: Text(L10n.of(context).username), + title: Text(L10n.of(context)!.username), subtitle: Text(user.id), trailing: Icon(Icons.adaptive.share_outlined), onTap: () => FluffyShare.share( @@ -150,7 +150,7 @@ class _TextWithIcon extends StatelessWidget { const _TextWithIcon( this.text, this.iconData, { - Key key, + Key? key, }) : super(key: key); @override diff --git a/lib/utils/account_bundles.dart b/lib/utils/account_bundles.dart index fbced64d..f45f9dc7 100644 --- a/lib/utils/account_bundles.dart +++ b/lib/utils/account_bundles.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'package:matrix/matrix.dart'; class AccountBundles { diff --git a/lib/utils/background_push.dart b/lib/utils/background_push.dart index 9f159ddb..3347f176 100644 --- a/lib/utils/background_push.dart +++ b/lib/utils/background_push.dart @@ -26,7 +26,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_cache_manager/flutter_cache_manager.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; -import 'package:flutter_gen/gen_l10n/l10n_en.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:http/http.dart' as http; import 'package:matrix/matrix.dart'; @@ -47,27 +46,26 @@ class NoTokenException implements Exception { } class BackgroundPush { - static BackgroundPush _instance; + static BackgroundPush? _instance; final FlutterLocalNotificationsPlugin _flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); Client client; - BuildContext context; - GlobalKey router; - String _fcmToken; - void Function(String errorMsg, {Uri link}) onFcmError; - L10n l10n; - Store _store; + BuildContext? context; + GlobalKey? router; + String? _fcmToken; + void Function(String errorMsg, {Uri? link})? onFcmError; + L10n? l10n; + Store? _store; Store get store => _store ??= Store(); Future loadLocale() async { // inspired by _lookupL10n in .dart_tool/flutter_gen/gen_l10n/l10n.dart - l10n ??= (context != null ? L10n.of(context) : null) ?? - (await L10n.delegate.load(window.locale)) ?? - L10nEn(); + l10n ??= (context != null ? L10n.of(context!) : null) ?? + (await L10n.delegate.load(window.locale)); } final pendingTests = >{}; - DateTime lastReceivedPush; + DateTime? lastReceivedPush; bool upAction = false; @@ -94,12 +92,12 @@ class BackgroundPush { factory BackgroundPush.clientOnly(Client client) { _instance ??= BackgroundPush._(client); - return _instance; + return _instance!; } factory BackgroundPush( - Client _client, BuildContext _context, GlobalKey router, - {final void Function(String errorMsg, {Uri link}) onFcmError}) { + Client _client, BuildContext _context, GlobalKey? router, + {final void Function(String errorMsg, {Uri? link})? onFcmError}) { final instance = BackgroundPush.clientOnly(_client); instance.context = _context; // ignore: prefer_initializing_formals @@ -119,15 +117,15 @@ class BackgroundPush { setupPush(); } - final _fcmSharedIsolate = null; //FcmSharedIsolate(); + final dynamic _fcmSharedIsolate = null; //FcmSharedIsolate(); - StreamSubscription onLogin; - StreamSubscription onRoomSync; + StreamSubscription? onLogin; + StreamSubscription? onRoomSync; Future setupPusher({ - String gatewayUrl, - String token, - Set oldTokens, + String? gatewayUrl, + String? token, + Set? oldTokens, bool useDeviceSpecificAppId = false, }) async { if (PlatformInfos.isIOS) { @@ -135,10 +133,11 @@ class BackgroundPush { } final clientName = PlatformInfos.clientName; oldTokens ??= {}; - final pushers = await client.getPushers().catchError((e) { - Logs().w('[Push] Unable to request pushers', e); - return []; - }); + final pushers = await (client.getPushers().catchError((e) { + Logs().w('[Push] Unable to request pushers', e); + return []; + })) ?? + []; var setNewPusher = false; // Just the plain app id, we add the .data_message suffix later var appId = AppConfig.pushNotificationsAppId; @@ -152,7 +151,7 @@ class BackgroundPush { appId += '.data_message'; } final thisAppId = useDeviceSpecificAppId ? deviceAppId : appId; - if (gatewayUrl != null && token != null && clientName != null) { + if (gatewayUrl != null && token != null) { final currentPushers = pushers.where((pusher) => pusher.pushkey == token); if (currentPushers.length == 1 && currentPushers.first.kind == 'http' && @@ -179,12 +178,8 @@ class BackgroundPush { pusher.pushkey != token && deviceAppId == pusher.appId) || oldTokens.contains(pusher.pushkey)) { - pusher.kind = null; try { - await client.postPusher( - pusher, - append: true, - ); + await client.deletePusher(pusher); Logs().i('[Push] Removed legacy pusher for this device'); } catch (err) { Logs().w('[Push] Failed to remove old pusher', err); @@ -195,13 +190,13 @@ class BackgroundPush { try { await client.postPusher( Pusher( - pushkey: token, + pushkey: token!, appId: thisAppId, appDisplayName: clientName, - deviceDisplayName: client.deviceName, + deviceDisplayName: client.deviceName!, lang: 'en', data: PusherData( - url: Uri.parse(gatewayUrl), + url: Uri.parse(gatewayUrl!), format: AppConfig.pushNotificationsPusherFormat, ), kind: 'http', @@ -259,13 +254,13 @@ class BackgroundPush { await loadLocale(); if (PlatformInfos.isAndroid) { onFcmError?.call( - l10n.noGoogleServicesWarning, + l10n!.noGoogleServicesWarning, link: Uri.parse( AppConfig.enablePushTutorial, ), ); } - onFcmError?.call(l10n.oopsPushError); + onFcmError?.call(l10n!.oopsPushError); if (null == await store.getItem(SettingKeys.showNoGoogle)) { await store.setItemBool(SettingKeys.showNoGoogle, false); @@ -291,19 +286,21 @@ class BackgroundPush { ); } - Future goToRoom(String roomId) async { + Future goToRoom(String? roomId) async { try { Logs().v('[Push] Attempting to go to room $roomId...'); if (router == null) { return; } + await client.roomsLoading; + await client.accountDataLoading; final isStory = client - ?.getRoomById(roomId) + .getRoomById(roomId!) ?.getState(EventTypes.RoomCreate) ?.content - ?.tryGet('type') == + .tryGet('type') == ClientStoriesExtension.storiesRoomType; - router.currentState.toSegments([isStory ? 'stories' : 'rooms', roomId]); + router!.currentState!.toSegments([isStory ? 'stories' : 'rooms', roomId]); } catch (e, s) { Logs().e('[Push] Failed to open room', e, s); } @@ -318,10 +315,9 @@ class BackgroundPush { // initialise the plugin. app_icon needs to be a added as a drawable resource to the Android head project const initializationSettingsAndroid = AndroidInitializationSettings('notifications_icon'); - final initializationSettingsIOS = - IOSInitializationSettings(onDidReceiveLocalNotification: (i, a, b, c) { - return null; - }); + final initializationSettingsIOS = IOSInitializationSettings( + onDidReceiveLocalNotification: (i, a, b, c) async => null, + ); final initializationSettings = InitializationSettings( android: initializationSettingsAndroid, iOS: initializationSettingsIOS, @@ -338,9 +334,8 @@ class BackgroundPush { Future _onFcmMessage(Map message) async { Logs().v('[Push] Foreground message received'); - Map data; + final data = Map.from(message['data'] ?? message); try { - data = Map.from(message['data'] ?? message); await _onMessage(data); } catch (e, s) { Logs().e('[Push] Error while processing notification', e, s); @@ -350,7 +345,7 @@ class BackgroundPush { Future _newUpEndpoint(String newEndpoint) async { upAction = true; - if (newEndpoint?.isEmpty ?? true) { + if (newEndpoint.isEmpty) { await _upUnregistered(); return; } @@ -377,7 +372,7 @@ class BackgroundPush { '[Push] No self-hosted unified push gateway present: ' + newEndpoint); } Logs().i('[Push] UnifiedPush using endpoint ' + endpoint); - final oldTokens = {}; + final oldTokens = {}; try { final fcmToken = await _fcmSharedIsolate?.getToken(); oldTokens.add(fcmToken); @@ -408,9 +403,9 @@ class BackgroundPush { Future _onUpMessage(String message) async { upAction = true; - Map data; + final data = + Map.from(json.decode(message)['notification']); try { - data = Map.from(json.decode(message)['notification']); await _onMessage(data); } catch (e, s) { Logs().e('[Push] Error while processing notification', e, s); @@ -428,12 +423,14 @@ class BackgroundPush { pendingTests.remove(eventId)?.complete(); return; } - final unread = ((data['counts'] is String - ? json - .decode(data.tryGet('counts', TryGet.optional) ?? '{}') - : data.tryGet>('counts', TryGet.optional) ?? - {}) as Map) - .tryGet('unread'); + + // For legacy reasons the counts map could be a String encoded JSON: + final countsMap = + data.tryGetMap('counts', TryGet.silent) ?? + (jsonDecode(data.tryGet('counts') ?? '{}') + as Map); + final unread = countsMap.tryGet('unread'); + if ((roomId?.isEmpty ?? true) || (eventId?.isEmpty ?? true) || unread == 0) { @@ -478,24 +475,24 @@ class BackgroundPush { await _showNotification(roomId, eventId); } - Future eventExists(String roomId, String eventId) async { + Future eventExists(String roomId, String? eventId) async { final room = client.getRoomById(roomId); if (room == null) return false; - return (await client.database.getEventById(eventId, room)) != null; + return (await client.database!.getEventById(eventId!, room)) != null; } /// Workaround for the problem that local notification IDs must be int but we /// sort by [roomId] which is a String. To make sure that we don't have duplicated /// IDs we map the [roomId] to a number and store this number. - Map idMap; + late Map idMap; Future _loadIdMap() async { - idMap ??= Map.from(json.decode( + idMap = Map.from(json.decode( (await store.getItem(SettingKeys.notificationCurrentIds)) ?? '{}')); } Future mapRoomIdToInt(String roomId) async { await _loadIdMap(); - int currentInt; + int? currentInt; try { currentInt = idMap[roomId]; } catch (_) { @@ -504,13 +501,13 @@ class BackgroundPush { if (currentInt != null) { return currentInt; } - currentInt = 0; + var nCurrentInt = 0; while (idMap.values.contains(currentInt)) { - currentInt++; + nCurrentInt++; } - idMap[roomId] = currentInt; + idMap[roomId] = nCurrentInt; await store.setItem(SettingKeys.notificationCurrentIds, json.encode(idMap)); - return currentInt; + return nCurrentInt; } bool _clearingPushLock = false; @@ -520,7 +517,7 @@ class BackgroundPush { } try { _clearingPushLock = true; - Iterable emptyRooms; + late Iterable emptyRooms; if (getFromServer) { Logs().v('[Push] Got new clearing push'); var syncErrored = false; @@ -541,8 +538,7 @@ class BackgroundPush { }); if (!syncErrored) { emptyRooms = client.rooms - .where((r) => - r.notificationCount == 0 || r.notificationCount == null) + .where((r) => r.notificationCount == 0) .map((r) => r.id); } } @@ -561,25 +557,23 @@ class BackgroundPush { '[Push] failed to fetch pending notifications for clearing push, falling back...', e); emptyRooms = client.rooms - .where((r) => - r.notificationCount == 0 || r.notificationCount == null) + .where((r) => r.notificationCount == 0) .map((r) => r.id); } } } else { emptyRooms = client.rooms - .where( - (r) => r.notificationCount == 0 || r.notificationCount == null) + .where((r) => r.notificationCount == 0) .map((r) => r.id); } await _loadIdMap(); var changed = false; for (final roomId in emptyRooms) { - if (idMap[roomId] != null) { - final id = idMap[roomId]; + final id = idMap[roomId]; + if (id != null) { idMap.remove(roomId); changed = true; - await _flutterLocalNotificationsPlugin?.cancel(id); + await _flutterLocalNotificationsPlugin.cancel(id); } } if (changed) { @@ -598,15 +592,14 @@ class BackgroundPush { throw 'Room not found'; } await room.postLoad(); - final event = await client.database.getEventById(eventId, room); + final event = await client.database!.getEventById(eventId, room); - final activeRoomId = router.currentState.pathParameters['roomid']; + final activeRoomId = router!.currentState!.pathParameters['roomid']; if (((activeRoomId?.isNotEmpty ?? false) && activeRoomId == room.id && client.syncPresence == null) || - (event != null && - (room.notificationCount == 0 || room.notificationCount == null))) { + (event != null && (room.notificationCount == 0))) { return; } @@ -614,11 +607,11 @@ class BackgroundPush { await loadLocale(); // Calculate title - final title = l10n.unreadMessages(room.notificationCount ?? 0); + final title = l10n!.unreadMessages(room.notificationCount); // Calculate the body - final body = event.getLocalizedBody( - MatrixLocals(L10n.of(context)), + final body = event!.getLocalizedBody( + MatrixLocals(L10n.of(context!)!), withSenderNamePrefix: !room.isDirectChat, plaintextBody: true, hideReply: true, @@ -629,7 +622,7 @@ class BackgroundPush { final avatar = room.avatar == null ? null : await DefaultCacheManager().getSingleFile( - event.room.avatar + event.room.avatar! .getThumbnail( client, width: 126, @@ -638,7 +631,7 @@ class BackgroundPush { .toString(), ); final person = Person( - name: room.getLocalizedDisplayname(MatrixLocals(l10n)), + name: room.getLocalizedDisplayname(MatrixLocals(l10n!)), icon: avatar == null ? null : BitmapFilePathAndroidIcon(avatar.path), ); @@ -650,12 +643,12 @@ class BackgroundPush { messages: [ Message( body, - event?.originServerTs ?? DateTime.now(), + event.originServerTs, person, ) ], ), - ticker: l10n.newMessageInFluffyChat, + ticker: l10n!.newMessageInFluffyChat, ); const iOSPlatformChannelSpecifics = IOSNotificationDetails(); final platformChannelSpecifics = NotificationDetails( @@ -664,7 +657,7 @@ class BackgroundPush { ); await _flutterLocalNotificationsPlugin.show( await mapRoomIdToInt(room.id), - room.getLocalizedDisplayname(MatrixLocals(l10n)), + room.getLocalizedDisplayname(MatrixLocals(l10n!)), body, platformChannelSpecifics, payload: roomId, @@ -676,16 +669,15 @@ class BackgroundPush { await setupLocalNotificationsPlugin(); await loadLocale(); - final String eventId = data['event_id']; - final String roomId = data['room_id']; - final unread = ((data['counts'] is String - ? json.decode( - data.tryGet('counts', TryGet.optional) ?? '{}') - : data.tryGet>( - 'counts', TryGet.optional) ?? - {}) as Map) - .tryGet('unread', TryGet.optional) ?? - 1; + final String? eventId = data['event_id']; + final String? roomId = data['room_id']; + + // For legacy reasons the counts map could be a String encoded JSON: + final countsMap = data.tryGetMap('counts') ?? + (jsonDecode(data.tryGet('counts') ?? '{}') + as Map); + final unread = countsMap.tryGet('unread') ?? 1; + if (unread == 0 || roomId == null || eventId == null) { await _onClearingPush(); return; @@ -698,11 +690,11 @@ class BackgroundPush { android: androidPlatformChannelSpecifics, iOS: iOSPlatformChannelSpecifics, ); - final title = l10n.unreadChats(unread); + final title = l10n!.unreadChats(unread); await _flutterLocalNotificationsPlugin.show( await mapRoomIdToInt(roomId), title, - l10n.openAppToReadMessages, + l10n!.openAppToReadMessages, platformChannelSpecifics, payload: roomId, ); @@ -712,8 +704,8 @@ class BackgroundPush { } AndroidNotificationDetails _getAndroidNotificationDetails( - {MessagingStyleInformation styleInformation, String ticker}) { - final color = (context != null ? Theme.of(context).primaryColor : null) ?? + {MessagingStyleInformation? styleInformation, String? ticker}) { + final color = (context != null ? Theme.of(context!).primaryColor : null) ?? const Color(0xFF5625BA); return AndroidNotificationDetails( diff --git a/lib/utils/beautify_string_extension.dart b/lib/utils/beautify_string_extension.dart index 7811460a..b555d6de 100644 --- a/lib/utils/beautify_string_extension.dart +++ b/lib/utils/beautify_string_extension.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - extension BeautifyStringExtension on String { String get beautified { var beautifiedStr = ''; diff --git a/lib/utils/custom_scroll_behaviour.dart b/lib/utils/custom_scroll_behaviour.dart index f61f4285..84721115 100644 --- a/lib/utils/custom_scroll_behaviour.dart +++ b/lib/utils/custom_scroll_behaviour.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; diff --git a/lib/utils/date_time_extension.dart b/lib/utils/date_time_extension.dart index 54c89d9a..e37b4f0e 100644 --- a/lib/utils/date_time_extension.dart +++ b/lib/utils/date_time_extension.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; diff --git a/lib/utils/famedlysdk_store.dart b/lib/utils/famedlysdk_store.dart index 043c190d..f917402d 100644 --- a/lib/utils/famedlysdk_store.dart +++ b/lib/utils/famedlysdk_store.dart @@ -9,11 +9,11 @@ import 'package:fluffychat/utils/platform_infos.dart'; // see https://github.com/mogol/flutter_secure_storage/issues/161#issuecomment-704578453 class AsyncMutex { - Completer _completer; + Completer? _completer; Future lock() async { while (_completer != null) { - await _completer.future; + await _completer!.future; } _completer = Completer(); @@ -21,15 +21,15 @@ class AsyncMutex { void unlock() { assert(_completer != null); - final completer = _completer; + final completer = _completer!; _completer = null; completer.complete(); } } class Store { - LocalStorage storage; - final FlutterSecureStorage secureStorage; + LocalStorage? storage; + final FlutterSecureStorage? secureStorage; static final _mutex = AsyncMutex(); Store() @@ -44,22 +44,22 @@ class Store { ? null : await getApplicationDocumentsDirectory()); storage = LocalStorage('LocalStorage', directory?.path); - await storage.ready; + await storage!.ready; } } - Future getItem(String key) async { + Future getItem(String key) async { if (!PlatformInfos.isMobile) { await _setupLocalStorage(); try { - return storage.getItem(key)?.toString(); + return storage!.getItem(key)?.toString(); } catch (_) { return null; } } try { await _mutex.lock(); - return await secureStorage.read(key: key); + return await secureStorage!.read(key: key); } catch (_) { return null; } finally { @@ -67,7 +67,7 @@ class Store { } } - Future getItemBool(String key, [bool defaultValue]) async { + Future getItemBool(String key, [bool? defaultValue]) async { final value = await getItem(key); if (value == null) { return defaultValue ?? false; @@ -76,14 +76,14 @@ class Store { return value == '1' || value.toLowerCase() == 'true'; } - Future setItem(String key, String value) async { + Future setItem(String key, String? value) async { if (!PlatformInfos.isMobile) { await _setupLocalStorage(); - return await storage.setItem(key, value); + return await storage!.setItem(key, value); } try { await _mutex.lock(); - return await secureStorage.write(key: key, value: value); + return await secureStorage!.write(key: key, value: value); } finally { _mutex.unlock(); } @@ -96,11 +96,11 @@ class Store { Future deleteItem(String key) async { if (!PlatformInfos.isMobile) { await _setupLocalStorage(); - return await storage.deleteItem(key); + return await storage!.deleteItem(key); } try { await _mutex.lock(); - return await secureStorage.delete(key: key); + return await secureStorage!.delete(key: key); } finally { _mutex.unlock(); } diff --git a/lib/utils/fluffy_share.dart b/lib/utils/fluffy_share.dart index 2d3f909b..b417903d 100644 --- a/lib/utils/fluffy_share.dart +++ b/lib/utils/fluffy_share.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; diff --git a/lib/utils/get_client_secret.dart b/lib/utils/get_client_secret.dart index b141350c..d86cd388 100644 --- a/lib/utils/get_client_secret.dart +++ b/lib/utils/get_client_secret.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'dart:math'; const _chars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz1234567890'; diff --git a/lib/utils/localized_exception_extension.dart b/lib/utils/localized_exception_extension.dart index 7191bbdf..16dd7f4f 100644 --- a/lib/utils/localized_exception_extension.dart +++ b/lib/utils/localized_exception_extension.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'dart:io'; import 'package:flutter/material.dart'; diff --git a/lib/utils/matrix_sdk_extensions.dart/client_presence_extension.dart b/lib/utils/matrix_sdk_extensions.dart/client_presence_extension.dart index d7274df8..fcabae5e 100644 --- a/lib/utils/matrix_sdk_extensions.dart/client_presence_extension.dart +++ b/lib/utils/matrix_sdk_extensions.dart/client_presence_extension.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'package:matrix/matrix.dart'; extension ClientPresenceExtension on Client { diff --git a/lib/utils/matrix_sdk_extensions.dart/client_stories_extension.dart b/lib/utils/matrix_sdk_extensions.dart/client_stories_extension.dart index 15eca426..f2e1627a 100644 --- a/lib/utils/matrix_sdk_extensions.dart/client_stories_extension.dart +++ b/lib/utils/matrix_sdk_extensions.dart/client_stories_extension.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'package:flutter/cupertino.dart'; import 'package:adaptive_dialog/adaptive_dialog.dart'; diff --git a/lib/utils/matrix_sdk_extensions.dart/device_extension.dart b/lib/utils/matrix_sdk_extensions.dart/device_extension.dart index 0eea82f0..55f3ebfc 100644 --- a/lib/utils/matrix_sdk_extensions.dart/device_extension.dart +++ b/lib/utils/matrix_sdk_extensions.dart/device_extension.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'package:flutter/material.dart'; import 'package:matrix/matrix.dart'; diff --git a/lib/utils/matrix_sdk_extensions.dart/event_extension.dart b/lib/utils/matrix_sdk_extensions.dart/event_extension.dart index 520dc403..cd55e905 100644 --- a/lib/utils/matrix_sdk_extensions.dart/event_extension.dart +++ b/lib/utils/matrix_sdk_extensions.dart/event_extension.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; diff --git a/lib/utils/matrix_sdk_extensions.dart/filtered_timeline_extension.dart b/lib/utils/matrix_sdk_extensions.dart/filtered_timeline_extension.dart index 4dda918e..565a07a9 100644 --- a/lib/utils/matrix_sdk_extensions.dart/filtered_timeline_extension.dart +++ b/lib/utils/matrix_sdk_extensions.dart/filtered_timeline_extension.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'package:matrix/matrix.dart'; import '../../config/app_config.dart'; diff --git a/lib/utils/matrix_sdk_extensions.dart/fluffybox_database.dart b/lib/utils/matrix_sdk_extensions.dart/fluffybox_database.dart index 89a6d42a..12a906a5 100644 --- a/lib/utils/matrix_sdk_extensions.dart/fluffybox_database.dart +++ b/lib/utils/matrix_sdk_extensions.dart/fluffybox_database.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'dart:convert'; import 'dart:io'; import 'dart:typed_data'; diff --git a/lib/utils/matrix_sdk_extensions.dart/flutter_matrix_hive_database.dart b/lib/utils/matrix_sdk_extensions.dart/flutter_matrix_hive_database.dart index 3ee56bde..9879ff9c 100644 --- a/lib/utils/matrix_sdk_extensions.dart/flutter_matrix_hive_database.dart +++ b/lib/utils/matrix_sdk_extensions.dart/flutter_matrix_hive_database.dart @@ -14,7 +14,7 @@ import 'package:path_provider/path_provider.dart'; import '../platform_infos.dart'; class FlutterMatrixHiveStore extends FamedlySdkHiveDatabase { - FlutterMatrixHiveStore(String name, {HiveCipher encryptionCipher}) + FlutterMatrixHiveStore(String name, {HiveCipher? encryptionCipher}) : super( name, encryptionCipher: encryptionCipher, @@ -28,7 +28,7 @@ class FlutterMatrixHiveStore extends FamedlySdkHiveDatabase { if (!kIsWeb && !_hiveInitialized) { _hiveInitialized = true; } - HiveCipher hiverCipher; + HiveCipher? hiverCipher; try { // Workaround for secure storage is calling Platform.operatingSystem on web if (kIsWeb || Platform.isLinux) throw MissingPluginException(); @@ -83,12 +83,12 @@ class FlutterMatrixHiveStore extends FamedlySdkHiveDatabase { return (await getApplicationDocumentsDirectory()).path; } } catch (_) { - return (await getDownloadsDirectory()).path; + return (await getDownloadsDirectory())!.path; } } @override - Future getFile(Uri mxcUri) async { + Future getFile(Uri mxcUri) async { if (!supportsFileStoring) return null; final tempDirectory = await _getFileStoreDirectory(); final file = diff --git a/lib/utils/matrix_sdk_extensions.dart/ios_badge_client_extension.dart b/lib/utils/matrix_sdk_extensions.dart/ios_badge_client_extension.dart index 36eccfa0..6c2e4d12 100644 --- a/lib/utils/matrix_sdk_extensions.dart/ios_badge_client_extension.dart +++ b/lib/utils/matrix_sdk_extensions.dart/ios_badge_client_extension.dart @@ -9,8 +9,7 @@ extension IosBadgeClientExtension on Client { if (PlatformInfos.isIOS) { // Workaround for iOS not clearing notifications with fcm_shared_isolate if (!rooms.any((r) => - r.membership == Membership.invite || - (r.notificationCount != null && r.notificationCount > 0))) { + r.membership == Membership.invite || (r.notificationCount > 0))) { // ignore: unawaited_futures FlutterLocalNotificationsPlugin().cancelAll(); FlutterAppBadger.removeBadge(); diff --git a/lib/utils/matrix_sdk_extensions.dart/matrix_file_extension.dart b/lib/utils/matrix_sdk_extensions.dart/matrix_file_extension.dart index 303d9feb..37689bfe 100644 --- a/lib/utils/matrix_sdk_extensions.dart/matrix_file_extension.dart +++ b/lib/utils/matrix_sdk_extensions.dart/matrix_file_extension.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'dart:io'; import 'package:flutter/material.dart'; diff --git a/lib/utils/matrix_sdk_extensions.dart/matrix_locals.dart b/lib/utils/matrix_sdk_extensions.dart/matrix_locals.dart index b5908876..a755f124 100644 --- a/lib/utils/matrix_sdk_extensions.dart/matrix_locals.dart +++ b/lib/utils/matrix_sdk_extensions.dart/matrix_locals.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:matrix/matrix.dart'; diff --git a/lib/utils/matrix_sdk_extensions.dart/presence_extension.dart b/lib/utils/matrix_sdk_extensions.dart/presence_extension.dart index 5d5b195d..1698e537 100644 --- a/lib/utils/matrix_sdk_extensions.dart/presence_extension.dart +++ b/lib/utils/matrix_sdk_extensions.dart/presence_extension.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; diff --git a/lib/utils/platform_infos.dart b/lib/utils/platform_infos.dart index 0359899a..47baf1a7 100644 --- a/lib/utils/platform_infos.dart +++ b/lib/utils/platform_infos.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'dart:io'; import 'package:flutter/foundation.dart'; diff --git a/lib/utils/resize_image.dart b/lib/utils/resize_image.dart index aed19b42..99dca101 100644 --- a/lib/utils/resize_image.dart +++ b/lib/utils/resize_image.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'dart:io'; import 'dart:math' as math; import 'dart:typed_data'; diff --git a/lib/utils/room_send_file_extension.dart b/lib/utils/room_send_file_extension.dart index 0b2775a7..1ae7e917 100644 --- a/lib/utils/room_send_file_extension.dart +++ b/lib/utils/room_send_file_extension.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'package:matrix/matrix.dart'; import 'resize_image.dart'; diff --git a/lib/utils/room_status_extension.dart b/lib/utils/room_status_extension.dart index e9bfde1a..fcbf4bcf 100644 --- a/lib/utils/room_status_extension.dart +++ b/lib/utils/room_status_extension.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'package:flutter/widgets.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; diff --git a/lib/utils/run_in_background.dart b/lib/utils/run_in_background.dart index 1ea4a7f3..e75d1452 100644 --- a/lib/utils/run_in_background.dart +++ b/lib/utils/run_in_background.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'dart:async'; import 'package:isolate/isolate.dart'; diff --git a/lib/utils/sentry_controller.dart b/lib/utils/sentry_controller.dart index 87708113..b805d995 100644 --- a/lib/utils/sentry_controller.dart +++ b/lib/utils/sentry_controller.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; diff --git a/lib/utils/stream_extension.dart b/lib/utils/stream_extension.dart index eb0eed96..afd8deba 100644 --- a/lib/utils/stream_extension.dart +++ b/lib/utils/stream_extension.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'dart:async'; extension StreamExtension on Stream { diff --git a/lib/utils/string_color.dart b/lib/utils/string_color.dart index 7e35841b..4ed39432 100644 --- a/lib/utils/string_color.dart +++ b/lib/utils/string_color.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'package:flutter/material.dart'; extension StringColor on String { diff --git a/lib/utils/uia_request_manager.dart b/lib/utils/uia_request_manager.dart index 08d74433..2c84ce54 100644 --- a/lib/utils/uia_request_manager.dart +++ b/lib/utils/uia_request_manager.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'dart:async'; import 'package:adaptive_dialog/adaptive_dialog.dart'; @@ -50,7 +48,8 @@ extension UiaRequestManager on MatrixState { ), ); case AuthenticationTypes.emailIdentity: - if (currentThreepidCreds == null || currentClientSecret == null) { + final currentThreepidCreds = this.currentThreepidCreds; + if (currentThreepidCreds == null) { return uiaRequest.cancel( UiaException(L10n.of(widget.context)!.serverRequiresEmail), ); diff --git a/lib/utils/url_launcher.dart b/lib/utils/url_launcher.dart index bc2e6dff..3d60efbd 100644 --- a/lib/utils/url_launcher.dart +++ b/lib/utils/url_launcher.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:adaptive_dialog/adaptive_dialog.dart'; +import 'package:collection/collection.dart' show IterableExtension; import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:future_loading_dialog/future_loading_dialog.dart'; import 'package:matrix/matrix.dart'; @@ -15,22 +16,22 @@ import 'package:fluffychat/widgets/public_room_bottom_sheet.dart'; import 'platform_infos.dart'; class UrlLauncher { - final String url; + final String? url; final BuildContext context; const UrlLauncher(this.context, this.url); void launchUrl() { - if (url.toLowerCase().startsWith(AppConfig.deepLinkPrefix) || - url.toLowerCase().startsWith(AppConfig.inviteLinkPrefix) || - {'#', '@', '!', '+', '\$'}.contains(url[0]) || - url.toLowerCase().startsWith(AppConfig.schemePrefix)) { + if (url!.toLowerCase().startsWith(AppConfig.deepLinkPrefix) || + url!.toLowerCase().startsWith(AppConfig.inviteLinkPrefix) || + {'#', '@', '!', '+', '\$'}.contains(url![0]) || + url!.toLowerCase().startsWith(AppConfig.schemePrefix)) { return openMatrixToUrl(); } - final uri = Uri.tryParse(url); + final uri = Uri.tryParse(url!); if (uri == null) { // we can't open this thing ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text(L10n.of(context).cantOpenUri(url)))); + SnackBar(content: Text(L10n.of(context)!.cantOpenUri(url!)))); return; } if (!{'https', 'http'}.contains(uri.scheme)) { @@ -38,8 +39,7 @@ class UrlLauncher { // we need to transmute geo URIs on desktop and on iOS if ((!PlatformInfos.isMobile || PlatformInfos.isIOS) && - uri.scheme == 'geo' && - uri.path != null) { + uri.scheme == 'geo') { final latlong = uri.path .split(';') .first @@ -64,12 +64,12 @@ class UrlLauncher { return; } } - launch(url); + launch(url!); return; } - if (uri.host == null) { + if (uri.host.isEmpty) { ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text(L10n.of(context).cantOpenUri(url)))); + SnackBar(content: Text(L10n.of(context)!.cantOpenUri(url!)))); return; } // okay, we have either an http or an https URI. @@ -87,7 +87,7 @@ class UrlLauncher { void openMatrixToUrl() async { final matrix = Matrix.of(context); - final url = this.url.replaceFirst( + final url = this.url!.replaceFirst( AppConfig.deepLinkPrefix, AppConfig.inviteLinkPrefix, ); @@ -96,10 +96,10 @@ class UrlLauncher { // identifiers (room id & event id), or it might also have a query part. // All this needs parsing. final identityParts = url.parseIdentifierIntoParts() ?? - Uri.tryParse(url)?.host?.parseIdentifierIntoParts() ?? + Uri.tryParse(url)?.host.parseIdentifierIntoParts() ?? Uri.tryParse(url) ?.pathSegments - ?.lastWhere((_) => true, orElse: () => null) + .lastWhereOrNull((_) => true) ?.parseIdentifierIntoParts(); if (identityParts == null) { return; // no match, nothing to do @@ -124,13 +124,11 @@ class UrlLauncher { if (response.error != null) { return; // nothing to do, the alias doesn't exist } - roomId = response.result.roomId; - servers.addAll(response.result.servers); - room = matrix.client.getRoomById(roomId); - } - if (identityParts.via != null) { - servers.addAll(identityParts.via); + roomId = response.result!.roomId; + servers.addAll(response.result!.servers!); + room = matrix.client.getRoomById(roomId!); } + servers.addAll(identityParts.via); if (room != null) { // we have the room, so....just open it if (event != null) { @@ -170,10 +168,10 @@ class UrlLauncher { context: context, future: () => Future.delayed(const Duration(seconds: 2))); if (event != null) { - VRouter.of(context).toSegments(['rooms', response.result], + VRouter.of(context).toSegments(['rooms', response.result!], queryParameters: {'event': event}); } else { - VRouter.of(context).toSegments(['rooms', response.result]); + VRouter.of(context).toSegments(['rooms', response.result!]); } } } diff --git a/lib/widgets/adaptive_flat_button.dart b/lib/widgets/adaptive_flat_button.dart index 0853184a..7faa7eed 100644 --- a/lib/widgets/adaptive_flat_button.dart +++ b/lib/widgets/adaptive_flat_button.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; diff --git a/lib/widgets/avatar.dart b/lib/widgets/avatar.dart index 194026f4..b470b902 100644 --- a/lib/widgets/avatar.dart +++ b/lib/widgets/avatar.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'package:flutter/material.dart'; import 'package:cached_network_image/cached_network_image.dart'; diff --git a/lib/widgets/chat_settings_popup_menu.dart b/lib/widgets/chat_settings_popup_menu.dart index 3319bee2..83d3af0d 100644 --- a/lib/widgets/chat_settings_popup_menu.dart +++ b/lib/widgets/chat_settings_popup_menu.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'dart:async'; import 'package:flutter/material.dart'; diff --git a/lib/widgets/connection_status_header.dart b/lib/widgets/connection_status_header.dart index e538a082..4d44e7d9 100644 --- a/lib/widgets/connection_status_header.dart +++ b/lib/widgets/connection_status_header.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'dart:async'; import 'package:flutter/material.dart'; diff --git a/lib/widgets/contacts_list.dart b/lib/widgets/contacts_list.dart index 00df9e9d..d51cf4a5 100644 --- a/lib/widgets/contacts_list.dart +++ b/lib/widgets/contacts_list.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'dart:async'; import 'package:flutter/material.dart'; diff --git a/lib/widgets/content_banner.dart b/lib/widgets/content_banner.dart index 34bf320d..46ea7465 100644 --- a/lib/widgets/content_banner.dart +++ b/lib/widgets/content_banner.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'package:flutter/material.dart'; import 'package:cached_network_image/cached_network_image.dart'; @@ -8,7 +6,7 @@ import 'package:matrix/matrix.dart'; import 'matrix.dart'; class ContentBanner extends StatelessWidget { - final Uri mxContent; + final Uri? mxContent; final double height; final IconData defaultIcon; final bool loading; @@ -16,8 +14,9 @@ class ContentBanner extends StatelessWidget { final Client? client; final double opacity; - const ContentBanner(this.mxContent, - {this.height = 400, + const ContentBanner( + {this.mxContent, + this.height = 400, this.defaultIcon = Icons.people_outlined, this.loading = false, this.onEdit, @@ -32,7 +31,7 @@ class ContentBanner extends StatelessWidget { final bannerSize = (mediaQuery.size.width * mediaQuery.devicePixelRatio).toInt(); final onEdit = this.onEdit; - final src = mxContent.getThumbnail( + final src = mxContent?.getThumbnail( client ?? Matrix.of(context).client, width: bannerSize, height: bannerSize, @@ -54,7 +53,7 @@ class ContentBanner extends StatelessWidget { bottom: 0, child: Opacity( opacity: opacity, - child: (!loading && mxContent.host.isNotEmpty) + child: (!loading && src != null) ? CachedNetworkImage( imageUrl: src.toString(), height: 300, diff --git a/lib/widgets/default_app_bar_search_field.dart b/lib/widgets/default_app_bar_search_field.dart index 4ba287b5..0be43755 100644 --- a/lib/widgets/default_app_bar_search_field.dart +++ b/lib/widgets/default_app_bar_search_field.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; diff --git a/lib/widgets/layouts/empty_page.dart b/lib/widgets/layouts/empty_page.dart index b7265a50..0f3b2d42 100644 --- a/lib/widgets/layouts/empty_page.dart +++ b/lib/widgets/layouts/empty_page.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'dart:math'; import 'package:flutter/material.dart'; diff --git a/lib/widgets/layouts/loading_view.dart b/lib/widgets/layouts/loading_view.dart index 45e55cc5..176708cc 100644 --- a/lib/widgets/layouts/loading_view.dart +++ b/lib/widgets/layouts/loading_view.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'package:flutter/material.dart'; import 'package:matrix/matrix.dart'; diff --git a/lib/widgets/layouts/max_width_body.dart b/lib/widgets/layouts/max_width_body.dart index f6a963e7..804f317f 100644 --- a/lib/widgets/layouts/max_width_body.dart +++ b/lib/widgets/layouts/max_width_body.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'dart:math'; import 'package:flutter/material.dart'; diff --git a/lib/widgets/layouts/one_page_card.dart b/lib/widgets/layouts/one_page_card.dart index 0ca4bec1..1c2d0e91 100644 --- a/lib/widgets/layouts/one_page_card.dart +++ b/lib/widgets/layouts/one_page_card.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'dart:math'; import 'package:flutter/material.dart'; diff --git a/lib/widgets/layouts/side_view_layout.dart b/lib/widgets/layouts/side_view_layout.dart index f54db182..d0955cba 100644 --- a/lib/widgets/layouts/side_view_layout.dart +++ b/lib/widgets/layouts/side_view_layout.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'package:flutter/material.dart'; import 'package:vrouter/vrouter.dart'; diff --git a/lib/widgets/layouts/two_column_layout.dart b/lib/widgets/layouts/two_column_layout.dart index 649e3560..0862eb67 100644 --- a/lib/widgets/layouts/two_column_layout.dart +++ b/lib/widgets/layouts/two_column_layout.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'package:flutter/material.dart'; import 'package:fluffychat/config/themes.dart'; diff --git a/lib/widgets/local_notifications_extension.dart b/lib/widgets/local_notifications_extension.dart index 86d850cb..f71fab80 100644 --- a/lib/widgets/local_notifications_extension.dart +++ b/lib/widgets/local_notifications_extension.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'dart:io'; import 'package:flutter/foundation.dart'; @@ -69,7 +67,7 @@ extension LocalNotificationsExtension on MatrixState { await appIconFile.writeAsBytes(response.bodyBytes); } } - final notification = await linuxNotifications.notify( + final notification = await linuxNotifications!.notify( title, body: body, replacesId: linuxNotificationIds[roomId] ?? 0, diff --git a/lib/widgets/lock_screen.dart b/lib/widgets/lock_screen.dart index 3a20cec1..b35061f1 100644 --- a/lib/widgets/lock_screen.dart +++ b/lib/widgets/lock_screen.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'package:flutter/material.dart'; import 'package:flutter_app_lock/flutter_app_lock.dart'; diff --git a/lib/widgets/log_view.dart b/lib/widgets/log_view.dart index d2f8e7ae..0c18fa50 100644 --- a/lib/widgets/log_view.dart +++ b/lib/widgets/log_view.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'package:flutter/material.dart'; import 'package:matrix/matrix.dart'; diff --git a/lib/widgets/matrix.dart b/lib/widgets/matrix.dart index ac992e3a..2bed15eb 100644 --- a/lib/widgets/matrix.dart +++ b/lib/widgets/matrix.dart @@ -6,6 +6,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:adaptive_theme/adaptive_theme.dart'; +import 'package:collection/collection.dart'; import 'package:desktop_notifications/desktop_notifications.dart'; import 'package:flutter_app_lock/flutter_app_lock.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; @@ -38,23 +39,23 @@ import 'local_notifications_extension.dart'; class Matrix extends StatefulWidget { static const String callNamespace = 'chat.fluffy.jitsi_call'; - final Widget child; + final Widget? child; - final GlobalKey router; + final GlobalKey? router; final BuildContext context; final List clients; - final Map queryParameters; + final Map? queryParameters; const Matrix({ this.child, - @required this.router, - @required this.context, - @required this.clients, + required this.router, + required this.context, + required this.clients, this.queryParameters, - Key key, + Key? key, }) : super(key: key); @override @@ -67,18 +68,18 @@ class Matrix extends StatefulWidget { class MatrixState extends State with WidgetsBindingObserver { int _activeClient = -1; - String activeBundle; + String? activeBundle; Store store = Store(); - BuildContext navigatorContext; + late BuildContext navigatorContext; - BackgroundPush _backgroundPush; + BackgroundPush? _backgroundPush; Client get client { if (widget.clients.isEmpty) { widget.clients.add(getLoginClient()); } if (_activeClient < 0 || _activeClient >= widget.clients.length) { - return currentBundle.first; + return currentBundle!.first!; } return widget.clients[_activeClient]; } @@ -88,19 +89,19 @@ class MatrixState extends State with WidgetsBindingObserver { int getClientIndexByMatrixId(String matrixId) => widget.clients.indexWhere((client) => client.userID == matrixId); - String currentClientSecret; - RequestTokenResponse currentThreepidCreds; + late String currentClientSecret; + RequestTokenResponse? currentThreepidCreds; - void setActiveClient(Client cl) { + void setActiveClient(Client? cl) { final i = widget.clients.indexWhere((c) => c == cl); - if (i != null) { + if (i != -1) { _activeClient = i; } else { - Logs().w('Tried to set an unknown client ${cl.userID} as active'); + Logs().w('Tried to set an unknown client ${cl!.userID} as active'); } } - List get currentBundle { + List? get currentBundle { if (!hasComplexBundles) { return List.from(widget.clients); } @@ -111,8 +112,8 @@ class MatrixState extends State with WidgetsBindingObserver { return bundles.values.first; } - Map> get accountBundles { - final resBundles = >{}; + Map> get accountBundles { + final resBundles = >{}; for (var i = 0; i < widget.clients.length; i++) { final bundles = widget.clients[i].accountBundles; for (final bundle in bundles) { @@ -120,18 +121,18 @@ class MatrixState extends State with WidgetsBindingObserver { continue; } resBundles[bundle.name] ??= []; - resBundles[bundle.name].add(_AccountBundleWithClient( + resBundles[bundle.name]!.add(_AccountBundleWithClient( client: widget.clients[i], bundle: bundle, )); } } for (final b in resBundles.values) { - b.sort((a, b) => a.bundle.priority == null + b.sort((a, b) => a.bundle!.priority == null ? 1 - : b.bundle.priority == null + : b.bundle!.priority == null ? -1 - : a.bundle.priority.compareTo(b.bundle.priority)); + : a.bundle!.priority!.compareTo(b.bundle!.priority!)); } return resBundles .map((k, v) => MapEntry(k, v.map((vv) => vv.client).toList())); @@ -139,13 +140,13 @@ class MatrixState extends State with WidgetsBindingObserver { bool get hasComplexBundles => accountBundles.values.any((v) => v.length > 1); - Client _loginClientCandidate; + Client? _loginClientCandidate; Client getLoginClient() { if (widget.clients.isNotEmpty && !client.isLogged()) { return client; } - _loginClientCandidate ??= ClientManager.createClient( + final candidate = _loginClientCandidate ??= ClientManager.createClient( '${AppConfig.applicationName}-${DateTime.now().millisecondsSinceEpoch}') ..onLoginStateChanged .stream @@ -153,31 +154,31 @@ class MatrixState extends State with WidgetsBindingObserver { .first .then((_) { if (!widget.clients.contains(_loginClientCandidate)) { - widget.clients.add(_loginClientCandidate); + widget.clients.add(_loginClientCandidate!); } - ClientManager.addClientNameToStore(_loginClientCandidate.clientName); - _registerSubs(_loginClientCandidate.clientName); + ClientManager.addClientNameToStore(_loginClientCandidate!.clientName); + _registerSubs(_loginClientCandidate!.clientName); _loginClientCandidate = null; - widget.router.currentState.to('/rooms'); + widget.router!.currentState!.to('/rooms'); }); - return _loginClientCandidate; + return candidate; } - Client getClientByName(String name) => widget.clients - .firstWhere((c) => c.clientName == name, orElse: () => null); + Client? getClientByName(String name) => + widget.clients.firstWhereOrNull((c) => c.clientName == name); - Map get shareContent => _shareContent; - set shareContent(Map content) { + Map? get shareContent => _shareContent; + set shareContent(Map? content) { _shareContent = content; onShareContentChanged.add(_shareContent); } - Map _shareContent; + Map? _shareContent; - final StreamController> onShareContentChanged = + final StreamController?> onShareContentChanged = StreamController.broadcast(); - File wallpaper; + File? wallpaper; void _initWithStore() async { try { @@ -187,7 +188,7 @@ class MatrixState extends State with WidgetsBindingObserver { if (statusMsg?.isNotEmpty ?? false) { Logs().v('Send cached status message: "$statusMsg"'); await client.setPresence( - client.userID, + client.userID!, PresenceType.online, statusMsg: statusMsg, ); @@ -206,15 +207,15 @@ class MatrixState extends State with WidgetsBindingObserver { final onNotification = {}; final onLoginStateChanged = >{}; final onUiaRequest = >{}; - StreamSubscription onFocusSub; - StreamSubscription onBlurSub; + StreamSubscription? onFocusSub; + StreamSubscription? onBlurSub; final onOwnPresence = >{}; - String _cachedPassword; - Timer _cachedPasswordClearTimer; - String get cachedPassword => _cachedPassword; + String? _cachedPassword; + Timer? _cachedPasswordClearTimer; + String? get cachedPassword => _cachedPassword; - set cachedPassword(String p) { + set cachedPassword(String? p) { Logs().d('Password cached'); _cachedPasswordClearTimer?.cancel(); _cachedPassword = p; @@ -226,7 +227,7 @@ class MatrixState extends State with WidgetsBindingObserver { bool webHasFocus = true; - String get activeRoomId => + String? get activeRoomId => VRouter.of(navigatorContext).pathParameters['roomid']; final linuxNotifications = @@ -236,7 +237,7 @@ class MatrixState extends State with WidgetsBindingObserver { @override void initState() { super.initState(); - WidgetsBinding.instance.addObserver(this); + WidgetsBinding.instance!.addObserver(this); initMatrix(); if (PlatformInfos.isWeb) { initConfig().then((_) => initSettings()); @@ -260,8 +261,8 @@ class MatrixState extends State with WidgetsBindingObserver { void _reportSyncError(SyncStatusUpdate update) => SentryController.captureException( - update.error.exception, - update.error.stackTrace, + update.error!.exception, + update.error!.stackTrace, ); void _registerSubs(String name) { @@ -276,9 +277,9 @@ class MatrixState extends State with WidgetsBindingObserver { .listen(_reportSyncError); onRoomKeyRequestSub[name] ??= c.onRoomKeyRequest.stream.listen((RoomKeyRequest request) async { - if (widget.clients.any((cl) => + if (widget.clients.any(((cl) => cl.userID == request.requestingDevice.userId && - cl.identityKey == request.requestingDevice.curve25519Key)) { + cl.identityKey == request.requestingDevice.curve25519Key))) { Logs().i( '[Key Request] Request is from one of our own clients, forwarding the key...'); await request.forwardKey(); @@ -309,20 +310,20 @@ class MatrixState extends State with WidgetsBindingObserver { if (loggedInWithMultipleClients && state != LoginState.loggedIn) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: Text(L10n.of(context).oneClientLoggedOut), + content: Text(L10n.of(context)!.oneClientLoggedOut), ), ); if (state != LoginState.loggedIn) { - widget.router.currentState.to( + widget.router!.currentState!.to( '/rooms', - queryParameters: widget.router.currentState.queryParameters, + queryParameters: widget.router!.currentState!.queryParameters, ); } } else { - widget.router.currentState.to( + widget.router!.currentState!.to( state == LoginState.loggedIn ? '/rooms' : '/home', - queryParameters: widget.router.currentState.queryParameters, + queryParameters: widget.router!.currentState!.queryParameters, ); } }); @@ -330,7 +331,7 @@ class MatrixState extends State with WidgetsBindingObserver { onOwnPresence[name] ??= c.onPresence.stream.listen((presence) { if (c.isLogged() && c.userID == presence.senderId && - presence.presence?.statusMsg != null) { + presence.presence.statusMsg != null) { Logs().v('Update status message: "${presence.presence.statusMsg}"'); store.setItem( SettingKeys.ownStatusMessage, presence.presence.statusMsg); @@ -367,7 +368,7 @@ class MatrixState extends State with WidgetsBindingObserver { void initMatrix() { // Display the app lock if (PlatformInfos.isMobile) { - WidgetsBinding.instance.addPostFrameCallback((_) { + WidgetsBinding.instance!.addPostFrameCallback((_) { ([TargetPlatform.linux].contains(Theme.of(context).platform) ? SharedPreferences.getInstance() .then((prefs) => prefs.getString(SettingKeys.appLockKey)) @@ -375,8 +376,8 @@ class MatrixState extends State with WidgetsBindingObserver { .read(key: SettingKeys.appLockKey)) .then((lock) { if (lock?.isNotEmpty ?? false) { - AppLock.of(widget.context).enable(); - AppLock.of(widget.context).showLockScreen(); + AppLock.of(widget.context)!.enable(); + AppLock.of(widget.context)!.showLockScreen(); } }); }); @@ -398,7 +399,7 @@ class MatrixState extends State with WidgetsBindingObserver { client, context, widget.router, - onFcmError: (errorMsg, {Uri link}) => Timer( + onFcmError: (errorMsg, {Uri? link}) => Timer( const Duration(seconds: 1), () { final banner = SnackBar( @@ -407,7 +408,7 @@ class MatrixState extends State with WidgetsBindingObserver { action: link == null ? null : SnackBarAction( - label: L10n.of(context).link, + label: L10n.of(context)!.link, onPressed: () => launch(link.toString()), ), ); @@ -435,54 +436,51 @@ class MatrixState extends State with WidgetsBindingObserver { } void initSettings() { - if (store != null) { - store.getItem(SettingKeys.jitsiInstance).then((final instance) => - AppConfig.jitsiInstance = instance ?? AppConfig.jitsiInstance); - store.getItem(SettingKeys.wallpaper).then((final path) async { - if (path == null) return; - final file = File(path); - if (await file.exists()) { - wallpaper = file; - } - }); - store.getItem(SettingKeys.fontSizeFactor).then((value) => - AppConfig.fontSizeFactor = - double.tryParse(value ?? '') ?? AppConfig.fontSizeFactor); - store.getItem(SettingKeys.bubbleSizeFactor).then((value) => - AppConfig.bubbleSizeFactor = - double.tryParse(value ?? '') ?? AppConfig.bubbleSizeFactor); - store - .getItemBool(SettingKeys.renderHtml, AppConfig.renderHtml) - .then((value) => AppConfig.renderHtml = value); - store - .getItemBool( - SettingKeys.hideRedactedEvents, AppConfig.hideRedactedEvents) - .then((value) => AppConfig.hideRedactedEvents = value); - store - .getItemBool( - SettingKeys.hideUnknownEvents, AppConfig.hideUnknownEvents) - .then((value) => AppConfig.hideUnknownEvents = value); - store - .getItemBool(SettingKeys.autoplayImages, AppConfig.autoplayImages) - .then((value) => AppConfig.autoplayImages = value); - store - .getItemBool(SettingKeys.sendOnEnter, AppConfig.sendOnEnter) - .then((value) => AppConfig.sendOnEnter = value); - store.getItem(SettingKeys.chatColor).then((value) { - if (value != null && int.tryParse(value) != null) { - AppConfig.chatColor = Color(int.parse(value)); - AdaptiveTheme.of(context).setTheme( - light: FluffyThemes.light, - dark: FluffyThemes.dark, - ); - } - }); - } + store.getItem(SettingKeys.jitsiInstance).then((final instance) => + AppConfig.jitsiInstance = instance ?? AppConfig.jitsiInstance); + store.getItem(SettingKeys.wallpaper).then((final path) async { + if (path == null) return; + final file = File(path); + if (await file.exists()) { + wallpaper = file; + } + }); + store.getItem(SettingKeys.fontSizeFactor).then((value) => + AppConfig.fontSizeFactor = + double.tryParse(value ?? '') ?? AppConfig.fontSizeFactor); + store.getItem(SettingKeys.bubbleSizeFactor).then((value) => + AppConfig.bubbleSizeFactor = + double.tryParse(value ?? '') ?? AppConfig.bubbleSizeFactor); + store + .getItemBool(SettingKeys.renderHtml, AppConfig.renderHtml) + .then((value) => AppConfig.renderHtml = value); + store + .getItemBool( + SettingKeys.hideRedactedEvents, AppConfig.hideRedactedEvents) + .then((value) => AppConfig.hideRedactedEvents = value); + store + .getItemBool(SettingKeys.hideUnknownEvents, AppConfig.hideUnknownEvents) + .then((value) => AppConfig.hideUnknownEvents = value); + store + .getItemBool(SettingKeys.autoplayImages, AppConfig.autoplayImages) + .then((value) => AppConfig.autoplayImages = value); + store + .getItemBool(SettingKeys.sendOnEnter, AppConfig.sendOnEnter) + .then((value) => AppConfig.sendOnEnter = value); + store.getItem(SettingKeys.chatColor).then((value) { + if (value != null && int.tryParse(value) != null) { + AppConfig.chatColor = Color(int.parse(value)); + AdaptiveTheme.of(context).setTheme( + light: FluffyThemes.light, + dark: FluffyThemes.dark, + ); + } + }); } @override void dispose() { - WidgetsBinding.instance.removeObserver(this); + WidgetsBinding.instance!.removeObserver(this); onRoomKeyRequestSub.values.map((s) => s.cancel()); onKeyVerificationRequestSub.values.map((s) => s.cancel()); @@ -510,10 +508,10 @@ class MatrixState extends State with WidgetsBindingObserver { class FixedThreepidCreds extends ThreepidCreds { FixedThreepidCreds({ - String sid, - String clientSecret, - String idServer, - String idAccessToken, + required String sid, + required String clientSecret, + String? idServer, + String? idAccessToken, }) : super( sid: sid, clientSecret: clientSecret, @@ -533,7 +531,7 @@ class FixedThreepidCreds extends ThreepidCreds { } class _AccountBundleWithClient { - final Client client; - final AccountBundle bundle; + final Client? client; + final AccountBundle? bundle; _AccountBundleWithClient({this.client, this.bundle}); } diff --git a/lib/widgets/permission_slider_dialog.dart b/lib/widgets/permission_slider_dialog.dart index eb7d5e09..47733e1b 100644 --- a/lib/widgets/permission_slider_dialog.dart +++ b/lib/widgets/permission_slider_dialog.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; diff --git a/lib/widgets/profile_bottom_sheet.dart b/lib/widgets/profile_bottom_sheet.dart index 86366ac4..8532b968 100644 --- a/lib/widgets/profile_bottom_sheet.dart +++ b/lib/widgets/profile_bottom_sheet.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'dart:math'; import 'package:flutter/material.dart'; @@ -77,7 +75,7 @@ class ProfileBottomSheet extends StatelessWidget { .adaptive(strokeWidth: 2), ) : ContentBanner( - profile.avatarUrl!, + mxContent: profile.avatarUrl, defaultIcon: Icons.person_outline, client: Matrix.of(context).client, ), diff --git a/lib/widgets/public_room_bottom_sheet.dart b/lib/widgets/public_room_bottom_sheet.dart index a21c3072..1aedfe26 100644 --- a/lib/widgets/public_room_bottom_sheet.dart +++ b/lib/widgets/public_room_bottom_sheet.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'dart:math'; import 'package:flutter/material.dart'; @@ -116,7 +114,7 @@ class PublicRoomBottomSheet extends StatelessWidget { ) else ContentBanner( - profile.avatarUrl!, + mxContent: profile.avatarUrl, height: 156, defaultIcon: Icons.person_outline, client: Matrix.of(context).client, diff --git a/lib/widgets/sentry_switch_list_tile.dart b/lib/widgets/sentry_switch_list_tile.dart index f5b378b5..d60df5ee 100644 --- a/lib/widgets/sentry_switch_list_tile.dart +++ b/lib/widgets/sentry_switch_list_tile.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'package:flutter/material.dart'; import 'package:fluffychat/utils/sentry_controller.dart'; diff --git a/lib/widgets/settings_switch_list_tile.dart b/lib/widgets/settings_switch_list_tile.dart index 0df7d675..3fc5f2b4 100644 --- a/lib/widgets/settings_switch_list_tile.dart +++ b/lib/widgets/settings_switch_list_tile.dart @@ -6,13 +6,13 @@ class SettingsSwitchListTile extends StatefulWidget { final bool defaultValue; final String storeKey; final String title; - final Function(bool) onChanged; + final Function(bool)? onChanged; const SettingsSwitchListTile.adaptive({ - Key key, + Key? key, this.defaultValue = false, - @required this.storeKey, - @required this.title, + required this.storeKey, + required this.title, this.onChanged, }) : super(key: key); @@ -35,7 +35,7 @@ class _SettingsSwitchListTileState extends State { await Matrix.of(context) .store .setItem(widget.storeKey, newValue.toString()); - setState(() => null); + setState(() {}); }, ), ); diff --git a/lib/widgets/unread_badge_back_button.dart b/lib/widgets/unread_badge_back_button.dart index 2af40308..c0970dcb 100644 --- a/lib/widgets/unread_badge_back_button.dart +++ b/lib/widgets/unread_badge_back_button.dart @@ -1,5 +1,3 @@ -//@dart=2.12 - import 'package:flutter/material.dart'; import 'package:matrix/matrix.dart'; diff --git a/pubspec.lock b/pubspec.lock index 77860055..1463c5af 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -170,7 +170,7 @@ packages: source: hosted version: "1.1.0" collection: - dependency: transitive + dependency: "direct main" description: name: collection url: "https://pub.dartlang.org" @@ -493,14 +493,14 @@ packages: name: flutter_olm url: "https://pub.dartlang.org" source: hosted - version: "1.1.2" + version: "1.2.0" flutter_openssl_crypto: dependency: "direct main" description: name: flutter_openssl_crypto url: "https://pub.dartlang.org" source: hosted - version: "0.0.1" + version: "0.1.0" flutter_plugin_android_lifecycle: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index d3a42b21..f8fc568d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,7 +4,7 @@ publish_to: none version: 1.2.0+2041 environment: - sdk: ">=2.11.0 <3.0.0" + sdk: '>=2.12.0 <3.0.0' dependencies: adaptive_dialog: ^1.1.0 @@ -14,6 +14,7 @@ dependencies: blurhash_dart: ^1.1.0 cached_network_image: ^3.1.0 chewie: ^1.2.2 + collection: ^1.15.0-nullsafety.4 cupertino_icons: any desktop_drop: ^0.3.0 desktop_notifications: ^0.6.1 @@ -35,8 +36,8 @@ dependencies: sdk: flutter flutter_map: ^0.14.0 flutter_matrix_html: ^1.1.0 - flutter_olm: ^1.1.2 - flutter_openssl_crypto: ^0.0.1 + flutter_olm: ^1.2.0 + flutter_openssl_crypto: ^0.1.0 flutter_secure_storage: ^5.0.2 flutter_slidable: ^1.1.0 flutter_svg: ^0.22.0 diff --git a/scripts/enable-android-google-services.patch b/scripts/enable-android-google-services.patch index c5680877..cb108e67 100644 --- a/scripts/enable-android-google-services.patch +++ b/scripts/enable-android-google-services.patch @@ -1,5 +1,5 @@ diff --git a/android/app/build.gradle b/android/app/build.gradle -index 63136570..3f33ea05 100644 +index 39c920e8..e27a49f5 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -80,11 +80,11 @@ flutter { @@ -17,10 +17,10 @@ index 63136570..3f33ea05 100644 -//apply plugin: 'com.google.gms.google-services' +apply plugin: 'com.google.gms.google-services' diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml -index 9cbecc16..1709ddc6 100644 +index eae7eadf..cf81a750 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml -@@ -82,12 +82,12 @@ +@@ -88,12 +88,12 @@ @@ -65,7 +65,7 @@ index 4ce5c41d..be58d662 100644 } diff --git a/lib/utils/background_push.dart b/lib/utils/background_push.dart -index ca660845..306da934 100644 +index f2eb9fb4..0234765f 100644 --- a/lib/utils/background_push.dart +++ b/lib/utils/background_push.dart @@ -39,7 +39,7 @@ import 'famedlysdk_store.dart'; @@ -77,20 +77,20 @@ index ca660845..306da934 100644 class NoTokenException implements Exception { String get cause => 'Cannot get firebase token'; -@@ -116,7 +116,7 @@ class BackgroundPush { +@@ -117,7 +117,7 @@ class BackgroundPush { setupPush(); } -- final _fcmSharedIsolate = null; //FcmSharedIsolate(); -+ final _fcmSharedIsolate = FcmSharedIsolate(); +- final dynamic _fcmSharedIsolate = null; //FcmSharedIsolate(); ++ final dynamic _fcmSharedIsolate = FcmSharedIsolate(); - StreamSubscription onLogin; - StreamSubscription onRoomSync; + StreamSubscription? onLogin; + StreamSubscription? onRoomSync; diff --git a/pubspec.yaml b/pubspec.yaml -index e1670a32..7e3238b0 100644 +index a1442ed2..ee0ce757 100644 --- a/pubspec.yaml +++ b/pubspec.yaml -@@ -16,8 +16,8 @@ dependencies: +@@ -21,8 +21,8 @@ dependencies: email_validator: ^2.0.1 emoji_picker_flutter: ^1.0.7 encrypt: ^5.0.1 diff --git a/test/utils/test_client.dart b/test/utils/test_client.dart index 373b20bb..dc84d4b5 100644 --- a/test/utils/test_client.dart +++ b/test/utils/test_client.dart @@ -25,9 +25,7 @@ Future prepareTestClient({ AuthenticationTypes.sso }, ); - if (homeserver != null) { - await client.checkHomeserver(homeserver); - } + await client.checkHomeserver(homeserver); if (loggedIn) { await client.login( LoginType.mLoginToken,