Compare commits
22 Commits
3.2.0+125
...
5d4b896f70
Author | SHA1 | Date | |
---|---|---|---|
|
5d4b896f70 | ||
|
a04dffdfe8 | ||
|
ff871943cf | ||
|
1a892ab227 | ||
|
af1b303211 | ||
|
6fd702eba8 | ||
|
d220d43cd2 | ||
|
6892afb974 | ||
|
007b46b080 | ||
|
67d130dc34 | ||
|
7e923c77fe | ||
|
a593b52812 | ||
|
520dc80303 | ||
|
001897bbcd | ||
|
bab29c23e3 | ||
|
76b39f2df3 | ||
|
509b3e145b | ||
|
2b80ebc2d0 | ||
|
0ab908dd2a | ||
|
6007467e7a | ||
|
3745157c42 | ||
|
94481ec7bd |
@@ -334,6 +334,7 @@
|
||||
"walletCreate": "Create a Wallet",
|
||||
"settingsServerUrl": "Server URL",
|
||||
"settingsApplied": "The settings has been applied.",
|
||||
"settingsCustomFontsHelper": "Use comma to seprate.",
|
||||
"notifications": "Notifications",
|
||||
"posts": "Posts",
|
||||
"settingsBackgroundImage": "Background Image",
|
||||
@@ -836,5 +837,9 @@
|
||||
"pollAddOption": "Add option",
|
||||
"pollOptionLabel": "Option label",
|
||||
"pollLongTextAnswerPreview": "Long text answer (preview)",
|
||||
"pollShortTextAnswerPreview": "Short text answer (preview)"
|
||||
"pollShortTextAnswerPreview": "Short text answer (preview)",
|
||||
"messageJumpNotLoaded": "The referenced message was not loaded, unable to jump to it.",
|
||||
"postUnlinkRealm": "No linked realm",
|
||||
"postSlug": "Slug",
|
||||
"postSlugHint": "The slug can be used to access your post via URL in the webpage, it should be publisher-wide unique."
|
||||
}
|
@@ -300,6 +300,7 @@
|
||||
"walletCreate": "创建钱包",
|
||||
"settingsServerUrl": "服务器 URL",
|
||||
"settingsApplied": "设置已应用。",
|
||||
"settingsCustomFontsHelper": "用逗号分隔。",
|
||||
"notifications": "通知",
|
||||
"posts": "帖子",
|
||||
"settingsBackgroundImage": "背景图片",
|
||||
@@ -811,5 +812,9 @@
|
||||
"filesListAdditional": {
|
||||
"one": "+{} 个文件被折叠",
|
||||
"other": "+{} 个文件被折叠"
|
||||
}
|
||||
},
|
||||
"messageJumpNotLoaded": "引用的消息没有被加载,无法跳转。",
|
||||
"postUnlinkRealm": "不关联领域",
|
||||
"postSlug": "别名",
|
||||
"postSlugHint": "这个别名可以用于在网页通过 URL 浏览到你的帖子,它应该在同一发布者中是唯一。"
|
||||
}
|
@@ -245,7 +245,7 @@ PODS:
|
||||
- PromisesObjC (= 2.4.0)
|
||||
- receive_sharing_intent (1.8.1):
|
||||
- Flutter
|
||||
- record_ios (1.0.0):
|
||||
- record_ios (1.1.0):
|
||||
- Flutter
|
||||
- SAMKeychain (1.5.3)
|
||||
- SDWebImage (5.21.1):
|
||||
@@ -510,7 +510,7 @@ SPEC CHECKSUMS:
|
||||
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
|
||||
PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851
|
||||
receive_sharing_intent: 222384f00ffe7e952bbfabaa9e3967cb87e5fe00
|
||||
record_ios: fee1c924aa4879b882ebca2b4bce6011bcfc3d8b
|
||||
record_ios: f75fa1d57f840012775c0e93a38a7f3ceea1a374
|
||||
SAMKeychain: 483e1c9f32984d50ca961e26818a534283b4cd5c
|
||||
SDWebImage: f29024626962457f3470184232766516dee8dfea
|
||||
share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a
|
||||
|
@@ -1,484 +0,0 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:island/database/drift_db.dart';
|
||||
import 'package:island/database/message.dart';
|
||||
import 'package:island/models/chat.dart';
|
||||
import 'package:island/models/file.dart';
|
||||
import 'package:island/services/file.dart';
|
||||
import 'package:island/widgets/alert.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
class MessageRepository {
|
||||
final SnChatRoom room;
|
||||
final SnChatMember identity;
|
||||
final Dio _apiClient;
|
||||
final AppDatabase _database;
|
||||
|
||||
final Map<String, LocalChatMessage> pendingMessages = {};
|
||||
final Map<String, Map<int, double>> fileUploadProgress = {};
|
||||
int? _totalCount;
|
||||
|
||||
MessageRepository(this.room, this.identity, this._apiClient, this._database);
|
||||
|
||||
Future<LocalChatMessage?> getLastMessages() async {
|
||||
final dbMessages = await _database.getMessagesForRoom(
|
||||
room.id,
|
||||
offset: 0,
|
||||
limit: 1,
|
||||
);
|
||||
|
||||
if (dbMessages.isEmpty) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return _database.companionToMessage(dbMessages.first);
|
||||
}
|
||||
|
||||
Future<bool> syncMessages() async {
|
||||
final lastMessage = await getLastMessages();
|
||||
if (lastMessage == null) return false;
|
||||
try {
|
||||
final resp = await _apiClient.post(
|
||||
'/sphere/chat/${room.id}/sync',
|
||||
data: {
|
||||
'last_sync_timestamp':
|
||||
lastMessage.toRemoteMessage().updatedAt.millisecondsSinceEpoch,
|
||||
},
|
||||
);
|
||||
|
||||
final response = MessageSyncResponse.fromJson(resp.data);
|
||||
for (final change in response.changes) {
|
||||
switch (change.action) {
|
||||
case MessageChangeAction.create:
|
||||
await receiveMessage(change.message!);
|
||||
break;
|
||||
case MessageChangeAction.update:
|
||||
await receiveMessageUpdate(change.message!);
|
||||
break;
|
||||
case MessageChangeAction.delete:
|
||||
await receiveMessageDeletion(change.messageId.toString());
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
showErrorAlert(err);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Future<List<LocalChatMessage>> listMessages({
|
||||
int offset = 0,
|
||||
int take = 20,
|
||||
bool synced = false,
|
||||
}) async {
|
||||
try {
|
||||
// For initial load, fetch latest messages in the background to sync.
|
||||
if (offset == 0 && !synced) {
|
||||
// Not awaiting this is intentional, for a quicker UI response.
|
||||
// The UI should rely on a stream from the database to get updates.
|
||||
_fetchAndCacheMessages(room.id, offset: 0, take: take).catchError((_) {
|
||||
// Best effort, errors will be handled by later fetches.
|
||||
return <LocalChatMessage>[];
|
||||
});
|
||||
}
|
||||
|
||||
final localMessages = await _getCachedMessages(
|
||||
room.id,
|
||||
offset: offset,
|
||||
take: take,
|
||||
);
|
||||
|
||||
// If local cache has messages, return them. This is the common case for scrolling up.
|
||||
if (localMessages.isNotEmpty) {
|
||||
return localMessages;
|
||||
}
|
||||
|
||||
// If local cache is empty, we've probably reached the end of cached history.
|
||||
// Fetch from remote. This will also be hit on first load if cache is empty.
|
||||
return await _fetchAndCacheMessages(room.id, offset: offset, take: take);
|
||||
} catch (e) {
|
||||
// Final fallback to cache in case of network errors during fetch.
|
||||
final localMessages = await _getCachedMessages(
|
||||
room.id,
|
||||
offset: offset,
|
||||
take: take,
|
||||
);
|
||||
|
||||
if (localMessages.isNotEmpty) {
|
||||
return localMessages;
|
||||
}
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<LocalChatMessage>> _getCachedMessages(
|
||||
String roomId, {
|
||||
int offset = 0,
|
||||
int take = 20,
|
||||
}) async {
|
||||
// Get messages from local database
|
||||
final dbMessages = await _database.getMessagesForRoom(
|
||||
roomId,
|
||||
offset: offset,
|
||||
limit: take,
|
||||
);
|
||||
final dbLocalMessages =
|
||||
dbMessages.map(_database.companionToMessage).toList();
|
||||
|
||||
// Combine with pending messages for the first page
|
||||
if (offset == 0) {
|
||||
final pendingForRoom =
|
||||
pendingMessages.values.where((msg) => msg.roomId == roomId).toList();
|
||||
|
||||
final allMessages = [...pendingForRoom, ...dbLocalMessages];
|
||||
allMessages.sort((a, b) => b.createdAt.compareTo(a.createdAt));
|
||||
|
||||
// Remove duplicates by ID, preserving the order
|
||||
final uniqueMessages = <LocalChatMessage>[];
|
||||
final seenIds = <String>{};
|
||||
for (final message in allMessages) {
|
||||
if (seenIds.add(message.id)) {
|
||||
uniqueMessages.add(message);
|
||||
}
|
||||
}
|
||||
return uniqueMessages;
|
||||
}
|
||||
|
||||
return dbLocalMessages;
|
||||
}
|
||||
|
||||
Future<List<LocalChatMessage>> _fetchAndCacheMessages(
|
||||
String roomId, {
|
||||
int offset = 0,
|
||||
int take = 20,
|
||||
}) async {
|
||||
// Use cached total count if available, otherwise fetch it
|
||||
if (_totalCount == null) {
|
||||
final response = await _apiClient.get(
|
||||
'/sphere/chat/$roomId/messages',
|
||||
queryParameters: {'offset': 0, 'take': 1},
|
||||
);
|
||||
_totalCount = int.parse(response.headers['x-total']?.firstOrNull ?? '0');
|
||||
}
|
||||
|
||||
if (offset >= _totalCount!) {
|
||||
return [];
|
||||
}
|
||||
|
||||
final response = await _apiClient.get(
|
||||
'/sphere/chat/$roomId/messages',
|
||||
queryParameters: {'offset': offset, 'take': take},
|
||||
);
|
||||
|
||||
final List<dynamic> data = response.data;
|
||||
// Update total count from response headers
|
||||
_totalCount = int.parse(response.headers['x-total']?.firstOrNull ?? '0');
|
||||
|
||||
final messages =
|
||||
data.map((json) {
|
||||
final remoteMessage = SnChatMessage.fromJson(json);
|
||||
return LocalChatMessage.fromRemoteMessage(
|
||||
remoteMessage,
|
||||
MessageStatus.sent,
|
||||
);
|
||||
}).toList();
|
||||
|
||||
for (final message in messages) {
|
||||
await _database.saveMessage(_database.messageToCompanion(message));
|
||||
if (message.nonce != null) {
|
||||
pendingMessages.removeWhere(
|
||||
(_, pendingMsg) => pendingMsg.nonce == message.nonce,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return messages;
|
||||
}
|
||||
|
||||
Future<LocalChatMessage> sendMessage(
|
||||
String token,
|
||||
String baseUrl,
|
||||
String roomId,
|
||||
String content,
|
||||
String nonce, {
|
||||
required List<UniversalFile> attachments,
|
||||
Map<String, dynamic>? meta,
|
||||
SnChatMessage? replyingTo,
|
||||
SnChatMessage? forwardingTo,
|
||||
SnChatMessage? editingTo,
|
||||
Function(LocalChatMessage)? onPending,
|
||||
Function(String, Map<int, double>)? onProgress,
|
||||
}) async {
|
||||
// Generate a unique nonce for this message
|
||||
final nonce = const Uuid().v4();
|
||||
|
||||
// Create a local message with pending status
|
||||
final mockMessage = SnChatMessage(
|
||||
id: 'pending_$nonce',
|
||||
chatRoomId: roomId,
|
||||
senderId: identity.id,
|
||||
content: content,
|
||||
createdAt: DateTime.now(),
|
||||
updatedAt: DateTime.now(),
|
||||
nonce: nonce,
|
||||
sender: identity,
|
||||
);
|
||||
|
||||
final localMessage = LocalChatMessage.fromRemoteMessage(
|
||||
mockMessage,
|
||||
MessageStatus.pending,
|
||||
);
|
||||
|
||||
// Store in memory and database
|
||||
pendingMessages[localMessage.id] = localMessage;
|
||||
fileUploadProgress[localMessage.id] = {};
|
||||
await _database.saveMessage(_database.messageToCompanion(localMessage));
|
||||
onPending?.call(localMessage);
|
||||
|
||||
try {
|
||||
var cloudAttachments = List.empty(growable: true);
|
||||
// Upload files
|
||||
for (var idx = 0; idx < attachments.length; idx++) {
|
||||
final cloudFile =
|
||||
await putMediaToCloud(
|
||||
fileData: attachments[idx],
|
||||
atk: token,
|
||||
baseUrl: baseUrl,
|
||||
filename: attachments[idx].data.name ?? 'Post media',
|
||||
mimetype:
|
||||
attachments[idx].data.mimeType ??
|
||||
switch (attachments[idx].type) {
|
||||
UniversalFileType.image => 'image/unknown',
|
||||
UniversalFileType.video => 'video/unknown',
|
||||
UniversalFileType.audio => 'audio/unknown',
|
||||
UniversalFileType.file => 'application/octet-stream',
|
||||
},
|
||||
onProgress: (progress, _) {
|
||||
fileUploadProgress[localMessage.id]?[idx] = progress;
|
||||
onProgress?.call(
|
||||
localMessage.id,
|
||||
fileUploadProgress[localMessage.id] ?? {},
|
||||
);
|
||||
},
|
||||
).future;
|
||||
if (cloudFile == null) {
|
||||
throw ArgumentError('Failed to upload the file...');
|
||||
}
|
||||
cloudAttachments.add(cloudFile);
|
||||
}
|
||||
|
||||
// Send to server
|
||||
final response = await _apiClient.request(
|
||||
editingTo == null
|
||||
? '/sphere/chat/$roomId/messages'
|
||||
: '/sphere/chat/$roomId/messages/${editingTo.id}',
|
||||
data: {
|
||||
'content': content,
|
||||
'attachments_id': cloudAttachments.map((e) => e.id).toList(),
|
||||
'replied_message_id': replyingTo?.id,
|
||||
'forwarded_message_id': forwardingTo?.id,
|
||||
'meta': meta,
|
||||
'nonce': nonce,
|
||||
},
|
||||
options: Options(method: editingTo == null ? 'POST' : 'PATCH'),
|
||||
);
|
||||
|
||||
// Update with server response
|
||||
final remoteMessage = SnChatMessage.fromJson(response.data);
|
||||
final updatedMessage = LocalChatMessage.fromRemoteMessage(
|
||||
remoteMessage,
|
||||
MessageStatus.sent,
|
||||
);
|
||||
|
||||
// Remove from pending and update in database
|
||||
pendingMessages.remove(localMessage.id);
|
||||
await _database.deleteMessage(localMessage.id);
|
||||
await _database.saveMessage(_database.messageToCompanion(updatedMessage));
|
||||
|
||||
return updatedMessage;
|
||||
} catch (e) {
|
||||
// Update status to failed
|
||||
localMessage.status = MessageStatus.failed;
|
||||
pendingMessages[localMessage.id] = localMessage;
|
||||
await _database.updateMessageStatus(
|
||||
localMessage.id,
|
||||
MessageStatus.failed,
|
||||
);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<LocalChatMessage> retryMessage(String pendingMessageId) async {
|
||||
final message = await getMessageById(pendingMessageId);
|
||||
if (message == null) {
|
||||
throw Exception('Message not found');
|
||||
}
|
||||
|
||||
// Update status back to pending
|
||||
message.status = MessageStatus.pending;
|
||||
pendingMessages[pendingMessageId] = message;
|
||||
await _database.updateMessageStatus(
|
||||
pendingMessageId,
|
||||
MessageStatus.pending,
|
||||
);
|
||||
|
||||
try {
|
||||
// Send to server
|
||||
var remoteMessage = message.toRemoteMessage();
|
||||
final response = await _apiClient.post(
|
||||
'/sphere/chat/${message.roomId}/messages',
|
||||
data: {
|
||||
'content': remoteMessage.content,
|
||||
'attachments_id': remoteMessage.attachments,
|
||||
'meta': remoteMessage.meta,
|
||||
'nonce': message.nonce,
|
||||
},
|
||||
);
|
||||
|
||||
// Update with server response
|
||||
remoteMessage = SnChatMessage.fromJson(response.data);
|
||||
final updatedMessage = LocalChatMessage.fromRemoteMessage(
|
||||
remoteMessage,
|
||||
MessageStatus.sent,
|
||||
);
|
||||
|
||||
// Remove from pending and update in database
|
||||
pendingMessages.remove(pendingMessageId);
|
||||
await _database.deleteMessage(pendingMessageId);
|
||||
await _database.saveMessage(_database.messageToCompanion(updatedMessage));
|
||||
|
||||
return updatedMessage;
|
||||
} catch (e) {
|
||||
// Update status to failed
|
||||
message.status = MessageStatus.failed;
|
||||
pendingMessages[pendingMessageId] = message;
|
||||
await _database.updateMessageStatus(
|
||||
pendingMessageId,
|
||||
MessageStatus.failed,
|
||||
);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<LocalChatMessage> receiveMessage(SnChatMessage remoteMessage) async {
|
||||
final localMessage = LocalChatMessage.fromRemoteMessage(
|
||||
remoteMessage,
|
||||
MessageStatus.sent,
|
||||
);
|
||||
|
||||
if (remoteMessage.nonce != null) {
|
||||
pendingMessages.removeWhere(
|
||||
(_, pendingMsg) => pendingMsg.nonce == remoteMessage.nonce,
|
||||
);
|
||||
}
|
||||
|
||||
await _database.saveMessage(_database.messageToCompanion(localMessage));
|
||||
return localMessage;
|
||||
}
|
||||
|
||||
Future<LocalChatMessage> receiveMessageUpdate(
|
||||
SnChatMessage remoteMessage,
|
||||
) async {
|
||||
final localMessage = LocalChatMessage.fromRemoteMessage(
|
||||
remoteMessage,
|
||||
MessageStatus.sent,
|
||||
);
|
||||
|
||||
await _database.updateMessage(_database.messageToCompanion(localMessage));
|
||||
return localMessage;
|
||||
}
|
||||
|
||||
Future<void> receiveMessageDeletion(String messageId) async {
|
||||
// Remove from pending messages if exists
|
||||
pendingMessages.remove(messageId);
|
||||
|
||||
// Delete from local database
|
||||
await _database.deleteMessage(messageId);
|
||||
}
|
||||
|
||||
Future<LocalChatMessage> updateMessage(
|
||||
String messageId,
|
||||
String content, {
|
||||
List<SnCloudFile>? attachments,
|
||||
Map<String, dynamic>? meta,
|
||||
}) async {
|
||||
final message = pendingMessages[messageId];
|
||||
if (message != null) {
|
||||
// Update pending message
|
||||
final rmMessage = message.toRemoteMessage();
|
||||
final updatedRemoteMessage = rmMessage.copyWith(
|
||||
content: content,
|
||||
meta: meta ?? rmMessage.meta,
|
||||
);
|
||||
final updatedLocalMessage = LocalChatMessage.fromRemoteMessage(
|
||||
updatedRemoteMessage,
|
||||
MessageStatus.pending,
|
||||
);
|
||||
pendingMessages[messageId] = updatedLocalMessage;
|
||||
await _database.updateMessage(
|
||||
_database.messageToCompanion(updatedLocalMessage),
|
||||
);
|
||||
return message;
|
||||
}
|
||||
|
||||
try {
|
||||
// Update on server
|
||||
final response = await _apiClient.put(
|
||||
'/sphere/chat/${room.id}/messages/$messageId',
|
||||
data: {'content': content, 'attachments': attachments, 'meta': meta},
|
||||
);
|
||||
|
||||
// Update local copy
|
||||
final remoteMessage = SnChatMessage.fromJson(response.data);
|
||||
final updatedMessage = LocalChatMessage.fromRemoteMessage(
|
||||
remoteMessage,
|
||||
MessageStatus.sent,
|
||||
);
|
||||
await _database.updateMessage(
|
||||
_database.messageToCompanion(updatedMessage),
|
||||
);
|
||||
return updatedMessage;
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> deleteMessage(String messageId) async {
|
||||
try {
|
||||
await _apiClient.delete('/sphere/chat/${room.id}/messages/$messageId');
|
||||
pendingMessages.remove(messageId);
|
||||
await _database.deleteMessage(messageId);
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<LocalChatMessage?> getMessageById(String messageId) async {
|
||||
try {
|
||||
// Attempt to get the message from the local database
|
||||
final localMessage =
|
||||
await (_database.select(_database.chatMessages)
|
||||
..where((tbl) => tbl.id.equals(messageId))).getSingleOrNull();
|
||||
if (localMessage != null) {
|
||||
return _database.companionToMessage(localMessage);
|
||||
}
|
||||
|
||||
// If not found locally, fetch from the server
|
||||
final response = await _apiClient.get(
|
||||
'/sphere/chat/${room.id}/messages/$messageId',
|
||||
);
|
||||
final remoteMessage = SnChatMessage.fromJson(response.data);
|
||||
final message = LocalChatMessage.fromRemoteMessage(
|
||||
remoteMessage,
|
||||
MessageStatus.sent,
|
||||
);
|
||||
|
||||
// Save the fetched message to the local database
|
||||
await _database.saveMessage(_database.messageToCompanion(message));
|
||||
return message;
|
||||
} catch (e) {
|
||||
if (e is DioException) return null;
|
||||
// Handle errors
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
@@ -11,8 +11,8 @@ sealed class SnScrappedLink with _$SnScrappedLink {
|
||||
required String title,
|
||||
required String? description,
|
||||
required String? imageUrl,
|
||||
required String faviconUrl,
|
||||
required String siteName,
|
||||
required String? faviconUrl,
|
||||
required String? siteName,
|
||||
required String? contentType,
|
||||
required String? author,
|
||||
required DateTime? publishedDate,
|
||||
|
@@ -15,7 +15,7 @@ T _$identity<T>(T value) => value;
|
||||
/// @nodoc
|
||||
mixin _$SnScrappedLink {
|
||||
|
||||
String get type; String get url; String get title; String? get description; String? get imageUrl; String get faviconUrl; String get siteName; String? get contentType; String? get author; DateTime? get publishedDate;
|
||||
String get type; String get url; String get title; String? get description; String? get imageUrl; String? get faviconUrl; String? get siteName; String? get contentType; String? get author; DateTime? get publishedDate;
|
||||
/// Create a copy of SnScrappedLink
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@@ -48,7 +48,7 @@ abstract mixin class $SnScrappedLinkCopyWith<$Res> {
|
||||
factory $SnScrappedLinkCopyWith(SnScrappedLink value, $Res Function(SnScrappedLink) _then) = _$SnScrappedLinkCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
String type, String url, String title, String? description, String? imageUrl, String faviconUrl, String siteName, String? contentType, String? author, DateTime? publishedDate
|
||||
String type, String url, String title, String? description, String? imageUrl, String? faviconUrl, String? siteName, String? contentType, String? author, DateTime? publishedDate
|
||||
});
|
||||
|
||||
|
||||
@@ -65,16 +65,16 @@ class _$SnScrappedLinkCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of SnScrappedLink
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? type = null,Object? url = null,Object? title = null,Object? description = freezed,Object? imageUrl = freezed,Object? faviconUrl = null,Object? siteName = null,Object? contentType = freezed,Object? author = freezed,Object? publishedDate = freezed,}) {
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? type = null,Object? url = null,Object? title = null,Object? description = freezed,Object? imageUrl = freezed,Object? faviconUrl = freezed,Object? siteName = freezed,Object? contentType = freezed,Object? author = freezed,Object? publishedDate = freezed,}) {
|
||||
return _then(_self.copyWith(
|
||||
type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable
|
||||
as String,url: null == url ? _self.url : url // ignore: cast_nullable_to_non_nullable
|
||||
as String,title: null == title ? _self.title : title // ignore: cast_nullable_to_non_nullable
|
||||
as String,description: freezed == description ? _self.description : description // ignore: cast_nullable_to_non_nullable
|
||||
as String?,imageUrl: freezed == imageUrl ? _self.imageUrl : imageUrl // ignore: cast_nullable_to_non_nullable
|
||||
as String?,faviconUrl: null == faviconUrl ? _self.faviconUrl : faviconUrl // ignore: cast_nullable_to_non_nullable
|
||||
as String,siteName: null == siteName ? _self.siteName : siteName // ignore: cast_nullable_to_non_nullable
|
||||
as String,contentType: freezed == contentType ? _self.contentType : contentType // ignore: cast_nullable_to_non_nullable
|
||||
as String?,faviconUrl: freezed == faviconUrl ? _self.faviconUrl : faviconUrl // ignore: cast_nullable_to_non_nullable
|
||||
as String?,siteName: freezed == siteName ? _self.siteName : siteName // ignore: cast_nullable_to_non_nullable
|
||||
as String?,contentType: freezed == contentType ? _self.contentType : contentType // ignore: cast_nullable_to_non_nullable
|
||||
as String?,author: freezed == author ? _self.author : author // ignore: cast_nullable_to_non_nullable
|
||||
as String?,publishedDate: freezed == publishedDate ? _self.publishedDate : publishedDate // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime?,
|
||||
@@ -159,7 +159,7 @@ return $default(_that);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String type, String url, String title, String? description, String? imageUrl, String faviconUrl, String siteName, String? contentType, String? author, DateTime? publishedDate)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String type, String url, String title, String? description, String? imageUrl, String? faviconUrl, String? siteName, String? contentType, String? author, DateTime? publishedDate)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _SnScrappedLink() when $default != null:
|
||||
return $default(_that.type,_that.url,_that.title,_that.description,_that.imageUrl,_that.faviconUrl,_that.siteName,_that.contentType,_that.author,_that.publishedDate);case _:
|
||||
@@ -180,7 +180,7 @@ return $default(_that.type,_that.url,_that.title,_that.description,_that.imageUr
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String type, String url, String title, String? description, String? imageUrl, String faviconUrl, String siteName, String? contentType, String? author, DateTime? publishedDate) $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String type, String url, String title, String? description, String? imageUrl, String? faviconUrl, String? siteName, String? contentType, String? author, DateTime? publishedDate) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _SnScrappedLink():
|
||||
return $default(_that.type,_that.url,_that.title,_that.description,_that.imageUrl,_that.faviconUrl,_that.siteName,_that.contentType,_that.author,_that.publishedDate);}
|
||||
@@ -197,7 +197,7 @@ return $default(_that.type,_that.url,_that.title,_that.description,_that.imageUr
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String type, String url, String title, String? description, String? imageUrl, String faviconUrl, String siteName, String? contentType, String? author, DateTime? publishedDate)? $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String type, String url, String title, String? description, String? imageUrl, String? faviconUrl, String? siteName, String? contentType, String? author, DateTime? publishedDate)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _SnScrappedLink() when $default != null:
|
||||
return $default(_that.type,_that.url,_that.title,_that.description,_that.imageUrl,_that.faviconUrl,_that.siteName,_that.contentType,_that.author,_that.publishedDate);case _:
|
||||
@@ -220,8 +220,8 @@ class _SnScrappedLink implements SnScrappedLink {
|
||||
@override final String title;
|
||||
@override final String? description;
|
||||
@override final String? imageUrl;
|
||||
@override final String faviconUrl;
|
||||
@override final String siteName;
|
||||
@override final String? faviconUrl;
|
||||
@override final String? siteName;
|
||||
@override final String? contentType;
|
||||
@override final String? author;
|
||||
@override final DateTime? publishedDate;
|
||||
@@ -259,7 +259,7 @@ abstract mixin class _$SnScrappedLinkCopyWith<$Res> implements $SnScrappedLinkCo
|
||||
factory _$SnScrappedLinkCopyWith(_SnScrappedLink value, $Res Function(_SnScrappedLink) _then) = __$SnScrappedLinkCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
String type, String url, String title, String? description, String? imageUrl, String faviconUrl, String siteName, String? contentType, String? author, DateTime? publishedDate
|
||||
String type, String url, String title, String? description, String? imageUrl, String? faviconUrl, String? siteName, String? contentType, String? author, DateTime? publishedDate
|
||||
});
|
||||
|
||||
|
||||
@@ -276,16 +276,16 @@ class __$SnScrappedLinkCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of SnScrappedLink
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? type = null,Object? url = null,Object? title = null,Object? description = freezed,Object? imageUrl = freezed,Object? faviconUrl = null,Object? siteName = null,Object? contentType = freezed,Object? author = freezed,Object? publishedDate = freezed,}) {
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? type = null,Object? url = null,Object? title = null,Object? description = freezed,Object? imageUrl = freezed,Object? faviconUrl = freezed,Object? siteName = freezed,Object? contentType = freezed,Object? author = freezed,Object? publishedDate = freezed,}) {
|
||||
return _then(_SnScrappedLink(
|
||||
type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable
|
||||
as String,url: null == url ? _self.url : url // ignore: cast_nullable_to_non_nullable
|
||||
as String,title: null == title ? _self.title : title // ignore: cast_nullable_to_non_nullable
|
||||
as String,description: freezed == description ? _self.description : description // ignore: cast_nullable_to_non_nullable
|
||||
as String?,imageUrl: freezed == imageUrl ? _self.imageUrl : imageUrl // ignore: cast_nullable_to_non_nullable
|
||||
as String?,faviconUrl: null == faviconUrl ? _self.faviconUrl : faviconUrl // ignore: cast_nullable_to_non_nullable
|
||||
as String,siteName: null == siteName ? _self.siteName : siteName // ignore: cast_nullable_to_non_nullable
|
||||
as String,contentType: freezed == contentType ? _self.contentType : contentType // ignore: cast_nullable_to_non_nullable
|
||||
as String?,faviconUrl: freezed == faviconUrl ? _self.faviconUrl : faviconUrl // ignore: cast_nullable_to_non_nullable
|
||||
as String?,siteName: freezed == siteName ? _self.siteName : siteName // ignore: cast_nullable_to_non_nullable
|
||||
as String?,contentType: freezed == contentType ? _self.contentType : contentType // ignore: cast_nullable_to_non_nullable
|
||||
as String?,author: freezed == author ? _self.author : author // ignore: cast_nullable_to_non_nullable
|
||||
as String?,publishedDate: freezed == publishedDate ? _self.publishedDate : publishedDate // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime?,
|
||||
|
@@ -13,8 +13,8 @@ _SnScrappedLink _$SnScrappedLinkFromJson(Map<String, dynamic> json) =>
|
||||
title: json['title'] as String,
|
||||
description: json['description'] as String?,
|
||||
imageUrl: json['image_url'] as String?,
|
||||
faviconUrl: json['favicon_url'] as String,
|
||||
siteName: json['site_name'] as String,
|
||||
faviconUrl: json['favicon_url'] as String?,
|
||||
siteName: json['site_name'] as String?,
|
||||
contentType: json['content_type'] as String?,
|
||||
author: json['author'] as String?,
|
||||
publishedDate:
|
||||
|
@@ -3,6 +3,7 @@ import 'package:island/models/file.dart';
|
||||
import 'package:island/models/post_category.dart';
|
||||
import 'package:island/models/post_tag.dart';
|
||||
import 'package:island/models/publisher.dart';
|
||||
import 'package:island/models/realm.dart';
|
||||
|
||||
part 'post.freezed.dart';
|
||||
part 'post.g.dart';
|
||||
@@ -18,6 +19,7 @@ sealed class SnPost with _$SnPost {
|
||||
@Default(null) DateTime? publishedAt,
|
||||
@Default(0) int visibility,
|
||||
String? content,
|
||||
String? slug,
|
||||
@Default(0) int type,
|
||||
Map<String, dynamic>? meta,
|
||||
@Default(0) int viewsUnique,
|
||||
@@ -31,6 +33,8 @@ sealed class SnPost with _$SnPost {
|
||||
SnPost? repliedPost,
|
||||
String? forwardedPostId,
|
||||
SnPost? forwardedPost,
|
||||
String? realmId,
|
||||
SnRealm? realm,
|
||||
@Default([]) List<SnCloudFile> attachments,
|
||||
required SnPublisher publisher,
|
||||
@Default({}) Map<String, int> reactionsCount,
|
||||
|
@@ -15,7 +15,7 @@ T _$identity<T>(T value) => value;
|
||||
/// @nodoc
|
||||
mixin _$SnPost {
|
||||
|
||||
String get id; String? get title; String? get description; String? get language; DateTime? get editedAt; DateTime? get publishedAt; int get visibility; String? get content; int get type; Map<String, dynamic>? get meta; int get viewsUnique; int get viewsTotal; int get upvotes; int get downvotes; int get repliesCount; String? get threadedPostId; SnPost? get threadedPost; String? get repliedPostId; SnPost? get repliedPost; String? get forwardedPostId; SnPost? get forwardedPost; List<SnCloudFile> get attachments; SnPublisher get publisher; Map<String, int> get reactionsCount; Map<String, bool> get reactionsMade; List<dynamic> get reactions; List<SnPostTag> get tags; List<SnPostCategory> get categories; List<dynamic> get collections; DateTime? get createdAt; DateTime? get updatedAt; DateTime? get deletedAt; bool get isTruncated;
|
||||
String get id; String? get title; String? get description; String? get language; DateTime? get editedAt; DateTime? get publishedAt; int get visibility; String? get content; String? get slug; int get type; Map<String, dynamic>? get meta; int get viewsUnique; int get viewsTotal; int get upvotes; int get downvotes; int get repliesCount; String? get threadedPostId; SnPost? get threadedPost; String? get repliedPostId; SnPost? get repliedPost; String? get forwardedPostId; SnPost? get forwardedPost; String? get realmId; SnRealm? get realm; List<SnCloudFile> get attachments; SnPublisher get publisher; Map<String, int> get reactionsCount; Map<String, bool> get reactionsMade; List<dynamic> get reactions; List<SnPostTag> get tags; List<SnPostCategory> get categories; List<dynamic> get collections; DateTime? get createdAt; DateTime? get updatedAt; DateTime? get deletedAt; bool get isTruncated;
|
||||
/// Create a copy of SnPost
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@@ -28,16 +28,16 @@ $SnPostCopyWith<SnPost> get copyWith => _$SnPostCopyWithImpl<SnPost>(this as SnP
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnPost&&(identical(other.id, id) || other.id == id)&&(identical(other.title, title) || other.title == title)&&(identical(other.description, description) || other.description == description)&&(identical(other.language, language) || other.language == language)&&(identical(other.editedAt, editedAt) || other.editedAt == editedAt)&&(identical(other.publishedAt, publishedAt) || other.publishedAt == publishedAt)&&(identical(other.visibility, visibility) || other.visibility == visibility)&&(identical(other.content, content) || other.content == content)&&(identical(other.type, type) || other.type == type)&&const DeepCollectionEquality().equals(other.meta, meta)&&(identical(other.viewsUnique, viewsUnique) || other.viewsUnique == viewsUnique)&&(identical(other.viewsTotal, viewsTotal) || other.viewsTotal == viewsTotal)&&(identical(other.upvotes, upvotes) || other.upvotes == upvotes)&&(identical(other.downvotes, downvotes) || other.downvotes == downvotes)&&(identical(other.repliesCount, repliesCount) || other.repliesCount == repliesCount)&&(identical(other.threadedPostId, threadedPostId) || other.threadedPostId == threadedPostId)&&(identical(other.threadedPost, threadedPost) || other.threadedPost == threadedPost)&&(identical(other.repliedPostId, repliedPostId) || other.repliedPostId == repliedPostId)&&(identical(other.repliedPost, repliedPost) || other.repliedPost == repliedPost)&&(identical(other.forwardedPostId, forwardedPostId) || other.forwardedPostId == forwardedPostId)&&(identical(other.forwardedPost, forwardedPost) || other.forwardedPost == forwardedPost)&&const DeepCollectionEquality().equals(other.attachments, attachments)&&(identical(other.publisher, publisher) || other.publisher == publisher)&&const DeepCollectionEquality().equals(other.reactionsCount, reactionsCount)&&const DeepCollectionEquality().equals(other.reactionsMade, reactionsMade)&&const DeepCollectionEquality().equals(other.reactions, reactions)&&const DeepCollectionEquality().equals(other.tags, tags)&&const DeepCollectionEquality().equals(other.categories, categories)&&const DeepCollectionEquality().equals(other.collections, collections)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.isTruncated, isTruncated) || other.isTruncated == isTruncated));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnPost&&(identical(other.id, id) || other.id == id)&&(identical(other.title, title) || other.title == title)&&(identical(other.description, description) || other.description == description)&&(identical(other.language, language) || other.language == language)&&(identical(other.editedAt, editedAt) || other.editedAt == editedAt)&&(identical(other.publishedAt, publishedAt) || other.publishedAt == publishedAt)&&(identical(other.visibility, visibility) || other.visibility == visibility)&&(identical(other.content, content) || other.content == content)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.type, type) || other.type == type)&&const DeepCollectionEquality().equals(other.meta, meta)&&(identical(other.viewsUnique, viewsUnique) || other.viewsUnique == viewsUnique)&&(identical(other.viewsTotal, viewsTotal) || other.viewsTotal == viewsTotal)&&(identical(other.upvotes, upvotes) || other.upvotes == upvotes)&&(identical(other.downvotes, downvotes) || other.downvotes == downvotes)&&(identical(other.repliesCount, repliesCount) || other.repliesCount == repliesCount)&&(identical(other.threadedPostId, threadedPostId) || other.threadedPostId == threadedPostId)&&(identical(other.threadedPost, threadedPost) || other.threadedPost == threadedPost)&&(identical(other.repliedPostId, repliedPostId) || other.repliedPostId == repliedPostId)&&(identical(other.repliedPost, repliedPost) || other.repliedPost == repliedPost)&&(identical(other.forwardedPostId, forwardedPostId) || other.forwardedPostId == forwardedPostId)&&(identical(other.forwardedPost, forwardedPost) || other.forwardedPost == forwardedPost)&&(identical(other.realmId, realmId) || other.realmId == realmId)&&(identical(other.realm, realm) || other.realm == realm)&&const DeepCollectionEquality().equals(other.attachments, attachments)&&(identical(other.publisher, publisher) || other.publisher == publisher)&&const DeepCollectionEquality().equals(other.reactionsCount, reactionsCount)&&const DeepCollectionEquality().equals(other.reactionsMade, reactionsMade)&&const DeepCollectionEquality().equals(other.reactions, reactions)&&const DeepCollectionEquality().equals(other.tags, tags)&&const DeepCollectionEquality().equals(other.categories, categories)&&const DeepCollectionEquality().equals(other.collections, collections)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.isTruncated, isTruncated) || other.isTruncated == isTruncated));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hashAll([runtimeType,id,title,description,language,editedAt,publishedAt,visibility,content,type,const DeepCollectionEquality().hash(meta),viewsUnique,viewsTotal,upvotes,downvotes,repliesCount,threadedPostId,threadedPost,repliedPostId,repliedPost,forwardedPostId,forwardedPost,const DeepCollectionEquality().hash(attachments),publisher,const DeepCollectionEquality().hash(reactionsCount),const DeepCollectionEquality().hash(reactionsMade),const DeepCollectionEquality().hash(reactions),const DeepCollectionEquality().hash(tags),const DeepCollectionEquality().hash(categories),const DeepCollectionEquality().hash(collections),createdAt,updatedAt,deletedAt,isTruncated]);
|
||||
int get hashCode => Object.hashAll([runtimeType,id,title,description,language,editedAt,publishedAt,visibility,content,slug,type,const DeepCollectionEquality().hash(meta),viewsUnique,viewsTotal,upvotes,downvotes,repliesCount,threadedPostId,threadedPost,repliedPostId,repliedPost,forwardedPostId,forwardedPost,realmId,realm,const DeepCollectionEquality().hash(attachments),publisher,const DeepCollectionEquality().hash(reactionsCount),const DeepCollectionEquality().hash(reactionsMade),const DeepCollectionEquality().hash(reactions),const DeepCollectionEquality().hash(tags),const DeepCollectionEquality().hash(categories),const DeepCollectionEquality().hash(collections),createdAt,updatedAt,deletedAt,isTruncated]);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'SnPost(id: $id, title: $title, description: $description, language: $language, editedAt: $editedAt, publishedAt: $publishedAt, visibility: $visibility, content: $content, type: $type, meta: $meta, viewsUnique: $viewsUnique, viewsTotal: $viewsTotal, upvotes: $upvotes, downvotes: $downvotes, repliesCount: $repliesCount, threadedPostId: $threadedPostId, threadedPost: $threadedPost, repliedPostId: $repliedPostId, repliedPost: $repliedPost, forwardedPostId: $forwardedPostId, forwardedPost: $forwardedPost, attachments: $attachments, publisher: $publisher, reactionsCount: $reactionsCount, reactionsMade: $reactionsMade, reactions: $reactions, tags: $tags, categories: $categories, collections: $collections, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, isTruncated: $isTruncated)';
|
||||
return 'SnPost(id: $id, title: $title, description: $description, language: $language, editedAt: $editedAt, publishedAt: $publishedAt, visibility: $visibility, content: $content, slug: $slug, type: $type, meta: $meta, viewsUnique: $viewsUnique, viewsTotal: $viewsTotal, upvotes: $upvotes, downvotes: $downvotes, repliesCount: $repliesCount, threadedPostId: $threadedPostId, threadedPost: $threadedPost, repliedPostId: $repliedPostId, repliedPost: $repliedPost, forwardedPostId: $forwardedPostId, forwardedPost: $forwardedPost, realmId: $realmId, realm: $realm, attachments: $attachments, publisher: $publisher, reactionsCount: $reactionsCount, reactionsMade: $reactionsMade, reactions: $reactions, tags: $tags, categories: $categories, collections: $collections, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, isTruncated: $isTruncated)';
|
||||
}
|
||||
|
||||
|
||||
@@ -48,11 +48,11 @@ abstract mixin class $SnPostCopyWith<$Res> {
|
||||
factory $SnPostCopyWith(SnPost value, $Res Function(SnPost) _then) = _$SnPostCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, int type, Map<String, dynamic>? meta, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, List<SnCloudFile> attachments, SnPublisher publisher, Map<String, int> reactionsCount, Map<String, bool> reactionsMade, List<dynamic> reactions, List<SnPostTag> tags, List<SnPostCategory> categories, List<dynamic> collections, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool isTruncated
|
||||
String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map<String, dynamic>? meta, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, String? realmId, SnRealm? realm, List<SnCloudFile> attachments, SnPublisher publisher, Map<String, int> reactionsCount, Map<String, bool> reactionsMade, List<dynamic> reactions, List<SnPostTag> tags, List<SnPostCategory> categories, List<dynamic> collections, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool isTruncated
|
||||
});
|
||||
|
||||
|
||||
$SnPostCopyWith<$Res>? get threadedPost;$SnPostCopyWith<$Res>? get repliedPost;$SnPostCopyWith<$Res>? get forwardedPost;$SnPublisherCopyWith<$Res> get publisher;
|
||||
$SnPostCopyWith<$Res>? get threadedPost;$SnPostCopyWith<$Res>? get repliedPost;$SnPostCopyWith<$Res>? get forwardedPost;$SnRealmCopyWith<$Res>? get realm;$SnPublisherCopyWith<$Res> get publisher;
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
@@ -65,7 +65,7 @@ class _$SnPostCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of SnPost
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? title = freezed,Object? description = freezed,Object? language = freezed,Object? editedAt = freezed,Object? publishedAt = freezed,Object? visibility = null,Object? content = freezed,Object? type = null,Object? meta = freezed,Object? viewsUnique = null,Object? viewsTotal = null,Object? upvotes = null,Object? downvotes = null,Object? repliesCount = null,Object? threadedPostId = freezed,Object? threadedPost = freezed,Object? repliedPostId = freezed,Object? repliedPost = freezed,Object? forwardedPostId = freezed,Object? forwardedPost = freezed,Object? attachments = null,Object? publisher = null,Object? reactionsCount = null,Object? reactionsMade = null,Object? reactions = null,Object? tags = null,Object? categories = null,Object? collections = null,Object? createdAt = freezed,Object? updatedAt = freezed,Object? deletedAt = freezed,Object? isTruncated = null,}) {
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? title = freezed,Object? description = freezed,Object? language = freezed,Object? editedAt = freezed,Object? publishedAt = freezed,Object? visibility = null,Object? content = freezed,Object? slug = freezed,Object? type = null,Object? meta = freezed,Object? viewsUnique = null,Object? viewsTotal = null,Object? upvotes = null,Object? downvotes = null,Object? repliesCount = null,Object? threadedPostId = freezed,Object? threadedPost = freezed,Object? repliedPostId = freezed,Object? repliedPost = freezed,Object? forwardedPostId = freezed,Object? forwardedPost = freezed,Object? realmId = freezed,Object? realm = freezed,Object? attachments = null,Object? publisher = null,Object? reactionsCount = null,Object? reactionsMade = null,Object? reactions = null,Object? tags = null,Object? categories = null,Object? collections = null,Object? createdAt = freezed,Object? updatedAt = freezed,Object? deletedAt = freezed,Object? isTruncated = null,}) {
|
||||
return _then(_self.copyWith(
|
||||
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
||||
as String,title: freezed == title ? _self.title : title // ignore: cast_nullable_to_non_nullable
|
||||
@@ -75,6 +75,7 @@ as String?,editedAt: freezed == editedAt ? _self.editedAt : editedAt // ignore:
|
||||
as DateTime?,publishedAt: freezed == publishedAt ? _self.publishedAt : publishedAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime?,visibility: null == visibility ? _self.visibility : visibility // ignore: cast_nullable_to_non_nullable
|
||||
as int,content: freezed == content ? _self.content : content // ignore: cast_nullable_to_non_nullable
|
||||
as String?,slug: freezed == slug ? _self.slug : slug // ignore: cast_nullable_to_non_nullable
|
||||
as String?,type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable
|
||||
as int,meta: freezed == meta ? _self.meta : meta // ignore: cast_nullable_to_non_nullable
|
||||
as Map<String, dynamic>?,viewsUnique: null == viewsUnique ? _self.viewsUnique : viewsUnique // ignore: cast_nullable_to_non_nullable
|
||||
@@ -88,7 +89,9 @@ as SnPost?,repliedPostId: freezed == repliedPostId ? _self.repliedPostId : repli
|
||||
as String?,repliedPost: freezed == repliedPost ? _self.repliedPost : repliedPost // ignore: cast_nullable_to_non_nullable
|
||||
as SnPost?,forwardedPostId: freezed == forwardedPostId ? _self.forwardedPostId : forwardedPostId // ignore: cast_nullable_to_non_nullable
|
||||
as String?,forwardedPost: freezed == forwardedPost ? _self.forwardedPost : forwardedPost // ignore: cast_nullable_to_non_nullable
|
||||
as SnPost?,attachments: null == attachments ? _self.attachments : attachments // ignore: cast_nullable_to_non_nullable
|
||||
as SnPost?,realmId: freezed == realmId ? _self.realmId : realmId // ignore: cast_nullable_to_non_nullable
|
||||
as String?,realm: freezed == realm ? _self.realm : realm // ignore: cast_nullable_to_non_nullable
|
||||
as SnRealm?,attachments: null == attachments ? _self.attachments : attachments // ignore: cast_nullable_to_non_nullable
|
||||
as List<SnCloudFile>,publisher: null == publisher ? _self.publisher : publisher // ignore: cast_nullable_to_non_nullable
|
||||
as SnPublisher,reactionsCount: null == reactionsCount ? _self.reactionsCount : reactionsCount // ignore: cast_nullable_to_non_nullable
|
||||
as Map<String, int>,reactionsMade: null == reactionsMade ? _self.reactionsMade : reactionsMade // ignore: cast_nullable_to_non_nullable
|
||||
@@ -143,6 +146,18 @@ $SnPostCopyWith<$Res>? get forwardedPost {
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$SnRealmCopyWith<$Res>? get realm {
|
||||
if (_self.realm == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $SnRealmCopyWith<$Res>(_self.realm!, (value) {
|
||||
return _then(_self.copyWith(realm: value));
|
||||
});
|
||||
}/// Create a copy of SnPost
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$SnPublisherCopyWith<$Res> get publisher {
|
||||
|
||||
return $SnPublisherCopyWith<$Res>(_self.publisher, (value) {
|
||||
@@ -227,10 +242,10 @@ return $default(_that);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, int type, Map<String, dynamic>? meta, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, List<SnCloudFile> attachments, SnPublisher publisher, Map<String, int> reactionsCount, Map<String, bool> reactionsMade, List<dynamic> reactions, List<SnPostTag> tags, List<SnPostCategory> categories, List<dynamic> collections, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool isTruncated)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map<String, dynamic>? meta, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, String? realmId, SnRealm? realm, List<SnCloudFile> attachments, SnPublisher publisher, Map<String, int> reactionsCount, Map<String, bool> reactionsMade, List<dynamic> reactions, List<SnPostTag> tags, List<SnPostCategory> categories, List<dynamic> collections, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool isTruncated)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _SnPost() when $default != null:
|
||||
return $default(_that.id,_that.title,_that.description,_that.language,_that.editedAt,_that.publishedAt,_that.visibility,_that.content,_that.type,_that.meta,_that.viewsUnique,_that.viewsTotal,_that.upvotes,_that.downvotes,_that.repliesCount,_that.threadedPostId,_that.threadedPost,_that.repliedPostId,_that.repliedPost,_that.forwardedPostId,_that.forwardedPost,_that.attachments,_that.publisher,_that.reactionsCount,_that.reactionsMade,_that.reactions,_that.tags,_that.categories,_that.collections,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.isTruncated);case _:
|
||||
return $default(_that.id,_that.title,_that.description,_that.language,_that.editedAt,_that.publishedAt,_that.visibility,_that.content,_that.slug,_that.type,_that.meta,_that.viewsUnique,_that.viewsTotal,_that.upvotes,_that.downvotes,_that.repliesCount,_that.threadedPostId,_that.threadedPost,_that.repliedPostId,_that.repliedPost,_that.forwardedPostId,_that.forwardedPost,_that.realmId,_that.realm,_that.attachments,_that.publisher,_that.reactionsCount,_that.reactionsMade,_that.reactions,_that.tags,_that.categories,_that.collections,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.isTruncated);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
@@ -248,10 +263,10 @@ return $default(_that.id,_that.title,_that.description,_that.language,_that.edit
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, int type, Map<String, dynamic>? meta, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, List<SnCloudFile> attachments, SnPublisher publisher, Map<String, int> reactionsCount, Map<String, bool> reactionsMade, List<dynamic> reactions, List<SnPostTag> tags, List<SnPostCategory> categories, List<dynamic> collections, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool isTruncated) $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map<String, dynamic>? meta, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, String? realmId, SnRealm? realm, List<SnCloudFile> attachments, SnPublisher publisher, Map<String, int> reactionsCount, Map<String, bool> reactionsMade, List<dynamic> reactions, List<SnPostTag> tags, List<SnPostCategory> categories, List<dynamic> collections, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool isTruncated) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _SnPost():
|
||||
return $default(_that.id,_that.title,_that.description,_that.language,_that.editedAt,_that.publishedAt,_that.visibility,_that.content,_that.type,_that.meta,_that.viewsUnique,_that.viewsTotal,_that.upvotes,_that.downvotes,_that.repliesCount,_that.threadedPostId,_that.threadedPost,_that.repliedPostId,_that.repliedPost,_that.forwardedPostId,_that.forwardedPost,_that.attachments,_that.publisher,_that.reactionsCount,_that.reactionsMade,_that.reactions,_that.tags,_that.categories,_that.collections,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.isTruncated);}
|
||||
return $default(_that.id,_that.title,_that.description,_that.language,_that.editedAt,_that.publishedAt,_that.visibility,_that.content,_that.slug,_that.type,_that.meta,_that.viewsUnique,_that.viewsTotal,_that.upvotes,_that.downvotes,_that.repliesCount,_that.threadedPostId,_that.threadedPost,_that.repliedPostId,_that.repliedPost,_that.forwardedPostId,_that.forwardedPost,_that.realmId,_that.realm,_that.attachments,_that.publisher,_that.reactionsCount,_that.reactionsMade,_that.reactions,_that.tags,_that.categories,_that.collections,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.isTruncated);}
|
||||
}
|
||||
/// A variant of `when` that fallback to returning `null`
|
||||
///
|
||||
@@ -265,10 +280,10 @@ return $default(_that.id,_that.title,_that.description,_that.language,_that.edit
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, int type, Map<String, dynamic>? meta, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, List<SnCloudFile> attachments, SnPublisher publisher, Map<String, int> reactionsCount, Map<String, bool> reactionsMade, List<dynamic> reactions, List<SnPostTag> tags, List<SnPostCategory> categories, List<dynamic> collections, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool isTruncated)? $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map<String, dynamic>? meta, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, String? realmId, SnRealm? realm, List<SnCloudFile> attachments, SnPublisher publisher, Map<String, int> reactionsCount, Map<String, bool> reactionsMade, List<dynamic> reactions, List<SnPostTag> tags, List<SnPostCategory> categories, List<dynamic> collections, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool isTruncated)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _SnPost() when $default != null:
|
||||
return $default(_that.id,_that.title,_that.description,_that.language,_that.editedAt,_that.publishedAt,_that.visibility,_that.content,_that.type,_that.meta,_that.viewsUnique,_that.viewsTotal,_that.upvotes,_that.downvotes,_that.repliesCount,_that.threadedPostId,_that.threadedPost,_that.repliedPostId,_that.repliedPost,_that.forwardedPostId,_that.forwardedPost,_that.attachments,_that.publisher,_that.reactionsCount,_that.reactionsMade,_that.reactions,_that.tags,_that.categories,_that.collections,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.isTruncated);case _:
|
||||
return $default(_that.id,_that.title,_that.description,_that.language,_that.editedAt,_that.publishedAt,_that.visibility,_that.content,_that.slug,_that.type,_that.meta,_that.viewsUnique,_that.viewsTotal,_that.upvotes,_that.downvotes,_that.repliesCount,_that.threadedPostId,_that.threadedPost,_that.repliedPostId,_that.repliedPost,_that.forwardedPostId,_that.forwardedPost,_that.realmId,_that.realm,_that.attachments,_that.publisher,_that.reactionsCount,_that.reactionsMade,_that.reactions,_that.tags,_that.categories,_that.collections,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.isTruncated);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
@@ -280,7 +295,7 @@ return $default(_that.id,_that.title,_that.description,_that.language,_that.edit
|
||||
@JsonSerializable()
|
||||
|
||||
class _SnPost implements SnPost {
|
||||
const _SnPost({required this.id, this.title, this.description, this.language, this.editedAt, this.publishedAt = null, this.visibility = 0, this.content, this.type = 0, final Map<String, dynamic>? meta, this.viewsUnique = 0, this.viewsTotal = 0, this.upvotes = 0, this.downvotes = 0, this.repliesCount = 0, this.threadedPostId, this.threadedPost, this.repliedPostId, this.repliedPost, this.forwardedPostId, this.forwardedPost, final List<SnCloudFile> attachments = const [], required this.publisher, final Map<String, int> reactionsCount = const {}, final Map<String, bool> reactionsMade = const {}, final List<dynamic> reactions = const [], final List<SnPostTag> tags = const [], final List<SnPostCategory> categories = const [], final List<dynamic> collections = const [], this.createdAt = null, this.updatedAt = null, this.deletedAt, this.isTruncated = false}): _meta = meta,_attachments = attachments,_reactionsCount = reactionsCount,_reactionsMade = reactionsMade,_reactions = reactions,_tags = tags,_categories = categories,_collections = collections;
|
||||
const _SnPost({required this.id, this.title, this.description, this.language, this.editedAt, this.publishedAt = null, this.visibility = 0, this.content, this.slug, this.type = 0, final Map<String, dynamic>? meta, this.viewsUnique = 0, this.viewsTotal = 0, this.upvotes = 0, this.downvotes = 0, this.repliesCount = 0, this.threadedPostId, this.threadedPost, this.repliedPostId, this.repliedPost, this.forwardedPostId, this.forwardedPost, this.realmId, this.realm, final List<SnCloudFile> attachments = const [], required this.publisher, final Map<String, int> reactionsCount = const {}, final Map<String, bool> reactionsMade = const {}, final List<dynamic> reactions = const [], final List<SnPostTag> tags = const [], final List<SnPostCategory> categories = const [], final List<dynamic> collections = const [], this.createdAt = null, this.updatedAt = null, this.deletedAt, this.isTruncated = false}): _meta = meta,_attachments = attachments,_reactionsCount = reactionsCount,_reactionsMade = reactionsMade,_reactions = reactions,_tags = tags,_categories = categories,_collections = collections;
|
||||
factory _SnPost.fromJson(Map<String, dynamic> json) => _$SnPostFromJson(json);
|
||||
|
||||
@override final String id;
|
||||
@@ -291,6 +306,7 @@ class _SnPost implements SnPost {
|
||||
@override@JsonKey() final DateTime? publishedAt;
|
||||
@override@JsonKey() final int visibility;
|
||||
@override final String? content;
|
||||
@override final String? slug;
|
||||
@override@JsonKey() final int type;
|
||||
final Map<String, dynamic>? _meta;
|
||||
@override Map<String, dynamic>? get meta {
|
||||
@@ -312,6 +328,8 @@ class _SnPost implements SnPost {
|
||||
@override final SnPost? repliedPost;
|
||||
@override final String? forwardedPostId;
|
||||
@override final SnPost? forwardedPost;
|
||||
@override final String? realmId;
|
||||
@override final SnRealm? realm;
|
||||
final List<SnCloudFile> _attachments;
|
||||
@override@JsonKey() List<SnCloudFile> get attachments {
|
||||
if (_attachments is EqualUnmodifiableListView) return _attachments;
|
||||
@@ -380,16 +398,16 @@ Map<String, dynamic> toJson() {
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnPost&&(identical(other.id, id) || other.id == id)&&(identical(other.title, title) || other.title == title)&&(identical(other.description, description) || other.description == description)&&(identical(other.language, language) || other.language == language)&&(identical(other.editedAt, editedAt) || other.editedAt == editedAt)&&(identical(other.publishedAt, publishedAt) || other.publishedAt == publishedAt)&&(identical(other.visibility, visibility) || other.visibility == visibility)&&(identical(other.content, content) || other.content == content)&&(identical(other.type, type) || other.type == type)&&const DeepCollectionEquality().equals(other._meta, _meta)&&(identical(other.viewsUnique, viewsUnique) || other.viewsUnique == viewsUnique)&&(identical(other.viewsTotal, viewsTotal) || other.viewsTotal == viewsTotal)&&(identical(other.upvotes, upvotes) || other.upvotes == upvotes)&&(identical(other.downvotes, downvotes) || other.downvotes == downvotes)&&(identical(other.repliesCount, repliesCount) || other.repliesCount == repliesCount)&&(identical(other.threadedPostId, threadedPostId) || other.threadedPostId == threadedPostId)&&(identical(other.threadedPost, threadedPost) || other.threadedPost == threadedPost)&&(identical(other.repliedPostId, repliedPostId) || other.repliedPostId == repliedPostId)&&(identical(other.repliedPost, repliedPost) || other.repliedPost == repliedPost)&&(identical(other.forwardedPostId, forwardedPostId) || other.forwardedPostId == forwardedPostId)&&(identical(other.forwardedPost, forwardedPost) || other.forwardedPost == forwardedPost)&&const DeepCollectionEquality().equals(other._attachments, _attachments)&&(identical(other.publisher, publisher) || other.publisher == publisher)&&const DeepCollectionEquality().equals(other._reactionsCount, _reactionsCount)&&const DeepCollectionEquality().equals(other._reactionsMade, _reactionsMade)&&const DeepCollectionEquality().equals(other._reactions, _reactions)&&const DeepCollectionEquality().equals(other._tags, _tags)&&const DeepCollectionEquality().equals(other._categories, _categories)&&const DeepCollectionEquality().equals(other._collections, _collections)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.isTruncated, isTruncated) || other.isTruncated == isTruncated));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnPost&&(identical(other.id, id) || other.id == id)&&(identical(other.title, title) || other.title == title)&&(identical(other.description, description) || other.description == description)&&(identical(other.language, language) || other.language == language)&&(identical(other.editedAt, editedAt) || other.editedAt == editedAt)&&(identical(other.publishedAt, publishedAt) || other.publishedAt == publishedAt)&&(identical(other.visibility, visibility) || other.visibility == visibility)&&(identical(other.content, content) || other.content == content)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.type, type) || other.type == type)&&const DeepCollectionEquality().equals(other._meta, _meta)&&(identical(other.viewsUnique, viewsUnique) || other.viewsUnique == viewsUnique)&&(identical(other.viewsTotal, viewsTotal) || other.viewsTotal == viewsTotal)&&(identical(other.upvotes, upvotes) || other.upvotes == upvotes)&&(identical(other.downvotes, downvotes) || other.downvotes == downvotes)&&(identical(other.repliesCount, repliesCount) || other.repliesCount == repliesCount)&&(identical(other.threadedPostId, threadedPostId) || other.threadedPostId == threadedPostId)&&(identical(other.threadedPost, threadedPost) || other.threadedPost == threadedPost)&&(identical(other.repliedPostId, repliedPostId) || other.repliedPostId == repliedPostId)&&(identical(other.repliedPost, repliedPost) || other.repliedPost == repliedPost)&&(identical(other.forwardedPostId, forwardedPostId) || other.forwardedPostId == forwardedPostId)&&(identical(other.forwardedPost, forwardedPost) || other.forwardedPost == forwardedPost)&&(identical(other.realmId, realmId) || other.realmId == realmId)&&(identical(other.realm, realm) || other.realm == realm)&&const DeepCollectionEquality().equals(other._attachments, _attachments)&&(identical(other.publisher, publisher) || other.publisher == publisher)&&const DeepCollectionEquality().equals(other._reactionsCount, _reactionsCount)&&const DeepCollectionEquality().equals(other._reactionsMade, _reactionsMade)&&const DeepCollectionEquality().equals(other._reactions, _reactions)&&const DeepCollectionEquality().equals(other._tags, _tags)&&const DeepCollectionEquality().equals(other._categories, _categories)&&const DeepCollectionEquality().equals(other._collections, _collections)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.isTruncated, isTruncated) || other.isTruncated == isTruncated));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hashAll([runtimeType,id,title,description,language,editedAt,publishedAt,visibility,content,type,const DeepCollectionEquality().hash(_meta),viewsUnique,viewsTotal,upvotes,downvotes,repliesCount,threadedPostId,threadedPost,repliedPostId,repliedPost,forwardedPostId,forwardedPost,const DeepCollectionEquality().hash(_attachments),publisher,const DeepCollectionEquality().hash(_reactionsCount),const DeepCollectionEquality().hash(_reactionsMade),const DeepCollectionEquality().hash(_reactions),const DeepCollectionEquality().hash(_tags),const DeepCollectionEquality().hash(_categories),const DeepCollectionEquality().hash(_collections),createdAt,updatedAt,deletedAt,isTruncated]);
|
||||
int get hashCode => Object.hashAll([runtimeType,id,title,description,language,editedAt,publishedAt,visibility,content,slug,type,const DeepCollectionEquality().hash(_meta),viewsUnique,viewsTotal,upvotes,downvotes,repliesCount,threadedPostId,threadedPost,repliedPostId,repliedPost,forwardedPostId,forwardedPost,realmId,realm,const DeepCollectionEquality().hash(_attachments),publisher,const DeepCollectionEquality().hash(_reactionsCount),const DeepCollectionEquality().hash(_reactionsMade),const DeepCollectionEquality().hash(_reactions),const DeepCollectionEquality().hash(_tags),const DeepCollectionEquality().hash(_categories),const DeepCollectionEquality().hash(_collections),createdAt,updatedAt,deletedAt,isTruncated]);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'SnPost(id: $id, title: $title, description: $description, language: $language, editedAt: $editedAt, publishedAt: $publishedAt, visibility: $visibility, content: $content, type: $type, meta: $meta, viewsUnique: $viewsUnique, viewsTotal: $viewsTotal, upvotes: $upvotes, downvotes: $downvotes, repliesCount: $repliesCount, threadedPostId: $threadedPostId, threadedPost: $threadedPost, repliedPostId: $repliedPostId, repliedPost: $repliedPost, forwardedPostId: $forwardedPostId, forwardedPost: $forwardedPost, attachments: $attachments, publisher: $publisher, reactionsCount: $reactionsCount, reactionsMade: $reactionsMade, reactions: $reactions, tags: $tags, categories: $categories, collections: $collections, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, isTruncated: $isTruncated)';
|
||||
return 'SnPost(id: $id, title: $title, description: $description, language: $language, editedAt: $editedAt, publishedAt: $publishedAt, visibility: $visibility, content: $content, slug: $slug, type: $type, meta: $meta, viewsUnique: $viewsUnique, viewsTotal: $viewsTotal, upvotes: $upvotes, downvotes: $downvotes, repliesCount: $repliesCount, threadedPostId: $threadedPostId, threadedPost: $threadedPost, repliedPostId: $repliedPostId, repliedPost: $repliedPost, forwardedPostId: $forwardedPostId, forwardedPost: $forwardedPost, realmId: $realmId, realm: $realm, attachments: $attachments, publisher: $publisher, reactionsCount: $reactionsCount, reactionsMade: $reactionsMade, reactions: $reactions, tags: $tags, categories: $categories, collections: $collections, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, isTruncated: $isTruncated)';
|
||||
}
|
||||
|
||||
|
||||
@@ -400,11 +418,11 @@ abstract mixin class _$SnPostCopyWith<$Res> implements $SnPostCopyWith<$Res> {
|
||||
factory _$SnPostCopyWith(_SnPost value, $Res Function(_SnPost) _then) = __$SnPostCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, int type, Map<String, dynamic>? meta, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, List<SnCloudFile> attachments, SnPublisher publisher, Map<String, int> reactionsCount, Map<String, bool> reactionsMade, List<dynamic> reactions, List<SnPostTag> tags, List<SnPostCategory> categories, List<dynamic> collections, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool isTruncated
|
||||
String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map<String, dynamic>? meta, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, String? realmId, SnRealm? realm, List<SnCloudFile> attachments, SnPublisher publisher, Map<String, int> reactionsCount, Map<String, bool> reactionsMade, List<dynamic> reactions, List<SnPostTag> tags, List<SnPostCategory> categories, List<dynamic> collections, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool isTruncated
|
||||
});
|
||||
|
||||
|
||||
@override $SnPostCopyWith<$Res>? get threadedPost;@override $SnPostCopyWith<$Res>? get repliedPost;@override $SnPostCopyWith<$Res>? get forwardedPost;@override $SnPublisherCopyWith<$Res> get publisher;
|
||||
@override $SnPostCopyWith<$Res>? get threadedPost;@override $SnPostCopyWith<$Res>? get repliedPost;@override $SnPostCopyWith<$Res>? get forwardedPost;@override $SnRealmCopyWith<$Res>? get realm;@override $SnPublisherCopyWith<$Res> get publisher;
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
@@ -417,7 +435,7 @@ class __$SnPostCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of SnPost
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? title = freezed,Object? description = freezed,Object? language = freezed,Object? editedAt = freezed,Object? publishedAt = freezed,Object? visibility = null,Object? content = freezed,Object? type = null,Object? meta = freezed,Object? viewsUnique = null,Object? viewsTotal = null,Object? upvotes = null,Object? downvotes = null,Object? repliesCount = null,Object? threadedPostId = freezed,Object? threadedPost = freezed,Object? repliedPostId = freezed,Object? repliedPost = freezed,Object? forwardedPostId = freezed,Object? forwardedPost = freezed,Object? attachments = null,Object? publisher = null,Object? reactionsCount = null,Object? reactionsMade = null,Object? reactions = null,Object? tags = null,Object? categories = null,Object? collections = null,Object? createdAt = freezed,Object? updatedAt = freezed,Object? deletedAt = freezed,Object? isTruncated = null,}) {
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? title = freezed,Object? description = freezed,Object? language = freezed,Object? editedAt = freezed,Object? publishedAt = freezed,Object? visibility = null,Object? content = freezed,Object? slug = freezed,Object? type = null,Object? meta = freezed,Object? viewsUnique = null,Object? viewsTotal = null,Object? upvotes = null,Object? downvotes = null,Object? repliesCount = null,Object? threadedPostId = freezed,Object? threadedPost = freezed,Object? repliedPostId = freezed,Object? repliedPost = freezed,Object? forwardedPostId = freezed,Object? forwardedPost = freezed,Object? realmId = freezed,Object? realm = freezed,Object? attachments = null,Object? publisher = null,Object? reactionsCount = null,Object? reactionsMade = null,Object? reactions = null,Object? tags = null,Object? categories = null,Object? collections = null,Object? createdAt = freezed,Object? updatedAt = freezed,Object? deletedAt = freezed,Object? isTruncated = null,}) {
|
||||
return _then(_SnPost(
|
||||
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
||||
as String,title: freezed == title ? _self.title : title // ignore: cast_nullable_to_non_nullable
|
||||
@@ -427,6 +445,7 @@ as String?,editedAt: freezed == editedAt ? _self.editedAt : editedAt // ignore:
|
||||
as DateTime?,publishedAt: freezed == publishedAt ? _self.publishedAt : publishedAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime?,visibility: null == visibility ? _self.visibility : visibility // ignore: cast_nullable_to_non_nullable
|
||||
as int,content: freezed == content ? _self.content : content // ignore: cast_nullable_to_non_nullable
|
||||
as String?,slug: freezed == slug ? _self.slug : slug // ignore: cast_nullable_to_non_nullable
|
||||
as String?,type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable
|
||||
as int,meta: freezed == meta ? _self._meta : meta // ignore: cast_nullable_to_non_nullable
|
||||
as Map<String, dynamic>?,viewsUnique: null == viewsUnique ? _self.viewsUnique : viewsUnique // ignore: cast_nullable_to_non_nullable
|
||||
@@ -440,7 +459,9 @@ as SnPost?,repliedPostId: freezed == repliedPostId ? _self.repliedPostId : repli
|
||||
as String?,repliedPost: freezed == repliedPost ? _self.repliedPost : repliedPost // ignore: cast_nullable_to_non_nullable
|
||||
as SnPost?,forwardedPostId: freezed == forwardedPostId ? _self.forwardedPostId : forwardedPostId // ignore: cast_nullable_to_non_nullable
|
||||
as String?,forwardedPost: freezed == forwardedPost ? _self.forwardedPost : forwardedPost // ignore: cast_nullable_to_non_nullable
|
||||
as SnPost?,attachments: null == attachments ? _self._attachments : attachments // ignore: cast_nullable_to_non_nullable
|
||||
as SnPost?,realmId: freezed == realmId ? _self.realmId : realmId // ignore: cast_nullable_to_non_nullable
|
||||
as String?,realm: freezed == realm ? _self.realm : realm // ignore: cast_nullable_to_non_nullable
|
||||
as SnRealm?,attachments: null == attachments ? _self._attachments : attachments // ignore: cast_nullable_to_non_nullable
|
||||
as List<SnCloudFile>,publisher: null == publisher ? _self.publisher : publisher // ignore: cast_nullable_to_non_nullable
|
||||
as SnPublisher,reactionsCount: null == reactionsCount ? _self._reactionsCount : reactionsCount // ignore: cast_nullable_to_non_nullable
|
||||
as Map<String, int>,reactionsMade: null == reactionsMade ? _self._reactionsMade : reactionsMade // ignore: cast_nullable_to_non_nullable
|
||||
@@ -496,6 +517,18 @@ $SnPostCopyWith<$Res>? get forwardedPost {
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$SnRealmCopyWith<$Res>? get realm {
|
||||
if (_self.realm == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $SnRealmCopyWith<$Res>(_self.realm!, (value) {
|
||||
return _then(_self.copyWith(realm: value));
|
||||
});
|
||||
}/// Create a copy of SnPost
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$SnPublisherCopyWith<$Res> get publisher {
|
||||
|
||||
return $SnPublisherCopyWith<$Res>(_self.publisher, (value) {
|
||||
|
@@ -21,6 +21,7 @@ _SnPost _$SnPostFromJson(Map<String, dynamic> json) => _SnPost(
|
||||
: DateTime.parse(json['published_at'] as String),
|
||||
visibility: (json['visibility'] as num?)?.toInt() ?? 0,
|
||||
content: json['content'] as String?,
|
||||
slug: json['slug'] as String?,
|
||||
type: (json['type'] as num?)?.toInt() ?? 0,
|
||||
meta: json['meta'] as Map<String, dynamic>?,
|
||||
viewsUnique: (json['views_unique'] as num?)?.toInt() ?? 0,
|
||||
@@ -43,6 +44,11 @@ _SnPost _$SnPostFromJson(Map<String, dynamic> json) => _SnPost(
|
||||
json['forwarded_post'] == null
|
||||
? null
|
||||
: SnPost.fromJson(json['forwarded_post'] as Map<String, dynamic>),
|
||||
realmId: json['realm_id'] as String?,
|
||||
realm:
|
||||
json['realm'] == null
|
||||
? null
|
||||
: SnRealm.fromJson(json['realm'] as Map<String, dynamic>),
|
||||
attachments:
|
||||
(json['attachments'] as List<dynamic>?)
|
||||
?.map((e) => SnCloudFile.fromJson(e as Map<String, dynamic>))
|
||||
@@ -95,6 +101,7 @@ Map<String, dynamic> _$SnPostToJson(_SnPost instance) => <String, dynamic>{
|
||||
'published_at': instance.publishedAt?.toIso8601String(),
|
||||
'visibility': instance.visibility,
|
||||
'content': instance.content,
|
||||
'slug': instance.slug,
|
||||
'type': instance.type,
|
||||
'meta': instance.meta,
|
||||
'views_unique': instance.viewsUnique,
|
||||
@@ -108,6 +115,8 @@ Map<String, dynamic> _$SnPostToJson(_SnPost instance) => <String, dynamic>{
|
||||
'replied_post': instance.repliedPost?.toJson(),
|
||||
'forwarded_post_id': instance.forwardedPostId,
|
||||
'forwarded_post': instance.forwardedPost?.toJson(),
|
||||
'realm_id': instance.realmId,
|
||||
'realm': instance.realm?.toJson(),
|
||||
'attachments': instance.attachments.map((e) => e.toJson()).toList(),
|
||||
'publisher': instance.publisher.toJson(),
|
||||
'reactions_count': instance.reactionsCount,
|
||||
|
@@ -23,6 +23,8 @@ const kAppSoundEffects = 'app_sound_effects';
|
||||
const kAppAprilFoolFeatures = 'app_april_fool_features';
|
||||
const kAppWindowSize = 'app_window_size';
|
||||
const kAppEnterToSend = 'app_enter_to_send';
|
||||
const kFeaturedPostsCollapsedId =
|
||||
'featured_posts_collapsed_id'; // Key for storing the ID of the collapsed featured post
|
||||
|
||||
const Map<String, FilterQuality> kImageQualityLevel = {
|
||||
'settingsImageQualityLowest': FilterQuality.none,
|
||||
|
@@ -1,6 +1,8 @@
|
||||
import 'dart:io' show Platform;
|
||||
import 'package:animations/animations.dart';
|
||||
import 'package:firebase_analytics/firebase_analytics.dart';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/foundation.dart' show kIsWeb;
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:island/screens/about.dart';
|
||||
@@ -20,9 +22,9 @@ import 'package:island/screens/notification.dart';
|
||||
import 'package:island/screens/wallet.dart';
|
||||
import 'package:island/screens/account/relationship.dart';
|
||||
import 'package:island/screens/account/profile.dart';
|
||||
import 'package:island/screens/account/me/update.dart';
|
||||
import 'package:island/screens/account/me/profile_update.dart';
|
||||
import 'package:island/screens/account/leveling.dart';
|
||||
import 'package:island/screens/account/me/settings.dart';
|
||||
import 'package:island/screens/account/me/account_settings.dart';
|
||||
import 'package:island/screens/chat/chat.dart';
|
||||
import 'package:island/screens/chat/room.dart';
|
||||
import 'package:island/screens/chat/room_detail.dart';
|
||||
@@ -56,12 +58,34 @@ final rootNavigatorKey = GlobalKey<NavigatorState>();
|
||||
final _shellNavigatorKey = GlobalKey<NavigatorState>();
|
||||
final _tabsShellKey = GlobalKey<NavigatorState>();
|
||||
|
||||
Widget _tabPagesTransitionBuilder(
|
||||
BuildContext context,
|
||||
Animation<double> animation,
|
||||
Animation<double> secondaryAnimation,
|
||||
Widget child,
|
||||
) {
|
||||
return FadeThroughTransition(
|
||||
animation: animation,
|
||||
secondaryAnimation: secondaryAnimation,
|
||||
fillColor: Theme.of(context).colorScheme.surface,
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
|
||||
bool get _supportsAnalytics =>
|
||||
kIsWeb ||
|
||||
Platform.isAndroid ||
|
||||
Platform.isIOS ||
|
||||
Platform.isMacOS ||
|
||||
Platform.isWindows;
|
||||
|
||||
// Provider for the router
|
||||
final routerProvider = Provider<GoRouter>((ref) {
|
||||
return GoRouter(
|
||||
navigatorKey: rootNavigatorKey,
|
||||
initialLocation: '/',
|
||||
observers: [
|
||||
if (_supportsAnalytics)
|
||||
FirebaseAnalyticsObserver(analytics: FirebaseAnalytics.instance),
|
||||
],
|
||||
routes: [
|
||||
@@ -339,7 +363,12 @@ final routerProvider = Provider<GoRouter>((ref) {
|
||||
GoRoute(
|
||||
name: 'explore',
|
||||
path: '/',
|
||||
builder: (context, state) => const ExploreScreen(),
|
||||
pageBuilder:
|
||||
(context, state) => CustomTransitionPage(
|
||||
key: const ValueKey('explore'),
|
||||
child: const ExploreScreen(),
|
||||
transitionsBuilder: _tabPagesTransitionBuilder,
|
||||
),
|
||||
),
|
||||
GoRoute(
|
||||
name: 'postSearch',
|
||||
@@ -389,8 +418,12 @@ final routerProvider = Provider<GoRouter>((ref) {
|
||||
|
||||
// Chat tab
|
||||
ShellRoute(
|
||||
builder:
|
||||
(context, state, child) => ChatShellScreen(child: child),
|
||||
pageBuilder:
|
||||
(context, state, child) => CustomTransitionPage(
|
||||
key: const ValueKey('chat'),
|
||||
child: ChatShellScreen(child: child),
|
||||
transitionsBuilder: _tabPagesTransitionBuilder,
|
||||
),
|
||||
routes: [
|
||||
GoRoute(
|
||||
name: 'chatList',
|
||||
@@ -433,7 +466,12 @@ final routerProvider = Provider<GoRouter>((ref) {
|
||||
GoRoute(
|
||||
name: 'realmList',
|
||||
path: '/realms',
|
||||
builder: (context, state) => const RealmListScreen(),
|
||||
pageBuilder:
|
||||
(context, state) => CustomTransitionPage(
|
||||
key: const ValueKey('realms'),
|
||||
child: const RealmListScreen(),
|
||||
transitionsBuilder: _tabPagesTransitionBuilder,
|
||||
),
|
||||
routes: [
|
||||
GoRoute(
|
||||
name: 'realmNew',
|
||||
@@ -461,8 +499,12 @@ final routerProvider = Provider<GoRouter>((ref) {
|
||||
|
||||
// Account tab
|
||||
ShellRoute(
|
||||
builder:
|
||||
(context, state, child) => AccountShellScreen(child: child),
|
||||
pageBuilder:
|
||||
(context, state, child) => CustomTransitionPage(
|
||||
key: const ValueKey('account'),
|
||||
child: AccountShellScreen(child: child),
|
||||
transitionsBuilder: _tabPagesTransitionBuilder,
|
||||
),
|
||||
routes: [
|
||||
GoRoute(
|
||||
name: 'account',
|
||||
|
@@ -178,7 +178,8 @@ class _AboutScreenState extends ConsumerState<AboutScreen> {
|
||||
context,
|
||||
icon: Symbols.label,
|
||||
label: 'aboutDeviceName'.tr(),
|
||||
value: _deviceInfo?.data['name'],
|
||||
value:
|
||||
_deviceInfo?.data['name'] ?? 'unknown'.tr(),
|
||||
),
|
||||
_buildInfoItem(
|
||||
context,
|
||||
|
@@ -23,7 +23,7 @@ import 'package:material_symbols_icons/symbols.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
|
||||
part 'settings.g.dart';
|
||||
part 'account_settings.g.dart';
|
||||
|
||||
@riverpod
|
||||
Future<List<SnAuthFactor>> authFactors(Ref ref) async {
|
@@ -1,6 +1,6 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'settings.dart';
|
||||
part of 'account_settings.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
@@ -1,3 +1,4 @@
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:croppy/croppy.dart' hide cropImage;
|
||||
import 'package:dropdown_button2/dropdown_button2.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
@@ -168,11 +169,18 @@ class UpdateProfileScreen extends HookConsumerWidget {
|
||||
'location': locationController.text,
|
||||
'time_zone': timeZoneController.text,
|
||||
'birthday': birthday.value?.toUtc().toIso8601String(),
|
||||
'links': links.value,
|
||||
'links':
|
||||
links.value
|
||||
.where((e) => e.name.isNotEmpty && e.url.isNotEmpty)
|
||||
.toList(),
|
||||
},
|
||||
);
|
||||
final userNotifier = ref.read(userInfoProvider.notifier);
|
||||
userNotifier.fetchUser();
|
||||
links.value =
|
||||
links.value
|
||||
.where((e) => e.name.isNotEmpty && e.url.isNotEmpty)
|
||||
.toList();
|
||||
} catch (err) {
|
||||
showErrorAlert(err);
|
||||
} finally {
|
||||
@@ -568,6 +576,7 @@ class UpdateProfileScreen extends HookConsumerWidget {
|
||||
children: [
|
||||
for (var i = 0; i < links.value.length; i++)
|
||||
Row(
|
||||
key: ValueKey(links.value[i].hashCode),
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
Expanded(
|
||||
@@ -610,8 +619,10 @@ class UpdateProfileScreen extends HookConsumerWidget {
|
||||
IconButton(
|
||||
icon: const Icon(Symbols.delete),
|
||||
onPressed: () {
|
||||
links.value = List.from(links.value)
|
||||
..removeAt(i);
|
||||
links.value =
|
||||
links.value
|
||||
.whereIndexed((idx, _) => idx != i)
|
||||
.toList();
|
||||
},
|
||||
),
|
||||
],
|
@@ -6,7 +6,7 @@ import 'package:gap/gap.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:island/models/auth.dart';
|
||||
import 'package:island/pods/network.dart';
|
||||
import 'package:island/screens/account/me/settings.dart';
|
||||
import 'package:island/screens/account/me/account_settings.dart';
|
||||
import 'package:island/screens/auth/oidc.native.dart';
|
||||
import 'package:island/services/text.dart';
|
||||
import 'package:island/services/time.dart';
|
||||
|
@@ -6,7 +6,7 @@ import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:gap/gap.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:island/pods/network.dart';
|
||||
import 'package:island/screens/account/me/update.dart';
|
||||
import 'package:island/screens/account/me/profile_update.dart';
|
||||
import 'package:island/widgets/alert.dart';
|
||||
import 'package:island/widgets/app_scaffold.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
|
@@ -23,7 +23,7 @@ import 'package:island/widgets/alert.dart';
|
||||
import 'package:island/widgets/app_scaffold.dart';
|
||||
import 'package:island/widgets/content/cloud_files.dart';
|
||||
import 'package:island/widgets/content/sheet.dart';
|
||||
import 'package:island/widgets/realms/selection_dropdown.dart';
|
||||
import 'package:island/widgets/realm/realm_selection_dropdown.dart';
|
||||
import 'package:island/widgets/response.dart';
|
||||
import 'package:island/screens/tabs.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,7 @@ part of 'room.dart';
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$messagesNotifierHash() => r'afc4d43f4948ec571118cef0321838a6cefc89c0';
|
||||
String _$messagesNotifierHash() => r'3740c02ab1e4dba9c8e619b63c40e2236a89b342';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
@@ -19,7 +19,7 @@ import 'package:island/services/responsive.dart';
|
||||
import 'package:island/widgets/alert.dart';
|
||||
import 'package:island/widgets/app_scaffold.dart';
|
||||
import 'package:island/widgets/content/cloud_files.dart';
|
||||
import 'package:island/widgets/realms/selection_dropdown.dart';
|
||||
import 'package:island/widgets/realm/realm_selection_dropdown.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
|
@@ -11,6 +11,7 @@ import 'package:island/models/realm.dart';
|
||||
import 'package:island/models/webfeed.dart';
|
||||
import 'package:island/pods/event_calendar.dart';
|
||||
import 'package:island/pods/userinfo.dart';
|
||||
import 'package:island/screens/notification.dart';
|
||||
import 'package:island/services/responsive.dart';
|
||||
import 'package:island/widgets/account/fortune_graph.dart';
|
||||
import 'package:island/widgets/app_scaffold.dart';
|
||||
@@ -30,6 +31,33 @@ import 'package:styled_widget/styled_widget.dart';
|
||||
|
||||
part 'explore.g.dart';
|
||||
|
||||
Widget notificationIndicatorWidget(
|
||||
BuildContext context, {
|
||||
required int count,
|
||||
EdgeInsets? margin,
|
||||
}) => Card(
|
||||
margin: margin,
|
||||
child: ListTile(
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(8)),
|
||||
),
|
||||
leading: const Icon(Symbols.notifications),
|
||||
title: Row(
|
||||
children: [
|
||||
Text('notifications').tr().fontSize(14),
|
||||
const Gap(8),
|
||||
Badge(label: Text(count.toString())),
|
||||
],
|
||||
),
|
||||
trailing: const Icon(Symbols.chevron_right),
|
||||
minTileHeight: 40,
|
||||
contentPadding: EdgeInsets.only(left: 16, right: 15),
|
||||
onTap: () {
|
||||
GoRouter.of(context).pushNamed('notifications');
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
class ExploreScreen extends HookConsumerWidget {
|
||||
const ExploreScreen({super.key});
|
||||
|
||||
@@ -77,6 +105,10 @@ class ExploreScreen extends HookConsumerWidget {
|
||||
|
||||
final user = ref.watch(userInfoProvider);
|
||||
|
||||
final notificationCount = ref.watch(
|
||||
notificationUnreadCountNotifierProvider,
|
||||
);
|
||||
|
||||
return AppScaffold(
|
||||
isNoBackground: false,
|
||||
appBar: AppBar(
|
||||
@@ -185,7 +217,7 @@ class ExploreScreen extends HookConsumerWidget {
|
||||
floatingActionButtonLocation: TabbedFabLocation(context),
|
||||
body: Builder(
|
||||
builder: (context) {
|
||||
final isWider = isWiderScreen(context);
|
||||
final isWide = isWideScreen(context);
|
||||
|
||||
final bodyView = _buildActivityList(
|
||||
context,
|
||||
@@ -193,13 +225,15 @@ class ExploreScreen extends HookConsumerWidget {
|
||||
currentFilter.value,
|
||||
);
|
||||
|
||||
if (isWider) {
|
||||
if (isWide) {
|
||||
return Row(
|
||||
children: [
|
||||
Flexible(flex: 3, child: bodyView.padding(left: 8)),
|
||||
if (user.value != null)
|
||||
Flexible(
|
||||
flex: 2,
|
||||
child: Align(
|
||||
alignment: Alignment.topCenter,
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
@@ -215,13 +249,28 @@ class ExploreScreen extends HookConsumerWidget {
|
||||
);
|
||||
},
|
||||
),
|
||||
if (notificationCount.value != null &&
|
||||
notificationCount.value! > 0)
|
||||
notificationIndicatorWidget(
|
||||
context,
|
||||
count: notificationCount.value ?? 0,
|
||||
margin: EdgeInsets.only(
|
||||
left: 8,
|
||||
right: 12,
|
||||
top: 8,
|
||||
),
|
||||
),
|
||||
PostFeaturedList().padding(
|
||||
left: 8,
|
||||
right: 12,
|
||||
top: 8,
|
||||
),
|
||||
FortuneGraphWidget(
|
||||
margin: EdgeInsets.only(left: 8, right: 12, top: 8),
|
||||
margin: EdgeInsets.only(
|
||||
left: 8,
|
||||
right: 12,
|
||||
top: 8,
|
||||
),
|
||||
events: events,
|
||||
constrainWidth: true,
|
||||
onPointSelected: onDaySelected,
|
||||
@@ -229,6 +278,7 @@ class ExploreScreen extends HookConsumerWidget {
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
else
|
||||
Flexible(
|
||||
@@ -268,7 +318,7 @@ class ExploreScreen extends HookConsumerWidget {
|
||||
activityListNotifierProvider(filter).notifier,
|
||||
);
|
||||
|
||||
final isWider = isWiderScreen(context);
|
||||
final isWide = isWideScreen(context);
|
||||
|
||||
return RefreshIndicator(
|
||||
onRefresh: () => Future.sync(activitiesNotifier.forceRefresh),
|
||||
@@ -283,7 +333,7 @@ class ExploreScreen extends HookConsumerWidget {
|
||||
widgetCount: widgetCount,
|
||||
endItemView: endItemView,
|
||||
activitiesNotifier: activitiesNotifier,
|
||||
contentOnly: isWider || filter != null,
|
||||
contentOnly: isWide || filter != null,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -380,6 +430,10 @@ class _ActivityListView extends HookConsumerWidget {
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final user = ref.watch(userInfoProvider);
|
||||
|
||||
final notificationCount = ref.watch(
|
||||
notificationUnreadCountNotifierProvider,
|
||||
);
|
||||
|
||||
return CustomScrollView(
|
||||
slivers: [
|
||||
SliverGap(12),
|
||||
@@ -393,6 +447,14 @@ class _ActivityListView extends HookConsumerWidget {
|
||||
SliverToBoxAdapter(
|
||||
child: PostFeaturedList().padding(horizontal: 8, bottom: 4, top: 4),
|
||||
),
|
||||
if (!contentOnly)
|
||||
SliverToBoxAdapter(
|
||||
child: notificationIndicatorWidget(
|
||||
context,
|
||||
count: notificationCount.value ?? 0,
|
||||
margin: EdgeInsets.only(left: 8, right: 8, top: 4, bottom: 4),
|
||||
),
|
||||
),
|
||||
SliverList.builder(
|
||||
itemCount: widgetCount,
|
||||
itemBuilder: (context, index) {
|
||||
|
@@ -3,14 +3,17 @@ import 'dart:math' as math;
|
||||
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:gap/gap.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:island/models/account.dart';
|
||||
import 'package:island/pods/network.dart';
|
||||
import 'package:island/pods/websocket.dart';
|
||||
import 'package:island/route.dart';
|
||||
import 'package:island/widgets/alert.dart';
|
||||
import 'package:island/widgets/app_scaffold.dart';
|
||||
import 'package:island/widgets/content/markdown.dart';
|
||||
import 'package:material_symbols_icons/material_symbols_icons.dart';
|
||||
import 'package:relative_time/relative_time.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:riverpod_paging_utils/riverpod_paging_utils.dart';
|
||||
@@ -62,6 +65,10 @@ class NotificationUnreadCountNotifier
|
||||
final current = await future;
|
||||
state = AsyncData(math.max(current - count, 0));
|
||||
}
|
||||
|
||||
void clear() async {
|
||||
state = AsyncData(0);
|
||||
}
|
||||
}
|
||||
|
||||
@riverpod
|
||||
@@ -111,8 +118,27 @@ class NotificationScreen extends HookConsumerWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
Future<void> markAllRead() async {
|
||||
showLoadingModal(context);
|
||||
final apiClient = ref.watch(apiClientProvider);
|
||||
await apiClient.post('/pusher/notifications/all/read');
|
||||
if (!context.mounted) return;
|
||||
hideLoadingModal(context);
|
||||
ref.invalidate(notificationListNotifierProvider);
|
||||
ref.watch(notificationUnreadCountNotifierProvider.notifier).clear();
|
||||
}
|
||||
|
||||
return AppScaffold(
|
||||
appBar: AppBar(title: const Text('notifications').tr()),
|
||||
appBar: AppBar(
|
||||
title: const Text('notifications').tr(),
|
||||
actions: [
|
||||
IconButton(
|
||||
onPressed: markAllRead,
|
||||
icon: const Icon(Symbols.mark_as_unread),
|
||||
),
|
||||
const Gap(8),
|
||||
],
|
||||
),
|
||||
body: PagingHelperView(
|
||||
provider: notificationListNotifierProvider,
|
||||
futureRefreshable: notificationListNotifierProvider.future,
|
||||
|
@@ -7,7 +7,7 @@ part of 'notification.dart';
|
||||
// **************************************************************************
|
||||
|
||||
String _$notificationUnreadCountNotifierHash() =>
|
||||
r'd199abf0d16944587e747798399a267a790341f3';
|
||||
r'0763b66bd64e5a9b7c317887e109ab367515dfa4';
|
||||
|
||||
/// See also [NotificationUnreadCountNotifier].
|
||||
@ProviderFor(NotificationUnreadCountNotifier)
|
||||
|
@@ -311,8 +311,8 @@ class ArticleComposeScreen extends HookConsumerWidget {
|
||||
valueListenable: state.attachmentProgress,
|
||||
builder: (context, progressMap, _) {
|
||||
return Wrap(
|
||||
spacing: 8,
|
||||
runSpacing: 8,
|
||||
spacing: 8,
|
||||
children: [
|
||||
for (var idx = 0; idx < attachments.length; idx++)
|
||||
SizedBox(
|
||||
|
@@ -51,12 +51,12 @@ class PostSearchNotifier
|
||||
final offset = cursor == null ? 0 : int.parse(cursor);
|
||||
|
||||
final response = await client.get(
|
||||
'/sphere/posts/search',
|
||||
'/sphere/posts',
|
||||
queryParameters: {
|
||||
'query': _currentQuery,
|
||||
'offset': offset,
|
||||
'take': _pageSize,
|
||||
'useVector': false,
|
||||
'vector': false,
|
||||
},
|
||||
);
|
||||
|
||||
|
@@ -147,7 +147,11 @@ class PublisherProfileScreen extends HookConsumerWidget {
|
||||
),
|
||||
backgroundColor: Theme.of(context).colorScheme.primary,
|
||||
offset: Offset(0, 48),
|
||||
child: ProfilePictureWidget(file: data.picture, radius: 32),
|
||||
child: ProfilePictureWidget(
|
||||
file: data.picture,
|
||||
radius: 32,
|
||||
borderRadius: data.type == 0 ? null : 12,
|
||||
),
|
||||
),
|
||||
onTap: () {
|
||||
Navigator.pop(context, true);
|
||||
|
@@ -26,7 +26,12 @@ StreamSubscription<WebSocketPacket> setupNotificationListener(
|
||||
final notification = SnNotification.fromJson(pkt.data!);
|
||||
showTopSnackBar(
|
||||
globalOverlay.currentState!,
|
||||
NotificationCard(notification: notification),
|
||||
Center(
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 480),
|
||||
child: NotificationCard(notification: notification),
|
||||
),
|
||||
),
|
||||
onTap: () {
|
||||
if (notification.meta['action_uri'] != null) {
|
||||
var uri = notification.meta['action_uri'] as String;
|
||||
@@ -53,9 +58,9 @@ StreamSubscription<WebSocketPacket> setupNotificationListener(
|
||||
(Platform.isMacOS ||
|
||||
Platform.isWindows ||
|
||||
Platform.isLinux))
|
||||
? 24
|
||||
? 28
|
||||
// ignore: use_build_context_synchronously
|
||||
: MediaQuery.of(context).padding.top + 8,
|
||||
: MediaQuery.of(context).padding.top + 16,
|
||||
bottom: 16,
|
||||
),
|
||||
);
|
||||
|
@@ -162,7 +162,7 @@ class AccountSessionSheet extends HookConsumerWidget {
|
||||
try {
|
||||
final apiClient = ref.watch(apiClientProvider);
|
||||
await apiClient.patch(
|
||||
'/accounts/me/devices/$sessionId/label',
|
||||
'/id/accounts/me/devices/$sessionId/label',
|
||||
data: jsonEncode(label),
|
||||
);
|
||||
ref.invalidate(authDevicesProvider);
|
||||
|
@@ -11,7 +11,12 @@ export 'content/alert.native.dart'
|
||||
void showSnackBar(String message, {SnackBarAction? action}) {
|
||||
showTopSnackBar(
|
||||
globalOverlay.currentState!,
|
||||
Card(child: Text(message).padding(horizontal: 20, vertical: 16)),
|
||||
ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 480),
|
||||
child: Center(
|
||||
child: Card(child: Text(message).padding(horizontal: 20, vertical: 16)),
|
||||
),
|
||||
),
|
||||
snackBarPosition: SnackBarPosition.bottom,
|
||||
);
|
||||
}
|
||||
|
@@ -256,6 +256,7 @@ class ProfilePictureWidget extends ConsumerWidget {
|
||||
final String? fileId;
|
||||
final SnCloudFile? file;
|
||||
final double radius;
|
||||
final double? borderRadius;
|
||||
final IconData? fallbackIcon;
|
||||
final Color? fallbackColor;
|
||||
const ProfilePictureWidget({
|
||||
@@ -263,6 +264,7 @@ class ProfilePictureWidget extends ConsumerWidget {
|
||||
this.fileId,
|
||||
this.file,
|
||||
this.radius = 20,
|
||||
this.borderRadius,
|
||||
this.fallbackIcon,
|
||||
this.fallbackColor,
|
||||
});
|
||||
@@ -273,7 +275,10 @@ class ProfilePictureWidget extends ConsumerWidget {
|
||||
final uri = '$serverUrl/drive/files/${file?.id ?? fileId}';
|
||||
|
||||
return ClipRRect(
|
||||
borderRadius: BorderRadius.all(Radius.circular(radius)),
|
||||
borderRadius:
|
||||
borderRadius == null
|
||||
? BorderRadius.all(Radius.circular(radius))
|
||||
: BorderRadius.all(Radius.circular(borderRadius!)),
|
||||
child: Container(
|
||||
width: radius * 2,
|
||||
height: radius * 2,
|
||||
|
@@ -57,11 +57,11 @@ class EmbedLinkWidget extends StatelessWidget {
|
||||
Row(
|
||||
children: [
|
||||
// Favicon
|
||||
if (link.faviconUrl.isNotEmpty) ...[
|
||||
if (link.faviconUrl?.isNotEmpty ?? false) ...[
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
child: UniversalImage(
|
||||
uri: link.faviconUrl,
|
||||
uri: link.faviconUrl!,
|
||||
width: 16,
|
||||
height: 16,
|
||||
fit: BoxFit.cover,
|
||||
@@ -80,8 +80,8 @@ class EmbedLinkWidget extends StatelessWidget {
|
||||
// Site name
|
||||
Expanded(
|
||||
child: Text(
|
||||
link.siteName.isNotEmpty
|
||||
? link.siteName
|
||||
(link.siteName?.isNotEmpty ?? false)
|
||||
? link.siteName!
|
||||
: Uri.parse(link.url).host,
|
||||
style: theme.textTheme.bodySmall?.copyWith(
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
|
@@ -183,9 +183,15 @@ class MarkdownTextContent extends HookConsumerWidget {
|
||||
);
|
||||
}
|
||||
}
|
||||
final content = ConstrainedBox(
|
||||
final content = ClipRRect(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(maxHeight: 360),
|
||||
child: UniversalImage(uri: uri.toString(), fit: BoxFit.contain),
|
||||
child: UniversalImage(
|
||||
uri: uri.toString(),
|
||||
fit: BoxFit.contain,
|
||||
),
|
||||
),
|
||||
);
|
||||
return content;
|
||||
},
|
||||
|
@@ -5,11 +5,15 @@ import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:gap/gap.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:island/models/post_category.dart';
|
||||
import 'package:island/models/realm.dart';
|
||||
import 'package:island/pods/network.dart';
|
||||
import 'package:island/screens/realm/realms.dart';
|
||||
import 'package:island/widgets/content/cloud_files.dart';
|
||||
import 'package:island/widgets/content/sheet.dart';
|
||||
import 'package:island/widgets/post/compose_shared.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
import 'package:textfield_tags/textfield_tags.dart';
|
||||
|
||||
part 'compose_settings_sheet.g.dart';
|
||||
@@ -129,7 +133,9 @@ class ComposeSettingsSheet extends HookConsumerWidget {
|
||||
// Listen to visibility changes to trigger rebuilds
|
||||
final currentVisibility = useValueListenable(state.visibility);
|
||||
final currentCategories = useValueListenable(state.categories);
|
||||
final currentRealm = useValueListenable(state.realm);
|
||||
final postCategories = ref.watch(postCategoriesProvider);
|
||||
final userRealms = ref.watch(realmsJoinedProvider);
|
||||
|
||||
IconData getVisibilityIcon(int visibilityValue) {
|
||||
switch (visibilityValue) {
|
||||
@@ -223,6 +229,24 @@ class ComposeSettingsSheet extends HookConsumerWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
spacing: 16,
|
||||
children: [
|
||||
// Slug field
|
||||
TextField(
|
||||
controller: state.contentController,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'postSlug'.tr(),
|
||||
hintText: 'postSlugHint'.tr(),
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
vertical: 9,
|
||||
horizontal: 16,
|
||||
),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
),
|
||||
onTapOutside:
|
||||
(_) => FocusManager.instance.primaryFocus?.unfocus(),
|
||||
),
|
||||
|
||||
// Tags field
|
||||
TextFieldTags(
|
||||
textfieldTagsController: state.tagsController,
|
||||
@@ -244,7 +268,6 @@ class ComposeSettingsSheet extends HookConsumerWidget {
|
||||
),
|
||||
|
||||
// Categories field
|
||||
// FIXME: Sometimes the entire dropdown crashes: 'package:flutter/src/rendering/stack.dart': Failed assertion: line 799 pos 12: 'firstChild == null || child != null': is not true.
|
||||
DropdownButtonFormField2<SnPostCategory>(
|
||||
isExpanded: true,
|
||||
decoration: InputDecoration(
|
||||
@@ -306,7 +329,7 @@ class ComposeSettingsSheet extends HookConsumerWidget {
|
||||
value: currentCategories.isEmpty ? null : currentCategories.last,
|
||||
onChanged: (_) {},
|
||||
selectedItemBuilder: (context) {
|
||||
return currentCategories.map((item) {
|
||||
return (postCategories.value ?? []).map((item) {
|
||||
return SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: Row(
|
||||
@@ -335,12 +358,89 @@ class ComposeSettingsSheet extends HookConsumerWidget {
|
||||
);
|
||||
}).toList();
|
||||
},
|
||||
buttonStyleData: const ButtonStyleData(
|
||||
padding: EdgeInsets.only(left: 16, right: 8),
|
||||
height: 38,
|
||||
),
|
||||
menuItemStyleData: const MenuItemStyleData(
|
||||
height: 38,
|
||||
padding: EdgeInsets.zero,
|
||||
),
|
||||
),
|
||||
|
||||
// Realm selection
|
||||
DropdownButtonFormField2<SnRealm?>(
|
||||
isExpanded: true,
|
||||
decoration: InputDecoration(
|
||||
contentPadding: const EdgeInsets.symmetric(vertical: 9),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
),
|
||||
hint: Text('realm'.tr(), style: const TextStyle(fontSize: 15)),
|
||||
items: [
|
||||
DropdownMenuItem<SnRealm?>(
|
||||
value: null,
|
||||
child: Row(
|
||||
children: [
|
||||
const CircleAvatar(
|
||||
radius: 16,
|
||||
child: Icon(Symbols.link_off, fill: 1),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Text('postUnlinkRealm').tr(),
|
||||
],
|
||||
).padding(left: 16, right: 8),
|
||||
),
|
||||
if (userRealms.hasValue)
|
||||
...(userRealms.value ?? []).map(
|
||||
(realm) => DropdownMenuItem<SnRealm?>(
|
||||
value: realm,
|
||||
child: Row(
|
||||
children: [
|
||||
ProfilePictureWidget(
|
||||
fileId: realm.picture?.id,
|
||||
fallbackIcon: Symbols.workspaces,
|
||||
radius: 16,
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Text(realm.name),
|
||||
],
|
||||
).padding(left: 16, right: 8),
|
||||
),
|
||||
),
|
||||
],
|
||||
value: currentRealm,
|
||||
onChanged: (value) {
|
||||
state.realm.value = value;
|
||||
},
|
||||
selectedItemBuilder: (context) {
|
||||
return (userRealms.value ?? []).map((_) {
|
||||
return Row(
|
||||
children: [
|
||||
if (currentRealm == null)
|
||||
const CircleAvatar(
|
||||
radius: 16,
|
||||
child: Icon(Symbols.link_off, fill: 1),
|
||||
)
|
||||
else
|
||||
ProfilePictureWidget(
|
||||
fileId: currentRealm.picture?.id,
|
||||
fallbackIcon: Symbols.workspaces,
|
||||
radius: 16,
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Text(currentRealm?.name ?? 'postUnlinkRealm'.tr()),
|
||||
],
|
||||
);
|
||||
}).toList();
|
||||
},
|
||||
buttonStyleData: const ButtonStyleData(
|
||||
padding: EdgeInsets.only(left: 16, right: 8),
|
||||
height: 40,
|
||||
),
|
||||
menuItemStyleData: const MenuItemStyleData(
|
||||
height: 40,
|
||||
height: 56,
|
||||
padding: EdgeInsets.zero,
|
||||
),
|
||||
),
|
||||
|
@@ -9,6 +9,7 @@ import 'package:island/models/file.dart';
|
||||
import 'package:island/models/post.dart';
|
||||
import 'package:island/models/post_category.dart';
|
||||
import 'package:island/models/publisher.dart';
|
||||
import 'package:island/models/realm.dart';
|
||||
import 'package:island/pods/config.dart';
|
||||
import 'package:island/pods/network.dart';
|
||||
import 'package:island/services/file.dart';
|
||||
@@ -26,6 +27,7 @@ class ComposeState {
|
||||
final TextEditingController titleController;
|
||||
final TextEditingController descriptionController;
|
||||
final TextEditingController contentController;
|
||||
final TextEditingController slugController;
|
||||
final ValueNotifier<int> visibility;
|
||||
final ValueNotifier<List<UniversalFile>> attachments;
|
||||
final ValueNotifier<Map<int, double>> attachmentProgress;
|
||||
@@ -33,6 +35,7 @@ class ComposeState {
|
||||
final ValueNotifier<bool> submitting;
|
||||
final ValueNotifier<List<SnPostCategory>> categories;
|
||||
StringTagController tagsController;
|
||||
final ValueNotifier<SnRealm?> realm;
|
||||
final String draftId;
|
||||
int postType;
|
||||
// Linked poll id for this compose session (nullable)
|
||||
@@ -43,6 +46,7 @@ class ComposeState {
|
||||
required this.titleController,
|
||||
required this.descriptionController,
|
||||
required this.contentController,
|
||||
required this.slugController,
|
||||
required this.visibility,
|
||||
required this.attachments,
|
||||
required this.attachmentProgress,
|
||||
@@ -50,6 +54,7 @@ class ComposeState {
|
||||
required this.submitting,
|
||||
required this.tagsController,
|
||||
required this.categories,
|
||||
required this.realm,
|
||||
required this.draftId,
|
||||
this.postType = 0,
|
||||
String? pollId,
|
||||
@@ -104,6 +109,7 @@ class ComposeLogic {
|
||||
text: originalPost?.description,
|
||||
),
|
||||
contentController: TextEditingController(text: originalPost?.content),
|
||||
slugController: TextEditingController(text: originalPost?.slug),
|
||||
visibility: ValueNotifier<int>(originalPost?.visibility ?? 0),
|
||||
submitting: ValueNotifier<bool>(false),
|
||||
attachmentProgress: ValueNotifier<Map<int, double>>({}),
|
||||
@@ -112,6 +118,7 @@ class ComposeLogic {
|
||||
categories: ValueNotifier<List<SnPostCategory>>(
|
||||
originalPost?.categories ?? [],
|
||||
),
|
||||
realm: ValueNotifier(originalPost?.realm),
|
||||
draftId: id,
|
||||
postType: postType,
|
||||
// initialize without poll by default
|
||||
@@ -135,12 +142,14 @@ class ComposeLogic {
|
||||
titleController: TextEditingController(text: draft.title),
|
||||
descriptionController: TextEditingController(text: draft.description),
|
||||
contentController: TextEditingController(text: draft.content),
|
||||
slugController: TextEditingController(text: draft.slug),
|
||||
visibility: ValueNotifier<int>(draft.visibility),
|
||||
submitting: ValueNotifier<bool>(false),
|
||||
attachmentProgress: ValueNotifier<Map<int, double>>({}),
|
||||
currentPublisher: ValueNotifier<SnPublisher?>(null),
|
||||
tagsController: tagsController,
|
||||
categories: ValueNotifier<List<SnPostCategory>>([]),
|
||||
realm: ValueNotifier(null),
|
||||
draftId: draft.id,
|
||||
postType: postType,
|
||||
pollId: null,
|
||||
@@ -629,6 +638,8 @@ class ComposeLogic {
|
||||
'title': state.titleController.text,
|
||||
'description': state.descriptionController.text,
|
||||
'content': state.contentController.text,
|
||||
if (state.slugController.text.isNotEmpty)
|
||||
'slug': state.slugController.text,
|
||||
'visibility': state.visibility.value,
|
||||
'attachments':
|
||||
state.attachments.value
|
||||
@@ -640,6 +651,7 @@ class ComposeLogic {
|
||||
if (forwardedPost != null) 'forwarded_post_id': forwardedPost.id,
|
||||
'tags': state.tagsController.getTags,
|
||||
'categories': state.categories.value.map((e) => e.slug).toList(),
|
||||
if (state.realm.value != null) 'realm_id': state.realm.value?.id,
|
||||
if (state.pollId.value != null) 'poll_id': state.pollId.value,
|
||||
};
|
||||
|
||||
@@ -733,6 +745,7 @@ class ComposeLogic {
|
||||
state.currentPublisher.dispose();
|
||||
state.tagsController.dispose();
|
||||
state.categories.dispose();
|
||||
state.realm.dispose();
|
||||
state.pollId.dispose();
|
||||
}
|
||||
}
|
||||
|
@@ -7,6 +7,7 @@ import 'package:material_symbols_icons/symbols.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:island/widgets/post/post_item.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
import 'package:island/pods/config.dart'; // Import config.dart for shared preferences keys and provider
|
||||
|
||||
part 'post_featured.g.dart';
|
||||
|
||||
@@ -25,7 +26,13 @@ class PostFeaturedList extends HookConsumerWidget {
|
||||
final featuredPostsAsync = ref.watch(featuredPostsProvider);
|
||||
|
||||
final pageViewController = usePageController();
|
||||
final prefs = ref.watch(sharedPreferencesProvider);
|
||||
final pageViewCurrent = useState(0);
|
||||
final previousFirstPostId = useState<String?>(null);
|
||||
final storedCollapsedId = useState<String?>(
|
||||
prefs.getString(kFeaturedPostsCollapsedId),
|
||||
);
|
||||
final isCollapsed = useState(false);
|
||||
|
||||
useEffect(() {
|
||||
pageViewController.addListener(() {
|
||||
@@ -34,6 +41,59 @@ class PostFeaturedList extends HookConsumerWidget {
|
||||
return null;
|
||||
}, [pageViewController]);
|
||||
|
||||
// Log isCollapsed state changes
|
||||
useEffect(() {
|
||||
debugPrint(
|
||||
'PostFeaturedList: isCollapsed changed to ${isCollapsed.value}',
|
||||
);
|
||||
return null;
|
||||
}, [isCollapsed.value]);
|
||||
|
||||
useEffect(() {
|
||||
if (featuredPostsAsync.hasValue && featuredPostsAsync.value!.isNotEmpty) {
|
||||
final currentFirstPostId = featuredPostsAsync.value!.first.id;
|
||||
debugPrint(
|
||||
'PostFeaturedList: Current first post ID: $currentFirstPostId',
|
||||
);
|
||||
debugPrint(
|
||||
'PostFeaturedList: Previous first post ID: ${previousFirstPostId.value}',
|
||||
);
|
||||
debugPrint(
|
||||
'PostFeaturedList: Stored collapsed ID: ${storedCollapsedId.value}',
|
||||
);
|
||||
|
||||
if (previousFirstPostId.value == null) {
|
||||
// Initial load
|
||||
previousFirstPostId.value = currentFirstPostId;
|
||||
isCollapsed.value = (storedCollapsedId.value == currentFirstPostId);
|
||||
debugPrint(
|
||||
'PostFeaturedList: Initial load. isCollapsed set to ${isCollapsed.value}',
|
||||
);
|
||||
} else if (previousFirstPostId.value != currentFirstPostId) {
|
||||
// First post changed, expand by default
|
||||
previousFirstPostId.value = currentFirstPostId;
|
||||
isCollapsed.value = false;
|
||||
prefs.remove(
|
||||
kFeaturedPostsCollapsedId,
|
||||
); // Clear stored ID if post changes
|
||||
debugPrint(
|
||||
'PostFeaturedList: First post changed. isCollapsed set to false.',
|
||||
);
|
||||
} else {
|
||||
// Same first post, maintain current collapse state
|
||||
// No change needed for isCollapsed.value unless manually toggled
|
||||
debugPrint(
|
||||
'PostFeaturedList: Same first post. Maintaining current collapse state.',
|
||||
);
|
||||
}
|
||||
} else {
|
||||
debugPrint(
|
||||
'PostFeaturedList: featuredPostsAsync has no value or is empty.',
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}, [featuredPostsAsync.value]);
|
||||
|
||||
return ClipRRect(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
||||
child: Card(
|
||||
@@ -73,10 +133,48 @@ class PostFeaturedList extends HookConsumerWidget {
|
||||
},
|
||||
icon: const Icon(Symbols.arrow_right),
|
||||
),
|
||||
IconButton(
|
||||
padding: EdgeInsets.zero,
|
||||
visualDensity: VisualDensity.compact,
|
||||
constraints: const BoxConstraints(),
|
||||
onPressed: () {
|
||||
isCollapsed.value = !isCollapsed.value;
|
||||
debugPrint(
|
||||
'PostFeaturedList: Manual toggle. isCollapsed set to ${isCollapsed.value}',
|
||||
);
|
||||
if (isCollapsed.value &&
|
||||
featuredPostsAsync.hasValue &&
|
||||
featuredPostsAsync.value!.isNotEmpty) {
|
||||
prefs.setString(
|
||||
kFeaturedPostsCollapsedId,
|
||||
featuredPostsAsync.value!.first.id,
|
||||
);
|
||||
debugPrint(
|
||||
'PostFeaturedList: Stored collapsed ID: ${featuredPostsAsync.value!.first.id}',
|
||||
);
|
||||
} else {
|
||||
prefs.remove(kFeaturedPostsCollapsedId);
|
||||
debugPrint(
|
||||
'PostFeaturedList: Removed stored collapsed ID.',
|
||||
);
|
||||
}
|
||||
},
|
||||
icon: Icon(
|
||||
isCollapsed.value
|
||||
? Symbols.expand_more
|
||||
: Symbols.expand_less,
|
||||
),
|
||||
),
|
||||
],
|
||||
).padding(horizontal: 16, vertical: 8),
|
||||
featuredPostsAsync.when(
|
||||
loading: () => const Center(child: CircularProgressIndicator()),
|
||||
AnimatedSize(
|
||||
duration: const Duration(milliseconds: 300),
|
||||
curve: Curves.easeInOut,
|
||||
child: Visibility(
|
||||
visible: !isCollapsed.value,
|
||||
child: featuredPostsAsync.when(
|
||||
loading:
|
||||
() => const Center(child: CircularProgressIndicator()),
|
||||
error: (error, stack) => Center(child: Text('Error: $error')),
|
||||
data: (posts) {
|
||||
return SizedBox(
|
||||
@@ -97,6 +195,8 @@ class PostFeaturedList extends HookConsumerWidget {
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@@ -117,8 +117,12 @@ class PostActionableItem extends HookConsumerWidget {
|
||||
await File('${directory.path}/image.png').create();
|
||||
await imagePath.writeAsBytes(image);
|
||||
|
||||
if (context.mounted) hideLoadingModal(context);
|
||||
await Share.shareXFiles([XFile(imagePath.path)]);
|
||||
if (!context.mounted) return;
|
||||
hideLoadingModal(context);
|
||||
final box = context.findRenderObject() as RenderBox?;
|
||||
await Share.shareXFiles([
|
||||
XFile(imagePath.path),
|
||||
], sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size);
|
||||
})
|
||||
.catchError((err) {
|
||||
if (context.mounted) hideLoadingModal(context);
|
||||
@@ -174,7 +178,7 @@ class PostActionableItem extends HookConsumerWidget {
|
||||
image: MenuImage.icon(Symbols.link),
|
||||
callback: () {
|
||||
Clipboard.setData(
|
||||
ClipboardData(text: 'https://solsynth.dev/posts/${item.id}'),
|
||||
ClipboardData(text: 'https://solian.app/posts/${item.id}'),
|
||||
);
|
||||
},
|
||||
),
|
||||
|
@@ -559,7 +559,11 @@ class PostHeader extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
: null,
|
||||
child: ProfilePictureWidget(file: item.publisher.picture, radius: 16),
|
||||
child: ProfilePictureWidget(
|
||||
file: item.publisher.picture,
|
||||
radius: 16,
|
||||
borderRadius: item.publisher.type == 0 ? null : 6,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Column(
|
||||
@@ -567,12 +571,38 @@ class PostHeader extends StatelessWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
spacing: 4,
|
||||
children: [
|
||||
Text(item.publisher.nick).bold(),
|
||||
if (item.publisher.verification != null)
|
||||
VerificationMark(mark: item.publisher.verification!),
|
||||
Text('@${item.publisher.name}').fontSize(11),
|
||||
if (item.realm == null)
|
||||
Text('@${item.publisher.name}').fontSize(11)
|
||||
else
|
||||
...([
|
||||
const Icon(Symbols.arrow_right, size: 14),
|
||||
InkWell(
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
spacing: 5,
|
||||
children: [
|
||||
Text(item.realm!.name),
|
||||
ProfilePictureWidget(
|
||||
file: item.realm!.picture,
|
||||
fallbackIcon: Symbols.group,
|
||||
radius: 9,
|
||||
),
|
||||
],
|
||||
),
|
||||
onTap: () {
|
||||
GoRouter.of(context).pushNamed(
|
||||
'realmDetail',
|
||||
pathParameters: {'slug': item.realm!.slug},
|
||||
);
|
||||
},
|
||||
),
|
||||
]),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
|
@@ -340,22 +340,33 @@ class _ShareSheetState extends ConsumerState<ShareSheet> {
|
||||
Future<void> _shareToSystem() async {
|
||||
if (!widget.toSystem) return;
|
||||
|
||||
final box = context.findRenderObject() as RenderBox?;
|
||||
|
||||
setState(() => _isLoading = true);
|
||||
try {
|
||||
switch (widget.content.type) {
|
||||
case ShareContentType.text:
|
||||
if (widget.content.text?.isNotEmpty == true) {
|
||||
await Share.share(widget.content.text!);
|
||||
await Share.share(
|
||||
widget.content.text!,
|
||||
sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size,
|
||||
);
|
||||
}
|
||||
break;
|
||||
case ShareContentType.link:
|
||||
if (widget.content.link?.isNotEmpty == true) {
|
||||
await Share.share(widget.content.link!);
|
||||
await Share.share(
|
||||
widget.content.link!,
|
||||
sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size,
|
||||
);
|
||||
}
|
||||
break;
|
||||
case ShareContentType.file:
|
||||
if (widget.content.files?.isNotEmpty == true) {
|
||||
await Share.shareXFiles(widget.content.files!);
|
||||
await Share.shareXFiles(
|
||||
widget.content.files!,
|
||||
sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size,
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -879,7 +890,8 @@ class _LinkPreview extends ConsumerWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Favicon and image
|
||||
if (embed.imageUrl != null || embed.faviconUrl.isNotEmpty)
|
||||
if (embed.imageUrl != null ||
|
||||
(embed.faviconUrl?.isNotEmpty ?? false))
|
||||
Container(
|
||||
width: 60,
|
||||
height: 60,
|
||||
@@ -899,11 +911,14 @@ class _LinkPreview extends ConsumerWidget {
|
||||
errorBuilder: (context, error, stackTrace) {
|
||||
return _buildFaviconFallback(
|
||||
context,
|
||||
embed.faviconUrl,
|
||||
embed.faviconUrl ?? '',
|
||||
);
|
||||
},
|
||||
)
|
||||
: _buildFaviconFallback(context, embed.faviconUrl),
|
||||
: _buildFaviconFallback(
|
||||
context,
|
||||
embed.faviconUrl ?? '',
|
||||
),
|
||||
),
|
||||
),
|
||||
// Content
|
||||
@@ -912,9 +927,9 @@ class _LinkPreview extends ConsumerWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Site name
|
||||
if (embed.siteName.isNotEmpty)
|
||||
if (embed.siteName?.isNotEmpty ?? false)
|
||||
Text(
|
||||
embed.siteName,
|
||||
embed.siteName!,
|
||||
style: Theme.of(context).textTheme.labelSmall?.copyWith(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
|
@@ -41,7 +41,7 @@ endif()
|
||||
# of modifying this function.
|
||||
function(APPLY_STANDARD_SETTINGS TARGET)
|
||||
target_compile_features(${TARGET} PUBLIC cxx_std_14)
|
||||
target_compile_options(${TARGET} PRIVATE -Wall -Werror)
|
||||
target_compile_options(${TARGET} PRIVATE -Wall -Wextra)
|
||||
target_compile_options(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-O3>")
|
||||
target_compile_definitions(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:NDEBUG>")
|
||||
endfunction()
|
||||
|
@@ -195,7 +195,7 @@ PODS:
|
||||
- PromisesObjC (2.4.0)
|
||||
- PromisesSwift (2.4.0):
|
||||
- PromisesObjC (= 2.4.0)
|
||||
- record_macos (1.0.0):
|
||||
- record_macos (1.1.0):
|
||||
- FlutterMacOS
|
||||
- SAMKeychain (1.5.3)
|
||||
- share_plus (0.0.1):
|
||||
@@ -422,7 +422,7 @@ SPEC CHECKSUMS:
|
||||
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
|
||||
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
|
||||
PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851
|
||||
record_macos: 295d70bd5fb47145df78df7b80e6697cd18403c0
|
||||
record_macos: 43194b6c06ca6f8fa132e2acea72b202b92a0f5b
|
||||
SAMKeychain: 483e1c9f32984d50ca961e26818a534283b4cd5c
|
||||
share_plus: 510bf0af1a42cd602274b4629920c9649c52f4cc
|
||||
shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7
|
||||
|
64
pubspec.lock
64
pubspec.lock
@@ -1233,66 +1233,66 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: image_picker
|
||||
sha256: "021834d9c0c3de46bf0fe40341fa07168407f694d9b2bb18d532dc1261867f7a"
|
||||
sha256: "736eb56a911cf24d1859315ad09ddec0b66104bc41a7f8c5b96b4e2620cf5041"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.2"
|
||||
version: "1.2.0"
|
||||
image_picker_android:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: image_picker_android
|
||||
sha256: b08e9a04d0f8d91f4a6e767a745b9871bfbc585410205c311d0492de20a7ccd6
|
||||
sha256: e83b2b05141469c5e19d77e1dfa11096b6b1567d09065b2265d7c6904560050c
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.8.12+25"
|
||||
version: "0.8.13"
|
||||
image_picker_for_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image_picker_for_web
|
||||
sha256: "717eb042ab08c40767684327be06a5d8dbb341fe791d514e4b92c7bbe1b7bb83"
|
||||
sha256: "40c2a6a0da15556dc0f8e38a3246064a971a9f512386c3339b89f76db87269b6"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.6"
|
||||
version: "3.1.0"
|
||||
image_picker_ios:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image_picker_ios
|
||||
sha256: "05da758e67bc7839e886b3959848aa6b44ff123ab4b28f67891008afe8ef9100"
|
||||
sha256: eb06fe30bab4c4497bad449b66448f50edcc695f1c59408e78aa3a8059eb8f0e
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.8.12+2"
|
||||
version: "0.8.13"
|
||||
image_picker_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image_picker_linux
|
||||
sha256: "34a65f6740df08bbbeb0a1abd8e6d32107941fd4868f67a507b25601651022c9"
|
||||
sha256: "1f81c5f2046b9ab724f85523e4af65be1d47b038160a8c8deed909762c308ed4"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.2.1+2"
|
||||
version: "0.2.2"
|
||||
image_picker_macos:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image_picker_macos
|
||||
sha256: "1b90ebbd9dcf98fb6c1d01427e49a55bd96b5d67b8c67cf955d60a5de74207c1"
|
||||
sha256: d58cd9d67793d52beefd6585b12050af0a7663c0c2a6ece0fb110a35d6955e04
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.2.1+2"
|
||||
version: "0.2.2"
|
||||
image_picker_platform_interface:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: image_picker_platform_interface
|
||||
sha256: "886d57f0be73c4b140004e78b9f28a8914a09e50c2d816bdd0520051a71236a0"
|
||||
sha256: "9f143b0dba3e459553209e20cc425c9801af48e6dfa4f01a0fcf927be3f41665"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.10.1"
|
||||
version: "2.11.0"
|
||||
image_picker_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image_picker_windows
|
||||
sha256: "6ad07afc4eb1bc25f3a01084d28520496c4a3bb0cb13685435838167c9dcedeb"
|
||||
sha256: d248c86554a72b5495a31c56f060cf73a41c7ff541689327b1a7dbccc33adfae
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.2.1+1"
|
||||
version: "0.2.2"
|
||||
intl:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1897,58 +1897,58 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: record
|
||||
sha256: daeb3f9b3fea9797094433fe6e49a879d8e4ca4207740bc6dc7e4a58764f0817
|
||||
sha256: "3d08502b77edf2a864aa6e4cd7874b983d42a80f3689431da053cc5e85c1ad21"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.0.0"
|
||||
version: "6.1.0"
|
||||
record_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: record_android
|
||||
sha256: "97d7122455f30de89a01c6c244c839085be6b12abca251fc0e78f67fed73628b"
|
||||
sha256: "8b170e33d9866f9b51e01a767d7e1ecb97b9ecd629950bd87a47c79359ec57f8"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.3"
|
||||
version: "1.4.0"
|
||||
record_ios:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: record_ios
|
||||
sha256: "73706ebbece6150654c9d6f57897cf9b622c581148304132ba85dba15df0fdfb"
|
||||
sha256: ad97d0a75933c44bcf5aff648e86e32fc05eb61f8fbef190f14968c8eaf86692
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
version: "1.1.0"
|
||||
record_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: record_linux
|
||||
sha256: "0626678a092c75ce6af1e32fe7fd1dea709b92d308bc8e3b6d6348e2430beb95"
|
||||
sha256: "785e8e8d6db109aa606d0669d95aaae416458aaa39782bb0abe0bee74eee17d7"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
version: "1.2.0"
|
||||
record_macos:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: record_macos
|
||||
sha256: "02240833fde16c33fcf2c589f3e08d4394b704761b4a3bb609d872ff3043fbbd"
|
||||
sha256: f1399bca76a1634da109e5b0cba764ed8332a2b4da49c704c66d2c553405ed81
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
version: "1.1.0"
|
||||
record_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: record_platform_interface
|
||||
sha256: c1ad38f51e4af88a085b3e792a22c685cb3e7c23fc37aa7ce44c4cf18f25fe89
|
||||
sha256: b0065fdf1ec28f5a634d676724d388a77e43ce7646fb049949f58c69f3fcb4ed
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
version: "1.4.0"
|
||||
record_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: record_web
|
||||
sha256: a12856d0b3dd03d336b4b10d7520a8b3e21649a06a8f95815318feaa8f07adbb
|
||||
sha256: "4f0adf20c9ccafcc02d71111fd91fba1ca7b17a7453902593e5a9b25b74a5c56"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.9"
|
||||
version: "1.2.0"
|
||||
record_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -2568,10 +2568,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vector_graphics_compiler
|
||||
sha256: "557a315b7d2a6dbb0aaaff84d857967ce6bdc96a63dc6ee2a57ce5a6ee5d3331"
|
||||
sha256: ca81fdfaf62a5ab45d7296614aea108d2c7d0efca8393e96174bf4d51e6725b0
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.17"
|
||||
version: "1.1.18"
|
||||
vector_math:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@@ -72,11 +72,11 @@ dependencies:
|
||||
tus_client_dart:
|
||||
git: https://github.com/LittleSheep2Code/tus_client.git
|
||||
cross_file: ^0.3.4+2
|
||||
image_picker: ^1.1.2
|
||||
image_picker: ^1.2.0
|
||||
file_picker: ^10.3.1
|
||||
riverpod_annotation: ^2.6.1
|
||||
image_picker_platform_interface: ^2.10.1
|
||||
image_picker_android: ^0.8.12+25
|
||||
image_picker_platform_interface: ^2.11.0
|
||||
image_picker_android: ^0.8.13
|
||||
super_context_menu: ^0.9.1
|
||||
modal_bottom_sheet: ^3.0.0
|
||||
firebase_messaging: ^16.0.0
|
||||
@@ -107,7 +107,7 @@ dependencies:
|
||||
livekit_client: ^2.5.0+hotfix.1
|
||||
pasteboard: ^0.4.0
|
||||
flutter_colorpicker: ^1.1.0
|
||||
record: ^6.0.0
|
||||
record: ^6.1.0
|
||||
qr_flutter: ^4.1.0
|
||||
flutter_otp_text_field: ^1.5.1+1
|
||||
palette_generator: ^0.3.3+7
|
||||
|
Reference in New Issue
Block a user