Merge branch 'main' of https://github.com/krille-chan/fluffychat
This commit is contained in:
commit
e12723fdaa
98 changed files with 1450 additions and 1014 deletions
|
|
@ -122,7 +122,7 @@ class BackgroundPush {
|
|||
//<GOOGLE_SERVICES>firebase.setListeners(
|
||||
//<GOOGLE_SERVICES> onMessage: (message) => pushHelper(
|
||||
//<GOOGLE_SERVICES> PushNotification.fromJson(
|
||||
//<GOOGLE_SERVICES> Map<String, dynamic>.from(message['data'] ?? message),
|
||||
//<GOOGLE_SERVICES> message.tryGetMap<String, Object>('data') ?? message,
|
||||
//<GOOGLE_SERVICES> ),
|
||||
//<GOOGLE_SERVICES> client: client,
|
||||
//<GOOGLE_SERVICES> l10n: l10n,
|
||||
|
|
@ -351,6 +351,9 @@ class BackgroundPush {
|
|||
Future<void> setupFirebase() async {
|
||||
Logs().v('Setup firebase');
|
||||
if (_fcmToken?.isEmpty ?? true) {
|
||||
if (PlatformInfos.isIOS) {
|
||||
//<GOOGLE_SERVICES>await firebase.requestPermission();
|
||||
}
|
||||
try {
|
||||
//<GOOGLE_SERVICES>_fcmToken = await firebase.getToken();
|
||||
if (_fcmToken == null) throw ('PushToken is null');
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ Future<List<XFile>> selectFiles(
|
|||
final result = await AppLock.of(context).pauseWhile(
|
||||
showFutureLoadingDialog(
|
||||
context: context,
|
||||
future: () => FilePicker.platform.pickFiles(
|
||||
future: () => FilePicker.pickFiles(
|
||||
compressionQuality: 0,
|
||||
allowMultiple: allowMultiple,
|
||||
type: type,
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ abstract class FluffyShare {
|
|||
BuildContext context, {
|
||||
bool copyOnly = false,
|
||||
}) async {
|
||||
final l10n = L10n.of(context);
|
||||
final scaffoldMessenger = ScaffoldMessenger.of(context);
|
||||
if (PlatformInfos.isMobile && !copyOnly) {
|
||||
final box = context.findRenderObject() as RenderBox;
|
||||
await SharePlus.instance.share(
|
||||
|
|
@ -24,21 +26,20 @@ abstract class FluffyShare {
|
|||
}
|
||||
await Clipboard.setData(ClipboardData(text: text));
|
||||
if (!PlatformInfos.isMobile) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
showCloseIcon: true,
|
||||
content: Text(L10n.of(context).copiedToClipboard),
|
||||
),
|
||||
scaffoldMessenger.showSnackBar(
|
||||
SnackBar(showCloseIcon: true, content: Text(l10n.copiedToClipboard)),
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static Future<void> shareInviteLink(BuildContext context) async {
|
||||
final l10n = L10n.of(context);
|
||||
final client = Matrix.of(context).client;
|
||||
final ownProfile = await client.fetchOwnProfile();
|
||||
if (!context.mounted) return;
|
||||
await FluffyShare.share(
|
||||
L10n.of(context).inviteText(
|
||||
l10n.inviteText(
|
||||
ownProfile.displayName ?? client.userID!,
|
||||
'https://matrix.to/#/${client.userID}?client=im.fluffychat',
|
||||
),
|
||||
|
|
|
|||
|
|
@ -25,12 +25,14 @@ extension LocalizedBody on Event {
|
|||
|
||||
Future<void> saveFile(BuildContext context) async {
|
||||
final matrixFile = await _getFile(context);
|
||||
if (!context.mounted) return;
|
||||
|
||||
matrixFile.result?.save(context);
|
||||
}
|
||||
|
||||
Future<void> shareFile(BuildContext context) async {
|
||||
final matrixFile = await _getFile(context);
|
||||
if (!context.mounted) return;
|
||||
|
||||
matrixFile.result?.share(context);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ extension MatrixFileExtension on MatrixFile {
|
|||
Future<void> save(BuildContext context) async {
|
||||
final scaffoldMessenger = ScaffoldMessenger.of(context);
|
||||
final l10n = L10n.of(context);
|
||||
final downloadPath = await FilePicker.platform.saveFile(
|
||||
final downloadPath = await FilePicker.saveFile(
|
||||
dialogTitle: l10n.saveFile,
|
||||
fileName: name,
|
||||
type: filePickerFileType,
|
||||
|
|
|
|||
|
|
@ -47,15 +47,17 @@ abstract class PlatformInfos {
|
|||
}
|
||||
|
||||
static Future<void> showDialog(BuildContext context) async {
|
||||
final l10n = L10n.of(context);
|
||||
final version = await PlatformInfos.getVersion();
|
||||
if (!context.mounted) return;
|
||||
showAboutDialog(
|
||||
context: context,
|
||||
children: [
|
||||
Text(L10n.of(context).versionWithNumber(version)),
|
||||
Text(l10n.versionWithNumber(version)),
|
||||
TextButton.icon(
|
||||
onPressed: () => launchUrlString(AppConfig.sourceCodeUrl),
|
||||
icon: const Icon(Icons.source_outlined),
|
||||
label: Text(L10n.of(context).sourceCode),
|
||||
label: Text(l10n.sourceCode),
|
||||
),
|
||||
Builder(
|
||||
builder: (innerContext) {
|
||||
|
|
@ -65,7 +67,7 @@ abstract class PlatformInfos {
|
|||
Navigator.of(innerContext).pop();
|
||||
},
|
||||
icon: const Icon(Icons.list_outlined),
|
||||
label: Text(L10n.of(context).logs),
|
||||
label: Text(l10n.logs),
|
||||
);
|
||||
},
|
||||
),
|
||||
|
|
@ -77,7 +79,7 @@ abstract class PlatformInfos {
|
|||
Navigator.of(innerContext).pop();
|
||||
},
|
||||
icon: const Icon(Icons.settings_applications_outlined),
|
||||
label: Text(L10n.of(context).advancedConfigs),
|
||||
label: Text(l10n.advancedConfigs),
|
||||
);
|
||||
},
|
||||
),
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ import 'package:flutter_shortcuts_new/flutter_shortcuts_new.dart';
|
|||
import 'package:matrix/matrix.dart';
|
||||
|
||||
const notificationAvatarDimension = 128;
|
||||
const String groupKey = 'im.fluffychat.messages';
|
||||
const int summaryId = -1;
|
||||
|
||||
Future<void> pushHelper(
|
||||
PushNotification notification, {
|
||||
|
|
@ -53,6 +55,7 @@ Future<void> pushHelper(
|
|||
AppSettings.applicationName.value,
|
||||
(notification.counts?.unread ?? 0).toString(),
|
||||
),
|
||||
groupKey: groupKey,
|
||||
importance: Importance.high,
|
||||
priority: Priority.max,
|
||||
shortcutId: notification.roomId,
|
||||
|
|
@ -252,7 +255,7 @@ Future<void> _tryPushHelper(
|
|||
),
|
||||
importance: Importance.high,
|
||||
priority: Priority.max,
|
||||
groupKey: event.room.spaceParents.firstOrNull?.roomId ?? 'rooms',
|
||||
groupKey: groupKey,
|
||||
actions: event.type == EventTypes.RoomMember || !useNotificationActions
|
||||
? null
|
||||
: <AndroidNotificationAction>[
|
||||
|
|
@ -300,6 +303,41 @@ Future<void> _tryPushHelper(
|
|||
event.eventId,
|
||||
).toString(),
|
||||
);
|
||||
|
||||
// Send summary notification on Android
|
||||
if (PlatformInfos.isAndroid) {
|
||||
final activeNotifications =
|
||||
(await flutterLocalNotificationsPlugin.getActiveNotifications())
|
||||
.where((n) => n.groupKey == groupKey)
|
||||
.toList();
|
||||
|
||||
if (activeNotifications.isEmpty) {
|
||||
return;
|
||||
}
|
||||
|
||||
final title = l10n.unreadChatsInApp(
|
||||
AppSettings.applicationName.value,
|
||||
activeNotifications.length.toString(),
|
||||
);
|
||||
|
||||
await flutterLocalNotificationsPlugin.show(
|
||||
id: summaryId,
|
||||
notificationDetails: NotificationDetails(
|
||||
android: AndroidNotificationDetails(
|
||||
AppConfig.pushNotificationsChannelId,
|
||||
l10n.incomingMessages,
|
||||
groupKey: groupKey,
|
||||
setAsGroupSummary: true,
|
||||
styleInformation: InboxStyleInformation(
|
||||
activeNotifications.map((n) => n.body ?? '').toList(),
|
||||
contentTitle: title,
|
||||
summaryText: title,
|
||||
),
|
||||
autoCancel: false,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
Logs().v('Push helper has been completed!');
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ abstract class UpdateNotifier {
|
|||
|
||||
static Future<void> showUpdateSnackBar(BuildContext context) async {
|
||||
final scaffoldMessenger = ScaffoldMessenger.of(context);
|
||||
final l10n = L10n.of(context);
|
||||
final currentVersion = await PlatformInfos.getVersion();
|
||||
final store = await SharedPreferences.getInstance();
|
||||
final storedVersion = store.getString(versionStoreKey);
|
||||
|
|
@ -20,9 +21,9 @@ abstract class UpdateNotifier {
|
|||
SnackBar(
|
||||
duration: const Duration(seconds: 30),
|
||||
showCloseIcon: true,
|
||||
content: Text(L10n.of(context).updateInstalled(currentVersion)),
|
||||
content: Text(l10n.updateInstalled(currentVersion)),
|
||||
action: SnackBarAction(
|
||||
label: L10n.of(context).changelog,
|
||||
label: l10n.changelog,
|
||||
onPressed: () => launchUrlString(AppConfig.changelogUrl),
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ Future<void> connectToHomeserverFlow(
|
|||
|
||||
if ((kIsWeb || PlatformInfos.isLinux) &&
|
||||
(supportsSso || authMetadata != null || (signUp && regLink != null))) {
|
||||
if (!context.mounted) return;
|
||||
final consent = await showOkCancelAlertDialog(
|
||||
context: context,
|
||||
title: l10n.appWantsToUseForLogin(homeserverInput),
|
||||
|
|
@ -45,7 +46,9 @@ Future<void> connectToHomeserverFlow(
|
|||
okLabel: l10n.continueText,
|
||||
);
|
||||
if (consent != OkCancelResult.ok) return;
|
||||
if (!context.mounted) return;
|
||||
}
|
||||
if (!context.mounted) return;
|
||||
|
||||
if (authMetadata != null && AppSettings.enableMatrixNativeOIDC.value) {
|
||||
await oidcLoginFlow(client, context, signUp);
|
||||
|
|
@ -55,6 +58,7 @@ Future<void> connectToHomeserverFlow(
|
|||
if (signUp && regLink != null) {
|
||||
await launchUrlString(regLink);
|
||||
}
|
||||
if (!context.mounted) return;
|
||||
final pathSegments = List.of(
|
||||
GoRouter.of(context).routeInformationProvider.value.uri.pathSegments,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -27,6 +27,8 @@ class UrlLauncher {
|
|||
const UrlLauncher(this.context, this.url, [this.name]);
|
||||
|
||||
Future<void> launchUrl() async {
|
||||
final l10n = L10n.of(context);
|
||||
final scaffoldMessenger = ScaffoldMessenger.of(context);
|
||||
if (url!.toLowerCase().startsWith(AppConfig.deepLinkPrefix) ||
|
||||
url!.toLowerCase().startsWith(AppConfig.inviteLinkPrefix) ||
|
||||
{'#', '@', '!', '+', '\$'}.contains(url![0]) ||
|
||||
|
|
@ -36,8 +38,8 @@ class UrlLauncher {
|
|||
final uri = Uri.tryParse(url!);
|
||||
if (uri == null) {
|
||||
// we can't open this thing
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text(L10n.of(context).cantOpenUri(url!))),
|
||||
scaffoldMessenger.showSnackBar(
|
||||
SnackBar(content: Text(l10n.cantOpenUri(url!))),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
|
@ -47,10 +49,10 @@ class UrlLauncher {
|
|||
// that the user can see the actual url before opening the browser.
|
||||
final consent = await showOkCancelAlertDialog(
|
||||
context: context,
|
||||
title: L10n.of(context).openLinkInBrowser,
|
||||
title: l10n.openLinkInBrowser,
|
||||
message: url,
|
||||
okLabel: L10n.of(context).open,
|
||||
cancelLabel: L10n.of(context).cancel,
|
||||
okLabel: l10n.open,
|
||||
cancelLabel: l10n.cancel,
|
||||
);
|
||||
if (consent != OkCancelResult.ok) return;
|
||||
}
|
||||
|
|
@ -90,8 +92,8 @@ class UrlLauncher {
|
|||
return;
|
||||
}
|
||||
if (uri.host.isEmpty) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text(L10n.of(context).cantOpenUri(url!))),
|
||||
scaffoldMessenger.showSnackBar(
|
||||
SnackBar(content: Text(l10n.cantOpenUri(url!))),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
|
@ -161,6 +163,7 @@ class UrlLauncher {
|
|||
}
|
||||
}
|
||||
servers.addAll(identityParts.via);
|
||||
if (!context.mounted) return;
|
||||
if (room != null) {
|
||||
if (room.isSpace) {
|
||||
// TODO: Implement navigate to space
|
||||
|
|
@ -178,6 +181,7 @@ class UrlLauncher {
|
|||
}
|
||||
return;
|
||||
} else {
|
||||
if (!context.mounted) return;
|
||||
await showAdaptiveDialog(
|
||||
context: context,
|
||||
builder: (c) =>
|
||||
|
|
@ -185,6 +189,7 @@ class UrlLauncher {
|
|||
);
|
||||
}
|
||||
if (roomIdOrAlias.sigil == '!') {
|
||||
if (!context.mounted) return;
|
||||
if (await showOkCancelAlertDialog(
|
||||
useRootNavigator: false,
|
||||
context: context,
|
||||
|
|
@ -192,6 +197,7 @@ class UrlLauncher {
|
|||
) ==
|
||||
OkCancelResult.ok) {
|
||||
roomId = roomIdOrAlias;
|
||||
if (!context.mounted) return;
|
||||
final response = await showFutureLoadingDialog(
|
||||
context: context,
|
||||
future: () => matrix.client.joinRoom(
|
||||
|
|
@ -200,11 +206,13 @@ class UrlLauncher {
|
|||
),
|
||||
);
|
||||
if (response.error != null) return;
|
||||
if (!context.mounted) return;
|
||||
// wait for two seconds so that it probably came down /sync
|
||||
await showFutureLoadingDialog(
|
||||
context: context,
|
||||
future: () => Future.delayed(const Duration(seconds: 2)),
|
||||
);
|
||||
if (!context.mounted) return;
|
||||
if (event != null) {
|
||||
context.go(
|
||||
Uri(
|
||||
|
|
@ -228,6 +236,7 @@ class UrlLauncher {
|
|||
return Profile(userId: userId);
|
||||
}),
|
||||
);
|
||||
if (!context.mounted) return;
|
||||
await UserDialog.show(
|
||||
context: context,
|
||||
profile: profileResult.result!,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue