refactor: Update to Dart 3.10 with . shorthands
This commit is contained in:
parent
75a37f3f7c
commit
1ea649f01e
167 changed files with 3351 additions and 3912 deletions
|
|
@ -49,7 +49,8 @@ class AdaptiveDialogAction extends StatelessWidget {
|
|||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: borderRadius ??
|
||||
borderRadius:
|
||||
borderRadius ??
|
||||
BorderRadius.circular(AppConfig.borderRadius),
|
||||
),
|
||||
backgroundColor: autofocus
|
||||
|
|
|
|||
|
|
@ -86,10 +86,7 @@ class DialogTextField extends StatelessWidget {
|
|||
if (errorText != null)
|
||||
Text(
|
||||
errorText,
|
||||
style: TextStyle(
|
||||
fontSize: 11,
|
||||
color: theme.colorScheme.error,
|
||||
),
|
||||
style: TextStyle(fontSize: 11, color: theme.colorScheme.error),
|
||||
textAlign: TextAlign.left,
|
||||
),
|
||||
],
|
||||
|
|
|
|||
|
|
@ -37,10 +37,7 @@ class PublicRoomDialog extends StatelessWidget {
|
|||
}
|
||||
final roomId = chunk != null && knock
|
||||
? await client.knockRoom(chunk.roomId, via: via)
|
||||
: await client.joinRoom(
|
||||
roomAlias ?? chunk!.roomId,
|
||||
via: via,
|
||||
);
|
||||
: await client.joinRoom(roomAlias ?? chunk!.roomId, via: via);
|
||||
|
||||
if (!knock && client.getRoomById(roomId) == null) {
|
||||
await client.waitForRoomInSync(roomId);
|
||||
|
|
@ -78,11 +75,9 @@ class PublicRoomDialog extends StatelessWidget {
|
|||
final chunk = this.chunk;
|
||||
if (chunk != null) return chunk;
|
||||
final query = await Matrix.of(context).client.queryPublicRooms(
|
||||
server: roomAlias!.domain,
|
||||
filter: PublicRoomQueryFilter(
|
||||
genericSearchTerm: roomAlias,
|
||||
),
|
||||
);
|
||||
server: roomAlias!.domain,
|
||||
filter: PublicRoomQueryFilter(genericSearchTerm: roomAlias),
|
||||
);
|
||||
if (!query.chunk.any(_testRoom)) {
|
||||
throw (L10n.of(context).noRoomsFound);
|
||||
}
|
||||
|
|
@ -115,8 +110,8 @@ class PublicRoomDialog extends StatelessWidget {
|
|||
return SingleChildScrollView(
|
||||
child: Column(
|
||||
spacing: 8,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
mainAxisSize: .min,
|
||||
crossAxisAlignment: .stretch,
|
||||
children: [
|
||||
if (roomLink != null)
|
||||
HoverBuilder(
|
||||
|
|
@ -125,9 +120,7 @@ class PublicRoomDialog extends StatelessWidget {
|
|||
cursor: SystemMouseCursors.click,
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
Clipboard.setData(
|
||||
ClipboardData(text: roomLink),
|
||||
);
|
||||
Clipboard.setData(ClipboardData(text: roomLink));
|
||||
setState(() {
|
||||
copied = true;
|
||||
});
|
||||
|
|
@ -137,8 +130,9 @@ class PublicRoomDialog extends StatelessWidget {
|
|||
children: [
|
||||
WidgetSpan(
|
||||
child: Padding(
|
||||
padding:
|
||||
const EdgeInsets.only(right: 4.0),
|
||||
padding: const EdgeInsets.only(
|
||||
right: 4.0,
|
||||
),
|
||||
child: AnimatedScale(
|
||||
duration:
|
||||
FluffyThemes.animationDuration,
|
||||
|
|
@ -146,8 +140,8 @@ class PublicRoomDialog extends StatelessWidget {
|
|||
scale: hovered
|
||||
? 1.33
|
||||
: copied
|
||||
? 1.25
|
||||
: 1.0,
|
||||
? 1.25
|
||||
: 1.0,
|
||||
child: Icon(
|
||||
copied
|
||||
? Icons.check_circle
|
||||
|
|
@ -160,8 +154,9 @@ class PublicRoomDialog extends StatelessWidget {
|
|||
),
|
||||
TextSpan(text: roomLink),
|
||||
],
|
||||
style: theme.textTheme.bodyMedium
|
||||
?.copyWith(fontSize: 10),
|
||||
style: theme.textTheme.bodyMedium?.copyWith(
|
||||
fontSize: 10,
|
||||
),
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
|
|
@ -176,25 +171,26 @@ class PublicRoomDialog extends StatelessWidget {
|
|||
size: Avatar.defaultSize * 2,
|
||||
onTap: avatar != null
|
||||
? () => showDialog(
|
||||
context: context,
|
||||
builder: (_) => MxcImageViewer(avatar),
|
||||
)
|
||||
context: context,
|
||||
builder: (_) => MxcImageViewer(avatar),
|
||||
)
|
||||
: null,
|
||||
),
|
||||
),
|
||||
if (profile?.numJoinedMembers != null)
|
||||
Text(
|
||||
L10n.of(context).countParticipants(
|
||||
profile?.numJoinedMembers ?? 0,
|
||||
),
|
||||
L10n.of(
|
||||
context,
|
||||
).countParticipants(profile?.numJoinedMembers ?? 0),
|
||||
style: const TextStyle(fontSize: 10),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
if (topic != null && topic.isNotEmpty)
|
||||
SelectableLinkify(
|
||||
text: topic,
|
||||
textScaleFactor:
|
||||
MediaQuery.textScalerOf(context).scale(1),
|
||||
textScaleFactor: MediaQuery.textScalerOf(
|
||||
context,
|
||||
).scale(1),
|
||||
textAlign: TextAlign.center,
|
||||
options: const LinkifyOptions(humanize: false),
|
||||
linkStyle: TextStyle(
|
||||
|
|
@ -221,8 +217,8 @@ class PublicRoomDialog extends StatelessWidget {
|
|||
Matrix.of(context).client.getRoomById(chunk!.roomId) == null
|
||||
? L10n.of(context).knock
|
||||
: chunk?.roomType == 'm.space'
|
||||
? L10n.of(context).joinSpace
|
||||
: L10n.of(context).joinRoom,
|
||||
? L10n.of(context).joinSpace
|
||||
: L10n.of(context).joinRoom,
|
||||
),
|
||||
),
|
||||
AdaptiveDialogAction(
|
||||
|
|
|
|||
|
|
@ -32,10 +32,7 @@ Future<T?> showModalActionPopup<T>({
|
|||
ListTile(
|
||||
title: title == null
|
||||
? null
|
||||
: Text(
|
||||
title,
|
||||
style: theme.textTheme.labelSmall,
|
||||
),
|
||||
: Text(title, style: theme.textTheme.labelSmall),
|
||||
subtitle: message == null ? null : Text(message),
|
||||
),
|
||||
const Divider(height: 1),
|
||||
|
|
@ -49,8 +46,9 @@ Future<T?> showModalActionPopup<T>({
|
|||
style: action.isDestructive
|
||||
? TextStyle(
|
||||
color: theme.colorScheme.error,
|
||||
fontWeight:
|
||||
action.isDefaultAction ? FontWeight.bold : null,
|
||||
fontWeight: action.isDefaultAction
|
||||
? FontWeight.bold
|
||||
: null,
|
||||
)
|
||||
: null,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -16,50 +16,49 @@ Future<OkCancelResult?> showOkCancelAlertDialog({
|
|||
String? cancelLabel,
|
||||
bool isDestructive = false,
|
||||
bool useRootNavigator = true,
|
||||
}) =>
|
||||
showAdaptiveDialog<OkCancelResult>(
|
||||
context: context,
|
||||
useRootNavigator: useRootNavigator,
|
||||
builder: (context) => AlertDialog.adaptive(
|
||||
title: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 256),
|
||||
child: Text(title),
|
||||
),
|
||||
content: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 256),
|
||||
child: message == null
|
||||
? null
|
||||
: SelectableLinkify(
|
||||
text: message,
|
||||
textScaleFactor: MediaQuery.textScalerOf(context).scale(1),
|
||||
linkStyle: TextStyle(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
decorationColor: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
options: const LinkifyOptions(humanize: false),
|
||||
onOpen: (url) => UrlLauncher(context, url.url).launchUrl(),
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
AdaptiveDialogAction(
|
||||
onPressed: () => Navigator.of(context)
|
||||
.pop<OkCancelResult>(OkCancelResult.cancel),
|
||||
child: Text(cancelLabel ?? L10n.of(context).cancel),
|
||||
),
|
||||
AdaptiveDialogAction(
|
||||
onPressed: () =>
|
||||
Navigator.of(context).pop<OkCancelResult>(OkCancelResult.ok),
|
||||
autofocus: true,
|
||||
child: Text(
|
||||
okLabel ?? L10n.of(context).ok,
|
||||
style: isDestructive
|
||||
? TextStyle(color: Theme.of(context).colorScheme.error)
|
||||
: null,
|
||||
}) => showAdaptiveDialog<OkCancelResult>(
|
||||
context: context,
|
||||
useRootNavigator: useRootNavigator,
|
||||
builder: (context) => AlertDialog.adaptive(
|
||||
title: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 256),
|
||||
child: Text(title),
|
||||
),
|
||||
content: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 256),
|
||||
child: message == null
|
||||
? null
|
||||
: SelectableLinkify(
|
||||
text: message,
|
||||
textScaleFactor: MediaQuery.textScalerOf(context).scale(1),
|
||||
linkStyle: TextStyle(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
decorationColor: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
options: const LinkifyOptions(humanize: false),
|
||||
onOpen: (url) => UrlLauncher(context, url.url).launchUrl(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
AdaptiveDialogAction(
|
||||
onPressed: () =>
|
||||
Navigator.of(context).pop<OkCancelResult>(OkCancelResult.cancel),
|
||||
child: Text(cancelLabel ?? L10n.of(context).cancel),
|
||||
),
|
||||
);
|
||||
AdaptiveDialogAction(
|
||||
onPressed: () =>
|
||||
Navigator.of(context).pop<OkCancelResult>(OkCancelResult.ok),
|
||||
autofocus: true,
|
||||
child: Text(
|
||||
okLabel ?? L10n.of(context).ok,
|
||||
style: isDestructive
|
||||
? TextStyle(color: Theme.of(context).colorScheme.error)
|
||||
: null,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
Future<OkCancelResult?> showOkAlertDialog({
|
||||
required BuildContext context,
|
||||
|
|
@ -67,37 +66,36 @@ Future<OkCancelResult?> showOkAlertDialog({
|
|||
String? message,
|
||||
String? okLabel,
|
||||
bool useRootNavigator = true,
|
||||
}) =>
|
||||
showAdaptiveDialog<OkCancelResult>(
|
||||
context: context,
|
||||
useRootNavigator: useRootNavigator,
|
||||
builder: (context) => AlertDialog.adaptive(
|
||||
title: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 256),
|
||||
child: Text(title),
|
||||
),
|
||||
content: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 256),
|
||||
child: message == null
|
||||
? null
|
||||
: SelectableLinkify(
|
||||
text: message,
|
||||
textScaleFactor: MediaQuery.textScalerOf(context).scale(1),
|
||||
linkStyle: TextStyle(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
decorationColor: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
options: const LinkifyOptions(humanize: false),
|
||||
onOpen: (url) => UrlLauncher(context, url.url).launchUrl(),
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
AdaptiveDialogAction(
|
||||
onPressed: () =>
|
||||
Navigator.of(context).pop<OkCancelResult>(OkCancelResult.ok),
|
||||
autofocus: true,
|
||||
child: Text(okLabel ?? L10n.of(context).close),
|
||||
),
|
||||
],
|
||||
}) => showAdaptiveDialog<OkCancelResult>(
|
||||
context: context,
|
||||
useRootNavigator: useRootNavigator,
|
||||
builder: (context) => AlertDialog.adaptive(
|
||||
title: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 256),
|
||||
child: Text(title),
|
||||
),
|
||||
content: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 256),
|
||||
child: message == null
|
||||
? null
|
||||
: SelectableLinkify(
|
||||
text: message,
|
||||
textScaleFactor: MediaQuery.textScalerOf(context).scale(1),
|
||||
linkStyle: TextStyle(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
decorationColor: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
options: const LinkifyOptions(humanize: false),
|
||||
onOpen: (url) => UrlLauncher(context, url.url).launchUrl(),
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
AdaptiveDialogAction(
|
||||
onPressed: () =>
|
||||
Navigator.of(context).pop<OkCancelResult>(OkCancelResult.ok),
|
||||
autofocus: true,
|
||||
child: Text(okLabel ?? L10n.of(context).close),
|
||||
),
|
||||
);
|
||||
],
|
||||
),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ Future<String?> showTextInputDialog({
|
|||
content: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 256),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisSize: .min,
|
||||
children: [
|
||||
if (message != null)
|
||||
SelectableLinkify(
|
||||
|
|
|
|||
|
|
@ -22,15 +22,12 @@ class UserDialog extends StatelessWidget {
|
|||
required BuildContext context,
|
||||
required Profile profile,
|
||||
bool noProfileWarning = false,
|
||||
}) =>
|
||||
showAdaptiveDialog(
|
||||
context: context,
|
||||
barrierDismissible: true,
|
||||
builder: (context) => UserDialog(
|
||||
profile,
|
||||
noProfileWarning: noProfileWarning,
|
||||
),
|
||||
);
|
||||
}) => showAdaptiveDialog(
|
||||
context: context,
|
||||
barrierDismissible: true,
|
||||
builder: (context) =>
|
||||
UserDialog(profile, noProfileWarning: noProfileWarning),
|
||||
);
|
||||
|
||||
final Profile profile;
|
||||
final bool noProfileWarning;
|
||||
|
|
@ -41,7 +38,8 @@ class UserDialog extends StatelessWidget {
|
|||
Widget build(BuildContext context) {
|
||||
final client = Matrix.of(context).client;
|
||||
final dmRoomId = client.getDirectChatFromUserId(profile.userId);
|
||||
final displayname = profile.displayName ??
|
||||
final displayname =
|
||||
profile.displayName ??
|
||||
profile.userId.localpart ??
|
||||
L10n.of(context).user;
|
||||
var copied = false;
|
||||
|
|
@ -64,15 +62,15 @@ class UserDialog extends StatelessWidget {
|
|||
final presenceText = presence.currentlyActive == true
|
||||
? L10n.of(context).currentlyActive
|
||||
: lastActiveTimestamp != null
|
||||
? L10n.of(context).lastActiveAgo(
|
||||
lastActiveTimestamp.localizedTimeShort(context),
|
||||
)
|
||||
: null;
|
||||
? L10n.of(context).lastActiveAgo(
|
||||
lastActiveTimestamp.localizedTimeShort(context),
|
||||
)
|
||||
: null;
|
||||
return SingleChildScrollView(
|
||||
child: Column(
|
||||
spacing: 8,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
mainAxisSize: .min,
|
||||
crossAxisAlignment: .stretch,
|
||||
children: [
|
||||
Center(
|
||||
child: Avatar(
|
||||
|
|
@ -81,9 +79,9 @@ class UserDialog extends StatelessWidget {
|
|||
size: Avatar.defaultSize * 2,
|
||||
onTap: avatar != null
|
||||
? () => showDialog(
|
||||
context: context,
|
||||
builder: (_) => MxcImageViewer(avatar),
|
||||
)
|
||||
context: context,
|
||||
builder: (_) => MxcImageViewer(avatar),
|
||||
)
|
||||
: null,
|
||||
),
|
||||
),
|
||||
|
|
@ -112,8 +110,8 @@ class UserDialog extends StatelessWidget {
|
|||
scale: hovered
|
||||
? 1.33
|
||||
: copied
|
||||
? 1.25
|
||||
: 1.0,
|
||||
? 1.25
|
||||
: 1.0,
|
||||
child: Icon(
|
||||
copied
|
||||
? Icons.check_circle
|
||||
|
|
@ -126,8 +124,9 @@ class UserDialog extends StatelessWidget {
|
|||
),
|
||||
TextSpan(text: profile.userId),
|
||||
],
|
||||
style: theme.textTheme.bodyMedium
|
||||
?.copyWith(fontSize: 10),
|
||||
style: theme.textTheme.bodyMedium?.copyWith(
|
||||
fontSize: 10,
|
||||
),
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
|
|
@ -144,8 +143,9 @@ class UserDialog extends StatelessWidget {
|
|||
if (statusMsg != null)
|
||||
SelectableLinkify(
|
||||
text: statusMsg,
|
||||
textScaleFactor:
|
||||
MediaQuery.textScalerOf(context).scale(1),
|
||||
textScaleFactor: MediaQuery.textScalerOf(
|
||||
context,
|
||||
).scale(1),
|
||||
textAlign: TextAlign.center,
|
||||
options: const LinkifyOptions(humanize: false),
|
||||
linkStyle: TextStyle(
|
||||
|
|
|
|||
|
|
@ -82,8 +82,8 @@ class AppLock extends State<AppLockWidget> with WidgetsBindingObserver {
|
|||
}
|
||||
|
||||
void showLockScreen() => setState(() {
|
||||
_isLocked = true;
|
||||
});
|
||||
_isLocked = true;
|
||||
});
|
||||
|
||||
Future<T> pauseWhile<T>(Future<T> future) async {
|
||||
_paused = true;
|
||||
|
|
@ -94,20 +94,15 @@ class AppLock extends State<AppLockWidget> with WidgetsBindingObserver {
|
|||
}
|
||||
}
|
||||
|
||||
static AppLock of(BuildContext context) => Provider.of<AppLock>(
|
||||
context,
|
||||
listen: false,
|
||||
);
|
||||
static AppLock of(BuildContext context) =>
|
||||
Provider.of<AppLock>(context, listen: false);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => Provider<AppLock>(
|
||||
create: (_) => this,
|
||||
child: Stack(
|
||||
fit: StackFit.expand,
|
||||
children: [
|
||||
widget.child,
|
||||
if (isLocked) const LockScreen(),
|
||||
],
|
||||
),
|
||||
);
|
||||
create: (_) => this,
|
||||
child: Stack(
|
||||
fit: StackFit.expand,
|
||||
children: [widget.child, if (isLocked) const LockScreen()],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,10 +42,12 @@ class Avatar extends StatelessWidget {
|
|||
final theme = Theme.of(context);
|
||||
|
||||
final name = this.name;
|
||||
final fallbackLetters =
|
||||
name == null || name.isEmpty ? '@' : name.substring(0, 1);
|
||||
final fallbackLetters = name == null || name.isEmpty
|
||||
? '@'
|
||||
: name.substring(0, 1);
|
||||
|
||||
final noPic = mxContent == null ||
|
||||
final noPic =
|
||||
mxContent == null ||
|
||||
mxContent.toString().isEmpty ||
|
||||
mxContent.toString() == 'null';
|
||||
final borderRadius = this.borderRadius ?? BorderRadius.circular(size / 2);
|
||||
|
|
@ -113,8 +115,8 @@ class Avatar extends StatelessWidget {
|
|||
final dotColor = presence.presence.isOnline
|
||||
? Colors.green
|
||||
: presence.presence.isUnavailable
|
||||
? Colors.orange
|
||||
: Colors.grey;
|
||||
? Colors.orange
|
||||
: Colors.grey;
|
||||
return Positioned(
|
||||
bottom: -3,
|
||||
right: -3,
|
||||
|
|
@ -147,10 +149,7 @@ class Avatar extends StatelessWidget {
|
|||
if (onTap == null) return container;
|
||||
return MouseRegion(
|
||||
cursor: SystemMouseCursors.click,
|
||||
child: GestureDetector(
|
||||
onTap: onTap,
|
||||
child: container,
|
||||
),
|
||||
child: GestureDetector(onTap: onTap, child: container),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@ class AvatarPageHeader extends StatelessWidget {
|
|||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: FluffyThemes.columnWidth),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisSize: .min,
|
||||
crossAxisAlignment: .center,
|
||||
spacing: 8.0,
|
||||
children: [
|
||||
Stack(
|
||||
|
|
@ -58,7 +58,7 @@ class AvatarPageHeader extends StatelessWidget {
|
|||
child: LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
mainAxisAlignment: .center,
|
||||
children: [
|
||||
ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
|
|
@ -87,7 +87,7 @@ class AvatarPageHeader extends StatelessWidget {
|
|||
),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
mainAxisAlignment: .spaceEvenly,
|
||||
children: iconButtons,
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -25,9 +25,7 @@ class BlurHash extends StatefulWidget {
|
|||
class _BlurHashState extends State<BlurHash> {
|
||||
Uint8List? _data;
|
||||
|
||||
static Future<Uint8List> getBlurhashData(
|
||||
BlurhashData blurhashData,
|
||||
) async {
|
||||
static Future<Uint8List> getBlurhashData(BlurhashData blurhashData) async {
|
||||
final blurhash = b.BlurHash.decode(blurhashData.hsh);
|
||||
final img = blurhash.toImage(blurhashData.w, blurhashData.h);
|
||||
return Uint8List.fromList(image.encodePng(img));
|
||||
|
|
@ -46,11 +44,7 @@ class _BlurHashState extends State<BlurHash> {
|
|||
|
||||
return _data ??= await compute(
|
||||
getBlurhashData,
|
||||
BlurhashData(
|
||||
hsh: widget.blurhash,
|
||||
w: width,
|
||||
h: height,
|
||||
),
|
||||
BlurhashData(hsh: widget.blurhash, w: width, h: height),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -84,21 +78,10 @@ class BlurhashData {
|
|||
final int w;
|
||||
final int h;
|
||||
|
||||
const BlurhashData({
|
||||
required this.hsh,
|
||||
required this.w,
|
||||
required this.h,
|
||||
});
|
||||
const BlurhashData({required this.hsh, required this.w, required this.h});
|
||||
|
||||
factory BlurhashData.fromJson(Map<String, dynamic> json) => BlurhashData(
|
||||
hsh: json['hsh'],
|
||||
w: json['w'],
|
||||
h: json['h'],
|
||||
);
|
||||
factory BlurhashData.fromJson(Map<String, dynamic> json) =>
|
||||
BlurhashData(hsh: json['hsh'], w: json['w'], h: json['h']);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'hsh': hsh,
|
||||
'w': w,
|
||||
'h': h,
|
||||
};
|
||||
Map<String, dynamic> toJson() => {'hsh': hsh, 'w': w, 'h': h};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,10 +36,7 @@ class ChatSettingsPopupMenuState extends State<ChatSettingsPopupMenu> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
notificationChangeSub ??= Matrix.of(context)
|
||||
.client
|
||||
.onSync
|
||||
.stream
|
||||
notificationChangeSub ??= Matrix.of(context).client.onSync.stream
|
||||
.where(
|
||||
(syncUpdate) =>
|
||||
syncUpdate.accountData?.any(
|
||||
|
|
@ -47,9 +44,7 @@ class ChatSettingsPopupMenuState extends State<ChatSettingsPopupMenu> {
|
|||
) ??
|
||||
false,
|
||||
)
|
||||
.listen(
|
||||
(u) => setState(() {}),
|
||||
);
|
||||
.listen((u) => setState(() {}));
|
||||
return Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
|
|
|
|||
|
|
@ -53,9 +53,7 @@ class _ConfigViewerState extends State<ConfigViewer> {
|
|||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Advanced configurations'),
|
||||
leading: BackButton(
|
||||
onPressed: () => context.go('/'),
|
||||
),
|
||||
leading: BackButton(onPressed: () => context.go('/')),
|
||||
),
|
||||
body: Column(
|
||||
children: [
|
||||
|
|
@ -65,9 +63,7 @@ class _ConfigViewerState extends State<ConfigViewer> {
|
|||
color: theme.colorScheme.errorContainer,
|
||||
child: Text(
|
||||
'Changing configs by hand is untested! Use without any warranty!',
|
||||
style: TextStyle(
|
||||
color: theme.colorScheme.onErrorContainer,
|
||||
),
|
||||
style: TextStyle(color: theme.colorScheme.onErrorContainer),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
|
|
|
|||
|
|
@ -21,10 +21,10 @@ class _FluffyChatErrorWidgetState extends State<FluffyChatErrorWidget> {
|
|||
}
|
||||
knownExceptions.add(widget.details.exception.toString());
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
ErrorReporter(context, 'Error Widget').onErrorCallback(
|
||||
widget.details.exception,
|
||||
widget.details.stack,
|
||||
);
|
||||
ErrorReporter(
|
||||
context,
|
||||
'Error Widget',
|
||||
).onErrorCallback(widget.details.exception, widget.details.stack);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -46,8 +46,11 @@ class FluffyChatApp extends StatelessWidget {
|
|||
title: AppSettings.applicationName.value,
|
||||
themeMode: themeMode,
|
||||
theme: FluffyThemes.buildTheme(context, Brightness.light, primaryColor),
|
||||
darkTheme:
|
||||
FluffyThemes.buildTheme(context, Brightness.dark, primaryColor),
|
||||
darkTheme: FluffyThemes.buildTheme(
|
||||
context,
|
||||
Brightness.dark,
|
||||
primaryColor,
|
||||
),
|
||||
scrollBehavior: CustomScrollBehavior(),
|
||||
localizationsDelegates: L10n.localizationsDelegates,
|
||||
supportedLocales: L10n.supportedLocales,
|
||||
|
|
|
|||
|
|
@ -54,10 +54,7 @@ Future<Result<T>> showFutureLoadingDialog<T>({
|
|||
),
|
||||
);
|
||||
return result ??
|
||||
Result.error(
|
||||
Exception('FutureDialog canceled'),
|
||||
StackTrace.current,
|
||||
);
|
||||
Result.error(Exception('FutureDialog canceled'), StackTrace.current);
|
||||
}
|
||||
|
||||
class LoadingDialog<T> extends StatefulWidget {
|
||||
|
|
@ -114,15 +111,13 @@ class LoadingDialogState<T> extends State<LoadingDialog> {
|
|||
content: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 256),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
crossAxisAlignment: .center,
|
||||
children: [
|
||||
if (exception == null) ...[
|
||||
StreamBuilder(
|
||||
stream: widget.onProgressStream,
|
||||
builder: (context, snapshot) =>
|
||||
CircularProgressIndicator.adaptive(
|
||||
value: snapshot.data,
|
||||
),
|
||||
CircularProgressIndicator.adaptive(value: snapshot.data),
|
||||
),
|
||||
const SizedBox(width: 20),
|
||||
],
|
||||
|
|
@ -141,12 +136,9 @@ class LoadingDialogState<T> extends State<LoadingDialog> {
|
|||
? null
|
||||
: [
|
||||
AdaptiveDialogAction(
|
||||
onPressed: () => Navigator.of(context).pop<Result<T>>(
|
||||
Result.error(
|
||||
exception,
|
||||
stackTrace,
|
||||
),
|
||||
),
|
||||
onPressed: () => Navigator.of(
|
||||
context,
|
||||
).pop<Result<T>>(Result.error(exception, stackTrace)),
|
||||
child: Text(widget.backLabel ?? L10n.of(context).close),
|
||||
),
|
||||
],
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ class LoginScaffold extends StatelessWidget {
|
|||
),
|
||||
),
|
||||
),
|
||||
const _PrivacyButtons(mainAxisAlignment: MainAxisAlignment.center),
|
||||
const _PrivacyButtons(mainAxisAlignment: .center),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
|
@ -95,31 +95,19 @@ class _PrivacyButtons extends StatelessWidget {
|
|||
children: [
|
||||
TextButton(
|
||||
onPressed: () => launchUrlString(AppConfig.website),
|
||||
child: Text(
|
||||
L10n.of(context).website,
|
||||
style: shadowTextStyle,
|
||||
),
|
||||
child: Text(L10n.of(context).website, style: shadowTextStyle),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () => launchUrlString(AppConfig.supportUrl),
|
||||
child: Text(
|
||||
L10n.of(context).help,
|
||||
style: shadowTextStyle,
|
||||
),
|
||||
child: Text(L10n.of(context).help, style: shadowTextStyle),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () => launchUrl(AppConfig.privacyUrl),
|
||||
child: Text(
|
||||
L10n.of(context).privacy,
|
||||
style: shadowTextStyle,
|
||||
),
|
||||
child: Text(L10n.of(context).privacy, style: shadowTextStyle),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () => PlatformInfos.showDialog(context),
|
||||
child: Text(
|
||||
L10n.of(context).about,
|
||||
style: shadowTextStyle,
|
||||
),
|
||||
child: Text(L10n.of(context).about, style: shadowTextStyle),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
|
|||
|
|
@ -35,11 +35,10 @@ class MaxWidthBody extends StatelessWidget {
|
|||
),
|
||||
child: Material(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius:
|
||||
BorderRadius.circular(AppConfig.borderRadius),
|
||||
side: BorderSide(
|
||||
color: theme.dividerColor,
|
||||
borderRadius: BorderRadius.circular(
|
||||
AppConfig.borderRadius,
|
||||
),
|
||||
side: BorderSide(color: theme.dividerColor),
|
||||
),
|
||||
clipBehavior: Clip.hardEdge,
|
||||
child: Padding(
|
||||
|
|
|
|||
|
|
@ -25,15 +25,8 @@ class TwoColumnLayout extends StatelessWidget {
|
|||
width: FluffyThemes.columnWidth + FluffyThemes.navRailWidth,
|
||||
child: mainView,
|
||||
),
|
||||
Container(
|
||||
width: 1.0,
|
||||
color: theme.dividerColor,
|
||||
),
|
||||
Expanded(
|
||||
child: ClipRRect(
|
||||
child: sideView,
|
||||
),
|
||||
),
|
||||
Container(width: 1.0, color: theme.dividerColor),
|
||||
Expanded(child: ClipRRect(child: sideView)),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -33,11 +33,13 @@ extension LocalNotificationsExtension on MatrixState {
|
|||
}
|
||||
}
|
||||
|
||||
final title =
|
||||
event.room.getLocalizedDisplayname(MatrixLocals(L10n.of(context)));
|
||||
final title = event.room.getLocalizedDisplayname(
|
||||
MatrixLocals(L10n.of(context)),
|
||||
);
|
||||
final body = await event.calcLocalizedBody(
|
||||
MatrixLocals(L10n.of(context)),
|
||||
withSenderNamePrefix: !event.room.isDirectChat ||
|
||||
withSenderNamePrefix:
|
||||
!event.room.isDirectChat ||
|
||||
event.room.lastEvent?.senderId == client.userID,
|
||||
plaintextBody: true,
|
||||
hideReply: true,
|
||||
|
|
@ -66,13 +68,13 @@ extension LocalNotificationsExtension on MatrixState {
|
|||
Logs().d('Unable to pre-download avatar for web notification', e, s);
|
||||
}
|
||||
|
||||
thumbnailUri =
|
||||
await event.senderFromMemoryOrFallback.avatarUrl?.getThumbnailUri(
|
||||
client,
|
||||
width: size,
|
||||
height: size,
|
||||
method: thumbnailMethod,
|
||||
);
|
||||
thumbnailUri = await event.senderFromMemoryOrFallback.avatarUrl
|
||||
?.getThumbnailUri(
|
||||
client,
|
||||
width: size,
|
||||
height: size,
|
||||
method: thumbnailMethod,
|
||||
);
|
||||
}
|
||||
|
||||
_audioPlayer.play();
|
||||
|
|
@ -133,8 +135,9 @@ extension LocalNotificationsExtension on MatrixState {
|
|||
hints: hints,
|
||||
);
|
||||
notification.action.then((actionStr) {
|
||||
var action = DesktopNotificationActions.values
|
||||
.singleWhereOrNull((a) => a.name == actionStr);
|
||||
var action = DesktopNotificationActions.values.singleWhereOrNull(
|
||||
(a) => a.name == actionStr,
|
||||
);
|
||||
if (action == null && actionStr == "default") {
|
||||
action = DesktopNotificationActions.openChat;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,10 +79,7 @@ class _LockScreenState extends State<LockScreen> {
|
|||
shrinkWrap: true,
|
||||
children: [
|
||||
Center(
|
||||
child: Image.asset(
|
||||
'assets/info-logo.png',
|
||||
width: 256,
|
||||
),
|
||||
child: Image.asset('assets/info-logo.png', width: 256),
|
||||
),
|
||||
TextField(
|
||||
controller: _textEditingController,
|
||||
|
|
@ -95,9 +92,7 @@ class _LockScreenState extends State<LockScreen> {
|
|||
onChanged: tryUnlock,
|
||||
onSubmitted: tryUnlock,
|
||||
style: const TextStyle(fontSize: 40),
|
||||
inputFormatters: [
|
||||
LengthLimitingTextInputFormatter(4),
|
||||
],
|
||||
inputFormatters: [LengthLimitingTextInputFormatter(4)],
|
||||
decoration: InputDecoration(
|
||||
errorText: _errorText,
|
||||
hintText: '****',
|
||||
|
|
|
|||
|
|
@ -15,17 +15,14 @@ class LogViewerState extends State<LogViewer> {
|
|||
double fontSize = 14;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final outputEvents = Logs()
|
||||
.outputEvents
|
||||
final outputEvents = Logs().outputEvents
|
||||
.where((e) => e.level.index <= logLevel.index)
|
||||
.toList();
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.black,
|
||||
appBar: AppBar(
|
||||
title: Text(logLevel.toString()),
|
||||
leading: BackButton(
|
||||
onPressed: () => context.go('/'),
|
||||
),
|
||||
leading: BackButton(onPressed: () => context.go('/')),
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.zoom_in_outlined),
|
||||
|
|
@ -55,9 +52,7 @@ class LogViewerState extends State<LogViewer> {
|
|||
scrollDirection: Axis.horizontal,
|
||||
child: SelectableText(
|
||||
outputEvents[i].toDisplayString(),
|
||||
style: TextStyle(
|
||||
color: outputEvents[i].color,
|
||||
),
|
||||
style: TextStyle(color: outputEvents[i].color),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -120,10 +120,7 @@ class MatrixState extends State<Matrix> with WidgetsBindingObserver {
|
|||
}
|
||||
resBundles[bundle.name] ??= [];
|
||||
resBundles[bundle.name]!.add(
|
||||
_AccountBundleWithClient(
|
||||
client: widget.clients[i],
|
||||
bundle: bundle,
|
||||
),
|
||||
_AccountBundleWithClient(client: widget.clients[i], bundle: bundle),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -132,12 +129,13 @@ class MatrixState extends State<Matrix> with WidgetsBindingObserver {
|
|||
(a, b) => a.bundle!.priority == null
|
||||
? 1
|
||||
: b.bundle!.priority == null
|
||||
? -1
|
||||
: a.bundle!.priority!.compareTo(b.bundle!.priority!),
|
||||
? -1
|
||||
: a.bundle!.priority!.compareTo(b.bundle!.priority!),
|
||||
);
|
||||
}
|
||||
return resBundles
|
||||
.map((k, v) => MapEntry(k, v.map((vv) => vv.client).toList()));
|
||||
return resBundles.map(
|
||||
(k, v) => MapEntry(k, v.map((vv) => vv.client).toList()),
|
||||
);
|
||||
}
|
||||
|
||||
bool get hasComplexBundles => accountBundles.values.any((v) => v.length > 1);
|
||||
|
|
@ -151,27 +149,26 @@ class MatrixState extends State<Matrix> with WidgetsBindingObserver {
|
|||
if (widget.clients.isNotEmpty && !client.isLogged()) {
|
||||
return client;
|
||||
}
|
||||
final candidate =
|
||||
_loginClientCandidate ??= await ClientManager.createClient(
|
||||
'${AppSettings.applicationName.value}-${DateTime.now().millisecondsSinceEpoch}',
|
||||
store,
|
||||
)
|
||||
..onLoginStateChanged
|
||||
.stream
|
||||
final candidate = _loginClientCandidate ??=
|
||||
await ClientManager.createClient(
|
||||
'${AppSettings.applicationName.value}-${DateTime.now().millisecondsSinceEpoch}',
|
||||
store,
|
||||
)
|
||||
..onLoginStateChanged.stream
|
||||
.where((l) => l == LoginState.loggedIn)
|
||||
.first
|
||||
.then((_) {
|
||||
if (!widget.clients.contains(_loginClientCandidate)) {
|
||||
widget.clients.add(_loginClientCandidate!);
|
||||
}
|
||||
ClientManager.addClientNameToStore(
|
||||
_loginClientCandidate!.clientName,
|
||||
store,
|
||||
);
|
||||
_registerSubs(_loginClientCandidate!.clientName);
|
||||
_loginClientCandidate = null;
|
||||
FluffyChatApp.router.go('/backup');
|
||||
});
|
||||
if (!widget.clients.contains(_loginClientCandidate)) {
|
||||
widget.clients.add(_loginClientCandidate!);
|
||||
}
|
||||
ClientManager.addClientNameToStore(
|
||||
_loginClientCandidate!.clientName,
|
||||
store,
|
||||
);
|
||||
_registerSubs(_loginClientCandidate!.clientName);
|
||||
_loginClientCandidate = null;
|
||||
FluffyChatApp.router.go('/backup');
|
||||
});
|
||||
if (widget.clients.isEmpty) widget.clients.add(candidate);
|
||||
return candidate;
|
||||
}
|
||||
|
|
@ -210,8 +207,9 @@ class MatrixState extends State<Matrix> with WidgetsBindingObserver {
|
|||
return route.split('/')[2];
|
||||
}
|
||||
|
||||
final linuxNotifications =
|
||||
PlatformInfos.isLinux ? NotificationsClient() : null;
|
||||
final linuxNotifications = PlatformInfos.isLinux
|
||||
? NotificationsClient()
|
||||
: null;
|
||||
final Map<String, int> linuxNotificationIds = {};
|
||||
|
||||
@override
|
||||
|
|
@ -229,8 +227,9 @@ class MatrixState extends State<Matrix> with WidgetsBindingObserver {
|
|||
);
|
||||
return;
|
||||
}
|
||||
onRoomKeyRequestSub[name] ??=
|
||||
c.onRoomKeyRequest.stream.listen((RoomKeyRequest request) async {
|
||||
onRoomKeyRequestSub[name] ??= c.onRoomKeyRequest.stream.listen((
|
||||
RoomKeyRequest request,
|
||||
) async {
|
||||
if (widget.clients.any(
|
||||
((cl) =>
|
||||
cl.userID == request.requestingDevice.userId &&
|
||||
|
|
@ -244,22 +243,24 @@ class MatrixState extends State<Matrix> with WidgetsBindingObserver {
|
|||
});
|
||||
onKeyVerificationRequestSub[name] ??= c.onKeyVerificationRequest.stream
|
||||
.listen((KeyVerification request) async {
|
||||
var hidPopup = false;
|
||||
request.onUpdate = () {
|
||||
if (!hidPopup &&
|
||||
{KeyVerificationState.done, KeyVerificationState.error}
|
||||
.contains(request.state)) {
|
||||
FluffyChatApp.router.pop('dialog');
|
||||
}
|
||||
hidPopup = true;
|
||||
};
|
||||
request.onUpdate = null;
|
||||
hidPopup = true;
|
||||
await KeyVerificationDialog(request: request).show(
|
||||
FluffyChatApp.router.routerDelegate.navigatorKey.currentContext ??
|
||||
context,
|
||||
);
|
||||
});
|
||||
var hidPopup = false;
|
||||
request.onUpdate = () {
|
||||
if (!hidPopup &&
|
||||
{
|
||||
KeyVerificationState.done,
|
||||
KeyVerificationState.error,
|
||||
}.contains(request.state)) {
|
||||
FluffyChatApp.router.pop('dialog');
|
||||
}
|
||||
hidPopup = true;
|
||||
};
|
||||
request.onUpdate = null;
|
||||
hidPopup = true;
|
||||
await KeyVerificationDialog(request: request).show(
|
||||
FluffyChatApp.router.routerDelegate.navigatorKey.currentContext ??
|
||||
context,
|
||||
);
|
||||
});
|
||||
onLoginStateChanged[name] ??= c.onLoginStateChanged.stream.listen((state) {
|
||||
final loggedInWithMultipleClients = widget.clients.length > 1;
|
||||
if (state == LoginState.loggedOut) {
|
||||
|
|
@ -273,25 +274,25 @@ class MatrixState extends State<Matrix> with WidgetsBindingObserver {
|
|||
FluffyChatApp.router.routerDelegate.navigatorKey.currentContext ??
|
||||
context,
|
||||
).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(L10n.of(context).oneClientLoggedOut),
|
||||
),
|
||||
SnackBar(content: Text(L10n.of(context).oneClientLoggedOut)),
|
||||
);
|
||||
|
||||
if (state != LoginState.loggedIn) {
|
||||
FluffyChatApp.router.go('/rooms');
|
||||
}
|
||||
} else {
|
||||
FluffyChatApp.router
|
||||
.go(state == LoginState.loggedIn ? '/backup' : '/home');
|
||||
FluffyChatApp.router.go(
|
||||
state == LoginState.loggedIn ? '/backup' : '/home',
|
||||
);
|
||||
}
|
||||
});
|
||||
onUiaRequest[name] ??= c.onUiaRequest.stream.listen(uiaRequestHandler);
|
||||
if (PlatformInfos.isWeb || PlatformInfos.isLinux) {
|
||||
c.onSync.stream.first.then((s) {
|
||||
html.Notification.requestPermission();
|
||||
onNotification[name] ??=
|
||||
c.onNotification.stream.listen(showLocalNotification);
|
||||
onNotification[name] ??= c.onNotification.stream.listen(
|
||||
showLocalNotification,
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -322,13 +323,18 @@ class MatrixState extends State<Matrix> with WidgetsBindingObserver {
|
|||
this,
|
||||
onFcmError: (errorMsg, {Uri? link}) async {
|
||||
final result = await showOkCancelAlertDialog(
|
||||
context: FluffyChatApp
|
||||
.router.routerDelegate.navigatorKey.currentContext ??
|
||||
context:
|
||||
FluffyChatApp
|
||||
.router
|
||||
.routerDelegate
|
||||
.navigatorKey
|
||||
.currentContext ??
|
||||
context,
|
||||
title: L10n.of(context).pushNotificationsNotAvailable,
|
||||
message: errorMsg,
|
||||
okLabel:
|
||||
link == null ? L10n.of(context).ok : L10n.of(context).learnMore,
|
||||
okLabel: link == null
|
||||
? L10n.of(context).ok
|
||||
: L10n.of(context).learnMore,
|
||||
cancelLabel: L10n.of(context).doNotShowAgain,
|
||||
);
|
||||
if (result == OkCancelResult.ok && link != null) {
|
||||
|
|
@ -357,11 +363,13 @@ class MatrixState extends State<Matrix> with WidgetsBindingObserver {
|
|||
|
||||
@override
|
||||
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||
final foreground = state != AppLifecycleState.inactive &&
|
||||
final foreground =
|
||||
state != AppLifecycleState.inactive &&
|
||||
state != AppLifecycleState.paused;
|
||||
for (final client in widget.clients) {
|
||||
client.syncPresence =
|
||||
state == AppLifecycleState.resumed ? null : PresenceType.unavailable;
|
||||
client.syncPresence = state == AppLifecycleState.resumed
|
||||
? null
|
||||
: PresenceType.unavailable;
|
||||
if (PlatformInfos.isMobile) {
|
||||
client.backgroundSync = foreground;
|
||||
client.requestHistoryOnLimitedTimeline = !foreground;
|
||||
|
|
@ -389,10 +397,7 @@ class MatrixState extends State<Matrix> with WidgetsBindingObserver {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Provider(
|
||||
create: (_) => this,
|
||||
child: widget.child,
|
||||
);
|
||||
return Provider(create: (_) => this, child: widget.child);
|
||||
}
|
||||
|
||||
Future<void> dehydrateAction(BuildContext context) async {
|
||||
|
|
@ -412,9 +417,7 @@ class MatrixState extends State<Matrix> with WidgetsBindingObserver {
|
|||
final export = result.result;
|
||||
if (export == null) return;
|
||||
|
||||
final exportBytes = Uint8List.fromList(
|
||||
const Utf8Codec().encode(export),
|
||||
);
|
||||
final exportBytes = Uint8List.fromList(const Utf8Codec().encode(export));
|
||||
|
||||
final exportFileName =
|
||||
'fluffychat-export-${DateFormat(DateFormat.YEAR_MONTH_DAY).format(DateTime.now())}.fluffybackup';
|
||||
|
|
|
|||
|
|
@ -50,8 +50,8 @@ void showMemberActionsPopupMenu({
|
|||
presenceBackgroundColor: theme.colorScheme.surfaceContainer,
|
||||
),
|
||||
Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: .min,
|
||||
crossAxisAlignment: .start,
|
||||
children: [
|
||||
ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 128),
|
||||
|
|
@ -109,16 +109,16 @@ void showMemberActionsPopupMenu({
|
|||
const Icon(Icons.admin_panel_settings_outlined),
|
||||
const SizedBox(width: 18),
|
||||
Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: .min,
|
||||
crossAxisAlignment: .start,
|
||||
children: [
|
||||
Text(L10n.of(context).chatPermissions),
|
||||
Text(
|
||||
user.powerLevel < 50
|
||||
? L10n.of(context).userLevel(user.powerLevel)
|
||||
: user.powerLevel < 100
|
||||
? L10n.of(context).moderatorLevel(user.powerLevel)
|
||||
: L10n.of(context).adminLevel(user.powerLevel),
|
||||
? L10n.of(context).moderatorLevel(user.powerLevel)
|
||||
: L10n.of(context).adminLevel(user.powerLevel),
|
||||
style: const TextStyle(fontSize: 10),
|
||||
),
|
||||
],
|
||||
|
|
@ -267,10 +267,7 @@ void showMemberActionsPopupMenu({
|
|||
|
||||
final result = await showFutureLoadingDialog(
|
||||
context: context,
|
||||
future: () => user.room.client.reportUser(
|
||||
user.id,
|
||||
reason,
|
||||
),
|
||||
future: () => user.room.client.reportUser(user.id, reason),
|
||||
);
|
||||
if (result.error != null) return;
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
|
|
|
|||
|
|
@ -27,24 +27,20 @@ class SpacesNavigationRail extends StatelessWidget {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final client = Matrix.of(context).client;
|
||||
final isSettings = GoRouter.of(context)
|
||||
.routeInformationProvider
|
||||
.value
|
||||
.uri
|
||||
.path
|
||||
.startsWith('/rooms/settings');
|
||||
final isSettings = GoRouter.of(
|
||||
context,
|
||||
).routeInformationProvider.value.uri.path.startsWith('/rooms/settings');
|
||||
return Material(
|
||||
child: SafeArea(
|
||||
child: StreamBuilder(
|
||||
key: ValueKey(
|
||||
client.userID.toString(),
|
||||
),
|
||||
key: ValueKey(client.userID.toString()),
|
||||
stream: client.onSync.stream
|
||||
.where((s) => s.hasRoomUpdate)
|
||||
.rateLimit(const Duration(seconds: 1)),
|
||||
builder: (context, _) {
|
||||
final allSpaces =
|
||||
client.rooms.where((room) => room.isSpace).toList();
|
||||
final allSpaces = client.rooms
|
||||
.where((room) => room.isSpace)
|
||||
.toList();
|
||||
|
||||
return SizedBox(
|
||||
width: FluffyThemes.isColumnMode(context)
|
||||
|
|
@ -86,12 +82,13 @@ class SpacesNavigationRail extends StatelessWidget {
|
|||
);
|
||||
}
|
||||
final space = allSpaces[i];
|
||||
final displayname =
|
||||
allSpaces[i].getLocalizedDisplayname(
|
||||
MatrixLocals(L10n.of(context)),
|
||||
);
|
||||
final spaceChildrenIds =
|
||||
space.spaceChildren.map((c) => c.roomId).toSet();
|
||||
final displayname = allSpaces[i]
|
||||
.getLocalizedDisplayname(
|
||||
MatrixLocals(L10n.of(context)),
|
||||
);
|
||||
final spaceChildrenIds = space.spaceChildren
|
||||
.map((c) => c.roomId)
|
||||
.toSet();
|
||||
return NaviRailItem(
|
||||
toolTip: displayname,
|
||||
isSelected: activeSpaceId == space.id,
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@ Future<int?> showPermissionChooser(
|
|||
content: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 256, maxHeight: 256),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
mainAxisSize: .min,
|
||||
crossAxisAlignment: .stretch,
|
||||
spacing: 12.0,
|
||||
children: [
|
||||
Text(L10n.of(context).setPermissionsLevelDescription),
|
||||
|
|
|
|||
|
|
@ -13,10 +13,7 @@ import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_file_extension.dar
|
|||
import 'package:fluffychat/widgets/future_loading_dialog.dart';
|
||||
import '../config/themes.dart';
|
||||
|
||||
Future<void> showQrCodeViewer(
|
||||
BuildContext context,
|
||||
String content,
|
||||
) =>
|
||||
Future<void> showQrCodeViewer(BuildContext context, String content) =>
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => QrCodeViewer(content: content),
|
||||
|
|
@ -32,11 +29,7 @@ class QrCodeViewer extends StatelessWidget {
|
|||
context: context,
|
||||
future: () async {
|
||||
final inviteLink = 'https://matrix.to/#/$content';
|
||||
final image = QRImage(
|
||||
inviteLink,
|
||||
size: 256,
|
||||
radius: 1,
|
||||
).generate();
|
||||
final image = QRImage(inviteLink, size: 256, radius: 1).generate();
|
||||
return compute(encodePng, image);
|
||||
},
|
||||
);
|
||||
|
|
@ -76,10 +69,7 @@ class QrCodeViewer extends StatelessWidget {
|
|||
backgroundColor: Colors.black.withAlpha(128),
|
||||
),
|
||||
icon: Icon(Icons.adaptive.share_outlined),
|
||||
onPressed: () => FluffyShare.share(
|
||||
inviteLink,
|
||||
context,
|
||||
),
|
||||
onPressed: () => FluffyShare.share(inviteLink, context),
|
||||
color: Colors.white,
|
||||
tooltip: L10n.of(context).share,
|
||||
),
|
||||
|
|
@ -105,11 +95,12 @@ class QrCodeViewer extends StatelessWidget {
|
|||
borderRadius: BorderRadius.circular(AppConfig.borderRadius),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisSize: .min,
|
||||
children: [
|
||||
ConstrainedBox(
|
||||
constraints:
|
||||
const BoxConstraints(maxWidth: FluffyThemes.columnWidth),
|
||||
constraints: const BoxConstraints(
|
||||
maxWidth: FluffyThemes.columnWidth,
|
||||
),
|
||||
child: PrettyQrView.data(
|
||||
data: inviteLink,
|
||||
decoration: PrettyQrDecoration(
|
||||
|
|
|
|||
|
|
@ -64,9 +64,7 @@ class _ShareScaffoldDialogState extends State<ShareScaffoldDialog> {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
final rooms = Matrix.of(context)
|
||||
.client
|
||||
.rooms
|
||||
final rooms = Matrix.of(context).client.rooms
|
||||
.where(
|
||||
(room) =>
|
||||
room.canSendDefaultMessages &&
|
||||
|
|
@ -138,8 +136,9 @@ class _ShareScaffoldDialogState extends State<ShareScaffoldDialog> {
|
|||
),
|
||||
controlAffinity: ListTileControlAffinity.trailing,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius:
|
||||
BorderRadius.circular(AppConfig.borderRadius),
|
||||
borderRadius: BorderRadius.circular(
|
||||
AppConfig.borderRadius,
|
||||
),
|
||||
),
|
||||
secondary: Avatar(
|
||||
mxContent: room.avatar,
|
||||
|
|
|
|||
|
|
@ -12,7 +12,8 @@ class ThemeBuilder extends StatefulWidget {
|
|||
BuildContext context,
|
||||
ThemeMode themeMode,
|
||||
Color? primaryColor,
|
||||
) builder;
|
||||
)
|
||||
builder;
|
||||
|
||||
final String themeModeSettingsKey;
|
||||
final String primaryColorSettingsKey;
|
||||
|
|
@ -38,28 +39,26 @@ class ThemeController extends State<ThemeBuilder> {
|
|||
Color? get primaryColor => _primaryColor;
|
||||
|
||||
static ThemeController of(BuildContext context) =>
|
||||
Provider.of<ThemeController>(
|
||||
context,
|
||||
listen: false,
|
||||
);
|
||||
Provider.of<ThemeController>(context, listen: false);
|
||||
|
||||
void _loadData(dynamic _) async {
|
||||
final preferences =
|
||||
_sharedPreferences ??= await SharedPreferences.getInstance();
|
||||
final preferences = _sharedPreferences ??=
|
||||
await SharedPreferences.getInstance();
|
||||
|
||||
final rawThemeMode = preferences.getString(widget.themeModeSettingsKey);
|
||||
final rawColor = preferences.getInt(widget.primaryColorSettingsKey);
|
||||
|
||||
setState(() {
|
||||
_themeMode = ThemeMode.values
|
||||
.singleWhereOrNull((value) => value.name == rawThemeMode);
|
||||
_themeMode = ThemeMode.values.singleWhereOrNull(
|
||||
(value) => value.name == rawThemeMode,
|
||||
);
|
||||
_primaryColor = rawColor == null ? null : Color(rawColor);
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> setThemeMode(ThemeMode newThemeMode) async {
|
||||
final preferences =
|
||||
_sharedPreferences ??= await SharedPreferences.getInstance();
|
||||
final preferences = _sharedPreferences ??=
|
||||
await SharedPreferences.getInstance();
|
||||
await preferences.setString(widget.themeModeSettingsKey, newThemeMode.name);
|
||||
setState(() {
|
||||
_themeMode = newThemeMode;
|
||||
|
|
@ -67,8 +66,8 @@ class ThemeController extends State<ThemeBuilder> {
|
|||
}
|
||||
|
||||
Future<void> setPrimaryColor(Color? newPrimaryColor) async {
|
||||
final preferences =
|
||||
_sharedPreferences ??= await SharedPreferences.getInstance();
|
||||
final preferences = _sharedPreferences ??=
|
||||
await SharedPreferences.getInstance();
|
||||
if (newPrimaryColor == null) {
|
||||
await preferences.remove(widget.primaryColorSettingsKey);
|
||||
} else {
|
||||
|
|
@ -93,11 +92,8 @@ class ThemeController extends State<ThemeBuilder> {
|
|||
return Provider(
|
||||
create: (_) => this,
|
||||
child: DynamicColorBuilder(
|
||||
builder: (light, _) => widget.builder(
|
||||
context,
|
||||
themeMode,
|
||||
primaryColor ?? light?.primary,
|
||||
),
|
||||
builder: (light, _) =>
|
||||
widget.builder(context, themeMode, primaryColor ?? light?.primary),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,9 +21,7 @@ class UnreadRoomsBadge extends StatelessWidget {
|
|||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
|
||||
final unreadCount = Matrix.of(context)
|
||||
.client
|
||||
.rooms
|
||||
final unreadCount = Matrix.of(context).client.rooms
|
||||
.where(filter)
|
||||
.where((r) => (r.isUnread || r.membership == Membership.invite))
|
||||
.length;
|
||||
|
|
@ -31,17 +29,11 @@ class UnreadRoomsBadge extends StatelessWidget {
|
|||
badgeStyle: b.BadgeStyle(
|
||||
badgeColor: theme.colorScheme.primary,
|
||||
elevation: 4,
|
||||
borderSide: BorderSide(
|
||||
color: theme.colorScheme.surface,
|
||||
width: 2,
|
||||
),
|
||||
borderSide: BorderSide(color: theme.colorScheme.surface, width: 2),
|
||||
),
|
||||
badgeContent: Text(
|
||||
unreadCount.toString(),
|
||||
style: TextStyle(
|
||||
color: theme.colorScheme.onPrimary,
|
||||
fontSize: 12,
|
||||
),
|
||||
style: TextStyle(color: theme.colorScheme.onPrimary, fontSize: 12),
|
||||
),
|
||||
showBadge: unreadCount != 0,
|
||||
badgeAnimation: const b.BadgeAnimation.scale(),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue