refactor: Make most of the utils null safe

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,3 +1,5 @@
//@dart=2.12
import 'dart:io';
import 'package:flutter/material.dart';
@ -12,9 +14,9 @@ extension LocalizedExceptionExtension on Object {
if (this is MatrixException) {
switch ((this as MatrixException).error) {
case MatrixError.M_FORBIDDEN:
return L10n.of(context).noPermission;
return L10n.of(context)!.noPermission;
case MatrixError.M_LIMIT_EXCEEDED:
return L10n.of(context).tooManyRequestsWarning;
return L10n.of(context)!.tooManyRequestsWarning;
default:
return (this as MatrixException).errorMessage;
}
@ -30,7 +32,7 @@ extension LocalizedExceptionExtension on Object {
.toString()
.replaceAll('{', '"')
.replaceAll('}', '"');
return L10n.of(context)
return L10n.of(context)!
.badServerVersionsException(serverVersions, supportedVersions);
}
if (this is BadServerLoginTypesException) {
@ -44,15 +46,15 @@ extension LocalizedExceptionExtension on Object {
.toString()
.replaceAll('{', '"')
.replaceAll('}', '"');
return L10n.of(context)
return L10n.of(context)!
.badServerLoginTypesException(serverVersions, supportedVersions);
}
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 UiaException) return toString();
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';
extension ClientPresenceExtension on Client {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,3 +1,5 @@
//@dart=2.12
import 'dart:io';
import 'package:flutter/foundation.dart';
@ -50,7 +52,7 @@ abstract class PlatformInfos {
Text('Version: $version'),
OutlinedButton(
onPressed: () => launch(AppConfig.sourceCodeUrl),
child: Text(L10n.of(context).sourceCode),
child: Text(L10n.of(context)!.sourceCode),
),
OutlinedButton(
onPressed: () => launch(AppConfig.emojiFontUrl),
@ -60,7 +62,7 @@ abstract class PlatformInfos {
onPressed: () => VRouter.of(context).to('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),
applicationName: AppConfig.applicationName,

View File

@ -1,20 +1,4 @@
/*
* 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/>.
*/
//@dart=2.12
import 'package:matrix/matrix.dart';
@ -23,12 +7,12 @@ import 'resize_image.dart';
extension RoomSendFileExtension on Room {
Future<Uri> sendFileEventWithThumbnail(
MatrixFile file, {
String txid,
Event inReplyTo,
String editEventId,
bool waitUntilSent,
String? txid,
Event? inReplyTo,
String? editEventId,
bool? waitUntilSent,
}) async {
MatrixFile thumbnail;
MatrixImageFile? thumbnail;
if (file is MatrixImageFile) {
thumbnail = await file.resizeImage();

View File

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

View File

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

View File

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

View File

@ -1,3 +1,5 @@
//@dart=2.12
import 'dart:async';
extension StreamExtension on Stream {
@ -5,11 +7,11 @@ extension StreamExtension on Stream {
/// stream, ratelimited by the Duration t
Stream<bool> rateLimit(Duration t) {
final controller = StreamController<bool>();
Timer timer;
Timer? timer;
var gotMessage = false;
// as we call our inline-defined function recursively we need to make sure that the
// variable exists prior of creating the function. Silly dart.
Function _onMessage;
Function? _onMessage;
// callback to determine if we should send out an update
_onMessage = () {
// do nothing if it is already closed
@ -25,7 +27,7 @@ extension StreamExtension on Stream {
// method to send out an update!
timer = null;
if (gotMessage) {
_onMessage();
_onMessage?.call();
}
});
} else {
@ -33,7 +35,7 @@ extension StreamExtension on Stream {
gotMessage = true;
}
};
final subscription = listen((_) => _onMessage(),
final subscription = listen((_) => _onMessage?.call(),
onDone: () => controller.close(),
onError: (e, s) => controller.addError(e, s));
// 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';
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 'package:adaptive_dialog/adaptive_dialog.dart';
@ -24,9 +26,9 @@ extension UiaRequestManager on MatrixState {
final input = cachedPassword ??
(await showTextInputDialog(
context: navigatorContext,
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(
minLines: 1,
@ -37,20 +39,20 @@ extension UiaRequestManager on MatrixState {
],
))
?.single;
if (input?.isEmpty ?? true) {
if (input == null || input.isEmpty) {
return uiaRequest.cancel();
}
return uiaRequest.completeStage(
AuthenticationPassword(
session: uiaRequest.session,
password: input,
identifier: AuthenticationUserIdentifier(user: client.userID),
identifier: AuthenticationUserIdentifier(user: client.userID!),
),
);
case AuthenticationTypes.emailIdentity:
if (currentThreepidCreds == null || currentClientSecret == null) {
return uiaRequest.cancel(
UiaException(L10n.of(widget.context).serverRequiresEmail),
UiaException(L10n.of(widget.context)!.serverRequiresEmail),
);
}
final auth = AuthenticationThreePidCreds(
@ -65,10 +67,10 @@ extension UiaRequestManager on MatrixState {
await showOkCancelAlertDialog(
useRootNavigator: false,
context: navigatorContext,
title: L10n.of(context).weSentYouAnEmail,
message: L10n.of(context).pleaseClickOnLink,
okLabel: L10n.of(context).iHaveClickedOnLink,
cancelLabel: L10n.of(context).cancel,
title: L10n.of(context)!.weSentYouAnEmail,
message: L10n.of(context)!.pleaseClickOnLink,
okLabel: L10n.of(context)!.iHaveClickedOnLink,
cancelLabel: L10n.of(context)!.cancel,
)) {
return uiaRequest.completeStage(auth);
}
@ -90,7 +92,7 @@ extension UiaRequestManager on MatrixState {
action: (_, __) {
uiaRequest.cancel();
},
label: L10n.of(context).cancel,
label: L10n.of(context)!.cancel,
id: 0,
),
);
@ -101,10 +103,10 @@ extension UiaRequestManager on MatrixState {
if (OkCancelResult.ok ==
await showOkCancelAlertDialog(
useRootNavigator: false,
message: L10n.of(context).pleaseFollowInstructionsOnWeb,
message: L10n.of(context)!.pleaseFollowInstructionsOnWeb,
context: navigatorContext,
okLabel: L10n.of(context).next,
cancelLabel: L10n.of(context).cancel,
okLabel: L10n.of(context)!.next,
cancelLabel: L10n.of(context)!.cancel,
)) {
return uiaRequest.completeStage(
AuthenticationData(session: uiaRequest.session),