Merge branch 'krille/null-safety' into 'main'

Null safety

See merge request famedly/fluffychat!550
This commit is contained in:
Krille Fear 2021-11-20 07:57:47 +00:00
commit 74e92f8474
11 changed files with 90 additions and 65 deletions

View File

@ -1,3 +1,5 @@
//@dart=2.12
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -5,12 +7,12 @@ import 'package:fluffychat/utils/platform_infos.dart';
class AdaptiveFlatButton extends StatelessWidget { class AdaptiveFlatButton extends StatelessWidget {
final String label; final String label;
final Color textColor; final Color? textColor;
final Function onPressed; final void Function()? onPressed;
const AdaptiveFlatButton({ const AdaptiveFlatButton({
Key key, Key? key,
@required this.label, required this.label,
this.textColor, this.textColor,
this.onPressed, this.onPressed,
}) : super(key: key); }) : super(key: key);

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';
@ -8,12 +10,12 @@ import 'package:fluffychat/utils/string_color.dart';
import 'matrix.dart'; import 'matrix.dart';
class Avatar extends StatelessWidget { class Avatar extends StatelessWidget {
final Uri mxContent; final Uri? mxContent;
final String name; final String? name;
final double size; final double size;
final Function onTap; final void Function()? onTap;
static const double defaultSize = 44; static const double defaultSize = 44;
final Client client; final Client? client;
final double fontSize; final double fontSize;
const Avatar( const Avatar(
@ -23,7 +25,7 @@ class Avatar extends StatelessWidget {
this.onTap, this.onTap,
this.client, this.client,
this.fontSize = 18, this.fontSize = 18,
Key key, Key? key,
}) : super(key: key); }) : super(key: key);
@override @override
@ -34,10 +36,13 @@ class Avatar extends StatelessWidget {
height: size * MediaQuery.of(context).devicePixelRatio, height: size * MediaQuery.of(context).devicePixelRatio,
); );
var fallbackLetters = '@'; var fallbackLetters = '@';
if ((name?.runes?.length ?? 0) >= 2) { final name = this.name;
fallbackLetters = String.fromCharCodes(name.runes, 0, 2); if (name != null) {
} else if ((name?.runes?.length ?? 0) == 1) { if (name.runes.length >= 2) {
fallbackLetters = name; fallbackLetters = String.fromCharCodes(name.runes, 0, 2);
} else if (name.runes.length == 1) {
fallbackLetters = name;
}
} }
final noPic = mxContent == null || final noPic = mxContent == null ||
mxContent.toString().isEmpty || mxContent.toString().isEmpty ||

View File

@ -1,3 +1,5 @@
//@dart=2.12
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -13,7 +15,7 @@ import 'matrix.dart';
class ChatSettingsPopupMenu extends StatefulWidget { class ChatSettingsPopupMenu extends StatefulWidget {
final Room room; final Room room;
final bool displayChatDetails; final bool displayChatDetails;
const ChatSettingsPopupMenu(this.room, this.displayChatDetails, {Key key}) const ChatSettingsPopupMenu(this.room, this.displayChatDetails, {Key? key})
: super(key: key); : super(key: key);
@override @override
@ -21,7 +23,7 @@ class ChatSettingsPopupMenu extends StatefulWidget {
} }
class _ChatSettingsPopupMenuState extends State<ChatSettingsPopupMenu> { class _ChatSettingsPopupMenuState extends State<ChatSettingsPopupMenu> {
StreamSubscription notificationChangeSub; StreamSubscription? notificationChangeSub;
@override @override
void dispose() { void dispose() {
@ -37,7 +39,7 @@ class _ChatSettingsPopupMenuState extends State<ChatSettingsPopupMenu> {
.stream .stream
.where((u) => u.type == 'm.push_rules') .where((u) => u.type == 'm.push_rules')
.listen( .listen(
(u) => setState(() => null), (u) => setState(() {}),
); );
final items = <PopupMenuEntry<String>>[ final items = <PopupMenuEntry<String>>[
widget.room.pushRuleState == PushRuleState.notify widget.room.pushRuleState == PushRuleState.notify
@ -47,7 +49,7 @@ class _ChatSettingsPopupMenuState extends State<ChatSettingsPopupMenu> {
children: [ children: [
const Icon(Icons.notifications_off_outlined), const Icon(Icons.notifications_off_outlined),
const SizedBox(width: 12), const SizedBox(width: 12),
Text(L10n.of(context).muteChat), Text(L10n.of(context)!.muteChat),
], ],
), ),
) )
@ -57,7 +59,7 @@ class _ChatSettingsPopupMenuState extends State<ChatSettingsPopupMenu> {
children: [ children: [
const Icon(Icons.notifications_on_outlined), const Icon(Icons.notifications_on_outlined),
const SizedBox(width: 12), const SizedBox(width: 12),
Text(L10n.of(context).unmuteChat), Text(L10n.of(context)!.unmuteChat),
], ],
), ),
), ),
@ -67,7 +69,7 @@ class _ChatSettingsPopupMenuState extends State<ChatSettingsPopupMenu> {
children: [ children: [
const Icon(Icons.delete_outlined), const Icon(Icons.delete_outlined),
const SizedBox(width: 12), const SizedBox(width: 12),
Text(L10n.of(context).leave), Text(L10n.of(context)!.leave),
], ],
), ),
), ),
@ -81,7 +83,7 @@ class _ChatSettingsPopupMenuState extends State<ChatSettingsPopupMenu> {
children: [ children: [
const Icon(Icons.info_outline_rounded), const Icon(Icons.info_outline_rounded),
const SizedBox(width: 12), const SizedBox(width: 12),
Text(L10n.of(context).chatDetails), Text(L10n.of(context)!.chatDetails),
], ],
), ),
), ),
@ -94,9 +96,9 @@ class _ChatSettingsPopupMenuState extends State<ChatSettingsPopupMenu> {
final confirmed = await showOkCancelAlertDialog( final confirmed = await showOkCancelAlertDialog(
useRootNavigator: false, useRootNavigator: false,
context: context, context: context,
title: L10n.of(context).areYouSure, title: L10n.of(context)!.areYouSure,
okLabel: L10n.of(context).ok, okLabel: L10n.of(context)!.ok,
cancelLabel: L10n.of(context).cancel, cancelLabel: L10n.of(context)!.cancel,
); );
if (confirmed == OkCancelResult.ok) { if (confirmed == OkCancelResult.ok) {
final success = await showFutureLoadingDialog( final success = await showFutureLoadingDialog(

View File

@ -1,3 +1,5 @@
//@dart=2.12
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -9,15 +11,15 @@ import '../utils/localized_exception_extension.dart';
import 'matrix.dart'; import 'matrix.dart';
class ConnectionStatusHeader extends StatefulWidget { class ConnectionStatusHeader extends StatefulWidget {
const ConnectionStatusHeader({Key key}) : super(key: key); const ConnectionStatusHeader({Key? key}) : super(key: key);
@override @override
_ConnectionStatusHeaderState createState() => _ConnectionStatusHeaderState(); _ConnectionStatusHeaderState createState() => _ConnectionStatusHeaderState();
} }
class _ConnectionStatusHeaderState extends State<ConnectionStatusHeader> { class _ConnectionStatusHeaderState extends State<ConnectionStatusHeader> {
StreamSubscription _onSyncSub; StreamSubscription? _onSyncSub;
StreamSubscription _onSyncErrorSub; StreamSubscription? _onSyncErrorSub;
bool get _connected => bool get _connected =>
DateTime.now().millisecondsSinceEpoch - DateTime.now().millisecondsSinceEpoch -
_lastSyncReceived.millisecondsSinceEpoch < _lastSyncReceived.millisecondsSinceEpoch <
@ -82,14 +84,15 @@ extension on SyncStatusUpdate {
String toLocalizedString(BuildContext context) { String toLocalizedString(BuildContext context) {
switch (status) { switch (status) {
case SyncStatus.waitingForResponse: case SyncStatus.waitingForResponse:
return L10n.of(context).loadingPleaseWait; return L10n.of(context)!.loadingPleaseWait;
case SyncStatus.error: case SyncStatus.error:
return (error.exception as Object).toLocalizedString(context); return ((error?.exception ?? Object()) as Object)
.toLocalizedString(context);
case SyncStatus.processing: case SyncStatus.processing:
case SyncStatus.cleaningUp: case SyncStatus.cleaningUp:
case SyncStatus.finished: case SyncStatus.finished:
default: default:
return L10n.of(context).synchronizingPleaseWait; return L10n.of(context)!.synchronizingPleaseWait;
} }
} }
} }

View File

@ -1,3 +1,5 @@
//@dart=2.12
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -14,15 +16,15 @@ class ContactsList extends StatefulWidget {
final TextEditingController searchController; final TextEditingController searchController;
const ContactsList({ const ContactsList({
Key key, Key? key,
@required this.searchController, required this.searchController,
}) : super(key: key); }) : super(key: key);
@override @override
_ContactsState createState() => _ContactsState(); _ContactsState createState() => _ContactsState();
} }
class _ContactsState extends State<ContactsList> { class _ContactsState extends State<ContactsList> {
StreamSubscription _onSync; StreamSubscription? _onSync;
@override @override
void dispose() { void dispose() {
@ -31,11 +33,11 @@ class _ContactsState extends State<ContactsList> {
} }
DateTime _lastSetState = DateTime.now(); DateTime _lastSetState = DateTime.now();
Timer _coolDown; Timer? _coolDown;
void _updateView() { void _updateView() {
_lastSetState = DateTime.now(); _lastSetState = DateTime.now();
setState(() => null); setState(() {});
} }
@override @override
@ -68,15 +70,16 @@ class _ContactsState extends State<ContactsList> {
class _ContactListTile extends StatelessWidget { class _ContactListTile extends StatelessWidget {
final Presence contact; final Presence contact;
const _ContactListTile({Key key, @required this.contact}) : super(key: key); const _ContactListTile({Key? key, required this.contact}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return FutureBuilder<Profile>( return FutureBuilder<Profile>(
future: future:
Matrix.of(context).client.getProfileFromUserId(contact.senderId), Matrix.of(context).client.getProfileFromUserId(contact.senderId),
builder: (context, snapshot) { builder: (context, snapshot) {
final displayname = final displayname = snapshot.data?.displayName ??
snapshot.data?.displayName ?? contact.senderId.localpart; contact.senderId.localpart ??
'No valid MXID';
final avatarUrl = snapshot.data?.avatarUrl; final avatarUrl = snapshot.data?.avatarUrl;
return ListTile( return ListTile(
leading: SizedBox( leading: SizedBox(
@ -108,7 +111,7 @@ class _ContactListTile extends StatelessWidget {
'rooms', 'rooms',
Matrix.of(context) Matrix.of(context)
.client .client
.getDirectChatFromUserId(contact.senderId) .getDirectChatFromUserId(contact.senderId)!
]), ]),
); );
}); });

View File

@ -1,3 +1,5 @@
//@dart=2.12
import 'dart:math'; import 'dart:math';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -5,7 +7,7 @@ import 'package:flutter/material.dart';
class EmptyPage extends StatelessWidget { class EmptyPage extends StatelessWidget {
final bool loading; final bool loading;
static const double _width = 200; static const double _width = 200;
const EmptyPage({this.loading = false, Key key}) : super(key: key); const EmptyPage({this.loading = false, Key? key}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final _width = min(MediaQuery.of(context).size.width, EmptyPage._width); final _width = min(MediaQuery.of(context).size.width, EmptyPage._width);

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';
@ -7,26 +9,21 @@ import 'package:fluffychat/widgets/layouts/empty_page.dart';
import 'package:fluffychat/widgets/matrix.dart'; import 'package:fluffychat/widgets/matrix.dart';
class LoadingView extends StatelessWidget { class LoadingView extends StatelessWidget {
const LoadingView({Key key}) : super(key: key); const LoadingView({Key? key}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
if (Matrix.of(context) WidgetsBinding.instance?.addPostFrameCallback(
.widget (_) => VRouter.of(context).to(
.clients Matrix.of(context)
.every((client) => client.loginState != null)) { .widget
WidgetsBinding.instance.addPostFrameCallback( .clients
(_) => VRouter.of(context).to( .any((client) => client.loginState == LoginState.loggedIn)
Matrix.of(context) ? '/rooms'
.widget : '/home',
.clients queryParameters: VRouter.of(context).queryParameters,
.any((client) => client.loginState == LoginState.loggedIn) ),
? '/rooms' );
: '/home',
queryParameters: VRouter.of(context).queryParameters,
),
);
}
return const EmptyPage(loading: true); return const EmptyPage(loading: true);
} }
} }

View File

@ -1,9 +1,11 @@
//@dart=2.12
import 'dart:math'; import 'dart:math';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class MaxWidthBody extends StatelessWidget { class MaxWidthBody extends StatelessWidget {
final Widget child; final Widget? child;
final double maxWidth; final double maxWidth;
final bool withScrolling; final bool withScrolling;
@ -11,7 +13,7 @@ class MaxWidthBody extends StatelessWidget {
this.child, this.child,
this.maxWidth = 600, this.maxWidth = 600,
this.withScrolling = false, this.withScrolling = false,
Key key, Key? key,
}) : super(key: key); }) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

View File

@ -1,3 +1,5 @@
//@dart=2.12
import 'dart:math'; import 'dart:math';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -8,14 +10,14 @@ import 'package:fluffychat/widgets/matrix.dart';
class OnePageCard extends StatelessWidget { class OnePageCard extends StatelessWidget {
final Widget child; final Widget child;
const OnePageCard({Key key, this.child}) : super(key: key); const OnePageCard({Key? key, required this.child}) : super(key: key);
static const int alpha = 12; static const int alpha = 12;
static num breakpoint = FluffyThemes.columnWidth * 2; static num breakpoint = FluffyThemes.columnWidth * 2;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final horizontalPadding = final horizontalPadding =
max((MediaQuery.of(context).size.width - 600) / 2, 24); max<double>((MediaQuery.of(context).size.width - 600) / 2, 24);
return MediaQuery.of(context).size.width <= breakpoint || return MediaQuery.of(context).size.width <= breakpoint ||
Matrix.of(context).client.isLogged() Matrix.of(context).client.isLogged()
? child ? child

View File

@ -1,3 +1,5 @@
//@dart=2.12
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:vrouter/vrouter.dart'; import 'package:vrouter/vrouter.dart';
@ -6,15 +8,16 @@ import 'package:fluffychat/config/themes.dart';
class SideViewLayout extends StatelessWidget { class SideViewLayout extends StatelessWidget {
final Widget mainView; final Widget mainView;
final Widget sideView; final Widget? sideView;
const SideViewLayout({Key key, @required this.mainView, this.sideView}) const SideViewLayout({Key? key, required this.mainView, this.sideView})
: super(key: key); : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var currentUrl = Uri.decodeFull(VRouter.of(context).url); var currentUrl = Uri.decodeFull(VRouter.of(context).url);
if (!currentUrl.endsWith('/')) currentUrl += '/'; if (!currentUrl.endsWith('/')) currentUrl += '/';
final hideSideView = currentUrl.split('/').length == 4; final hideSideView = currentUrl.split('/').length == 4;
final sideView = this.sideView;
return sideView == null return sideView == null
? mainView ? mainView
: MediaQuery.of(context).size.width < FluffyThemes.columnWidth * 3.5 && : MediaQuery.of(context).size.width < FluffyThemes.columnWidth * 3.5 &&

View File

@ -1,3 +1,5 @@
//@dart=2.12
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:fluffychat/config/themes.dart'; import 'package:fluffychat/config/themes.dart';
@ -6,9 +8,11 @@ class TwoColumnLayout extends StatelessWidget {
final Widget mainView; final Widget mainView;
final Widget sideView; final Widget sideView;
const TwoColumnLayout( const TwoColumnLayout({
{Key key, @required this.mainView, @required this.sideView}) Key? key,
: super(key: key); required this.mainView,
required this.sideView,
}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
if (MediaQuery.of(context).size.width <= FluffyThemes.columnWidth * 2) { if (MediaQuery.of(context).size.width <= FluffyThemes.columnWidth * 2) {