From 9e9d8b6fabc800214ff325ec67415bd9a70f5e0c Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Wed, 4 Jun 2025 01:59:17 +0800 Subject: [PATCH] :bug: Bug fixes, and fixes --- ios/Podfile.lock | 12 ++ lib/database/message_repository.dart | 2 +- .../creators/stickers/pack_detail.dart | 2 +- lib/screens/creators/stickers/stickers.dart | 163 ++++++++--------- lib/screens/creators/stickers/stickers.g.dart | 149 +++++++++++++++ lib/screens/posts/compose.dart | 2 +- lib/widgets/content/attachment_preview.dart | 18 +- .../content/cloud_file_collection.dart | 169 +++++++++++++++++- lib/widgets/content/cloud_file_picker.dart | 2 +- lib/widgets/content/cloud_files.dart | 3 +- macos/Podfile.lock | 6 + macos/Runner/Info.plist | 2 +- pubspec.lock | 10 +- pubspec.yaml | 1 + 14 files changed, 435 insertions(+), 106 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 9bcb861..f206203 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -90,6 +90,8 @@ PODS: - flutter_webrtc (0.14.0): - Flutter - WebRTC-SDK (= 125.6422.07) + - gal (1.0.0): + - Flutter - GoogleDataTransport (10.1.0): - nanopb (~> 3.30910.0) - PromisesObjC (~> 2.4) @@ -144,6 +146,8 @@ PODS: - Flutter - FlutterMacOS - PromisesObjC (2.4.0) + - record_ios (1.0.0): + - Flutter - SAMKeychain (1.5.3) - SDWebImage (5.21.0): - SDWebImage/Core (= 5.21.0) @@ -201,6 +205,7 @@ DEPENDENCIES: - flutter_platform_alert (from `.symlinks/plugins/flutter_platform_alert/ios`) - flutter_udid (from `.symlinks/plugins/flutter_udid/ios`) - flutter_webrtc (from `.symlinks/plugins/flutter_webrtc/ios`) + - gal (from `.symlinks/plugins/gal/ios`) - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) - irondash_engine_context (from `.symlinks/plugins/irondash_engine_context/ios`) - Kingfisher (~> 8.0) @@ -210,6 +215,7 @@ DEPENDENCIES: - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) - pasteboard (from `.symlinks/plugins/pasteboard/ios`) - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) + - record_ios (from `.symlinks/plugins/record_ios/ios`) - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) - sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`) - sqlite3_flutter_libs (from `.symlinks/plugins/sqlite3_flutter_libs/darwin`) @@ -265,6 +271,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/flutter_udid/ios" flutter_webrtc: :path: ".symlinks/plugins/flutter_webrtc/ios" + gal: + :path: ".symlinks/plugins/gal/ios" image_picker_ios: :path: ".symlinks/plugins/image_picker_ios/ios" irondash_engine_context: @@ -281,6 +289,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/pasteboard/ios" path_provider_foundation: :path: ".symlinks/plugins/path_provider_foundation/darwin" + record_ios: + :path: ".symlinks/plugins/record_ios/ios" shared_preferences_foundation: :path: ".symlinks/plugins/shared_preferences_foundation/darwin" sqflite_darwin: @@ -317,6 +327,7 @@ SPEC CHECKSUMS: flutter_platform_alert: bf3b5fcd4ac14bd637e20527e9c471633071afd3 flutter_udid: f7c3884e6ec2951efe4f9de082257fc77c4d15e9 flutter_webrtc: fd0d3bdef8766a0736dbbe2e5b7e85f1f3c52117 + gal: 29e711cd17bccb47f839d9b30afe9bc9750950b2 GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7 GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1 image_picker_ios: 7fe1ff8e34c1790d6fff70a32484959f563a928a @@ -331,6 +342,7 @@ SPEC CHECKSUMS: pasteboard: 49088aeb6119d51f976a421db60d8e1ab079b63c path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564 PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 + record_ios: fee1c924aa4879b882ebca2b4bce6011bcfc3d8b SAMKeychain: 483e1c9f32984d50ca961e26818a534283b4cd5c SDWebImage: f84b0feeb08d2d11e6a9b843cb06d75ebf5b8868 shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7 diff --git a/lib/database/message_repository.dart b/lib/database/message_repository.dart index aeb40f7..43f8426 100644 --- a/lib/database/message_repository.dart +++ b/lib/database/message_repository.dart @@ -231,7 +231,7 @@ class MessageRepository { for (var idx = 0; idx < attachments.length; idx++) { final cloudFile = await putMediaToCloud( - fileData: attachments[idx].data, + fileData: attachments[idx], atk: token, baseUrl: baseUrl, filename: attachments[idx].data.name ?? 'Post media', diff --git a/lib/screens/creators/stickers/pack_detail.dart b/lib/screens/creators/stickers/pack_detail.dart index fdd347f..0d6f11b 100644 --- a/lib/screens/creators/stickers/pack_detail.dart +++ b/lib/screens/creators/stickers/pack_detail.dart @@ -298,7 +298,7 @@ class _StickerPackActionMenu extends HookConsumerWidget { if (confirm) { final client = ref.watch(apiClientProvider); client.delete('/stickers/$packId'); - ref.invalidate(stickerPacksProvider); + ref.invalidate(stickerPacksNotifierProvider); if (context.mounted) context.router.maybePop(true); } }); diff --git a/lib/screens/creators/stickers/stickers.dart b/lib/screens/creators/stickers/stickers.dart index d57f0fd..8017f41 100644 --- a/lib/screens/creators/stickers/stickers.dart +++ b/lib/screens/creators/stickers/stickers.dart @@ -13,7 +13,7 @@ import 'package:island/widgets/app_scaffold.dart'; import 'package:material_symbols_icons/symbols.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:styled_widget/styled_widget.dart'; -import 'package:very_good_infinite_list/very_good_infinite_list.dart'; +import 'package:riverpod_paging_utils/riverpod_paging_utils.dart'; part 'stickers.g.dart'; @@ -24,9 +24,6 @@ class StickersScreen extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final stickersState = ref.watch(stickerPacksProvider); - final stickersNotifier = ref.watch(stickerPacksProvider.notifier); - return AppScaffold( appBar: AppBar( title: const Text('stickers').tr(), @@ -37,7 +34,7 @@ class StickersScreen extends HookConsumerWidget { value, ) { if (value != null) { - stickersNotifier.refresh(); + ref.invalidate(stickerPacksNotifierProvider(pubName)); } }); }, @@ -46,104 +43,90 @@ class StickersScreen extends HookConsumerWidget { const Gap(8), ], ), - body: stickersState.when( - data: - (stickers) => RefreshIndicator( - onRefresh: stickersNotifier.refresh, - child: InfiniteList( - padding: EdgeInsets.zero, - itemCount: stickers.length, - hasReachedMax: stickersNotifier.isReachedMax, - isLoading: stickersNotifier.isLoading, - onFetchData: stickersNotifier.fetchMore, - itemBuilder: (context, index) { - return ListTile( - title: Text(stickers[index].name), - subtitle: Text(stickers[index].description), - trailing: const Icon(Symbols.chevron_right), - onTap: () { - context.router.push( - StickerPackDetailRoute( - pubName: pubName, - id: stickers[index].id, - ), - ); - }, - ); - }, - ), - ), - loading: () => const CircularProgressIndicator(), - error: (error, stack) => Text('Error: $error'), - ), + body: SliverStickerPacksList(pubName: pubName), ); } } -final stickerPacksProvider = StateNotifierProvider< - StickerPacksNotifier, - AsyncValue> ->((ref) { - return StickerPacksNotifier(ref.watch(apiClientProvider)); -}); +class SliverStickerPacksList extends HookConsumerWidget { + final String pubName; + const SliverStickerPacksList({super.key, required this.pubName}); -class StickerPacksNotifier - extends StateNotifier>> { - final Dio _apiClient; - StickerPacksNotifier(this._apiClient) : super(const AsyncValue.loading()) { - fetchStickers(); + @override + Widget build(BuildContext context, WidgetRef ref) { + return PagingHelperView( + provider: stickerPacksNotifierProvider(pubName), + futureRefreshable: stickerPacksNotifierProvider(pubName).future, + notifierRefreshable: stickerPacksNotifierProvider(pubName).notifier, + contentBuilder: + (data, widgetCount, endItemView) => ListView.builder( + padding: EdgeInsets.zero, + itemCount: widgetCount, + itemBuilder: (context, index) { + if (index == widgetCount - 1) { + return endItemView; + } + + final sticker = data.items[index]; + return ListTile( + title: Text(sticker.name), + subtitle: Text(sticker.description), + trailing: const Icon(Symbols.chevron_right), + onTap: () { + context.router.push( + StickerPackDetailRoute(pubName: pubName, id: sticker.id), + ); + }, + ); + }, + ), + ); + } +} + +@riverpod +class StickerPacksNotifier extends _$StickerPacksNotifier + with CursorPagingNotifierMixin { + static const int _pageSize = 20; + + @override + Future> build(String pubName) { + return fetch(cursor: null); } - int offset = 0; - int take = 20; - int total = 0; - - bool isLoading = false; - bool get isReachedMax => - state.valueOrNull != null && state.valueOrNull!.length >= total; - - Future fetchStickers() async { - if (isLoading) return; - isLoading = true; + @override + Future> fetch({ + required String? cursor, + }) async { + final client = ref.read(apiClientProvider); + final offset = cursor == null ? 0 : int.parse(cursor); try { - final response = await _apiClient.get( - '/stickers?offset=$offset&take=$take', + final response = await client.get( + '/stickers', + queryParameters: { + 'offset': offset, + 'take': _pageSize, + 'pubName': pubName, + }, ); - if (response.statusCode == 200) { - total = int.parse(response.headers.value('X-Total') ?? '0'); - final newStickers = - response.data - .map((e) => SnStickerPack.fromJson(e)) - .cast() - .toList(); - state = AsyncValue.data( - state.valueOrNull != null - ? [...state.value!, ...newStickers] - : newStickers, - ); - offset += take; - } else { - state = AsyncValue.error('Failed to load stickers', StackTrace.current); - } - } catch (err, stackTrace) { - state = AsyncValue.error(err, stackTrace); - } finally { - isLoading = false; + final total = int.parse(response.headers.value('X-Total') ?? '0'); + final List data = response.data; + final stickers = data.map((e) => SnStickerPack.fromJson(e)).toList(); + + final hasMore = offset + stickers.length < total; + final nextCursor = hasMore ? (offset + stickers.length).toString() : null; + + return CursorPagingData( + items: stickers, + hasMore: hasMore, + nextCursor: nextCursor, + ); + } catch (err) { + rethrow; } } - - Future fetchMore() async { - if (state.valueOrNull == null || state.valueOrNull!.length >= total) return; - await fetchStickers(); - } - - Future refresh() async { - offset = 0; - state = const AsyncValue.loading(); - await fetchStickers(); - } } @riverpod diff --git a/lib/screens/creators/stickers/stickers.g.dart b/lib/screens/creators/stickers/stickers.g.dart index d3bae95..583b25e 100644 --- a/lib/screens/creators/stickers/stickers.g.dart +++ b/lib/screens/creators/stickers/stickers.g.dart @@ -147,5 +147,154 @@ class _StickerPackProviderElement String? get packId => (origin as StickerPackProvider).packId; } +String _$stickerPacksNotifierHash() => + r'2feff50a7896eb8759fe91e9626b0409354d9fee'; + +abstract class _$StickerPacksNotifier + extends BuildlessAutoDisposeAsyncNotifier> { + late final String pubName; + + FutureOr> build(String pubName); +} + +/// See also [StickerPacksNotifier]. +@ProviderFor(StickerPacksNotifier) +const stickerPacksNotifierProvider = StickerPacksNotifierFamily(); + +/// See also [StickerPacksNotifier]. +class StickerPacksNotifierFamily + extends Family>> { + /// See also [StickerPacksNotifier]. + const StickerPacksNotifierFamily(); + + /// See also [StickerPacksNotifier]. + StickerPacksNotifierProvider call(String pubName) { + return StickerPacksNotifierProvider(pubName); + } + + @override + StickerPacksNotifierProvider getProviderOverride( + covariant StickerPacksNotifierProvider provider, + ) { + return call(provider.pubName); + } + + static const Iterable? _dependencies = null; + + @override + Iterable? get dependencies => _dependencies; + + static const Iterable? _allTransitiveDependencies = null; + + @override + Iterable? get allTransitiveDependencies => + _allTransitiveDependencies; + + @override + String? get name => r'stickerPacksNotifierProvider'; +} + +/// See also [StickerPacksNotifier]. +class StickerPacksNotifierProvider + extends + AutoDisposeAsyncNotifierProviderImpl< + StickerPacksNotifier, + CursorPagingData + > { + /// See also [StickerPacksNotifier]. + StickerPacksNotifierProvider(String pubName) + : this._internal( + () => StickerPacksNotifier()..pubName = pubName, + from: stickerPacksNotifierProvider, + name: r'stickerPacksNotifierProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') + ? null + : _$stickerPacksNotifierHash, + dependencies: StickerPacksNotifierFamily._dependencies, + allTransitiveDependencies: + StickerPacksNotifierFamily._allTransitiveDependencies, + pubName: pubName, + ); + + StickerPacksNotifierProvider._internal( + super._createNotifier, { + required super.name, + required super.dependencies, + required super.allTransitiveDependencies, + required super.debugGetCreateSourceHash, + required super.from, + required this.pubName, + }) : super.internal(); + + final String pubName; + + @override + FutureOr> runNotifierBuild( + covariant StickerPacksNotifier notifier, + ) { + return notifier.build(pubName); + } + + @override + Override overrideWith(StickerPacksNotifier Function() create) { + return ProviderOverride( + origin: this, + override: StickerPacksNotifierProvider._internal( + () => create()..pubName = pubName, + from: from, + name: null, + dependencies: null, + allTransitiveDependencies: null, + debugGetCreateSourceHash: null, + pubName: pubName, + ), + ); + } + + @override + AutoDisposeAsyncNotifierProviderElement< + StickerPacksNotifier, + CursorPagingData + > + createElement() { + return _StickerPacksNotifierProviderElement(this); + } + + @override + bool operator ==(Object other) { + return other is StickerPacksNotifierProvider && other.pubName == pubName; + } + + @override + int get hashCode { + var hash = _SystemHash.combine(0, runtimeType.hashCode); + hash = _SystemHash.combine(hash, pubName.hashCode); + + return _SystemHash.finish(hash); + } +} + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +mixin StickerPacksNotifierRef + on AutoDisposeAsyncNotifierProviderRef> { + /// The parameter `pubName` of this provider. + String get pubName; +} + +class _StickerPacksNotifierProviderElement + extends + AutoDisposeAsyncNotifierProviderElement< + StickerPacksNotifier, + CursorPagingData + > + with StickerPacksNotifierRef { + _StickerPacksNotifierProviderElement(super.provider); + + @override + String get pubName => (origin as StickerPacksNotifierProvider).pubName; +} + // ignore_for_file: type=lint // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package diff --git a/lib/screens/posts/compose.dart b/lib/screens/posts/compose.dart index d0a1f26..2d87525 100644 --- a/lib/screens/posts/compose.dart +++ b/lib/screens/posts/compose.dart @@ -142,7 +142,7 @@ class PostComposeScreen extends HookConsumerWidget { attachmentProgress.value = {...attachmentProgress.value, index: 0}; final cloudFile = await putMediaToCloud( - fileData: attachment.data, + fileData: attachment, atk: token, baseUrl: baseUrl, filename: attachment.data.name ?? 'Post media', diff --git a/lib/widgets/content/attachment_preview.dart b/lib/widgets/content/attachment_preview.dart index 25c8be7..8932dda 100644 --- a/lib/widgets/content/attachment_preview.dart +++ b/lib/widgets/content/attachment_preview.dart @@ -43,7 +43,23 @@ class AttachmentPreview extends StatelessWidget { return CloudFileWidget(item: item.data); } else if (item.data is XFile) { if (item.type == UniversalFileType.image) { - return Image.file(File(item.data.path)); + final file = item.data as XFile; + if (file.path.isEmpty) { + return FutureBuilder( + future: file.readAsBytes(), + builder: (context, snapshot) { + if (snapshot.hasData) { + return Image.memory(snapshot.data!); + } + return const Center( + child: CircularProgressIndicator(), + ); + }, + ); + } + return kIsWeb + ? Image.network(file.path) + : Image.file(File(file.path)); } else { return Center( child: Text( diff --git a/lib/widgets/content/cloud_file_collection.dart b/lib/widgets/content/cloud_file_collection.dart index 7007185..0501296 100644 --- a/lib/widgets/content/cloud_file_collection.dart +++ b/lib/widgets/content/cloud_file_collection.dart @@ -6,13 +6,17 @@ import 'package:flutter/material.dart'; import 'package:flutter_blurhash/flutter_blurhash.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:gap/gap.dart'; +import 'package:gal/gal.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:island/models/file.dart'; import 'package:island/pods/config.dart'; import 'package:island/widgets/content/cloud_files.dart'; +import 'package:path/path.dart' show extension; +import 'package:path_provider/path_provider.dart'; import 'package:photo_view/photo_view.dart'; import 'package:styled_widget/styled_widget.dart'; import 'package:uuid/uuid.dart'; +import 'package:dio/dio.dart'; class CloudFileList extends HookConsumerWidget { final List files; @@ -110,6 +114,7 @@ class CloudFileList extends HookConsumerWidget { heroTag: heroTags[i], isImage: files[i].mimeType?.startsWith('image') ?? false, disableZoomIn: disableZoomIn, + fit: BoxFit.cover, ), ], onTap: (i) { @@ -175,6 +180,47 @@ class CloudFileZoomIn extends HookConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { final serverUrl = ref.watch(serverUrlProvider); final photoViewController = useMemoized(() => PhotoViewController(), []); + final rotation = useState(0); + + Future saveToGallery() async { + try { + // Show loading indicator + final scaffold = ScaffoldMessenger.of(context); + scaffold.showSnackBar( + const SnackBar( + content: Text('Saving image to gallery...'), + duration: Duration(seconds: 1), + ), + ); + + // Get the image URL + final imageUrl = '$serverUrl/files/${item.id}?original=true'; + + // Create a temporary file to save the image + final tempDir = await getTemporaryDirectory(); + final filePath = '${tempDir.path}/${item.id}.${extension(item.name)}'; + + await Dio().download(imageUrl, filePath); + await Gal.putImage(filePath); + + // Show success message + scaffold.showSnackBar( + const SnackBar( + content: Text('Image saved to gallery'), + duration: Duration(seconds: 2), + ), + ); + } catch (e) { + // Show error message + if (!context.mounted) return; + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Failed to save image: $e'), + duration: const Duration(seconds: 2), + ), + ); + } + } return DismissiblePage( isFullScreen: true, @@ -195,16 +241,119 @@ class CloudFileZoomIn extends HookConsumerWidget { imageProvider: CloudImageWidget.provider( fileId: item.id, serverUrl: serverUrl, + original: true, ), + // Apply rotation transformation + customSize: MediaQuery.of(context).size, + basePosition: Alignment.center, + filterQuality: FilterQuality.high, ), ), - // Close button + // Close button and save button Positioned( - top: MediaQuery.of(context).padding.top + 20, - right: 20, - child: IconButton( - icon: Icon(Icons.close, color: Colors.white), - onPressed: () => Navigator.of(context).pop(), + top: MediaQuery.of(context).padding.top + 16, + right: 16, + left: 16, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + IconButton( + icon: Icon( + Icons.save_alt, + color: Colors.white, + shadows: [ + Shadow( + color: Colors.black54, + blurRadius: 5.0, + offset: Offset(1.0, 1.0), + ), + ], + ), + onPressed: () async { + saveToGallery(); + }, + ), + ], + ), + IconButton( + icon: Icon( + Icons.close, + color: Colors.white, + shadows: [ + Shadow( + color: Colors.black54, + blurRadius: 5.0, + offset: Offset(1.0, 1.0), + ), + ], + ), + onPressed: () => Navigator.of(context).pop(), + ), + ], + ), + ), + // Rotation controls + Positioned( + bottom: MediaQuery.of(context).padding.bottom + 16, + left: 16, + right: 16, + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + IconButton( + icon: Icon(Icons.remove, color: Colors.white), + onPressed: () { + photoViewController.scale = + (photoViewController.scale ?? 1) - 0.05; + }, + ), + IconButton( + icon: Icon(Icons.add, color: Colors.white), + onPressed: () { + photoViewController.scale = + (photoViewController.scale ?? 1) + 0.05; + }, + ), + const Gap(8), + IconButton( + icon: Icon( + Icons.rotate_left, + color: Colors.white, + shadows: [ + Shadow( + color: Colors.black54, + blurRadius: 5.0, + offset: Offset(1.0, 1.0), + ), + ], + ), + onPressed: () { + rotation.value = (rotation.value - 1) % 4; + photoViewController.rotation = + rotation.value * -math.pi / 2; + }, + ), + IconButton( + icon: Icon( + Icons.rotate_right, + color: Colors.white, + shadows: [ + Shadow( + color: Colors.black54, + blurRadius: 5.0, + offset: Offset(1.0, 1.0), + ), + ], + ), + onPressed: () { + rotation.value = (rotation.value + 1) % 4; + photoViewController.rotation = + rotation.value * -math.pi / 2; + }, + ), + ], ), ), ], @@ -219,6 +368,7 @@ class _CloudFileListEntry extends StatelessWidget { final bool isImage; final bool disableZoomIn; final VoidCallback? onTap; + final BoxFit fit; const _CloudFileListEntry({ required this.file, @@ -226,11 +376,13 @@ class _CloudFileListEntry extends StatelessWidget { required this.isImage, required this.disableZoomIn, this.onTap, + this.fit = BoxFit.contain, }); @override Widget build(BuildContext context) { final content = Stack( + fit: StackFit.expand, children: [ if (isImage) Positioned.fill( @@ -247,9 +399,10 @@ class _CloudFileListEntry extends StatelessWidget { item: file, heroTag: heroTag, noBlurhash: true, - ).center() + fit: fit, + ) else - CloudFileWidget(item: file, heroTag: heroTag), + CloudFileWidget(item: file, heroTag: heroTag, fit: fit), ], ); diff --git a/lib/widgets/content/cloud_file_picker.dart b/lib/widgets/content/cloud_file_picker.dart index 3ade712..3cc8c68 100644 --- a/lib/widgets/content/cloud_file_picker.dart +++ b/lib/widgets/content/cloud_file_picker.dart @@ -56,7 +56,7 @@ class CloudFilePicker extends HookConsumerWidget { final file = files.value[idx]; final cloudFile = await putMediaToCloud( - fileData: file.data, + fileData: file, atk: token, baseUrl: baseUrl, filename: file.data.name ?? 'Post media', diff --git a/lib/widgets/content/cloud_files.dart b/lib/widgets/content/cloud_files.dart index 9f15337..359a862 100644 --- a/lib/widgets/content/cloud_files.dart +++ b/lib/widgets/content/cloud_files.dart @@ -79,8 +79,9 @@ class CloudImageWidget extends ConsumerWidget { static ImageProvider provider({ required String fileId, required String serverUrl, + bool original = false, }) { - final uri = '$serverUrl/files/$fileId'; + final uri = '$serverUrl/files/$fileId?original=$original'; return CachedNetworkImageProvider(uri); } } diff --git a/macos/Podfile.lock b/macos/Podfile.lock index 10c06ee..55cc8b0 100644 --- a/macos/Podfile.lock +++ b/macos/Podfile.lock @@ -107,6 +107,8 @@ PODS: - Flutter - FlutterMacOS - PromisesObjC (2.4.0) + - record_macos (1.0.0): + - FlutterMacOS - SAMKeychain (1.5.3) - shared_preferences_foundation (0.0.1): - Flutter @@ -167,6 +169,7 @@ DEPENDENCIES: - package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`) - pasteboard (from `Flutter/ephemeral/.symlinks/plugins/pasteboard/macos`) - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`) + - record_macos (from `Flutter/ephemeral/.symlinks/plugins/record_macos/macos`) - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`) - sqflite_darwin (from `Flutter/ephemeral/.symlinks/plugins/sqflite_darwin/darwin`) - sqlite3_flutter_libs (from `Flutter/ephemeral/.symlinks/plugins/sqlite3_flutter_libs/darwin`) @@ -232,6 +235,8 @@ EXTERNAL SOURCES: :path: Flutter/ephemeral/.symlinks/plugins/pasteboard/macos path_provider_foundation: :path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin + record_macos: + :path: Flutter/ephemeral/.symlinks/plugins/record_macos/macos shared_preferences_foundation: :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin sqflite_darwin: @@ -278,6 +283,7 @@ SPEC CHECKSUMS: pasteboard: 278d8100149f940fb795d6b3a74f0720c890ecb7 path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564 PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 + record_macos: 295d70bd5fb47145df78df7b80e6697cd18403c0 SAMKeychain: 483e1c9f32984d50ca961e26818a534283b4cd5c shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7 sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0 diff --git a/macos/Runner/Info.plist b/macos/Runner/Info.plist index aff0216..ea79168 100644 --- a/macos/Runner/Info.plist +++ b/macos/Runner/Info.plist @@ -15,7 +15,7 @@ CFBundleInfoDictionaryVersion 6.0 CFBundleName - $(PRODUCT_NAME) + Solian CFBundlePackageType APPL CFBundleShortVersionString diff --git a/pubspec.lock b/pubspec.lock index 5a52011..90bf095 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -917,6 +917,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.0" + gal: + dependency: "direct main" + description: + name: gal + sha256: "1bdef5879e4569910cfd8c77f460f98fcb7a1f910026af1daa80869856c67d66" + url: "https://pub.dev" + source: hosted + version: "1.9.1" gap: dependency: "direct main" description: @@ -2041,7 +2049,7 @@ packages: description: path: "." ref: HEAD - resolved-ref: "55fd380bcca8c984773711062ac7dfdbfa87c9d1" + resolved-ref: "55e0eecfb7a7af67be4a7b6e8e73d128d4460436" url: "https://github.com/LittleSheep2Code/tus_client.git" source: git version: "2.5.0" diff --git a/pubspec.yaml b/pubspec.yaml index 2007d85..0280a9d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -98,6 +98,7 @@ dependencies: visibility_detector: ^0.4.0+2 flutter_native_splash: ^2.4.6 photo_view: ^0.15.0 + gal: ^1.9.1 dismissible_page: ^1.0.2 super_sliver_list: ^0.4.1 flutter_webrtc: ^0.14.1