refactor: Make most of the utils null safe

This commit is contained in:
Krille Fear 2021-12-03 17:29:32 +01:00
parent 110d0506aa
commit 265ef0ebb2
23 changed files with 140 additions and 112 deletions

View file

@ -1,8 +1,10 @@
//@dart=2.12
import 'package:matrix/matrix.dart'; import 'package:matrix/matrix.dart';
class AccountBundles { class AccountBundles {
String prefix; String? prefix;
List<AccountBundle> bundles; List<AccountBundle>? bundles;
AccountBundles({this.prefix, this.bundles}); AccountBundles({this.prefix, this.bundles});
@ -23,13 +25,14 @@ class AccountBundles {
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {
if (prefix != null) 'prefix': prefix, if (prefix != null) 'prefix': prefix,
if (bundles != null) 'bundles': bundles.map((v) => v.toJson()).toList(), if (bundles != null)
'bundles': bundles!.map((v) => v.toJson()).toList(),
}; };
} }
class AccountBundle { class AccountBundle {
String name; String? name;
int priority; int? priority;
AccountBundle({this.name, this.priority}); AccountBundle({this.name, this.priority});
@ -47,9 +50,9 @@ const accountBundlesType = 'im.fluffychat.account_bundles';
extension AccountBundlesExtension on Client { extension AccountBundlesExtension on Client {
List<AccountBundle> get accountBundles { List<AccountBundle> get accountBundles {
List<AccountBundle> ret; List<AccountBundle>? ret;
if (accountData.containsKey(accountBundlesType)) { if (accountData.containsKey(accountBundlesType)) {
ret = AccountBundles.fromJson(accountData[accountBundlesType].content) ret = AccountBundles.fromJson(accountData[accountBundlesType]!.content)
.bundles; .bundles;
} }
ret ??= []; ret ??= [];
@ -62,12 +65,12 @@ extension AccountBundlesExtension on Client {
return ret; return ret;
} }
Future<void> setAccountBundle(String name, [int priority]) async { Future<void> setAccountBundle(String name, [int? priority]) async {
final data = final data =
AccountBundles.fromJson(accountData[accountBundlesType]?.content ?? {}); AccountBundles.fromJson(accountData[accountBundlesType]?.content ?? {});
var foundBundle = false; var foundBundle = false;
data.bundles ??= []; final bundles = data.bundles ??= [];
for (final bundle in data.bundles) { for (final bundle in bundles) {
if (bundle.name == name) { if (bundle.name == name) {
bundle.priority = priority; bundle.priority = priority;
foundBundle = true; foundBundle = true;
@ -75,9 +78,9 @@ extension AccountBundlesExtension on Client {
} }
} }
if (!foundBundle) { if (!foundBundle) {
data.bundles.add(AccountBundle(name: name, priority: priority)); bundles.add(AccountBundle(name: name, priority: priority));
} }
await setAccountData(userID, accountBundlesType, data.toJson()); await setAccountData(userID!, accountBundlesType, data.toJson());
} }
Future<void> removeFromAccountBundle(String name) async { Future<void> removeFromAccountBundle(String name) async {
@ -85,15 +88,15 @@ extension AccountBundlesExtension on Client {
return; // nothing to do return; // nothing to do
} }
final data = final data =
AccountBundles.fromJson(accountData[accountBundlesType].content); AccountBundles.fromJson(accountData[accountBundlesType]!.content);
if (data.bundles == null) return; if (data.bundles == null) return;
data.bundles.removeWhere((b) => b.name == name); data.bundles!.removeWhere((b) => b.name == name);
await setAccountData(userID, accountBundlesType, data.toJson()); await setAccountData(userID!, accountBundlesType, data.toJson());
} }
String get sendPrefix { String get sendPrefix {
final data = final data =
AccountBundles.fromJson(accountData[accountBundlesType]?.content ?? {}); AccountBundles.fromJson(accountData[accountBundlesType]?.content ?? {});
return data.prefix; return data.prefix!;
} }
} }

View file

@ -1,3 +1,5 @@
//@dart=2.12
extension BeautifyStringExtension on String { extension BeautifyStringExtension on String {
String get beautified { String get beautified {
var beautifiedStr = ''; var beautifiedStr = '';

View file

@ -1,3 +1,5 @@
//@dart=2.12
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';

View file

@ -1,3 +1,5 @@
//@dart=2.12
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart';
@ -61,25 +63,25 @@ extension DateTimeExtension on DateTime {
} else if (sameWeek) { } else if (sameWeek) {
switch (weekday) { switch (weekday) {
case 1: case 1:
return L10n.of(context).monday; return L10n.of(context)!.monday;
case 2: case 2:
return L10n.of(context).tuesday; return L10n.of(context)!.tuesday;
case 3: case 3:
return L10n.of(context).wednesday; return L10n.of(context)!.wednesday;
case 4: case 4:
return L10n.of(context).thursday; return L10n.of(context)!.thursday;
case 5: case 5:
return L10n.of(context).friday; return L10n.of(context)!.friday;
case 6: case 6:
return L10n.of(context).saturday; return L10n.of(context)!.saturday;
case 7: case 7:
return L10n.of(context).sunday; return L10n.of(context)!.sunday;
} }
} else if (sameYear) { } else if (sameYear) {
return L10n.of(context).dateWithoutYear( return L10n.of(context)!.dateWithoutYear(
month.toString().padLeft(2, '0'), day.toString().padLeft(2, '0')); month.toString().padLeft(2, '0'), day.toString().padLeft(2, '0'));
} }
return L10n.of(context).dateWithYear(year.toString(), return L10n.of(context)!.dateWithYear(year.toString(),
month.toString().padLeft(2, '0'), day.toString().padLeft(2, '0')); month.toString().padLeft(2, '0'), day.toString().padLeft(2, '0'));
} }
@ -94,7 +96,7 @@ extension DateTimeExtension on DateTime {
final sameDay = sameYear && now.month == month && now.day == day; final sameDay = sameYear && now.month == month && now.day == day;
if (sameDay) return localizedTimeOfDay(context); if (sameDay) return localizedTimeOfDay(context);
return L10n.of(context).dateAndTimeOfDay( return L10n.of(context)!.dateAndTimeOfDay(
localizedTimeShort(context), localizedTimeOfDay(context)); localizedTimeShort(context), localizedTimeOfDay(context));
} }

View file

@ -1,3 +1,5 @@
//@dart=2.12
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
@ -15,7 +17,7 @@ abstract class FluffyShare {
ClipboardData(text: text), ClipboardData(text: text),
); );
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(L10n.of(context).copiedToClipboard))); SnackBar(content: Text(L10n.of(context)!.copiedToClipboard)));
return; return;
} }
} }

