mirror of
https://gitlab.com/famedly/fluffychat.git
synced 2025-01-26 03:54:15 +01:00
Merge branch 'krille/null-safe-widgets' into 'main'
refactor: Make widgets null safe See merge request famedly/fluffychat!698
This commit is contained in:
commit
e4ca34ddcc
@ -10,6 +10,7 @@ import 'package:flutter_gen/gen_l10n/l10n.dart';
|
|||||||
import 'package:matrix/matrix.dart';
|
import 'package:matrix/matrix.dart';
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
|
||||||
|
import 'package:fluffychat/utils/localized_exception_extension.dart';
|
||||||
import 'package:fluffychat/utils/sentry_controller.dart';
|
import 'package:fluffychat/utils/sentry_controller.dart';
|
||||||
import '../../../utils/matrix_sdk_extensions.dart/event_extension.dart';
|
import '../../../utils/matrix_sdk_extensions.dart/event_extension.dart';
|
||||||
|
|
||||||
@ -66,7 +67,7 @@ class _AudioPlayerState extends State<AudioPlayerWidget> {
|
|||||||
await widget.event.downloadAndDecryptAttachmentCached();
|
await widget.event.downloadAndDecryptAttachmentCached();
|
||||||
if (matrixFile == null) throw ('Download failed');
|
if (matrixFile == null) throw ('Download failed');
|
||||||
final tempDir = await getTemporaryDirectory();
|
final tempDir = await getTemporaryDirectory();
|
||||||
final fileName = widget.event.content.tryGet<String>('url')!;
|
final fileName = widget.event.attachmentOrThumbnailMxcUrl()!.toString();
|
||||||
final file = File('${tempDir.path}/$fileName');
|
final file = File('${tempDir.path}/$fileName');
|
||||||
await file.writeAsBytes(matrixFile.bytes);
|
await file.writeAsBytes(matrixFile.bytes);
|
||||||
|
|
||||||
@ -79,7 +80,7 @@ class _AudioPlayerState extends State<AudioPlayerWidget> {
|
|||||||
Logs().v('Could not download audio file', e, s);
|
Logs().v('Could not download audio file', e, s);
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(
|
SnackBar(
|
||||||
content: Text(e.toString()),
|
content: Text(e.toLocalizedString(context)),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ class _EventVideoPlayerState extends State<EventVideoPlayer> {
|
|||||||
_networkUri = html.Url.createObjectUrlFromBlob(blob);
|
_networkUri = html.Url.createObjectUrlFromBlob(blob);
|
||||||
} else {
|
} else {
|
||||||
final tempDir = await getTemporaryDirectory();
|
final tempDir = await getTemporaryDirectory();
|
||||||
final fileName = widget.event.content.tryGet<String>('url')!;
|
final fileName = widget.event.attachmentOrThumbnailMxcUrl()!.toString();
|
||||||
final file = File('${tempDir.path}/$fileName');
|
final file = File('${tempDir.path}/$fileName');
|
||||||
if (await file.exists() == false) {
|
if (await file.exists() == false) {
|
||||||
await file.writeAsBytes(videoFile.bytes);
|
await file.writeAsBytes(videoFile.bytes);
|
||||||
|
@ -45,7 +45,7 @@ class SearchController extends State<Search> {
|
|||||||
showModalBottomSheet(
|
showModalBottomSheet(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (c) => PublicRoomBottomSheet(
|
builder: (c) => PublicRoomBottomSheet(
|
||||||
roomAlias: room.canonicalAlias,
|
roomAlias: room.canonicalAlias ?? room.roomId,
|
||||||
outerContext: context,
|
outerContext: context,
|
||||||
chunk: room,
|
chunk: room,
|
||||||
),
|
),
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
//@dart=2.12
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
@ -10,8 +12,8 @@ class ContentBanner extends StatelessWidget {
|
|||||||
final double height;
|
final double height;
|
||||||
final IconData defaultIcon;
|
final IconData defaultIcon;
|
||||||
final bool loading;
|
final bool loading;
|
||||||
final Function onEdit;
|
final void Function()? onEdit;
|
||||||
final Client client;
|
final Client? client;
|
||||||
final double opacity;
|
final double opacity;
|
||||||
|
|
||||||
const ContentBanner(this.mxContent,
|
const ContentBanner(this.mxContent,
|
||||||
@ -21,7 +23,7 @@ class ContentBanner extends StatelessWidget {
|
|||||||
this.onEdit,
|
this.onEdit,
|
||||||
this.client,
|
this.client,
|
||||||
this.opacity = 0.75,
|
this.opacity = 0.75,
|
||||||
Key key})
|
Key? key})
|
||||||
: super(key: key);
|
: super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -29,7 +31,8 @@ class ContentBanner extends StatelessWidget {
|
|||||||
final mediaQuery = MediaQuery.of(context);
|
final mediaQuery = MediaQuery.of(context);
|
||||||
final bannerSize =
|
final bannerSize =
|
||||||
(mediaQuery.size.width * mediaQuery.devicePixelRatio).toInt();
|
(mediaQuery.size.width * mediaQuery.devicePixelRatio).toInt();
|
||||||
final src = mxContent?.getThumbnail(
|
final onEdit = this.onEdit;
|
||||||
|
final src = mxContent.getThumbnail(
|
||||||
client ?? Matrix.of(context).client,
|
client ?? Matrix.of(context).client,
|
||||||
width: bannerSize,
|
width: bannerSize,
|
||||||
height: bannerSize,
|
height: bannerSize,
|
||||||
@ -51,14 +54,13 @@ class ContentBanner extends StatelessWidget {
|
|||||||
bottom: 0,
|
bottom: 0,
|
||||||
child: Opacity(
|
child: Opacity(
|
||||||
opacity: opacity,
|
opacity: opacity,
|
||||||
child:
|
child: (!loading && mxContent.host.isNotEmpty)
|
||||||
(!loading && mxContent != null && mxContent.host.isNotEmpty)
|
? CachedNetworkImage(
|
||||||
? CachedNetworkImage(
|
imageUrl: src.toString(),
|
||||||
imageUrl: src.toString(),
|
height: 300,
|
||||||
height: 300,
|
fit: BoxFit.cover,
|
||||||
fit: BoxFit.cover,
|
)
|
||||||
)
|
: Icon(defaultIcon, size: 200),
|
||||||
: Icon(defaultIcon, size: 200),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (onEdit != null)
|
if (onEdit != null)
|
||||||
@ -69,7 +71,7 @@ class ContentBanner extends StatelessWidget {
|
|||||||
mini: true,
|
mini: true,
|
||||||
onPressed: onEdit,
|
onPressed: onEdit,
|
||||||
backgroundColor: Theme.of(context).backgroundColor,
|
backgroundColor: Theme.of(context).backgroundColor,
|
||||||
foregroundColor: Theme.of(context).textTheme.bodyText1.color,
|
foregroundColor: Theme.of(context).textTheme.bodyText1?.color,
|
||||||
child: const Icon(Icons.camera_alt_outlined),
|
child: const Icon(Icons.camera_alt_outlined),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -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';
|
||||||
@ -5,22 +7,22 @@ import 'package:flutter_gen/gen_l10n/l10n.dart';
|
|||||||
import '../config/app_config.dart';
|
import '../config/app_config.dart';
|
||||||
|
|
||||||
class DefaultAppBarSearchField extends StatefulWidget {
|
class DefaultAppBarSearchField extends StatefulWidget {
|
||||||
final TextEditingController searchController;
|
final TextEditingController? searchController;
|
||||||
final void Function(String) onChanged;
|
final void Function(String)? onChanged;
|
||||||
final void Function(String) onSubmit;
|
final void Function(String)? onSubmit;
|
||||||
final Widget suffix;
|
final Widget? suffix;
|
||||||
final bool autofocus;
|
final bool autofocus;
|
||||||
final String prefixText;
|
final String? prefixText;
|
||||||
final String hintText;
|
final String? hintText;
|
||||||
final String labelText;
|
final String? labelText;
|
||||||
final EdgeInsets padding;
|
final EdgeInsets? padding;
|
||||||
final bool readOnly;
|
final bool readOnly;
|
||||||
final Widget prefixIcon;
|
final Widget? prefixIcon;
|
||||||
final bool unfocusOnClear;
|
final bool unfocusOnClear;
|
||||||
final bool autocorrect;
|
final bool autocorrect;
|
||||||
|
|
||||||
const DefaultAppBarSearchField({
|
const DefaultAppBarSearchField({
|
||||||
Key key,
|
Key? key,
|
||||||
this.searchController,
|
this.searchController,
|
||||||
this.onChanged,
|
this.onChanged,
|
||||||
this.onSubmit,
|
this.onSubmit,
|
||||||
@ -42,14 +44,14 @@ class DefaultAppBarSearchField extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class DefaultAppBarSearchFieldState extends State<DefaultAppBarSearchField> {
|
class DefaultAppBarSearchFieldState extends State<DefaultAppBarSearchField> {
|
||||||
TextEditingController _searchController;
|
late final TextEditingController _searchController;
|
||||||
bool _lastTextWasEmpty = false;
|
bool _lastTextWasEmpty = false;
|
||||||
final FocusNode _focusNode = FocusNode();
|
final FocusNode _focusNode = FocusNode();
|
||||||
|
|
||||||
void requestFocus() => _focusNode.requestFocus();
|
void requestFocus() => _focusNode.requestFocus();
|
||||||
|
|
||||||
void _updateSearchController() {
|
void _updateSearchController() {
|
||||||
final thisTextIsEmpty = _searchController.text?.isEmpty ?? false;
|
final thisTextIsEmpty = _searchController.text.isEmpty;
|
||||||
if (_lastTextWasEmpty != thisTextIsEmpty) {
|
if (_lastTextWasEmpty != thisTextIsEmpty) {
|
||||||
setState(() => _lastTextWasEmpty = thisTextIsEmpty);
|
setState(() => _lastTextWasEmpty = thisTextIsEmpty);
|
||||||
}
|
}
|
||||||
@ -61,7 +63,7 @@ class DefaultAppBarSearchFieldState extends State<DefaultAppBarSearchField> {
|
|||||||
_searchController = widget.searchController ?? TextEditingController();
|
_searchController = widget.searchController ?? TextEditingController();
|
||||||
// we need to remove the listener in the dispose method, so we need a reference to the callback
|
// we need to remove the listener in the dispose method, so we need a reference to the callback
|
||||||
_searchController.addListener(_updateSearchController);
|
_searchController.addListener(_updateSearchController);
|
||||||
_focusNode.addListener(() => setState(() => null));
|
_focusNode.addListener(() => setState(() {}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -108,9 +110,9 @@ class DefaultAppBarSearchFieldState extends State<DefaultAppBarSearchField> {
|
|||||||
suffixIcon: !widget.readOnly &&
|
suffixIcon: !widget.readOnly &&
|
||||||
(_focusNode.hasFocus ||
|
(_focusNode.hasFocus ||
|
||||||
(widget.suffix == null &&
|
(widget.suffix == null &&
|
||||||
(_searchController.text?.isNotEmpty ?? false)))
|
(_searchController.text.isNotEmpty)))
|
||||||
? IconButton(
|
? IconButton(
|
||||||
tooltip: L10n.of(context).clearText,
|
tooltip: L10n.of(context)!.clearText,
|
||||||
icon: const Icon(Icons.backspace_outlined),
|
icon: const Icon(Icons.backspace_outlined),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
_searchController.clear();
|
_searchController.clear();
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
//@dart=2.12
|
||||||
|
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
@ -18,14 +20,18 @@ extension LocalNotificationsExtension on MatrixState {
|
|||||||
final roomId = eventUpdate.roomID;
|
final roomId = eventUpdate.roomID;
|
||||||
if (webHasFocus && activeRoomId == roomId) return;
|
if (webHasFocus && activeRoomId == roomId) return;
|
||||||
final room = client.getRoomById(roomId);
|
final room = client.getRoomById(roomId);
|
||||||
|
if (room == null) {
|
||||||
|
Logs().w('Can not display notification for unknown room $roomId');
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (room.notificationCount == 0) return;
|
if (room.notificationCount == 0) return;
|
||||||
final event = Event.fromJson(eventUpdate.content, room);
|
final event = Event.fromJson(eventUpdate.content, room);
|
||||||
final title =
|
final title =
|
||||||
room.getLocalizedDisplayname(MatrixLocals(L10n.of(widget.context)));
|
room.getLocalizedDisplayname(MatrixLocals(L10n.of(widget.context)!));
|
||||||
final body = event.getLocalizedBody(
|
final body = event.getLocalizedBody(
|
||||||
MatrixLocals(L10n.of(widget.context)),
|
MatrixLocals(L10n.of(widget.context)!),
|
||||||
withSenderNamePrefix:
|
withSenderNamePrefix:
|
||||||
!room.isDirectChat || room.lastEvent.senderId == client.userID,
|
!room.isDirectChat || room.lastEvent?.senderId == client.userID,
|
||||||
plaintextBody: true,
|
plaintextBody: true,
|
||||||
hideReply: true,
|
hideReply: true,
|
||||||
hideEdit: true,
|
hideEdit: true,
|
||||||
@ -51,7 +57,7 @@ extension LocalNotificationsExtension on MatrixState {
|
|||||||
width: 56,
|
width: 56,
|
||||||
height: 56,
|
height: 56,
|
||||||
);
|
);
|
||||||
File appIconFile;
|
File? appIconFile;
|
||||||
if (appIconUrl != null) {
|
if (appIconUrl != null) {
|
||||||
final tempDirectory = await getApplicationSupportDirectory();
|
final tempDirectory = await getApplicationSupportDirectory();
|
||||||
final avatarDirectory =
|
final avatarDirectory =
|
||||||
@ -68,15 +74,15 @@ extension LocalNotificationsExtension on MatrixState {
|
|||||||
body: body,
|
body: body,
|
||||||
replacesId: linuxNotificationIds[roomId] ?? 0,
|
replacesId: linuxNotificationIds[roomId] ?? 0,
|
||||||
appName: AppConfig.applicationName,
|
appName: AppConfig.applicationName,
|
||||||
appIcon: appIconFile.path,
|
appIcon: appIconFile?.path ?? '',
|
||||||
actions: [
|
actions: [
|
||||||
NotificationAction(
|
NotificationAction(
|
||||||
DesktopNotificationActions.dismiss.name,
|
DesktopNotificationActions.dismiss.name,
|
||||||
L10n.of(widget.context).dismiss,
|
L10n.of(widget.context)!.dismiss,
|
||||||
),
|
),
|
||||||
NotificationAction(
|
NotificationAction(
|
||||||
DesktopNotificationActions.seen.name,
|
DesktopNotificationActions.seen.name,
|
||||||
L10n.of(widget.context).markAsRead,
|
L10n.of(widget.context)!.markAsRead,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
hints: [
|
hints: [
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
//@dart=2.12
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:flutter_app_lock/flutter_app_lock.dart';
|
import 'package:flutter_app_lock/flutter_app_lock.dart';
|
||||||
@ -12,7 +14,7 @@ import 'package:fluffychat/config/themes.dart';
|
|||||||
import 'layouts/one_page_card.dart';
|
import 'layouts/one_page_card.dart';
|
||||||
|
|
||||||
class LockScreen extends StatefulWidget {
|
class LockScreen extends StatefulWidget {
|
||||||
const LockScreen({Key key}) : super(key: key);
|
const LockScreen({Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_LockScreenState createState() => _LockScreenState();
|
_LockScreenState createState() => _LockScreenState();
|
||||||
@ -37,7 +39,7 @@ class _LockScreenState extends State<LockScreen> {
|
|||||||
automaticallyImplyLeading: false,
|
automaticallyImplyLeading: false,
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
centerTitle: true,
|
centerTitle: true,
|
||||||
title: Text(L10n.of(context).pleaseEnterYourPin),
|
title: Text(L10n.of(context)!.pleaseEnterYourPin),
|
||||||
backgroundColor: Colors.transparent,
|
backgroundColor: Colors.transparent,
|
||||||
),
|
),
|
||||||
extendBodyBehindAppBar: true,
|
extendBodyBehindAppBar: true,
|
||||||
@ -78,7 +80,7 @@ class _LockScreenState extends State<LockScreen> {
|
|||||||
prefs.getString(SettingKeys.appLockKey))
|
prefs.getString(SettingKeys.appLockKey))
|
||||||
: const FlutterSecureStorage()
|
: const FlutterSecureStorage()
|
||||||
.read(key: SettingKeys.appLockKey))) {
|
.read(key: SettingKeys.appLockKey))) {
|
||||||
AppLock.of(context).didUnlock();
|
AppLock.of(context)!.didUnlock();
|
||||||
} else {
|
} else {
|
||||||
_textEditingController.clear();
|
_textEditingController.clear();
|
||||||
setState(() => _wrongInput = true);
|
setState(() => _wrongInput = true);
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
|
//@dart=2.12
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:matrix/matrix.dart';
|
import 'package:matrix/matrix.dart';
|
||||||
|
|
||||||
class LogViewer extends StatefulWidget {
|
class LogViewer extends StatefulWidget {
|
||||||
const LogViewer({Key key}) : super(key: key);
|
const LogViewer({Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_LogViewerState createState() => _LogViewerState();
|
_LogViewerState createState() => _LogViewerState();
|
||||||
|
@ -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';
|
||||||
|
|
||||||
@ -8,11 +10,11 @@ import 'package:fluffychat/widgets/adaptive_flat_button.dart';
|
|||||||
|
|
||||||
class PermissionSliderDialog extends StatefulWidget {
|
class PermissionSliderDialog extends StatefulWidget {
|
||||||
const PermissionSliderDialog({
|
const PermissionSliderDialog({
|
||||||
Key key,
|
Key? key,
|
||||||
this.initialPermission = 0,
|
this.initialPermission = 0,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
Future<int> show(BuildContext context) => PlatformInfos.isCupertinoStyle
|
Future<int?> show(BuildContext context) => PlatformInfos.isCupertinoStyle
|
||||||
? showCupertinoDialog<int>(
|
? showCupertinoDialog<int>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) => this,
|
builder: (context) => this,
|
||||||
@ -30,7 +32,7 @@ class PermissionSliderDialog extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _PermissionSliderDialogState extends State<PermissionSliderDialog> {
|
class _PermissionSliderDialogState extends State<PermissionSliderDialog> {
|
||||||
int _permission;
|
late int _permission;
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
_permission = widget.initialPermission;
|
_permission = widget.initialPermission;
|
||||||
@ -40,7 +42,7 @@ class _PermissionSliderDialogState extends State<PermissionSliderDialog> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final title = Text(
|
final title = Text(
|
||||||
L10n.of(context).setPermissionsLevel,
|
L10n.of(context)!.setPermissionsLevel,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
);
|
);
|
||||||
final content = Column(
|
final content = Column(
|
||||||
@ -48,9 +50,9 @@ class _PermissionSliderDialogState extends State<PermissionSliderDialog> {
|
|||||||
children: [
|
children: [
|
||||||
Text('Level: ' +
|
Text('Level: ' +
|
||||||
(_permission == 100
|
(_permission == 100
|
||||||
? '$_permission (${L10n.of(context).admin})'
|
? '$_permission (${L10n.of(context)!.admin})'
|
||||||
: _permission >= 50
|
: _permission >= 50
|
||||||
? '$_permission (${L10n.of(context).moderator})'
|
? '$_permission (${L10n.of(context)!.moderator})'
|
||||||
: _permission.toString())),
|
: _permission.toString())),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 56,
|
height: 56,
|
||||||
@ -65,12 +67,12 @@ class _PermissionSliderDialogState extends State<PermissionSliderDialog> {
|
|||||||
);
|
);
|
||||||
final buttons = [
|
final buttons = [
|
||||||
AdaptiveFlatButton(
|
AdaptiveFlatButton(
|
||||||
label: L10n.of(context).cancel,
|
label: L10n.of(context)!.cancel,
|
||||||
onPressed: () =>
|
onPressed: () =>
|
||||||
Navigator.of(context, rootNavigator: false).pop<int>(null),
|
Navigator.of(context, rootNavigator: false).pop<int>(null),
|
||||||
),
|
),
|
||||||
AdaptiveFlatButton(
|
AdaptiveFlatButton(
|
||||||
label: L10n.of(context).confirm,
|
label: L10n.of(context)!.confirm,
|
||||||
onPressed: () =>
|
onPressed: () =>
|
||||||
Navigator.of(context, rootNavigator: false).pop<int>(_permission),
|
Navigator.of(context, rootNavigator: false).pop<int>(_permission),
|
||||||
),
|
),
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
//@dart=2.12
|
||||||
|
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@ -16,9 +18,9 @@ class ProfileBottomSheet extends StatelessWidget {
|
|||||||
final String userId;
|
final String userId;
|
||||||
final BuildContext outerContext;
|
final BuildContext outerContext;
|
||||||
const ProfileBottomSheet({
|
const ProfileBottomSheet({
|
||||||
@required this.userId,
|
required this.userId,
|
||||||
@required this.outerContext,
|
required this.outerContext,
|
||||||
Key key,
|
Key? key,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
void _startDirectChat(BuildContext context) async {
|
void _startDirectChat(BuildContext context) async {
|
||||||
@ -28,7 +30,7 @@ class ProfileBottomSheet extends StatelessWidget {
|
|||||||
future: () => client.startDirectChat(userId),
|
future: () => client.startDirectChat(userId),
|
||||||
);
|
);
|
||||||
if (result.error == null) {
|
if (result.error == null) {
|
||||||
VRouter.of(context).toSegments(['rooms', result.result]);
|
VRouter.of(context).toSegments(['rooms', result.result!]);
|
||||||
Navigator.of(context, rootNavigator: false).pop();
|
Navigator.of(context, rootNavigator: false).pop();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -52,7 +54,7 @@ class ProfileBottomSheet extends StatelessWidget {
|
|||||||
leading: IconButton(
|
leading: IconButton(
|
||||||
icon: const Icon(Icons.arrow_downward_outlined),
|
icon: const Icon(Icons.arrow_downward_outlined),
|
||||||
onPressed: Navigator.of(context, rootNavigator: false).pop,
|
onPressed: Navigator.of(context, rootNavigator: false).pop,
|
||||||
tooltip: L10n.of(context).close,
|
tooltip: L10n.of(context)!.close,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
body: FutureBuilder<Profile>(
|
body: FutureBuilder<Profile>(
|
||||||
@ -69,19 +71,20 @@ class ProfileBottomSheet extends StatelessWidget {
|
|||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
color: Theme.of(context).secondaryHeaderColor,
|
color: Theme.of(context).secondaryHeaderColor,
|
||||||
child: snapshot.hasError
|
child: snapshot.hasError
|
||||||
? Text(snapshot.error
|
? Text(snapshot.error!
|
||||||
.toLocalizedString(context))
|
.toLocalizedString(context))
|
||||||
: const CircularProgressIndicator
|
: const CircularProgressIndicator
|
||||||
.adaptive(strokeWidth: 2),
|
.adaptive(strokeWidth: 2),
|
||||||
)
|
)
|
||||||
: ContentBanner(
|
: ContentBanner(
|
||||||
profile.avatarUrl,
|
profile.avatarUrl!,
|
||||||
defaultIcon: Icons.person_outline,
|
defaultIcon: Icons.person_outline,
|
||||||
client: Matrix.of(context).client,
|
client: Matrix.of(context).client,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
title: Text(profile?.displayName ?? userId.localpart),
|
title: Text(
|
||||||
|
profile?.displayName ?? userId.localpart ?? ''),
|
||||||
subtitle: Text(userId),
|
subtitle: Text(userId),
|
||||||
trailing: const Icon(Icons.account_box_outlined),
|
trailing: const Icon(Icons.account_box_outlined),
|
||||||
),
|
),
|
||||||
@ -90,7 +93,7 @@ class ProfileBottomSheet extends StatelessWidget {
|
|||||||
padding: const EdgeInsets.all(12),
|
padding: const EdgeInsets.all(12),
|
||||||
child: ElevatedButton.icon(
|
child: ElevatedButton.icon(
|
||||||
onPressed: () => _startDirectChat(context),
|
onPressed: () => _startDirectChat(context),
|
||||||
label: Text(L10n.of(context).newChat),
|
label: Text(L10n.of(context)!.newChat),
|
||||||
icon: const Icon(Icons.send_outlined),
|
icon: const Icon(Icons.send_outlined),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
//@dart=2.12
|
||||||
|
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@ -16,12 +18,12 @@ import '../utils/localized_exception_extension.dart';
|
|||||||
class PublicRoomBottomSheet extends StatelessWidget {
|
class PublicRoomBottomSheet extends StatelessWidget {
|
||||||
final String roomAlias;
|
final String roomAlias;
|
||||||
final BuildContext outerContext;
|
final BuildContext outerContext;
|
||||||
final PublicRoomsChunk chunk;
|
final PublicRoomsChunk? chunk;
|
||||||
const PublicRoomBottomSheet({
|
const PublicRoomBottomSheet({
|
||||||
@required this.roomAlias,
|
required this.roomAlias,
|
||||||
@required this.outerContext,
|
required this.outerContext,
|
||||||
this.chunk,
|
this.chunk,
|
||||||
Key key,
|
Key? key,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
void _joinRoom(BuildContext context) async {
|
void _joinRoom(BuildContext context) async {
|
||||||
@ -31,11 +33,11 @@ class PublicRoomBottomSheet extends StatelessWidget {
|
|||||||
future: () => client.joinRoom(roomAlias),
|
future: () => client.joinRoom(roomAlias),
|
||||||
);
|
);
|
||||||
if (result.error == null) {
|
if (result.error == null) {
|
||||||
if (client.getRoomById(result.result) == null) {
|
if (client.getRoomById(result.result!) == null) {
|
||||||
await client.onSync.stream.firstWhere(
|
await client.onSync.stream.firstWhere(
|
||||||
(sync) => sync.rooms?.join?.containsKey(result.result) ?? false);
|
(sync) => sync.rooms?.join?.containsKey(result.result) ?? false);
|
||||||
}
|
}
|
||||||
VRouter.of(context).toSegments(['rooms', result.result]);
|
VRouter.of(context).toSegments(['rooms', result.result!]);
|
||||||
Navigator.of(context, rootNavigator: false).pop();
|
Navigator.of(context, rootNavigator: false).pop();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -46,6 +48,7 @@ class PublicRoomBottomSheet extends StatelessWidget {
|
|||||||
(r.aliases?.contains(roomAlias) ?? false);
|
(r.aliases?.contains(roomAlias) ?? false);
|
||||||
|
|
||||||
Future<PublicRoomsChunk> _search(BuildContext context) async {
|
Future<PublicRoomsChunk> _search(BuildContext context) async {
|
||||||
|
final chunk = this.chunk;
|
||||||
if (chunk != null) return chunk;
|
if (chunk != null) return chunk;
|
||||||
final query = await Matrix.of(context).client.queryPublicRooms(
|
final query = await Matrix.of(context).client.queryPublicRooms(
|
||||||
server: roomAlias.domain,
|
server: roomAlias.domain,
|
||||||
@ -53,16 +56,15 @@ class PublicRoomBottomSheet extends StatelessWidget {
|
|||||||
genericSearchTerm: roomAlias,
|
genericSearchTerm: roomAlias,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
if (!query.chunk.any(_testRoom) ?? true) {
|
if (!query.chunk.any(_testRoom)) {
|
||||||
throw (L10n.of(context).noRoomsFound);
|
throw (L10n.of(context)!.noRoomsFound);
|
||||||
}
|
}
|
||||||
return query.chunk.firstWhere(_testRoom);
|
return query.chunk.firstWhere(_testRoom);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final roomAlias =
|
final roomAlias = this.roomAlias;
|
||||||
this.roomAlias ?? chunk.canonicalAlias ?? chunk.aliases?.first ?? '';
|
|
||||||
return Center(
|
return Center(
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
width: min(
|
width: min(
|
||||||
@ -84,12 +86,12 @@ class PublicRoomBottomSheet extends StatelessWidget {
|
|||||||
leading: IconButton(
|
leading: IconButton(
|
||||||
icon: const Icon(Icons.arrow_downward_outlined),
|
icon: const Icon(Icons.arrow_downward_outlined),
|
||||||
onPressed: Navigator.of(context, rootNavigator: false).pop,
|
onPressed: Navigator.of(context, rootNavigator: false).pop,
|
||||||
tooltip: L10n.of(context).close,
|
tooltip: L10n.of(context)!.close,
|
||||||
),
|
),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton.icon(
|
TextButton.icon(
|
||||||
onPressed: () => _joinRoom(context),
|
onPressed: () => _joinRoom(context),
|
||||||
label: Text(L10n.of(context).joinRoom),
|
label: Text(L10n.of(context)!.joinRoom),
|
||||||
icon: const Icon(Icons.login_outlined),
|
icon: const Icon(Icons.login_outlined),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -108,26 +110,27 @@ class PublicRoomBottomSheet extends StatelessWidget {
|
|||||||
color: Theme.of(context).secondaryHeaderColor,
|
color: Theme.of(context).secondaryHeaderColor,
|
||||||
child: snapshot.hasError
|
child: snapshot.hasError
|
||||||
? Text(
|
? Text(
|
||||||
snapshot.error.toLocalizedString(context))
|
snapshot.error!.toLocalizedString(context))
|
||||||
: const CircularProgressIndicator.adaptive(
|
: const CircularProgressIndicator.adaptive(
|
||||||
strokeWidth: 2),
|
strokeWidth: 2),
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
ContentBanner(
|
ContentBanner(
|
||||||
profile.avatarUrl,
|
profile.avatarUrl!,
|
||||||
height: 156,
|
height: 156,
|
||||||
defaultIcon: Icons.person_outline,
|
defaultIcon: Icons.person_outline,
|
||||||
client: Matrix.of(context).client,
|
client: Matrix.of(context).client,
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
title: Text(profile?.name ?? roomAlias.localpart),
|
title:
|
||||||
|
Text(profile?.name ?? roomAlias.localpart ?? ''),
|
||||||
subtitle: Text(
|
subtitle: Text(
|
||||||
'${L10n.of(context).participant}: ${profile?.numJoinedMembers ?? 0}'),
|
'${L10n.of(context)!.participant}: ${profile?.numJoinedMembers ?? 0}'),
|
||||||
trailing: const Icon(Icons.account_box_outlined),
|
trailing: const Icon(Icons.account_box_outlined),
|
||||||
),
|
),
|
||||||
if (profile?.topic != null && profile.topic.isNotEmpty)
|
if (profile?.topic?.isNotEmpty ?? false)
|
||||||
ListTile(
|
ListTile(
|
||||||
subtitle: Html(data: profile.topic),
|
subtitle: Html(data: profile!.topic!),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
import 'package:flutter/material.dart';
|
//@dart=2.12
|
||||||
|
|
||||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:fluffychat/utils/sentry_controller.dart';
|
import 'package:fluffychat/utils/sentry_controller.dart';
|
||||||
|
|
||||||
class SentrySwitchListTile extends StatefulWidget {
|
class SentrySwitchListTile extends StatefulWidget {
|
||||||
final String label;
|
final String label;
|
||||||
|
|
||||||
const SentrySwitchListTile.adaptive({Key key, this.label}) : super(key: key);
|
const SentrySwitchListTile.adaptive({Key? key, required this.label})
|
||||||
|
: super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_SentrySwitchListTileState createState() => _SentrySwitchListTileState();
|
_SentrySwitchListTileState createState() => _SentrySwitchListTileState();
|
||||||
@ -23,11 +24,11 @@ class _SentrySwitchListTileState extends State<SentrySwitchListTile> {
|
|||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
_enabled = snapshot.data ?? false;
|
_enabled = snapshot.data ?? false;
|
||||||
return SwitchListTile.adaptive(
|
return SwitchListTile.adaptive(
|
||||||
title: Text(widget.label ?? L10n.of(context).sendBugReports),
|
title: Text(widget.label),
|
||||||
value: _enabled,
|
value: _enabled,
|
||||||
onChanged: (b) =>
|
onChanged: (b) =>
|
||||||
SentryController.toggleSentryAction(context, b).then(
|
SentryController.toggleSentryAction(context, b).then(
|
||||||
(_) => setState(() => null),
|
(_) => setState(() {}),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -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';
|
||||||
@ -9,8 +11,8 @@ class UnreadBadgeBackButton extends StatelessWidget {
|
|||||||
final String roomId;
|
final String roomId;
|
||||||
|
|
||||||
const UnreadBadgeBackButton({
|
const UnreadBadgeBackButton({
|
||||||
Key key,
|
Key? key,
|
||||||
@required this.roomId,
|
required this.roomId,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
Loading…
Reference in New Issue
Block a user