diff --git a/.github/workflows/versions.env b/.github/workflows/versions.env index 48b9dbee1..79809e38f 100644 --- a/.github/workflows/versions.env +++ b/.github/workflows/versions.env @@ -1,2 +1,2 @@ -FLUTTER_VERSION=3.38.3 +FLUTTER_VERSION=3.38.4 JAVA_VERSION=17 diff --git a/lib/pages/chat/chat.dart b/lib/pages/chat/chat.dart index d89fe55a6..49d09887e 100644 --- a/lib/pages/chat/chat.dart +++ b/lib/pages/chat/chat.dart @@ -8,6 +8,7 @@ import 'package:flutter/services.dart'; import 'package:collection/collection.dart'; import 'package:device_info_plus/device_info_plus.dart'; import 'package:emoji_picker_flutter/emoji_picker_flutter.dart'; +import 'package:file_picker/file_picker.dart'; import 'package:go_router/go_router.dart'; import 'package:image_picker/image_picker.dart'; import 'package:just_audio/just_audio.dart'; @@ -338,9 +339,14 @@ class ChatController extends State final timeline = this.timeline; if (timeline == null) return; Logs().v('Requesting future...'); - final mostRecentEventId = timeline.events.first.eventId; + + final mostRecentEvent = timeline.events.filterByVisibleInGui().firstOrNull; + await timeline.requestFuture(historyCount: _loadHistoryCount); - setReadMarker(eventId: mostRecentEventId); + + if (mostRecentEvent != null) { + setReadMarker(eventId: mostRecentEvent.eventId); + } } void _updateScrollController() { @@ -357,11 +363,6 @@ class ChatController extends State // setReadMarker(); // } // Pangea# - - if (scrollController.position.pixels == 0 || - scrollController.position.pixels == 64) { - requestFuture(); - } } void _loadDraft() async { @@ -679,7 +680,7 @@ class ChatController extends State void onInsert(int i) { // setState will be called by updateView() anyway - animateInEventIndex = i; + if (i <= 5) animateInEventIndex = i; } // #Pangea @@ -1099,7 +1100,7 @@ class ChatController extends State // Pangea# } - void sendFileAction({FileSelectorType type = FileSelectorType.any}) async { + void sendFileAction({FileType type = FileType.any}) async { final files = await selectFiles(context, allowMultiple: true, type: type); if (files.isEmpty) return; await showAdaptiveDialog( @@ -1811,10 +1812,10 @@ class ChatController extends State switch (choice) { case AddPopupMenuActions.image: - sendFileAction(type: FileSelectorType.images); + sendFileAction(type: FileType.image); return; case AddPopupMenuActions.video: - sendFileAction(type: FileSelectorType.videos); + sendFileAction(type: FileType.video); return; case AddPopupMenuActions.file: sendFileAction(); diff --git a/lib/pages/chat/chat_event_list.dart b/lib/pages/chat/chat_event_list.dart index 1601186e1..708e73f0a 100644 --- a/lib/pages/chat/chat_event_list.dart +++ b/lib/pages/chat/chat_event_list.dart @@ -5,6 +5,7 @@ import 'package:collection/collection.dart'; import 'package:scroll_to_index/scroll_to_index.dart'; import 'package:fluffychat/config/themes.dart'; +import 'package:fluffychat/l10n/l10n.dart'; import 'package:fluffychat/pages/chat/chat.dart'; import 'package:fluffychat/pages/chat/events/message.dart'; import 'package:fluffychat/pages/chat/seen_by_row.dart'; @@ -76,16 +77,16 @@ class ChatEventList extends StatelessWidget { (BuildContext context, int i) { // Footer to display typing indicator and read receipts: if (i == 0) { - if (timeline.isRequestingFuture) { - return const Center( - child: CircularProgressIndicator.adaptive(strokeWidth: 2), - ); - } if (timeline.canRequestFuture) { return Center( - child: IconButton( - onPressed: controller.requestFuture, - icon: const Icon(Icons.refresh_outlined), + child: TextButton.icon( + onPressed: timeline.isRequestingFuture + ? null + : controller.requestFuture, + icon: timeline.isRequestingFuture + ? CircularProgressIndicator.adaptive(strokeWidth: 2) + : const Icon(Icons.arrow_downward_outlined), + label: Text(L10n.of(context).loadMore), ), ); } @@ -125,16 +126,14 @@ class ChatEventList extends StatelessWidget { } } return Center( - child: AnimatedSwitcher( - duration: FluffyThemes.animationDuration, - child: timeline.canRequestHistory - ? IconButton( - onPressed: controller.requestHistory, - icon: const Icon(Icons.refresh_outlined), - ) - : const CircularProgressIndicator.adaptive( - strokeWidth: 2, - ), + child: TextButton.icon( + onPressed: timeline.isRequestingHistory + ? null + : controller.requestHistory, + icon: timeline.isRequestingHistory + ? CircularProgressIndicator.adaptive(strokeWidth: 2) + : const Icon(Icons.arrow_upward_outlined), + label: Text(L10n.of(context).loadMore), ), ); }, diff --git a/lib/pages/chat/chat_view.dart b/lib/pages/chat/chat_view.dart index 123bafd46..f9665e0aa 100644 --- a/lib/pages/chat/chat_view.dart +++ b/lib/pages/chat/chat_view.dart @@ -368,8 +368,6 @@ class ChatView extends StatelessWidget { ), ), // #Pangea - // floatingActionButtonLocation: - // FloatingActionButtonLocation.miniCenterFloat, // floatingActionButton: // controller.showScrollDownButton && // controller.selectedEvents.isEmpty diff --git a/lib/pages/chat/events/html_message.dart b/lib/pages/chat/events/html_message.dart index c60a85919..67dc32f1c 100644 --- a/lib/pages/chat/events/html_message.dart +++ b/lib/pages/chat/events/html_message.dart @@ -1146,22 +1146,27 @@ class MatrixPill extends StatelessWidget { ], ), ), - // child: Row( - // mainAxisSize: .min, - // children: [ - // Avatar(mxContent: avatar, name: name, size: 16), - // const SizedBox(width: 6), - // Text( - // name, - // style: TextStyle( - // color: color, - // decorationColor: color, - // decoration: TextDecoration.underline, - // fontSize: fontSize, - // height: 1.25, + // child: Text.rich( + // TextSpan( + // children: [ + // WidgetSpan( + // child: Padding( + // padding: const EdgeInsets.only(right: 4.0), + // child: Avatar(mxContent: avatar, name: name, size: 16), + // ), // ), - // ), - // ], + // TextSpan( + // text: name, + // style: TextStyle( + // color: color, + // decorationColor: color, + // decoration: TextDecoration.underline, + // fontSize: fontSize, + // height: 1.25, + // ), + // ), + // ], + // ), // ), // Pangea# ); diff --git a/lib/pages/chat_details/chat_details.dart b/lib/pages/chat_details/chat_details.dart index 9728fdcf4..46f59266b 100644 --- a/lib/pages/chat_details/chat_details.dart +++ b/lib/pages/chat_details/chat_details.dart @@ -3,6 +3,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:collection/collection.dart'; +import 'package:file_picker/file_picker.dart'; import 'package:image_picker/image_picker.dart'; import 'package:matrix/matrix.dart' as sdk; import 'package:matrix/matrix.dart'; @@ -215,7 +216,7 @@ class ChatDetailsController extends State final picked = await selectFiles( context, allowMultiple: false, - type: FileSelectorType.images, + type: FileType.image, ); final pickedFile = picked.firstOrNull; if (pickedFile == null) return; diff --git a/lib/pages/new_group/new_group.dart b/lib/pages/new_group/new_group.dart index f34d0b43a..c5737a32b 100644 --- a/lib/pages/new_group/new_group.dart +++ b/lib/pages/new_group/new_group.dart @@ -2,6 +2,7 @@ import 'dart:typed_data'; import 'package:flutter/material.dart'; +import 'package:file_picker/file_picker.dart'; import 'package:go_router/go_router.dart'; import 'package:matrix/matrix.dart' as sdk; import 'package:matrix/matrix.dart'; @@ -49,7 +50,7 @@ class NewGroupController extends State { void selectPhoto() async { final photo = await selectFiles( context, - type: FileSelectorType.images, + type: FileType.image, allowMultiple: false, ); final bytes = await photo.singleOrNull?.readAsBytes(); diff --git a/lib/pages/settings/settings.dart b/lib/pages/settings/settings.dart index 8daa4330f..291e467ec 100644 --- a/lib/pages/settings/settings.dart +++ b/lib/pages/settings/settings.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:collection/collection.dart'; +import 'package:file_picker/file_picker.dart'; import 'package:image_picker/image_picker.dart'; import 'package:matrix/matrix.dart'; @@ -134,7 +135,7 @@ class SettingsController extends State { if (result == null) return; file = MatrixFile(bytes: await result.readAsBytes(), name: result.path); } else { - final result = await selectFiles(context, type: FileSelectorType.images); + final result = await selectFiles(context, type: FileType.image); final pickedFile = result.firstOrNull; if (pickedFile == null) return; file = MatrixFile( diff --git a/lib/pages/settings_emotes/settings_emotes.dart b/lib/pages/settings_emotes/settings_emotes.dart index 06090351c..5999b7168 100644 --- a/lib/pages/settings_emotes/settings_emotes.dart +++ b/lib/pages/settings_emotes/settings_emotes.dart @@ -4,6 +4,7 @@ import 'package:archive/archive.dart' import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:file_picker/file_picker.dart'; import 'package:http/http.dart' hide Client; import 'package:matrix/matrix.dart'; @@ -294,7 +295,7 @@ class EmotesSettingsController extends State { void createStickers() async { final pickedFiles = await selectFiles( context, - type: FileSelectorType.images, + type: FileType.image, allowMultiple: true, ); if (pickedFiles.isEmpty) return; @@ -353,7 +354,7 @@ class EmotesSettingsController extends State { } Future importEmojiZip() async { - final result = await selectFiles(context, type: FileSelectorType.zip); + final result = await selectFiles(context, type: FileType.any); if (result.isEmpty) return; diff --git a/lib/pages/settings_style/settings_style.dart b/lib/pages/settings_style/settings_style.dart index f3d559a0d..b22e98fbb 100644 --- a/lib/pages/settings_style/settings_style.dart +++ b/lib/pages/settings_style/settings_style.dart @@ -1,5 +1,7 @@ import 'package:flutter/material.dart'; +import 'package:file_picker/file_picker.dart'; + import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/config/setting_keys.dart'; import 'package:fluffychat/utils/account_config.dart'; @@ -26,7 +28,7 @@ class SettingsStyleController extends State { void setWallpaper() async { final client = Matrix.of(context).client; - final picked = await selectFiles(context, type: FileSelectorType.images); + final picked = await selectFiles(context, type: FileType.image); final pickedFile = picked.firstOrNull; if (pickedFile == null) return; diff --git a/lib/pangea/chat_settings/pages/edit_course.dart b/lib/pangea/chat_settings/pages/edit_course.dart index e68ad995a..5ba7dc627 100644 --- a/lib/pangea/chat_settings/pages/edit_course.dart +++ b/lib/pangea/chat_settings/pages/edit_course.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; +import 'package:file_picker/file_picker.dart'; import 'package:image_picker/image_picker.dart'; import 'package:matrix/matrix.dart'; @@ -150,7 +151,7 @@ class EditCourseController extends State { final picked = await selectFiles( context, allowMultiple: false, - type: FileSelectorType.images, + type: FileType.image, ); final pickedFile = picked.firstOrNull; if (pickedFile == null) return; diff --git a/lib/utils/file_selector.dart b/lib/utils/file_selector.dart index 2798c469f..97e229c2e 100644 --- a/lib/utils/file_selector.dart +++ b/lib/utils/file_selector.dart @@ -9,7 +9,7 @@ import 'package:fluffychat/widgets/future_loading_dialog.dart'; Future> selectFiles( BuildContext context, { String? title, - FileSelectorType type = FileSelectorType.any, + FileType type = FileType.any, bool allowMultiple = false, }) async { final result = await AppLock.of(context).pauseWhile( @@ -18,117 +18,9 @@ Future> selectFiles( future: () => FilePicker.platform.pickFiles( compressionQuality: 0, allowMultiple: allowMultiple, - type: type.filePickerType, - allowedExtensions: type.extensions, + type: type, ), ), ); return result.result?.xFiles ?? []; } - -enum FileSelectorType { - any([], FileType.any, null), - images( - [ - XTypeGroup( - label: 'Images', - extensions: [ - 'jpg', - 'JPG', - 'jpeg', - 'JPEG', - 'png', - 'PNG', - 'webp', - 'WebP', - 'WEBP', - 'gif', - 'GIF', - 'bmp', - 'BMP', - 'tiff', - 'TIFF', - 'tif', - 'TIF', - 'heic', - 'HEIC', - 'svg', - 'SVG', - ], - ), - XTypeGroup( - label: 'JPG', - extensions: ['jpg', 'JPG', 'jpeg', 'JPEG'], - ), - XTypeGroup(label: 'PNG', extensions: ['png', 'PNG']), - XTypeGroup(label: 'WebP', extensions: ['webp', 'WebP', 'WEBP']), - XTypeGroup(label: 'GIF', extensions: ['gif', 'GIF']), - XTypeGroup(label: 'BMP', extensions: ['bmp', 'BMP']), - XTypeGroup( - label: 'TIFF', - extensions: ['tiff', 'TIFF', 'tif', 'TIF'], - ), - XTypeGroup(label: 'HEIC', extensions: ['heic', 'HEIC']), - XTypeGroup(label: 'SVG', extensions: ['svg', 'SVG']), - ], - FileType.image, - null, - ), - videos( - [ - XTypeGroup( - label: 'Videos', - extensions: [ - 'mp4', - 'MP4', - 'avi', - 'AVI', - 'webm', - 'WebM', - 'WEBM', - 'mov', - 'MOV', - 'mkv', - 'MKV', - 'wmv', - 'WMV', - 'flv', - 'FLV', - 'mpeg', - 'MPEG', - '3gp', - '3GP', - 'ogg', - 'OGG', - ], - ), - XTypeGroup(label: 'MP4', extensions: ['mp4', 'MP4']), - XTypeGroup(label: 'WebM', extensions: ['webm', 'WebM', 'WEBM']), - XTypeGroup(label: 'AVI', extensions: ['avi', 'AVI']), - XTypeGroup(label: 'MOV', extensions: ['mov', 'MOV']), - XTypeGroup(label: 'MKV', extensions: ['mkv', 'MKV']), - XTypeGroup(label: 'WMV', extensions: ['wmv', 'WMV']), - XTypeGroup(label: 'FLV', extensions: ['flv', 'FLV']), - XTypeGroup(label: 'MPEG', extensions: ['mpeg', 'MPEG']), - XTypeGroup(label: '3GP', extensions: ['3gp', '3GP']), - XTypeGroup(label: 'OGG', extensions: ['ogg', 'OGG']), - ], - FileType.video, - null, - ), - zip( - [ - XTypeGroup(label: 'ZIP', extensions: ['zip', 'ZIP']), - ], - FileType.custom, - ['zip', 'ZIP'], - ), - // #Pangea - media([], FileType.media, null); - // Pangea# - - const FileSelectorType(this.groups, this.filePickerType, this.extensions); - final List groups; - final FileType filePickerType; - final List? extensions; -} diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 2a35e3311..8a86b50bc 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -53,7 +53,7 @@ platforms: parts: flutter-git: source: https://github.com/flutter/flutter.git - source-tag: 3.38.1 + source-tag: 3.38.4 source-depth: 1 plugin: nil override-build: |