View file

@ -1,3 +1,5 @@
//@dart=2.12
import 'dart:math'; import 'dart:math';
const _chars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz1234567890'; const _chars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz1234567890';

View file

@ -1,3 +1,5 @@
//@dart=2.12
import 'dart:io'; import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -12,9 +14,9 @@ extension LocalizedExceptionExtension on Object {
if (this is MatrixException) { if (this is MatrixException) {
switch ((this as MatrixException).error) { switch ((this as MatrixException).error) {
case MatrixError.M_FORBIDDEN: case MatrixError.M_FORBIDDEN:
return L10n.of(context).noPermission; return L10n.of(context)!.noPermission;
case MatrixError.M_LIMIT_EXCEEDED: case MatrixError.M_LIMIT_EXCEEDED:
return L10n.of(context).tooManyRequestsWarning; return L10n.of(context)!.tooManyRequestsWarning;
default: default:
return (this as MatrixException).errorMessage; return (this as MatrixException).errorMessage;
} }
@ -30,7 +32,7 @@ extension LocalizedExceptionExtension on Object {
.toString() .toString()
.replaceAll('{', '"') .replaceAll('{', '"')
.replaceAll('}', '"'); .replaceAll('}', '"');
return L10n.of(context) return L10n.of(context)!
.badServerVersionsException(serverVersions, supportedVersions); .badServerVersionsException(serverVersions, supportedVersions);
} }
if (this is BadServerLoginTypesException) { if (this is BadServerLoginTypesException) {
@ -44,15 +46,15 @@ extension LocalizedExceptionExtension on Object {
.toString() .toString()
.replaceAll('{', '"') .replaceAll('{', '"')
.replaceAll('}', '"'); .replaceAll('}', '"');
return L10n.of(context) return L10n.of(context)!
.badServerLoginTypesException(serverVersions, supportedVersions); .badServerLoginTypesException(serverVersions, supportedVersions);
} }
if (this is MatrixConnectionException || this is SocketException) { if (this is MatrixConnectionException || this is SocketException) {
return L10n.of(context).noConnectionToTheServer; return L10n.of(context)!.noConnectionToTheServer;
} }
if (this is String) return toString(); if (this is String) return toString();
if (this is UiaException) return toString(); if (this is UiaException) return toString();
Logs().w('Something went wrong: ', this); Logs().w('Something went wrong: ', this);
return L10n.of(context).oopsSomethingWentWrong; return L10n.of(context)!.oopsSomethingWentWrong;
} }
} }

