Compare commits
	
		
			3 Commits
		
	
	
		
			3.2.0+133
			...
			b4996d069f
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| b4996d069f | |||
| bf4892b34d | |||
| 5f84751fd5 | 
| @@ -33,17 +33,27 @@ class AppDatabase extends _$AppDatabase { | |||||||
|         await _migrateToVersion6(m); |         await _migrateToVersion6(m); | ||||||
|       } |       } | ||||||
|       if (from < 7) { |       if (from < 7) { | ||||||
|         // Add new columns from SnChatMessage |         // Add new columns from SnChatMessage, ignore if they already exist | ||||||
|         await m.addColumn(chatMessages, chatMessages.updatedAt); |         final columnsToAdd = [ | ||||||
|         await m.addColumn(chatMessages, chatMessages.deletedAt); |           chatMessages.updatedAt, | ||||||
|         await m.addColumn(chatMessages, chatMessages.type); |           chatMessages.deletedAt, | ||||||
|         await m.addColumn(chatMessages, chatMessages.meta); |           chatMessages.type, | ||||||
|         await m.addColumn(chatMessages, chatMessages.membersMentioned); |           chatMessages.meta, | ||||||
|         await m.addColumn(chatMessages, chatMessages.editedAt); |           chatMessages.membersMentioned, | ||||||
|         await m.addColumn(chatMessages, chatMessages.attachments); |           chatMessages.editedAt, | ||||||
|         await m.addColumn(chatMessages, chatMessages.reactions); |           chatMessages.attachments, | ||||||
|         await m.addColumn(chatMessages, chatMessages.repliedMessageId); |           chatMessages.reactions, | ||||||
|         await m.addColumn(chatMessages, chatMessages.forwardedMessageId); |           chatMessages.repliedMessageId, | ||||||
|  |           chatMessages.forwardedMessageId, | ||||||
|  |         ]; | ||||||
|  |  | ||||||
|  |         for (final column in columnsToAdd) { | ||||||
|  |           try { | ||||||
|  |             await m.addColumn(chatMessages, column); | ||||||
|  |           } catch (e) { | ||||||
|  |             // Column already exists, skip | ||||||
|  |           } | ||||||
|  |         } | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|   ); |   ); | ||||||
|   | |||||||
| @@ -23,31 +23,3 @@ sealed class SnFilePool with _$SnFilePool { | |||||||
|   factory SnFilePool.fromJson(Map<String, dynamic> json) => |   factory SnFilePool.fromJson(Map<String, dynamic> json) => | ||||||
|       _$SnFilePoolFromJson(json); |       _$SnFilePoolFromJson(json); | ||||||
| } | } | ||||||
|  |  | ||||||
| extension SnFilePoolList on List<SnFilePool> { |  | ||||||
|   static List<SnFilePool> listFromResponse(dynamic data) { |  | ||||||
|     if (data is List) { |  | ||||||
|       return data |  | ||||||
|           .whereType<Map<String, dynamic>>() |  | ||||||
|           .map(SnFilePool.fromJson) |  | ||||||
|           .toList(); |  | ||||||
|     } |  | ||||||
|     throw ArgumentError('Unexpected response format: $data'); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   List<SnFilePool> filterValid() { |  | ||||||
|     return where((p) { |  | ||||||
|       final accept = p.policyConfig?['accept_types']; |  | ||||||
|  |  | ||||||
|       if (accept is List) { |  | ||||||
|         final acceptsOnlyMedia = accept.every((t) => |  | ||||||
|             t is String && |  | ||||||
|             (t.startsWith('image/') || |  | ||||||
|                 t.startsWith('video/') || |  | ||||||
|                 t.startsWith('audio/'))); |  | ||||||
|         if (acceptsOnlyMedia) return false; |  | ||||||
|       } |  | ||||||
|       return true; |  | ||||||
|     }).toList(); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|   | |||||||
| @@ -6,23 +6,19 @@ import 'package:island/pods/network.dart'; | |||||||
| final poolsProvider = FutureProvider<List<SnFilePool>>((ref) async { | final poolsProvider = FutureProvider<List<SnFilePool>>((ref) async { | ||||||
|   final dio = ref.watch(apiClientProvider); |   final dio = ref.watch(apiClientProvider); | ||||||
|   final response = await dio.get('/drive/pools'); |   final response = await dio.get('/drive/pools'); | ||||||
|   final pools = SnFilePoolList.listFromResponse(response.data); |   return response.data | ||||||
|   return pools.filterValid(); |       .map((e) => SnFilePool.fromJson(e)) | ||||||
|  |       .cast<SnFilePool>() | ||||||
|  |       .toList(); | ||||||
| }); | }); | ||||||
|  |  | ||||||
| String resolveDefaultPoolId(WidgetRef ref, List<SnFilePool> pools) { | String? resolveDefaultPoolId(WidgetRef ref, List<SnFilePool> pools) { | ||||||
|   final settings = ref.watch(appSettingsNotifierProvider); |   final settings = ref.watch(appSettingsNotifierProvider); | ||||||
|   final validPools = pools.filterValid(); |  | ||||||
|  |  | ||||||
|   final configuredId = settings.defaultPoolId; |   final configuredId = settings.defaultPoolId; | ||||||
|   if (configuredId != null && validPools.any((p) => p.id == configuredId)) { |   if (configuredId != null && pools.any((p) => p.id == configuredId)) { | ||||||
|     return configuredId; |     return configuredId; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   if (validPools.isNotEmpty) { |   return pools.firstOrNull?.id; | ||||||
|     return validPools.first.id; | } | ||||||
|   } |  | ||||||
|  |  | ||||||
|   // DEFAULT: Solar Network Driver |  | ||||||
|   return '500e5ed8-bd44-4359-bc0a-ec85e2adf447'; } |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -10,17 +10,19 @@ Future<void> resetDatabase(WidgetRef ref) async { | |||||||
|   if (kIsWeb) return; |   if (kIsWeb) return; | ||||||
|  |  | ||||||
|   final db = ref.read(databaseProvider); |   final db = ref.read(databaseProvider); | ||||||
|   final basepath = await getApplicationSupportDirectory(); |  | ||||||
|   final file = File(join(basepath.path, 'solar_network_data.sqlite')); |  | ||||||
|  |  | ||||||
|   // Close current database connection |   // Close current database connection | ||||||
|   db.close(); |   await db.close(); | ||||||
|  |  | ||||||
|   // Delete database file |   // Get the correct database file path | ||||||
|  |   final dbFolder = await getApplicationDocumentsDirectory(); | ||||||
|  |   final file = File(join(dbFolder.path, 'solar_network_data.sqlite')); | ||||||
|  |  | ||||||
|  |   // Delete database file if it exists | ||||||
|   if (await file.exists()) { |   if (await file.exists()) { | ||||||
|     await file.delete(); |     await file.delete(); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   // Force refresh the database provider |   // Force refresh the database provider to create a new instance | ||||||
|   ref.invalidate(databaseProvider); |   ref.invalidate(databaseProvider); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -935,7 +935,7 @@ class _ChatAttachmentUploaderSheetState | |||||||
|           if (snapshot.hasError) { |           if (snapshot.hasError) { | ||||||
|             return Center(child: Text('errorLoadingPools'.tr())); |             return Center(child: Text('errorLoadingPools'.tr())); | ||||||
|           } |           } | ||||||
|           final pools = snapshot.data!.filterValid(); |           final pools = snapshot.data!; | ||||||
|           selectedPoolId ??= resolveDefaultPoolId(widget.ref, pools); |           selectedPoolId ??= resolveDefaultPoolId(widget.ref, pools); | ||||||
|  |  | ||||||
|           return Column( |           return Column( | ||||||
| @@ -1162,9 +1162,7 @@ class _ChatAttachmentUploaderSheetState | |||||||
|  |  | ||||||
|     // Get the selected pool to check constraints |     // Get the selected pool to check constraints | ||||||
|     final pools = await widget.ref.read(poolsProvider.future); |     final pools = await widget.ref.read(poolsProvider.future); | ||||||
|     final selectedPool = pools.filterValid().firstWhere( |     final selectedPool = pools.firstWhere((p) => p.id == selectedPoolId); | ||||||
|       (p) => p.id == selectedPoolId, |  | ||||||
|     ); |  | ||||||
|  |  | ||||||
|     // Check constraints |     // Check constraints | ||||||
|     final maxFileSize = selectedPool.policyConfig?['max_file_size'] as int?; |     final maxFileSize = selectedPool.policyConfig?['max_file_size'] as int?; | ||||||
|   | |||||||
| @@ -6,7 +6,7 @@ part of 'file_list.dart'; | |||||||
| // RiverpodGenerator | // RiverpodGenerator | ||||||
| // ************************************************************************** | // ************************************************************************** | ||||||
|  |  | ||||||
| String _$billingUsageHash() => r'270ec8499378ee0c038aa44ad1c2e3ad9025740a'; | String _$billingUsageHash() => r'58d8bc774868d60781574c85d6b25869a79c57aa'; | ||||||
|  |  | ||||||
| /// See also [billingUsage]. | /// See also [billingUsage]. | ||||||
| @ProviderFor(billingUsage) | @ProviderFor(billingUsage) | ||||||
| @@ -25,7 +25,7 @@ final billingUsageProvider = | |||||||
| @Deprecated('Will be removed in 3.0. Use Ref instead') | @Deprecated('Will be removed in 3.0. Use Ref instead') | ||||||
| // ignore: unused_element | // ignore: unused_element | ||||||
| typedef BillingUsageRef = AutoDisposeFutureProviderRef<Map<String, dynamic>?>; | typedef BillingUsageRef = AutoDisposeFutureProviderRef<Map<String, dynamic>?>; | ||||||
| String _$billingQuotaHash() => r'0696b500fa8bb1270641bcacf262be58caff9b38'; | String _$billingQuotaHash() => r'4ec5d728e439015800abb2d0d673b5a7329cc654'; | ||||||
|  |  | ||||||
| /// See also [billingQuota]. | /// See also [billingQuota]. | ||||||
| @ProviderFor(billingQuota) | @ProviderFor(billingQuota) | ||||||
| @@ -45,7 +45,7 @@ final billingQuotaProvider = | |||||||
| // ignore: unused_element | // ignore: unused_element | ||||||
| typedef BillingQuotaRef = AutoDisposeFutureProviderRef<Map<String, dynamic>?>; | typedef BillingQuotaRef = AutoDisposeFutureProviderRef<Map<String, dynamic>?>; | ||||||
| String _$cloudFileListNotifierHash() => | String _$cloudFileListNotifierHash() => | ||||||
|     r'e2c8a076a9e635c7b43a87d00f78775427ba6334'; |     r'22c45a8ea23147a3835ba870ad2f0bb833f853ea'; | ||||||
|  |  | ||||||
| /// See also [CloudFileListNotifier]. | /// See also [CloudFileListNotifier]. | ||||||
| @ProviderFor(CloudFileListNotifier) | @ProviderFor(CloudFileListNotifier) | ||||||
|   | |||||||
| @@ -22,7 +22,6 @@ import 'package:path_provider/path_provider.dart'; | |||||||
| import 'package:styled_widget/styled_widget.dart'; | import 'package:styled_widget/styled_widget.dart'; | ||||||
| import 'package:island/pods/config.dart'; | import 'package:island/pods/config.dart'; | ||||||
| import 'package:island/pods/file_pool.dart'; | import 'package:island/pods/file_pool.dart'; | ||||||
| import 'package:island/models/file_pool.dart'; |  | ||||||
|  |  | ||||||
| class SettingsScreen extends HookConsumerWidget { | class SettingsScreen extends HookConsumerWidget { | ||||||
|   const SettingsScreen({super.key}); |   const SettingsScreen({super.key}); | ||||||
| @@ -417,7 +416,7 @@ class SettingsScreen extends HookConsumerWidget { | |||||||
|       if (user.value != null) |       if (user.value != null) | ||||||
|         pools.when( |         pools.when( | ||||||
|           data: (data) { |           data: (data) { | ||||||
|             final validPools = data.filterValid(); |             final validPools = data; | ||||||
|             final currentPoolId = resolveDefaultPoolId(ref, data); |             final currentPoolId = resolveDefaultPoolId(ref, data); | ||||||
|  |  | ||||||
|             return ListTile( |             return ListTile( | ||||||
| @@ -437,11 +436,14 @@ class SettingsScreen extends HookConsumerWidget { | |||||||
|                       validPools.map((p) { |                       validPools.map((p) { | ||||||
|                         return DropdownMenuItem<String>( |                         return DropdownMenuItem<String>( | ||||||
|                           value: p.id, |                           value: p.id, | ||||||
|  |                           child: Tooltip( | ||||||
|  |                             message: p.name, | ||||||
|                             child: Text( |                             child: Text( | ||||||
|                               p.name, |                               p.name, | ||||||
|                               maxLines: 1, |                               maxLines: 1, | ||||||
|                               overflow: TextOverflow.ellipsis, |                               overflow: TextOverflow.ellipsis, | ||||||
|                             ).fontSize(14), |                             ).fontSize(14), | ||||||
|  |                           ), | ||||||
|                         ); |                         ); | ||||||
|                       }).toList(), |                       }).toList(), | ||||||
|                   value: currentPoolId, |                   value: currentPoolId, | ||||||
|   | |||||||
| @@ -147,6 +147,7 @@ class AccountProfileCard extends HookConsumerWidget { | |||||||
|                       if (data.badges.isNotEmpty) |                       if (data.badges.isNotEmpty) | ||||||
|                         BadgeList(badges: data.badges).padding(top: 12), |                         BadgeList(badges: data.badges).padding(top: 12), | ||||||
|                       LevelingProgressCard( |                       LevelingProgressCard( | ||||||
|  |                         isCompact: true, | ||||||
|                         level: data.profile.level, |                         level: data.profile.level, | ||||||
|                         experience: data.profile.experience, |                         experience: data.profile.experience, | ||||||
|                         progress: data.profile.levelingProgress, |                         progress: data.profile.levelingProgress, | ||||||
|   | |||||||
| @@ -59,7 +59,7 @@ class _AttachmentUploaderSheetState extends State<AttachmentUploaderSheet> { | |||||||
|           if (snapshot.hasError) { |           if (snapshot.hasError) { | ||||||
|             return Center(child: Text('errorLoadingPools'.tr())); |             return Center(child: Text('errorLoadingPools'.tr())); | ||||||
|           } |           } | ||||||
|           final pools = snapshot.data!.filterValid(); |           final pools = snapshot.data!; | ||||||
|           selectedPoolId ??= resolveDefaultPoolId(widget.ref, pools); |           selectedPoolId ??= resolveDefaultPoolId(widget.ref, pools); | ||||||
|  |  | ||||||
|           return Column( |           return Column( | ||||||
| @@ -286,9 +286,7 @@ class _AttachmentUploaderSheetState extends State<AttachmentUploaderSheet> { | |||||||
|  |  | ||||||
|     // Get the selected pool to check constraints |     // Get the selected pool to check constraints | ||||||
|     final pools = await widget.ref.read(poolsProvider.future); |     final pools = await widget.ref.read(poolsProvider.future); | ||||||
|     final selectedPool = pools.filterValid().firstWhere( |     final selectedPool = pools.firstWhere((p) => p.id == selectedPoolId); | ||||||
|       (p) => p.id == selectedPoolId, |  | ||||||
|     ); |  | ||||||
|  |  | ||||||
|     // Check constraints |     // Check constraints | ||||||
|     final maxFileSize = selectedPool.policyConfig?['max_file_size'] as int?; |     final maxFileSize = selectedPool.policyConfig?['max_file_size'] as int?; | ||||||
|   | |||||||
| @@ -130,7 +130,7 @@ class MessageItem extends HookConsumerWidget { | |||||||
|  |  | ||||||
|     useEffect(() { |     useEffect(() { | ||||||
|       if (flashing) { |       if (flashing) { | ||||||
|         if (flashTimer.value != null) return null; |         flashTimer.value?.cancel(); | ||||||
|         isFlashing.value = true; |         isFlashing.value = true; | ||||||
|         flashTimer.value = Timer.periodic( |         flashTimer.value = Timer.periodic( | ||||||
|           const Duration(milliseconds: kFlashDuration), |           const Duration(milliseconds: kFlashDuration), | ||||||
| @@ -343,6 +343,10 @@ class MessageItemDisplayBubble extends HookConsumerWidget { | |||||||
|         isCurrentUser |         isCurrentUser | ||||||
|             ? Theme.of(context).colorScheme.onPrimaryContainer |             ? Theme.of(context).colorScheme.onPrimaryContainer | ||||||
|             : Theme.of(context).colorScheme.onSurfaceVariant; |             : Theme.of(context).colorScheme.onSurfaceVariant; | ||||||
|  |     final containerColor = | ||||||
|  |         isCurrentUser | ||||||
|  |             ? Theme.of(context).colorScheme.primaryContainer.withOpacity(0.5) | ||||||
|  |             : Theme.of(context).colorScheme.surfaceContainer; | ||||||
|  |  | ||||||
|     final hasBackground = |     final hasBackground = | ||||||
|         ref.watch(backgroundImageFileProvider).valueOrNull != null; |         ref.watch(backgroundImageFileProvider).valueOrNull != null; | ||||||
| @@ -377,6 +381,15 @@ class MessageItemDisplayBubble extends HookConsumerWidget { | |||||||
|               crossAxisAlignment: CrossAxisAlignment.end, |               crossAxisAlignment: CrossAxisAlignment.end, | ||||||
|               children: [ |               children: [ | ||||||
|                 Flexible( |                 Flexible( | ||||||
|  |                   child: Container( | ||||||
|  |                     decoration: BoxDecoration( | ||||||
|  |                       color: containerColor, | ||||||
|  |                       borderRadius: BorderRadius.circular(16), | ||||||
|  |                     ), | ||||||
|  |                     padding: const EdgeInsets.symmetric( | ||||||
|  |                       horizontal: 12, | ||||||
|  |                       vertical: 6, | ||||||
|  |                     ), | ||||||
|                     child: Column( |                     child: Column( | ||||||
|                       crossAxisAlignment: CrossAxisAlignment.start, |                       crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|                       children: [ |                       children: [ | ||||||
| @@ -471,6 +484,7 @@ class MessageItemDisplayBubble extends HookConsumerWidget { | |||||||
|                       ], |                       ], | ||||||
|                     ), |                     ), | ||||||
|                   ), |                   ), | ||||||
|  |                 ), | ||||||
|                 MessageIndicators( |                 MessageIndicators( | ||||||
|                   editedAt: remoteMessage.editedAt, |                   editedAt: remoteMessage.editedAt, | ||||||
|                   status: message.status, |                   status: message.status, | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| ; ================================================== | ; ================================================== | ||||||
| #define AppVersion "3.2.0" | #define AppVersion "3.2.0" | ||||||
| #define BuildNumber "132" | #define BuildNumber "134" | ||||||
| ; ================================================== | ; ================================================== | ||||||
|  |  | ||||||
| #define FullVersion AppVersion + "." + BuildNumber | #define FullVersion AppVersion + "." + BuildNumber | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user