View file

@ -1,3 +1,5 @@
//@dart=2.12
import 'package:matrix/matrix.dart'; import 'package:matrix/matrix.dart';
extension ClientPresenceExtension on Client { extension ClientPresenceExtension on Client {

View file

@ -1,3 +1,5 @@
//@dart=2.12
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:matrix/matrix.dart'; import 'package:matrix/matrix.dart';
@ -31,14 +33,14 @@ IconData _getIconFromName(String displayname) {
extension DeviceExtension on Device { extension DeviceExtension on Device {
String get displayname => String get displayname =>
(displayName?.isNotEmpty ?? false) ? displayName : 'Unknown device'; (displayName?.isNotEmpty ?? false) ? displayName! : 'Unknown device';
IconData get icon => _getIconFromName(displayname); IconData get icon => _getIconFromName(displayname);
} }
extension DeviceKeysExtension on DeviceKeys { extension DeviceKeysExtension on DeviceKeys {
String get displayname => (deviceDisplayName?.isNotEmpty ?? false) String get displayname => (deviceDisplayName?.isNotEmpty ?? false)
? deviceDisplayName ? deviceDisplayName!
: 'Unknown device'; : 'Unknown device';
IconData get icon => _getIconFromName(displayname); IconData get icon => _getIconFromName(displayname);

View file

@ -1,3 +1,5 @@
//@dart=2.12
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -19,10 +21,10 @@ extension LocalizedBody on Event {
bool get isAttachmentSmallEnough => bool get isAttachmentSmallEnough =>
infoMap['size'] is int && infoMap['size'] is int &&
infoMap['size'] < room.client.database.maxFileSize; infoMap['size'] < room.client.database!.maxFileSize;
bool get isThumbnailSmallEnough => bool get isThumbnailSmallEnough =>
thumbnailInfoMap['size'] is int && thumbnailInfoMap['size'] is int &&
thumbnailInfoMap['size'] < room.client.database.maxFileSize; thumbnailInfoMap['size'] < room.client.database!.maxFileSize;
bool get showThumbnail => bool get showThumbnail =>
[MessageTypes.Image, MessageTypes.Sticker, MessageTypes.Video] [MessageTypes.Image, MessageTypes.Sticker, MessageTypes.Video]
@ -32,7 +34,7 @@ extension LocalizedBody on Event {
isThumbnailSmallEnough || isThumbnailSmallEnough ||
(content['url'] is String)); (content['url'] is String));
String get sizeString { String? get sizeString {
if (content['info'] is Map<String, dynamic> && if (content['info'] is Map<String, dynamic> &&
content['info'].containsKey('size')) { content['info'].containsKey('size')) {
num size = content['info']['size']; num size = content['info']['size'];
@ -58,6 +60,7 @@ extension LocalizedBody on Event {
Future<bool> isAttachmentCached({bool getThumbnail = false}) async { Future<bool> isAttachmentCached({bool getThumbnail = false}) async {
final mxcUrl = attachmentOrThumbnailMxcUrl(getThumbnail: getThumbnail); final mxcUrl = attachmentOrThumbnailMxcUrl(getThumbnail: getThumbnail);
if (mxcUrl == null) return false;
// check if we have it in-memory // check if we have it in-memory
if (_downloadAndDecryptFutures.containsKey(mxcUrl)) { if (_downloadAndDecryptFutures.containsKey(mxcUrl)) {
return true; return true;
@ -72,7 +75,7 @@ extension LocalizedBody on Event {
return file != null; return file != null;
} }
Future<MatrixFile> downloadAndDecryptAttachmentCached( Future<MatrixFile?> downloadAndDecryptAttachmentCached(
{bool getThumbnail = false}) async { {bool getThumbnail = false}) async {
final mxcUrl = final mxcUrl =
attachmentOrThumbnailMxcUrl(getThumbnail: getThumbnail).toString(); attachmentOrThumbnailMxcUrl(getThumbnail: getThumbnail).toString();

View file

@ -1,3 +1,5 @@
//@dart=2.12
import 'package:matrix/matrix.dart'; import 'package:matrix/matrix.dart';
import '../../config/app_config.dart'; import '../../config/app_config.dart';
@ -30,13 +32,14 @@ extension FilteredTimelineExtension on Timeline {
filteredEvents[i - 1].isState && filteredEvents[i - 1].isState &&
!unfolded.contains(filteredEvents[i - 1].eventId)) { !unfolded.contains(filteredEvents[i - 1].eventId)) {
counter++; counter++;
filteredEvents[i].unsigned['im.fluffychat.collapsed_state_event'] = filteredEvents[i].unsigned ??= {};
filteredEvents[i].unsigned!['im.fluffychat.collapsed_state_event'] =
true; true;
} else { } else {
filteredEvents[i].unsigned['im.fluffychat.collapsed_state_event'] = filteredEvents[i].unsigned!['im.fluffychat.collapsed_state_event'] =
false; false;
filteredEvents[i] filteredEvents[i]
.unsigned['im.fluffychat.collapsed_state_event_count'] = counter; .unsigned!['im.fluffychat.collapsed_state_event_count'] = counter;
counter = 0; counter = 0;
} }
} }

View file

@ -1,3 +1,5 @@
//@dart=2.12
import 'dart:io'; import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -16,14 +18,14 @@ extension MatrixFileExtension on MatrixFile {
if (PlatformInfos.isMobile) { if (PlatformInfos.isMobile) {
final tmpDirectory = PlatformInfos.isAndroid final tmpDirectory = PlatformInfos.isAndroid
? (await getExternalStorageDirectories( ? (await getExternalStorageDirectories(
type: StorageDirectory.downloads)) type: StorageDirectory.downloads))!
.first .first
: await getTemporaryDirectory(); : await getTemporaryDirectory();
final path = '${tmpDirectory.path}$fileName'; final path = '${tmpDirectory.path}$fileName';
await File(path).writeAsBytes(bytes); await File(path).writeAsBytes(bytes);
await Share.shareFiles([path]); await Share.shareFiles([path]);
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(L10n.of(context).savedFileAs(path))), SnackBar(content: Text(L10n.of(context)!.savedFileAs(path))),
); );
return; return;
} else { } else {

View file

@ -1,3 +1,5 @@
//@dart=2.12
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:matrix/matrix.dart'; import 'package:matrix/matrix.dart';

View file

@ -1,3 +1,5 @@
//@dart=2.12
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart';
@ -8,25 +10,27 @@ import '../date_time_extension.dart';
extension PresenceExtension on Presence { extension PresenceExtension on Presence {
String getLocalizedLastActiveAgo(BuildContext context) { String getLocalizedLastActiveAgo(BuildContext context) {
if (presence.lastActiveAgo != null && presence.lastActiveAgo != 0) { if (presence.lastActiveAgo != null && presence.lastActiveAgo != 0) {
return L10n.of(context).lastActiveAgo(DateTime.fromMillisecondsSinceEpoch( return L10n.of(context)!.lastActiveAgo(
DateTime.now().millisecondsSinceEpoch - presence.lastActiveAgo) DateTime.fromMillisecondsSinceEpoch(
.localizedTimeShort(context)); DateTime.now().millisecondsSinceEpoch -
presence.lastActiveAgo!)
.localizedTimeShort(context));
} }
return L10n.of(context).lastSeenLongTimeAgo; return L10n.of(context)!.lastSeenLongTimeAgo;
} }
String getLocalizedStatusMessage(BuildContext context) { String getLocalizedStatusMessage(BuildContext context) {
if (presence.statusMsg?.isNotEmpty ?? false) { if (presence.statusMsg?.isNotEmpty ?? false) {
return presence.statusMsg; return presence.statusMsg!;
} }
if (presence.currentlyActive ?? false) { if (presence.currentlyActive ?? false) {
return L10n.of(context).currentlyActive; return L10n.of(context)!.currentlyActive;
} }
return getLocalizedLastActiveAgo(context); return getLocalizedLastActiveAgo(context);
} }
Color get color { Color get color {
switch (presence?.presence ?? PresenceType.offline) { switch (presence.presence) {
case PresenceType.online: case PresenceType.online:
return Colors.green; return Colors.green;
case PresenceType.offline: case PresenceType.offline:

View file

@ -1,3 +1,5 @@
//@dart=2.12
import 'dart:io'; import 'dart:io';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
@ -50,7 +52,7 @@ abstract class PlatformInfos {
Text('Version: $version'), Text('Version: $version'),
OutlinedButton( OutlinedButton(
onPressed: () => launch(AppConfig.sourceCodeUrl), onPressed: () => launch(AppConfig.sourceCodeUrl),
child: Text(L10n.of(context).sourceCode), child: Text(L10n.of(context)!.sourceCode),
), ),
OutlinedButton( OutlinedButton(
onPressed: () => launch(AppConfig.emojiFontUrl), onPressed: () => launch(AppConfig.emojiFontUrl),
@ -60,7 +62,7 @@ abstract class PlatformInfos {
onPressed: () => VRouter.of(context).to('logs'), onPressed: () => VRouter.of(context).to('logs'),
child: const Text('Logs'), child: const Text('Logs'),
), ),
SentrySwitchListTile.adaptive(label: L10n.of(context).sendBugReports), SentrySwitchListTile.adaptive(label: L10n.of(context)!.sendBugReports),
], ],
applicationIcon: Image.asset('assets/logo.png', width: 64, height: 64), applicationIcon: Image.asset('assets/logo.png', width: 64, height: 64),
applicationName: AppConfig.applicationName, applicationName: AppConfig.applicationName,

View file

@ -1,20 +1,4 @@
/* //@dart=2.12
* Famedly App
* Copyright (C) 2020 Famedly GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import 'package:matrix/matrix.dart'; import 'package:matrix/matrix.dart';
@ -23,12 +7,12 @@ import 'resize_image.dart';
extension RoomSendFileExtension on Room { extension RoomSendFileExtension on Room {
Future<Uri> sendFileEventWithThumbnail( Future<Uri> sendFileEventWithThumbnail(
MatrixFile file, { MatrixFile file, {
String txid, String? txid,
Event inReplyTo, Event? inReplyTo,
String editEventId, String? editEventId,
bool waitUntilSent, bool? waitUntilSent,
}) async { }) async {
MatrixFile thumbnail; MatrixImageFile? thumbnail;
if (file is MatrixImageFile) { if (file is MatrixImageFile) {
thumbnail = await file.resizeImage(); thumbnail = await file.resizeImage();

View file

@ -1,3 +1,5 @@
//@dart=2.12
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart';
@ -8,31 +10,32 @@ import 'date_time_extension.dart';
import 'matrix_sdk_extensions.dart/filtered_timeline_extension.dart'; import 'matrix_sdk_extensions.dart/filtered_timeline_extension.dart';
extension RoomStatusExtension on Room { extension RoomStatusExtension on Room {
Presence get directChatPresence => client.presences[directChatMatrixID]; Presence? get directChatPresence => client.presences[directChatMatrixID];
String getLocalizedStatus(BuildContext context) { String getLocalizedStatus(BuildContext context) {
if (isDirectChat) { if (isDirectChat) {
final directChatPresence = this.directChatPresence;
if (directChatPresence != null && if (directChatPresence != null &&
directChatPresence.presence != null &&
(directChatPresence.presence.lastActiveAgo != null || (directChatPresence.presence.lastActiveAgo != null ||
directChatPresence.presence.currentlyActive != null)) { directChatPresence.presence.currentlyActive != null)) {
if (directChatPresence.presence.statusMsg?.isNotEmpty ?? false) { if (directChatPresence.presence.statusMsg?.isNotEmpty ?? false) {
return directChatPresence.presence.statusMsg; return directChatPresence.presence.statusMsg!;
} }
if (directChatPresence.presence.currentlyActive == true) { if (directChatPresence.presence.currentlyActive == true) {
return L10n.of(context).currentlyActive; return L10n.of(context)!.currentlyActive;
} }
if (directChatPresence.presence.lastActiveAgo == null) { if (directChatPresence.presence.lastActiveAgo == null) {
return L10n.of(context).lastSeenLongTimeAgo; return L10n.of(context)!.lastSeenLongTimeAgo;
} }
final time = DateTime.fromMillisecondsSinceEpoch( final time = DateTime.fromMillisecondsSinceEpoch(
DateTime.now().millisecondsSinceEpoch - DateTime.now().millisecondsSinceEpoch -
directChatPresence.presence.lastActiveAgo); directChatPresence.presence.lastActiveAgo!);
return L10n.of(context).lastActiveAgo(time.localizedTimeShort(context)); return L10n.of(context)!
.lastActiveAgo(time.localizedTimeShort(context));
} }
return L10n.of(context).lastSeenLongTimeAgo; return L10n.of(context)!.lastSeenLongTimeAgo;
} }
return L10n.of(context) return L10n.of(context)!
.countParticipants(summary.mJoinedMemberCount.toString()); .countParticipants(summary.mJoinedMemberCount.toString());
} }
@ -42,23 +45,23 @@ extension RoomStatusExtension on Room {
typingUsers.removeWhere((User u) => u.id == client.userID); typingUsers.removeWhere((User u) => u.id == client.userID);
if (AppConfig.hideTypingUsernames) { if (AppConfig.hideTypingUsernames) {
typingText = L10n.of(context).isTyping; typingText = L10n.of(context)!.isTyping;
if (typingUsers.first.id != directChatMatrixID) { if (typingUsers.first.id != directChatMatrixID) {
typingText = typingText =
L10n.of(context).numUsersTyping(typingUsers.length.toString()); L10n.of(context)!.numUsersTyping(typingUsers.length.toString());
} }
} else if (typingUsers.length == 1) { } else if (typingUsers.length == 1) {
typingText = L10n.of(context).isTyping; typingText = L10n.of(context)!.isTyping;
if (typingUsers.first.id != directChatMatrixID) { if (typingUsers.first.id != directChatMatrixID) {
typingText = typingText =
L10n.of(context).userIsTyping(typingUsers.first.calcDisplayname()); L10n.of(context)!.userIsTyping(typingUsers.first.calcDisplayname());
} }
} else if (typingUsers.length == 2) { } else if (typingUsers.length == 2) {
typingText = L10n.of(context).userAndUserAreTyping( typingText = L10n.of(context)!.userAndUserAreTyping(
typingUsers.first.calcDisplayname(), typingUsers.first.calcDisplayname(),
typingUsers[1].calcDisplayname()); typingUsers[1].calcDisplayname());
} else if (typingUsers.length > 2) { } else if (typingUsers.length > 2) {
typingText = L10n.of(context).userAndOthersAreTyping( typingText = L10n.of(context)!.userAndOthersAreTyping(
typingUsers.first.calcDisplayname(), typingUsers.first.calcDisplayname(),
(typingUsers.length - 1).toString()); (typingUsers.length - 1).toString());
} }

View file

@ -1,3 +1,5 @@
//@dart=2.12
import 'dart:async'; import 'dart:async';
import 'package:isolate/isolate.dart'; import 'package:isolate/isolate.dart';

View file

@ -1,3 +1,5 @@
//@dart=2.12
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';

View file

@ -1,3 +1,5 @@
//@dart=2.12
import 'dart:async'; import 'dart:async';
extension StreamExtension on Stream { extension StreamExtension on Stream {
@ -5,11 +7,11 @@ extension StreamExtension on Stream {
/// stream, ratelimited by the Duration t /// stream, ratelimited by the Duration t
Stream<bool> rateLimit(Duration t) { Stream<bool> rateLimit(Duration t) {
final controller = StreamController<bool>(); final controller = StreamController<bool>();
Timer timer; Timer? timer;
var gotMessage = false; var gotMessage = false;
// as we call our inline-defined function recursively we need to make sure that the // as we call our inline-defined function recursively we need to make sure that the
// variable exists prior of creating the function. Silly dart. // variable exists prior of creating the function. Silly dart.
Function _onMessage; Function? _onMessage;
// callback to determine if we should send out an update // callback to determine if we should send out an update
_onMessage = () { _onMessage = () {
// do nothing if it is already closed // do nothing if it is already closed
@ -25,7 +27,7 @@ extension StreamExtension on Stream {
// method to send out an update! // method to send out an update!
timer = null; timer = null;
if (gotMessage) { if (gotMessage) {
_onMessage(); _onMessage?.call();
} }
}); });
} else { } else {
@ -33,7 +35,7 @@ extension StreamExtension on Stream {
gotMessage = true; gotMessage = true;
} }
}; };
final subscription = listen((_) => _onMessage(), final subscription = listen((_) => _onMessage?.call(),
onDone: () => controller.close(), onDone: () => controller.close(),
onError: (e, s) => controller.addError(e, s)); onError: (e, s) => controller.addError(e, s));
// add proper cleanup to the subscription and the controller, to not memory leak // add proper cleanup to the subscription and the controller, to not memory leak

View file

@ -1,3 +1,5 @@
//@dart=2.12
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
extension StringColor on String { extension StringColor on String {

View file

@ -1,4 +0,0 @@
// ignore: camel_case_types
class platformViewRegistry {
static void registerViewFactory(String _, dynamic __) {}
}

View file

@ -1,3 +1,5 @@
//@dart=2.12
import 'dart:async'; import 'dart:async';
import 'package:adaptive_dialog/adaptive_dialog.dart'; import 'package:adaptive_dialog/adaptive_dialog.dart';
@ -24,9 +26,9 @@ extension UiaRequestManager on MatrixState {
final input = cachedPassword ?? final input = cachedPassword ??
(await showTextInputDialog( (await showTextInputDialog(
context: navigatorContext, context: navigatorContext,
title: L10n.of(context).pleaseEnterYourPassword, title: L10n.of(context)!.pleaseEnterYourPassword,
okLabel: L10n.of(context).ok, okLabel: L10n.of(context)!.ok,
cancelLabel: L10n.of(context).cancel, cancelLabel: L10n.of(context)!.cancel,
textFields: [ textFields: [
const DialogTextField( const DialogTextField(
minLines: 1, minLines: 1,
@ -37,20 +39,20 @@ extension UiaRequestManager on MatrixState {
], ],
)) ))
?.single; ?.single;
if (input?.isEmpty ?? true) { if (input == null || input.isEmpty) {
return uiaRequest.cancel(); return uiaRequest.cancel();
} }
return uiaRequest.completeStage( return uiaRequest.completeStage(
AuthenticationPassword( AuthenticationPassword(
session: uiaRequest.session, session: uiaRequest.session,
password: input, password: input,
identifier: AuthenticationUserIdentifier(user: client.userID), identifier: AuthenticationUserIdentifier(user: client.userID!),
), ),
); );
case AuthenticationTypes.emailIdentity: case AuthenticationTypes.emailIdentity:
if (currentThreepidCreds == null || currentClientSecret == null) { if (currentThreepidCreds == null || currentClientSecret == null) {
return uiaRequest.cancel( return uiaRequest.cancel(
UiaException(L10n.of(widget.context).serverRequiresEmail), UiaException(L10n.of(widget.context)!.serverRequiresEmail),
); );
} }
final auth = AuthenticationThreePidCreds( final auth = AuthenticationThreePidCreds(
@ -65,10 +67,10 @@ extension UiaRequestManager on MatrixState {
await showOkCancelAlertDialog( await showOkCancelAlertDialog(
useRootNavigator: false, useRootNavigator: false,
context: navigatorContext, context: navigatorContext,
title: L10n.of(context).weSentYouAnEmail, title: L10n.of(context)!.weSentYouAnEmail,
message: L10n.of(context).pleaseClickOnLink, message: L10n.of(context)!.pleaseClickOnLink,
okLabel: L10n.of(context).iHaveClickedOnLink, okLabel: L10n.of(context)!.iHaveClickedOnLink,
cancelLabel: L10n.of(context).cancel, cancelLabel: L10n.of(context)!.cancel,
)) { )) {
return uiaRequest.completeStage(auth); return uiaRequest.completeStage(auth);
} }
@ -90,7 +92,7 @@ extension UiaRequestManager on MatrixState {
action: (_, __) { action: (_, __) {
uiaRequest.cancel(); uiaRequest.cancel();
}, },
label: L10n.of(context).cancel, label: L10n.of(context)!.cancel,
id: 0, id: 0,
), ),
); );
@ -101,10 +103,10 @@ extension UiaRequestManager on MatrixState {
if (OkCancelResult.ok == if (OkCancelResult.ok ==
await showOkCancelAlertDialog( await showOkCancelAlertDialog(
useRootNavigator: false, useRootNavigator: false,
message: L10n.of(context).pleaseFollowInstructionsOnWeb, message: L10n.of(context)!.pleaseFollowInstructionsOnWeb,
context: navigatorContext, context: navigatorContext,
okLabel: L10n.of(context).next, okLabel: L10n.of(context)!.next,
cancelLabel: L10n.of(context).cancel, cancelLabel: L10n.of(context)!.cancel,
)) { )) {
return uiaRequest.completeStage( return uiaRequest.completeStage(
AuthenticationData(session: uiaRequest.session), AuthenticationData(session: uiaRequest.session),