Compare commits

..

51 Commits

Author SHA1 Message Date
LittleSheep
7169aff841 🚀 Launch 3.2.0+127 2025-08-18 13:28:05 +08:00
LittleSheep
fac3efb50c 💄 Add status code to userinfo alert 2025-08-18 13:19:50 +08:00
LittleSheep
e809aadaea Userinfo failed to load alert 2025-08-18 13:08:57 +08:00
LittleSheep
f33b569221 🐛 Fix realm detail 2025-08-18 11:51:44 +08:00
LittleSheep
e5f2e2d146 🐛 Fix notification page cannot return 2025-08-18 11:43:12 +08:00
LittleSheep
11368d064f 🐛 Fix explore page 2025-08-18 11:42:42 +08:00
LittleSheep
246b163aec 🍱 Update notification icon 2025-08-18 02:36:29 +08:00
LittleSheep
10e0d2fe5f 🚀 Launch 3.2.0+126 2025-08-18 02:21:39 +08:00
LittleSheep
99e10cb612 Chat, realm member list with status 2025-08-18 02:01:13 +08:00
LittleSheep
1db6941431 💄 Optimize message styling 2025-08-17 23:13:59 +08:00
LittleSheep
8370da4fe3 Realm page redesgiened 2025-08-17 19:44:43 +08:00
LittleSheep
2bdf7029e9 💄 Optimize chat list tile 2025-08-17 13:51:02 +08:00
LittleSheep
86682a3a9a 💄 Optimize realm discovery list 2025-08-17 13:48:02 +08:00
LittleSheep
c3925e81b5 :drunk: Media offline error builder 2025-08-17 13:40:35 +08:00
LittleSheep
6f1f488490 💄 Limit realm card max description line 2025-08-17 13:36:02 +08:00
LittleSheep
31b2de2e46 💄 Update styling of realm list 2025-08-17 13:35:03 +08:00
LittleSheep
412dcfa62a 💄 Move the publisher invite icon to the list 2025-08-17 13:26:17 +08:00
LittleSheep
ffdc7e81ae 🐛 Make video being contained to prevent some issue 2025-08-17 13:15:55 +08:00
LittleSheep
1d3357803d 🐛 Fix post slug 2025-08-17 13:11:13 +08:00
LittleSheep
6c48aa2356 💄 Optimize attachment preview 2025-08-17 13:08:08 +08:00
LittleSheep
466e354679 💄 Optimize attachment in article 2025-08-17 13:02:52 +08:00
LittleSheep
5d4b896f70 Post slug 2025-08-17 12:47:00 +08:00
LittleSheep
a04dffdfe8 🐛 Fix missing sharePositionOrigin in share 2025-08-17 11:56:34 +08:00
LittleSheep
ff871943cf Show realm post indicator 2025-08-17 02:56:12 +08:00
LittleSheep
1a892ab227 Realm post, and post publisher is org is rounded rect 2025-08-17 02:37:45 +08:00
LittleSheep
af1b303211 Prevent user from setting empty links 2025-08-17 00:55:22 +08:00
LittleSheep
6fd702eba8 🐛 Fix profile update 2025-08-17 00:47:10 +08:00
LittleSheep
d220d43cd2 💄 Optimize chat room 2025-08-17 00:11:28 +08:00
LittleSheep
6892afb974 🔊 Add more logging and optimzation 2025-08-16 23:39:41 +08:00
LittleSheep
007b46b080 ♻️ Refactored the message repository logic 2025-08-16 23:07:21 +08:00
LittleSheep
67d130dc34 🔨 Sync the CMakeLists in linux to update date with the v2 modified version 2025-08-16 18:09:45 +08:00
LittleSheep
7e923c77fe 💄 Change explore screen wide mode breakpoint 2025-08-16 18:03:23 +08:00
LittleSheep
a593b52812 ♻️ Adjust the firebase analytics observer guard 2025-08-16 17:20:03 +08:00
LittleSheep
520dc80303 🔀 Merge pull request #169 from Texas0295/v3
🐛 linux: guard FirebaseAnalyticsObserver when Firebase is not initialized
2025-08-16 17:18:20 +08:00
LittleSheep
001897bbcd Notification indicator 2025-08-16 17:14:26 +08:00
Texas0295
bab29c23e3 🐛 linux: guard FirebaseAnalyticsObserver when Firebase is not initialized 2025-08-16 16:58:12 +08:00
LittleSheep
76b39f2df3 Mark all as read 2025-08-16 11:47:29 +08:00
LittleSheep
509b3e145b 🐛 Fix category selection render error 2025-08-16 02:39:00 +08:00
LittleSheep
2b80ebc2d0 🐛 Fix markdown image in chat close #167 2025-08-16 02:14:44 +08:00
LittleSheep
0ab908dd2a Auto collapse featured post if read 2025-08-16 02:02:06 +08:00
LittleSheep
6007467e7a 🐛 Fixes due to changes in backend 2025-08-15 03:33:20 +08:00
LittleSheep
3745157c42 💄 Optimize snackbars 2025-08-15 00:09:05 +08:00
LittleSheep
94481ec7bd 💫 Chnaged tab page animations 2025-08-14 14:21:57 +08:00
LittleSheep
fbfe8cbdee 🚀 Launch 3.2.0+125 2025-08-14 02:34:05 +08:00
LittleSheep
fbbab0a981 Send delete session requset when logout 2025-08-14 02:29:32 +08:00
LittleSheep
ae2fb3b303 👽 Support new authorized device 2025-08-14 02:10:21 +08:00
LittleSheep
3d7a4666ed 👔 Skip the debug mode crashlytics setup 2025-08-13 15:32:34 +08:00
LittleSheep
5d3e0fb800 🐛 Fix gha artificats has same name 2025-08-13 15:26:00 +08:00
LittleSheep
85ff52a661 🔨 Update windows setup build script and use gha to do so 2025-08-13 13:55:11 +08:00
LittleSheep
da7fd64a43 Merge branch 'v3' of https://github.com/Solsynth/Solian into v3 2025-08-13 13:40:58 +08:00
LittleSheep
3902633217 🔨 Update windows setup builder script 2025-08-13 13:40:53 +08:00
93 changed files with 4099 additions and 2798 deletions

View File

@@ -41,6 +41,15 @@ jobs:
with: with:
name: build-output-windows name: build-output-windows
path: build/windows/x64/runner/Release path: build/windows/x64/runner/Release
- name: Compile Installer
uses: Minionguyjpro/Inno-Setup-Action@v1.2.2
with:
path: setup.iss
- name: Archive installer artifacts
uses: actions/upload-artifact@v4
with:
name: build-output-windows-installer
path: Installer/windows-x86_64-setup.exe
build-linux: build-linux:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

View File

@@ -0,0 +1,41 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="192dp"
android:height="192dp"
android:viewportWidth="192"
android:viewportHeight="192">
<path
android:pathData="M54,147h86"
android:strokeLineJoin="round"
android:strokeWidth="12"
android:fillColor="#00000000"
android:strokeColor="#000"
android:strokeLineCap="round"/>
<path
android:pathData="M57,111s-2,-4.5 -2,-10m22,22s-4,7 -11,4m9,-22s-2,-4.5 -2,-10"
android:strokeLineJoin="round"
android:strokeWidth="10"
android:fillColor="#00000000"
android:strokeColor="#000"
android:strokeLineCap="round"/>
<path
android:pathData="M54,147a32,32 0,0 1,-12 -61.67A39,39 0,0 1,81 46m59,101a30,30 0,0 0,29.93 -28"
android:strokeLineJoin="round"
android:strokeWidth="12"
android:fillColor="#00000000"
android:strokeColor="#000"
android:strokeLineCap="round"/>
<path
android:pathData="M132,75m-4,0a4,4 0,1 1,8 0a4,4 0,1 1,-8 0"
android:strokeLineJoin="round"
android:strokeWidth="8"
android:fillColor="#00000000"
android:strokeColor="#000"
android:strokeLineCap="round"/>
<path
android:pathData="M112.5,41.22C100.84,47.96 93,60.56 93,75c0,6.38 1.53,12.39 4.24,17.71m69.51,-35.42A38.84,38.84 0,0 1,171 75c0,14.43 -7.84,27.03 -19.49,33.78m-0.79,-43.32A20.9,20.9 0,0 1,153 75c0,7.77 -4.22,14.56 -10.49,18.19m-21,-36.38C115.22,60.44 111,67.23 111,75a20.9,20.9 0,0 0,2.28 9.53"
android:strokeLineJoin="round"
android:strokeWidth="10"
android:fillColor="#00000000"
android:strokeColor="#000"
android:strokeLineCap="round"/>
</vector>

View File

@@ -334,6 +334,7 @@
"walletCreate": "Create a Wallet", "walletCreate": "Create a Wallet",
"settingsServerUrl": "Server URL", "settingsServerUrl": "Server URL",
"settingsApplied": "The settings has been applied.", "settingsApplied": "The settings has been applied.",
"settingsCustomFontsHelper": "Use comma to seprate.",
"notifications": "Notifications", "notifications": "Notifications",
"posts": "Posts", "posts": "Posts",
"settingsBackgroundImage": "Background Image", "settingsBackgroundImage": "Background Image",
@@ -836,5 +837,22 @@
"pollAddOption": "Add option", "pollAddOption": "Add option",
"pollOptionLabel": "Option label", "pollOptionLabel": "Option label",
"pollLongTextAnswerPreview": "Long text answer (preview)", "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.",
"attachmentOnDevice": "On-device",
"attachmentOnCloud": "On-cloud",
"attachments": "Attachments",
"publisherCollabInvitation": "Collabration invitations",
"publisherCollabInvitationCount": {
"zero": "No invitation",
"one": "{} available invitation",
"other": "{} available invitations"
},
"failedToLoadUserInfo": "Failed to load user info",
"failedToLoadUserInfoNetwork": "It seems be network issue, you can tap the button below to try again.",
"failedToLoadUserInfoUnauthorized": "It seems your session has been logged out or not available anymore, you can still try agian to fetch the user info if you want.",
"okay": "Okay"
}

File diff suppressed because it is too large Load Diff

BIN
assets/icons/icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 307 KiB

View File

@@ -245,7 +245,7 @@ PODS:
- PromisesObjC (= 2.4.0) - PromisesObjC (= 2.4.0)
- receive_sharing_intent (1.8.1): - receive_sharing_intent (1.8.1):
- Flutter - Flutter
- record_ios (1.0.0): - record_ios (1.1.0):
- Flutter - Flutter
- SAMKeychain (1.5.3) - SAMKeychain (1.5.3)
- SDWebImage (5.21.1): - SDWebImage (5.21.1):
@@ -510,7 +510,7 @@ SPEC CHECKSUMS:
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851 PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851
receive_sharing_intent: 222384f00ffe7e952bbfabaa9e3967cb87e5fe00 receive_sharing_intent: 222384f00ffe7e952bbfabaa9e3967cb87e5fe00
record_ios: fee1c924aa4879b882ebca2b4bce6011bcfc3d8b record_ios: f75fa1d57f840012775c0e93a38a7f3ceea1a374
SAMKeychain: 483e1c9f32984d50ca961e26818a534283b4cd5c SAMKeychain: 483e1c9f32984d50ca961e26818a534283b4cd5c
SDWebImage: f29024626962457f3470184232766516dee8dfea SDWebImage: f29024626962457f3470184232766516dee8dfea
share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a

View File

@@ -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;
}
}
}

View File

@@ -64,9 +64,10 @@ void main() async {
); );
// Although previous if case checked this. Still check is web or not // Although previous if case checked this. Still check is web or not
// Otherwise the web platform will broke due to there is no Platform api on the web // Otherwise the web platform will broke due to there is no Platform api on the web
if (kIsWeb || !Platform.isWindows) { // Skip crashlytics setup on debug mode to prevent unexpected report to firebase
if ((kIsWeb || !Platform.isWindows) && !kDebugMode) {
FlutterError.onError = FlutterError.onError =
FirebaseCrashlytics.instance.recordFlutterFatalError; FirebaseCrashlytics.instance.recordFlutterFatalError;
PlatformDispatcher.instance.onError = (error, stack) { PlatformDispatcher.instance.onError = (error, stack) {
FirebaseCrashlytics.instance.recordError(error, stack, fatal: true); FirebaseCrashlytics.instance.recordError(error, stack, fatal: true);
return true; return true;

View File

@@ -1,9 +1,10 @@
import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:island/models/auth.dart';
import 'package:island/models/file.dart'; import 'package:island/models/file.dart';
import 'package:island/models/wallet.dart'; import 'package:island/models/wallet.dart';
part 'user.freezed.dart'; part 'account.freezed.dart';
part 'user.g.dart'; part 'account.g.dart';
@freezed @freezed
sealed class SnAccount with _$SnAccount { sealed class SnAccount with _$SnAccount {
@@ -174,3 +175,36 @@ sealed class SnVerificationMark with _$SnVerificationMark {
factory SnVerificationMark.fromJson(Map<String, dynamic> json) => factory SnVerificationMark.fromJson(Map<String, dynamic> json) =>
_$SnVerificationMarkFromJson(json); _$SnVerificationMarkFromJson(json);
} }
@freezed
sealed class SnAuthDevice with _$SnAuthDevice {
const factory SnAuthDevice({
required String id,
required String deviceId,
required String deviceName,
required String? deviceLabel,
required String accountId,
required int platform,
@Default(false) bool isCurrent,
}) = _SnAuthDevice;
factory SnAuthDevice.fromJson(Map<String, dynamic> json) =>
_$SnAuthDeviceFromJson(json);
}
@freezed
sealed class SnAuthDeviceWithChallenge with _$SnAuthDeviceWithChallenge {
const factory SnAuthDeviceWithChallenge({
required String id,
required String deviceId,
required String deviceName,
required String? deviceLabel,
required String accountId,
required int platform,
required List<SnAuthChallenge> challenges,
@Default(false) bool isCurrent,
}) = _SnAuthDeviceWithChallengee;
factory SnAuthDeviceWithChallenge.fromJson(Map<String, dynamic> json) =>
_$SnAuthDeviceWithChallengeFromJson(json);
}

View File

@@ -3,7 +3,7 @@
// ignore_for_file: type=lint // ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark // ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'user.dart'; part of 'account.dart';
// ************************************************************************** // **************************************************************************
// FreezedGenerator // FreezedGenerator
@@ -2452,6 +2452,572 @@ as String?,
} }
}
/// @nodoc
mixin _$SnAuthDevice {
String get id; String get deviceId; String get deviceName; String? get deviceLabel; String get accountId; int get platform; bool get isCurrent;
/// Create a copy of SnAuthDevice
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$SnAuthDeviceCopyWith<SnAuthDevice> get copyWith => _$SnAuthDeviceCopyWithImpl<SnAuthDevice>(this as SnAuthDevice, _$identity);
/// Serializes this SnAuthDevice to a JSON map.
Map<String, dynamic> toJson();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnAuthDevice&&(identical(other.id, id) || other.id == id)&&(identical(other.deviceId, deviceId) || other.deviceId == deviceId)&&(identical(other.deviceName, deviceName) || other.deviceName == deviceName)&&(identical(other.deviceLabel, deviceLabel) || other.deviceLabel == deviceLabel)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.platform, platform) || other.platform == platform)&&(identical(other.isCurrent, isCurrent) || other.isCurrent == isCurrent));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,id,deviceId,deviceName,deviceLabel,accountId,platform,isCurrent);
@override
String toString() {
return 'SnAuthDevice(id: $id, deviceId: $deviceId, deviceName: $deviceName, deviceLabel: $deviceLabel, accountId: $accountId, platform: $platform, isCurrent: $isCurrent)';
}
}
/// @nodoc
abstract mixin class $SnAuthDeviceCopyWith<$Res> {
factory $SnAuthDeviceCopyWith(SnAuthDevice value, $Res Function(SnAuthDevice) _then) = _$SnAuthDeviceCopyWithImpl;
@useResult
$Res call({
String id, String deviceId, String deviceName, String? deviceLabel, String accountId, int platform, bool isCurrent
});
}
/// @nodoc
class _$SnAuthDeviceCopyWithImpl<$Res>
implements $SnAuthDeviceCopyWith<$Res> {
_$SnAuthDeviceCopyWithImpl(this._self, this._then);
final SnAuthDevice _self;
final $Res Function(SnAuthDevice) _then;
/// Create a copy of SnAuthDevice
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? deviceId = null,Object? deviceName = null,Object? deviceLabel = freezed,Object? accountId = null,Object? platform = null,Object? isCurrent = null,}) {
return _then(_self.copyWith(
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
as String,deviceId: null == deviceId ? _self.deviceId : deviceId // ignore: cast_nullable_to_non_nullable
as String,deviceName: null == deviceName ? _self.deviceName : deviceName // ignore: cast_nullable_to_non_nullable
as String,deviceLabel: freezed == deviceLabel ? _self.deviceLabel : deviceLabel // ignore: cast_nullable_to_non_nullable
as String?,accountId: null == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable
as String,platform: null == platform ? _self.platform : platform // ignore: cast_nullable_to_non_nullable
as int,isCurrent: null == isCurrent ? _self.isCurrent : isCurrent // ignore: cast_nullable_to_non_nullable
as bool,
));
}
}
/// Adds pattern-matching-related methods to [SnAuthDevice].
extension SnAuthDevicePatterns on SnAuthDevice {
/// A variant of `map` that fallback to returning `orElse`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _SnAuthDevice value)? $default,{required TResult orElse(),}){
final _that = this;
switch (_that) {
case _SnAuthDevice() when $default != null:
return $default(_that);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// Callbacks receives the raw object, upcasted.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case final Subclass2 value:
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _SnAuthDevice value) $default,){
final _that = this;
switch (_that) {
case _SnAuthDevice():
return $default(_that);}
}
/// A variant of `map` that fallback to returning `null`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _SnAuthDevice value)? $default,){
final _that = this;
switch (_that) {
case _SnAuthDevice() when $default != null:
return $default(_that);case _:
return null;
}
}
/// A variant of `when` that fallback to an `orElse` callback.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String deviceId, String deviceName, String? deviceLabel, String accountId, int platform, bool isCurrent)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _SnAuthDevice() when $default != null:
return $default(_that.id,_that.deviceId,_that.deviceName,_that.deviceLabel,_that.accountId,_that.platform,_that.isCurrent);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// As opposed to `map`, this offers destructuring.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case Subclass2(:final field2):
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String deviceId, String deviceName, String? deviceLabel, String accountId, int platform, bool isCurrent) $default,) {final _that = this;
switch (_that) {
case _SnAuthDevice():
return $default(_that.id,_that.deviceId,_that.deviceName,_that.deviceLabel,_that.accountId,_that.platform,_that.isCurrent);}
}
/// A variant of `when` that fallback to returning `null`
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String deviceId, String deviceName, String? deviceLabel, String accountId, int platform, bool isCurrent)? $default,) {final _that = this;
switch (_that) {
case _SnAuthDevice() when $default != null:
return $default(_that.id,_that.deviceId,_that.deviceName,_that.deviceLabel,_that.accountId,_that.platform,_that.isCurrent);case _:
return null;
}
}
}
/// @nodoc
@JsonSerializable()
class _SnAuthDevice implements SnAuthDevice {
const _SnAuthDevice({required this.id, required this.deviceId, required this.deviceName, required this.deviceLabel, required this.accountId, required this.platform, this.isCurrent = false});
factory _SnAuthDevice.fromJson(Map<String, dynamic> json) => _$SnAuthDeviceFromJson(json);
@override final String id;
@override final String deviceId;
@override final String deviceName;
@override final String? deviceLabel;
@override final String accountId;
@override final int platform;
@override@JsonKey() final bool isCurrent;
/// Create a copy of SnAuthDevice
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$SnAuthDeviceCopyWith<_SnAuthDevice> get copyWith => __$SnAuthDeviceCopyWithImpl<_SnAuthDevice>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$SnAuthDeviceToJson(this, );
}
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnAuthDevice&&(identical(other.id, id) || other.id == id)&&(identical(other.deviceId, deviceId) || other.deviceId == deviceId)&&(identical(other.deviceName, deviceName) || other.deviceName == deviceName)&&(identical(other.deviceLabel, deviceLabel) || other.deviceLabel == deviceLabel)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.platform, platform) || other.platform == platform)&&(identical(other.isCurrent, isCurrent) || other.isCurrent == isCurrent));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,id,deviceId,deviceName,deviceLabel,accountId,platform,isCurrent);
@override
String toString() {
return 'SnAuthDevice(id: $id, deviceId: $deviceId, deviceName: $deviceName, deviceLabel: $deviceLabel, accountId: $accountId, platform: $platform, isCurrent: $isCurrent)';
}
}
/// @nodoc
abstract mixin class _$SnAuthDeviceCopyWith<$Res> implements $SnAuthDeviceCopyWith<$Res> {
factory _$SnAuthDeviceCopyWith(_SnAuthDevice value, $Res Function(_SnAuthDevice) _then) = __$SnAuthDeviceCopyWithImpl;
@override @useResult
$Res call({
String id, String deviceId, String deviceName, String? deviceLabel, String accountId, int platform, bool isCurrent
});
}
/// @nodoc
class __$SnAuthDeviceCopyWithImpl<$Res>
implements _$SnAuthDeviceCopyWith<$Res> {
__$SnAuthDeviceCopyWithImpl(this._self, this._then);
final _SnAuthDevice _self;
final $Res Function(_SnAuthDevice) _then;
/// Create a copy of SnAuthDevice
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? deviceId = null,Object? deviceName = null,Object? deviceLabel = freezed,Object? accountId = null,Object? platform = null,Object? isCurrent = null,}) {
return _then(_SnAuthDevice(
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
as String,deviceId: null == deviceId ? _self.deviceId : deviceId // ignore: cast_nullable_to_non_nullable
as String,deviceName: null == deviceName ? _self.deviceName : deviceName // ignore: cast_nullable_to_non_nullable
as String,deviceLabel: freezed == deviceLabel ? _self.deviceLabel : deviceLabel // ignore: cast_nullable_to_non_nullable
as String?,accountId: null == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable
as String,platform: null == platform ? _self.platform : platform // ignore: cast_nullable_to_non_nullable
as int,isCurrent: null == isCurrent ? _self.isCurrent : isCurrent // ignore: cast_nullable_to_non_nullable
as bool,
));
}
}
SnAuthDeviceWithChallenge _$SnAuthDeviceWithChallengeFromJson(
Map<String, dynamic> json
) {
return _SnAuthDeviceWithChallengee.fromJson(
json
);
}
/// @nodoc
mixin _$SnAuthDeviceWithChallenge {
String get id; String get deviceId; String get deviceName; String? get deviceLabel; String get accountId; int get platform; List<SnAuthChallenge> get challenges; bool get isCurrent;
/// Create a copy of SnAuthDeviceWithChallenge
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$SnAuthDeviceWithChallengeCopyWith<SnAuthDeviceWithChallenge> get copyWith => _$SnAuthDeviceWithChallengeCopyWithImpl<SnAuthDeviceWithChallenge>(this as SnAuthDeviceWithChallenge, _$identity);
/// Serializes this SnAuthDeviceWithChallenge to a JSON map.
Map<String, dynamic> toJson();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnAuthDeviceWithChallenge&&(identical(other.id, id) || other.id == id)&&(identical(other.deviceId, deviceId) || other.deviceId == deviceId)&&(identical(other.deviceName, deviceName) || other.deviceName == deviceName)&&(identical(other.deviceLabel, deviceLabel) || other.deviceLabel == deviceLabel)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.platform, platform) || other.platform == platform)&&const DeepCollectionEquality().equals(other.challenges, challenges)&&(identical(other.isCurrent, isCurrent) || other.isCurrent == isCurrent));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,id,deviceId,deviceName,deviceLabel,accountId,platform,const DeepCollectionEquality().hash(challenges),isCurrent);
@override
String toString() {
return 'SnAuthDeviceWithChallenge(id: $id, deviceId: $deviceId, deviceName: $deviceName, deviceLabel: $deviceLabel, accountId: $accountId, platform: $platform, challenges: $challenges, isCurrent: $isCurrent)';
}
}
/// @nodoc
abstract mixin class $SnAuthDeviceWithChallengeCopyWith<$Res> {
factory $SnAuthDeviceWithChallengeCopyWith(SnAuthDeviceWithChallenge value, $Res Function(SnAuthDeviceWithChallenge) _then) = _$SnAuthDeviceWithChallengeCopyWithImpl;
@useResult
$Res call({
String id, String deviceId, String deviceName, String? deviceLabel, String accountId, int platform, List<SnAuthChallenge> challenges, bool isCurrent
});
}
/// @nodoc
class _$SnAuthDeviceWithChallengeCopyWithImpl<$Res>
implements $SnAuthDeviceWithChallengeCopyWith<$Res> {
_$SnAuthDeviceWithChallengeCopyWithImpl(this._self, this._then);
final SnAuthDeviceWithChallenge _self;
final $Res Function(SnAuthDeviceWithChallenge) _then;
/// Create a copy of SnAuthDeviceWithChallenge
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? deviceId = null,Object? deviceName = null,Object? deviceLabel = freezed,Object? accountId = null,Object? platform = null,Object? challenges = null,Object? isCurrent = null,}) {
return _then(_self.copyWith(
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
as String,deviceId: null == deviceId ? _self.deviceId : deviceId // ignore: cast_nullable_to_non_nullable
as String,deviceName: null == deviceName ? _self.deviceName : deviceName // ignore: cast_nullable_to_non_nullable
as String,deviceLabel: freezed == deviceLabel ? _self.deviceLabel : deviceLabel // ignore: cast_nullable_to_non_nullable
as String?,accountId: null == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable
as String,platform: null == platform ? _self.platform : platform // ignore: cast_nullable_to_non_nullable
as int,challenges: null == challenges ? _self.challenges : challenges // ignore: cast_nullable_to_non_nullable
as List<SnAuthChallenge>,isCurrent: null == isCurrent ? _self.isCurrent : isCurrent // ignore: cast_nullable_to_non_nullable
as bool,
));
}
}
/// Adds pattern-matching-related methods to [SnAuthDeviceWithChallenge].
extension SnAuthDeviceWithChallengePatterns on SnAuthDeviceWithChallenge {
/// A variant of `map` that fallback to returning `orElse`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _SnAuthDeviceWithChallengee value)? $default,{required TResult orElse(),}){
final _that = this;
switch (_that) {
case _SnAuthDeviceWithChallengee() when $default != null:
return $default(_that);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// Callbacks receives the raw object, upcasted.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case final Subclass2 value:
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _SnAuthDeviceWithChallengee value) $default,){
final _that = this;
switch (_that) {
case _SnAuthDeviceWithChallengee():
return $default(_that);}
}
/// A variant of `map` that fallback to returning `null`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _SnAuthDeviceWithChallengee value)? $default,){
final _that = this;
switch (_that) {
case _SnAuthDeviceWithChallengee() when $default != null:
return $default(_that);case _:
return null;
}
}
/// A variant of `when` that fallback to an `orElse` callback.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String deviceId, String deviceName, String? deviceLabel, String accountId, int platform, List<SnAuthChallenge> challenges, bool isCurrent)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _SnAuthDeviceWithChallengee() when $default != null:
return $default(_that.id,_that.deviceId,_that.deviceName,_that.deviceLabel,_that.accountId,_that.platform,_that.challenges,_that.isCurrent);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// As opposed to `map`, this offers destructuring.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case Subclass2(:final field2):
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String deviceId, String deviceName, String? deviceLabel, String accountId, int platform, List<SnAuthChallenge> challenges, bool isCurrent) $default,) {final _that = this;
switch (_that) {
case _SnAuthDeviceWithChallengee():
return $default(_that.id,_that.deviceId,_that.deviceName,_that.deviceLabel,_that.accountId,_that.platform,_that.challenges,_that.isCurrent);}
}
/// A variant of `when` that fallback to returning `null`
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String deviceId, String deviceName, String? deviceLabel, String accountId, int platform, List<SnAuthChallenge> challenges, bool isCurrent)? $default,) {final _that = this;
switch (_that) {
case _SnAuthDeviceWithChallengee() when $default != null:
return $default(_that.id,_that.deviceId,_that.deviceName,_that.deviceLabel,_that.accountId,_that.platform,_that.challenges,_that.isCurrent);case _:
return null;
}
}
}
/// @nodoc
@JsonSerializable()
class _SnAuthDeviceWithChallengee implements SnAuthDeviceWithChallenge {
const _SnAuthDeviceWithChallengee({required this.id, required this.deviceId, required this.deviceName, required this.deviceLabel, required this.accountId, required this.platform, required final List<SnAuthChallenge> challenges, this.isCurrent = false}): _challenges = challenges;
factory _SnAuthDeviceWithChallengee.fromJson(Map<String, dynamic> json) => _$SnAuthDeviceWithChallengeeFromJson(json);
@override final String id;
@override final String deviceId;
@override final String deviceName;
@override final String? deviceLabel;
@override final String accountId;
@override final int platform;
final List<SnAuthChallenge> _challenges;
@override List<SnAuthChallenge> get challenges {
if (_challenges is EqualUnmodifiableListView) return _challenges;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_challenges);
}
@override@JsonKey() final bool isCurrent;
/// Create a copy of SnAuthDeviceWithChallenge
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$SnAuthDeviceWithChallengeeCopyWith<_SnAuthDeviceWithChallengee> get copyWith => __$SnAuthDeviceWithChallengeeCopyWithImpl<_SnAuthDeviceWithChallengee>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$SnAuthDeviceWithChallengeeToJson(this, );
}
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnAuthDeviceWithChallengee&&(identical(other.id, id) || other.id == id)&&(identical(other.deviceId, deviceId) || other.deviceId == deviceId)&&(identical(other.deviceName, deviceName) || other.deviceName == deviceName)&&(identical(other.deviceLabel, deviceLabel) || other.deviceLabel == deviceLabel)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.platform, platform) || other.platform == platform)&&const DeepCollectionEquality().equals(other._challenges, _challenges)&&(identical(other.isCurrent, isCurrent) || other.isCurrent == isCurrent));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,id,deviceId,deviceName,deviceLabel,accountId,platform,const DeepCollectionEquality().hash(_challenges),isCurrent);
@override
String toString() {
return 'SnAuthDeviceWithChallenge(id: $id, deviceId: $deviceId, deviceName: $deviceName, deviceLabel: $deviceLabel, accountId: $accountId, platform: $platform, challenges: $challenges, isCurrent: $isCurrent)';
}
}
/// @nodoc
abstract mixin class _$SnAuthDeviceWithChallengeeCopyWith<$Res> implements $SnAuthDeviceWithChallengeCopyWith<$Res> {
factory _$SnAuthDeviceWithChallengeeCopyWith(_SnAuthDeviceWithChallengee value, $Res Function(_SnAuthDeviceWithChallengee) _then) = __$SnAuthDeviceWithChallengeeCopyWithImpl;
@override @useResult
$Res call({
String id, String deviceId, String deviceName, String? deviceLabel, String accountId, int platform, List<SnAuthChallenge> challenges, bool isCurrent
});
}
/// @nodoc
class __$SnAuthDeviceWithChallengeeCopyWithImpl<$Res>
implements _$SnAuthDeviceWithChallengeeCopyWith<$Res> {
__$SnAuthDeviceWithChallengeeCopyWithImpl(this._self, this._then);
final _SnAuthDeviceWithChallengee _self;
final $Res Function(_SnAuthDeviceWithChallengee) _then;
/// Create a copy of SnAuthDeviceWithChallenge
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? deviceId = null,Object? deviceName = null,Object? deviceLabel = freezed,Object? accountId = null,Object? platform = null,Object? challenges = null,Object? isCurrent = null,}) {
return _then(_SnAuthDeviceWithChallengee(
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
as String,deviceId: null == deviceId ? _self.deviceId : deviceId // ignore: cast_nullable_to_non_nullable
as String,deviceName: null == deviceName ? _self.deviceName : deviceName // ignore: cast_nullable_to_non_nullable
as String,deviceLabel: freezed == deviceLabel ? _self.deviceLabel : deviceLabel // ignore: cast_nullable_to_non_nullable
as String?,accountId: null == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable
as String,platform: null == platform ? _self.platform : platform // ignore: cast_nullable_to_non_nullable
as int,challenges: null == challenges ? _self._challenges : challenges // ignore: cast_nullable_to_non_nullable
as List<SnAuthChallenge>,isCurrent: null == isCurrent ? _self.isCurrent : isCurrent // ignore: cast_nullable_to_non_nullable
as bool,
));
}
} }
// dart format on // dart format on

View File

@@ -1,6 +1,6 @@
// GENERATED CODE - DO NOT MODIFY BY HAND // GENERATED CODE - DO NOT MODIFY BY HAND
part of 'user.dart'; part of 'account.dart';
// ************************************************************************** // **************************************************************************
// JsonSerializableGenerator // JsonSerializableGenerator
@@ -297,3 +297,54 @@ Map<String, dynamic> _$SnVerificationMarkToJson(_SnVerificationMark instance) =>
'description': instance.description, 'description': instance.description,
'verified_by': instance.verifiedBy, 'verified_by': instance.verifiedBy,
}; };
_SnAuthDevice _$SnAuthDeviceFromJson(Map<String, dynamic> json) =>
_SnAuthDevice(
id: json['id'] as String,
deviceId: json['device_id'] as String,
deviceName: json['device_name'] as String,
deviceLabel: json['device_label'] as String?,
accountId: json['account_id'] as String,
platform: (json['platform'] as num).toInt(),
isCurrent: json['is_current'] as bool? ?? false,
);
Map<String, dynamic> _$SnAuthDeviceToJson(_SnAuthDevice instance) =>
<String, dynamic>{
'id': instance.id,
'device_id': instance.deviceId,
'device_name': instance.deviceName,
'device_label': instance.deviceLabel,
'account_id': instance.accountId,
'platform': instance.platform,
'is_current': instance.isCurrent,
};
_SnAuthDeviceWithChallengee _$SnAuthDeviceWithChallengeeFromJson(
Map<String, dynamic> json,
) => _SnAuthDeviceWithChallengee(
id: json['id'] as String,
deviceId: json['device_id'] as String,
deviceName: json['device_name'] as String,
deviceLabel: json['device_label'] as String?,
accountId: json['account_id'] as String,
platform: (json['platform'] as num).toInt(),
challenges:
(json['challenges'] as List<dynamic>)
.map((e) => SnAuthChallenge.fromJson(e as Map<String, dynamic>))
.toList(),
isCurrent: json['is_current'] as bool? ?? false,
);
Map<String, dynamic> _$SnAuthDeviceWithChallengeeToJson(
_SnAuthDeviceWithChallengee instance,
) => <String, dynamic>{
'id': instance.id,
'device_id': instance.deviceId,
'device_name': instance.deviceName,
'device_label': instance.deviceLabel,
'account_id': instance.accountId,
'platform': instance.platform,
'challenges': instance.challenges.map((e) => e.toJson()).toList(),
'is_current': instance.isCurrent,
};

View File

@@ -1,5 +1,5 @@
import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:island/models/user.dart'; import 'package:island/models/account.dart';
part 'activity.freezed.dart'; part 'activity.freezed.dart';
part 'activity.g.dart'; part 'activity.g.dart';

View File

@@ -19,14 +19,12 @@ sealed class SnAuthChallenge with _$SnAuthChallenge {
required int stepRemain, required int stepRemain,
required int stepTotal, required int stepTotal,
required int failedAttempts, required int failedAttempts,
required int platform,
required int type, required int type,
required List<String> blacklistFactors, required List<String> blacklistFactors,
required List<dynamic> audiences, required List<dynamic> audiences,
required List<dynamic> scopes, required List<dynamic> scopes,
required String ipAddress, required String ipAddress,
required String userAgent, required String userAgent,
required String deviceId,
required String? nonce, required String? nonce,
required String? location, required String? location,
required String accountId, required String accountId,
@@ -76,22 +74,6 @@ sealed class SnAuthFactor with _$SnAuthFactor {
_$SnAuthFactorFromJson(json); _$SnAuthFactorFromJson(json);
} }
@freezed
sealed class SnAuthDevice with _$SnAuthDevice {
const factory SnAuthDevice({
required dynamic label,
required String userAgent,
required String deviceId,
required int platform,
required List<SnAuthSession> sessions,
// Not from backend, used for UI
@Default(false) bool isCurrent,
}) = _SnAuthDevice;
factory SnAuthDevice.fromJson(Map<String, dynamic> json) =>
_$SnAuthDeviceFromJson(json);
}
@freezed @freezed
sealed class SnAccountConnection with _$SnAccountConnection { sealed class SnAccountConnection with _$SnAccountConnection {
const factory SnAccountConnection({ const factory SnAccountConnection({

View File

@@ -272,7 +272,7 @@ as String,
/// @nodoc /// @nodoc
mixin _$SnAuthChallenge { mixin _$SnAuthChallenge {
String get id; DateTime get expiredAt; int get stepRemain; int get stepTotal; int get failedAttempts; int get platform; int get type; List<String> get blacklistFactors; List<dynamic> get audiences; List<dynamic> get scopes; String get ipAddress; String get userAgent; String get deviceId; String? get nonce; String? get location; String get accountId; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; String get id; DateTime get expiredAt; int get stepRemain; int get stepTotal; int get failedAttempts; int get type; List<String> get blacklistFactors; List<dynamic> get audiences; List<dynamic> get scopes; String get ipAddress; String get userAgent; String? get nonce; String? get location; String get accountId; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt;
/// Create a copy of SnAuthChallenge /// Create a copy of SnAuthChallenge
/// with the given fields replaced by the non-null parameter values. /// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false) @JsonKey(includeFromJson: false, includeToJson: false)
@@ -285,16 +285,16 @@ $SnAuthChallengeCopyWith<SnAuthChallenge> get copyWith => _$SnAuthChallengeCopyW
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnAuthChallenge&&(identical(other.id, id) || other.id == id)&&(identical(other.expiredAt, expiredAt) || other.expiredAt == expiredAt)&&(identical(other.stepRemain, stepRemain) || other.stepRemain == stepRemain)&&(identical(other.stepTotal, stepTotal) || other.stepTotal == stepTotal)&&(identical(other.failedAttempts, failedAttempts) || other.failedAttempts == failedAttempts)&&(identical(other.platform, platform) || other.platform == platform)&&(identical(other.type, type) || other.type == type)&&const DeepCollectionEquality().equals(other.blacklistFactors, blacklistFactors)&&const DeepCollectionEquality().equals(other.audiences, audiences)&&const DeepCollectionEquality().equals(other.scopes, scopes)&&(identical(other.ipAddress, ipAddress) || other.ipAddress == ipAddress)&&(identical(other.userAgent, userAgent) || other.userAgent == userAgent)&&(identical(other.deviceId, deviceId) || other.deviceId == deviceId)&&(identical(other.nonce, nonce) || other.nonce == nonce)&&(identical(other.location, location) || other.location == location)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)); return identical(this, other) || (other.runtimeType == runtimeType&&other is SnAuthChallenge&&(identical(other.id, id) || other.id == id)&&(identical(other.expiredAt, expiredAt) || other.expiredAt == expiredAt)&&(identical(other.stepRemain, stepRemain) || other.stepRemain == stepRemain)&&(identical(other.stepTotal, stepTotal) || other.stepTotal == stepTotal)&&(identical(other.failedAttempts, failedAttempts) || other.failedAttempts == failedAttempts)&&(identical(other.type, type) || other.type == type)&&const DeepCollectionEquality().equals(other.blacklistFactors, blacklistFactors)&&const DeepCollectionEquality().equals(other.audiences, audiences)&&const DeepCollectionEquality().equals(other.scopes, scopes)&&(identical(other.ipAddress, ipAddress) || other.ipAddress == ipAddress)&&(identical(other.userAgent, userAgent) || other.userAgent == userAgent)&&(identical(other.nonce, nonce) || other.nonce == nonce)&&(identical(other.location, location) || other.location == location)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt));
} }
@JsonKey(includeFromJson: false, includeToJson: false) @JsonKey(includeFromJson: false, includeToJson: false)
@override @override
int get hashCode => Object.hashAll([runtimeType,id,expiredAt,stepRemain,stepTotal,failedAttempts,platform,type,const DeepCollectionEquality().hash(blacklistFactors),const DeepCollectionEquality().hash(audiences),const DeepCollectionEquality().hash(scopes),ipAddress,userAgent,deviceId,nonce,location,accountId,createdAt,updatedAt,deletedAt]); int get hashCode => Object.hash(runtimeType,id,expiredAt,stepRemain,stepTotal,failedAttempts,type,const DeepCollectionEquality().hash(blacklistFactors),const DeepCollectionEquality().hash(audiences),const DeepCollectionEquality().hash(scopes),ipAddress,userAgent,nonce,location,accountId,createdAt,updatedAt,deletedAt);
@override @override
String toString() { String toString() {
return 'SnAuthChallenge(id: $id, expiredAt: $expiredAt, stepRemain: $stepRemain, stepTotal: $stepTotal, failedAttempts: $failedAttempts, platform: $platform, type: $type, blacklistFactors: $blacklistFactors, audiences: $audiences, scopes: $scopes, ipAddress: $ipAddress, userAgent: $userAgent, deviceId: $deviceId, nonce: $nonce, location: $location, accountId: $accountId, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; return 'SnAuthChallenge(id: $id, expiredAt: $expiredAt, stepRemain: $stepRemain, stepTotal: $stepTotal, failedAttempts: $failedAttempts, type: $type, blacklistFactors: $blacklistFactors, audiences: $audiences, scopes: $scopes, ipAddress: $ipAddress, userAgent: $userAgent, nonce: $nonce, location: $location, accountId: $accountId, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)';
} }
@@ -305,7 +305,7 @@ abstract mixin class $SnAuthChallengeCopyWith<$Res> {
factory $SnAuthChallengeCopyWith(SnAuthChallenge value, $Res Function(SnAuthChallenge) _then) = _$SnAuthChallengeCopyWithImpl; factory $SnAuthChallengeCopyWith(SnAuthChallenge value, $Res Function(SnAuthChallenge) _then) = _$SnAuthChallengeCopyWithImpl;
@useResult @useResult
$Res call({ $Res call({
String id, DateTime expiredAt, int stepRemain, int stepTotal, int failedAttempts, int platform, int type, List<String> blacklistFactors, List<dynamic> audiences, List<dynamic> scopes, String ipAddress, String userAgent, String deviceId, String? nonce, String? location, String accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt String id, DateTime expiredAt, int stepRemain, int stepTotal, int failedAttempts, int type, List<String> blacklistFactors, List<dynamic> audiences, List<dynamic> scopes, String ipAddress, String userAgent, String? nonce, String? location, String accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt
}); });
@@ -322,21 +322,19 @@ class _$SnAuthChallengeCopyWithImpl<$Res>
/// Create a copy of SnAuthChallenge /// Create a copy of SnAuthChallenge
/// with the given fields replaced by the non-null parameter values. /// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? expiredAt = null,Object? stepRemain = null,Object? stepTotal = null,Object? failedAttempts = null,Object? platform = null,Object? type = null,Object? blacklistFactors = null,Object? audiences = null,Object? scopes = null,Object? ipAddress = null,Object? userAgent = null,Object? deviceId = null,Object? nonce = freezed,Object? location = freezed,Object? accountId = null,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { @pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? expiredAt = null,Object? stepRemain = null,Object? stepTotal = null,Object? failedAttempts = null,Object? type = null,Object? blacklistFactors = null,Object? audiences = null,Object? scopes = null,Object? ipAddress = null,Object? userAgent = null,Object? nonce = freezed,Object? location = freezed,Object? accountId = null,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) {
return _then(_self.copyWith( return _then(_self.copyWith(
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
as String,expiredAt: null == expiredAt ? _self.expiredAt : expiredAt // ignore: cast_nullable_to_non_nullable as String,expiredAt: null == expiredAt ? _self.expiredAt : expiredAt // ignore: cast_nullable_to_non_nullable
as DateTime,stepRemain: null == stepRemain ? _self.stepRemain : stepRemain // ignore: cast_nullable_to_non_nullable as DateTime,stepRemain: null == stepRemain ? _self.stepRemain : stepRemain // ignore: cast_nullable_to_non_nullable
as int,stepTotal: null == stepTotal ? _self.stepTotal : stepTotal // ignore: cast_nullable_to_non_nullable as int,stepTotal: null == stepTotal ? _self.stepTotal : stepTotal // ignore: cast_nullable_to_non_nullable
as int,failedAttempts: null == failedAttempts ? _self.failedAttempts : failedAttempts // ignore: cast_nullable_to_non_nullable as int,failedAttempts: null == failedAttempts ? _self.failedAttempts : failedAttempts // ignore: cast_nullable_to_non_nullable
as int,platform: null == platform ? _self.platform : platform // ignore: cast_nullable_to_non_nullable
as int,type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable as int,type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable
as int,blacklistFactors: null == blacklistFactors ? _self.blacklistFactors : blacklistFactors // ignore: cast_nullable_to_non_nullable as int,blacklistFactors: null == blacklistFactors ? _self.blacklistFactors : blacklistFactors // ignore: cast_nullable_to_non_nullable
as List<String>,audiences: null == audiences ? _self.audiences : audiences // ignore: cast_nullable_to_non_nullable as List<String>,audiences: null == audiences ? _self.audiences : audiences // ignore: cast_nullable_to_non_nullable
as List<dynamic>,scopes: null == scopes ? _self.scopes : scopes // ignore: cast_nullable_to_non_nullable as List<dynamic>,scopes: null == scopes ? _self.scopes : scopes // ignore: cast_nullable_to_non_nullable
as List<dynamic>,ipAddress: null == ipAddress ? _self.ipAddress : ipAddress // ignore: cast_nullable_to_non_nullable as List<dynamic>,ipAddress: null == ipAddress ? _self.ipAddress : ipAddress // ignore: cast_nullable_to_non_nullable
as String,userAgent: null == userAgent ? _self.userAgent : userAgent // ignore: cast_nullable_to_non_nullable as String,userAgent: null == userAgent ? _self.userAgent : userAgent // ignore: cast_nullable_to_non_nullable
as String,deviceId: null == deviceId ? _self.deviceId : deviceId // ignore: cast_nullable_to_non_nullable
as String,nonce: freezed == nonce ? _self.nonce : nonce // ignore: cast_nullable_to_non_nullable as String,nonce: freezed == nonce ? _self.nonce : nonce // ignore: cast_nullable_to_non_nullable
as String?,location: freezed == location ? _self.location : location // ignore: cast_nullable_to_non_nullable as String?,location: freezed == location ? _self.location : location // ignore: cast_nullable_to_non_nullable
as String?,accountId: null == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable as String?,accountId: null == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable
@@ -425,10 +423,10 @@ return $default(_that);case _:
/// } /// }
/// ``` /// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, DateTime expiredAt, int stepRemain, int stepTotal, int failedAttempts, int platform, int type, List<String> blacklistFactors, List<dynamic> audiences, List<dynamic> scopes, String ipAddress, String userAgent, String deviceId, String? nonce, String? location, String accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,{required TResult orElse(),}) {final _that = this; @optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, DateTime expiredAt, int stepRemain, int stepTotal, int failedAttempts, int type, List<String> blacklistFactors, List<dynamic> audiences, List<dynamic> scopes, String ipAddress, String userAgent, String? nonce, String? location, String accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) { switch (_that) {
case _SnAuthChallenge() when $default != null: case _SnAuthChallenge() when $default != null:
return $default(_that.id,_that.expiredAt,_that.stepRemain,_that.stepTotal,_that.failedAttempts,_that.platform,_that.type,_that.blacklistFactors,_that.audiences,_that.scopes,_that.ipAddress,_that.userAgent,_that.deviceId,_that.nonce,_that.location,_that.accountId,_that.createdAt,_that.updatedAt,_that.deletedAt);case _: return $default(_that.id,_that.expiredAt,_that.stepRemain,_that.stepTotal,_that.failedAttempts,_that.type,_that.blacklistFactors,_that.audiences,_that.scopes,_that.ipAddress,_that.userAgent,_that.nonce,_that.location,_that.accountId,_that.createdAt,_that.updatedAt,_that.deletedAt);case _:
return orElse(); return orElse();
} }
@@ -446,10 +444,10 @@ return $default(_that.id,_that.expiredAt,_that.stepRemain,_that.stepTotal,_that.
/// } /// }
/// ``` /// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, DateTime expiredAt, int stepRemain, int stepTotal, int failedAttempts, int platform, int type, List<String> blacklistFactors, List<dynamic> audiences, List<dynamic> scopes, String ipAddress, String userAgent, String deviceId, String? nonce, String? location, String accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt) $default,) {final _that = this; @optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, DateTime expiredAt, int stepRemain, int stepTotal, int failedAttempts, int type, List<String> blacklistFactors, List<dynamic> audiences, List<dynamic> scopes, String ipAddress, String userAgent, String? nonce, String? location, String accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt) $default,) {final _that = this;
switch (_that) { switch (_that) {
case _SnAuthChallenge(): case _SnAuthChallenge():
return $default(_that.id,_that.expiredAt,_that.stepRemain,_that.stepTotal,_that.failedAttempts,_that.platform,_that.type,_that.blacklistFactors,_that.audiences,_that.scopes,_that.ipAddress,_that.userAgent,_that.deviceId,_that.nonce,_that.location,_that.accountId,_that.createdAt,_that.updatedAt,_that.deletedAt);} return $default(_that.id,_that.expiredAt,_that.stepRemain,_that.stepTotal,_that.failedAttempts,_that.type,_that.blacklistFactors,_that.audiences,_that.scopes,_that.ipAddress,_that.userAgent,_that.nonce,_that.location,_that.accountId,_that.createdAt,_that.updatedAt,_that.deletedAt);}
} }
/// A variant of `when` that fallback to returning `null` /// A variant of `when` that fallback to returning `null`
/// ///
@@ -463,10 +461,10 @@ return $default(_that.id,_that.expiredAt,_that.stepRemain,_that.stepTotal,_that.
/// } /// }
/// ``` /// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, DateTime expiredAt, int stepRemain, int stepTotal, int failedAttempts, int platform, int type, List<String> blacklistFactors, List<dynamic> audiences, List<dynamic> scopes, String ipAddress, String userAgent, String deviceId, String? nonce, String? location, String accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,) {final _that = this; @optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, DateTime expiredAt, int stepRemain, int stepTotal, int failedAttempts, int type, List<String> blacklistFactors, List<dynamic> audiences, List<dynamic> scopes, String ipAddress, String userAgent, String? nonce, String? location, String accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,) {final _that = this;
switch (_that) { switch (_that) {
case _SnAuthChallenge() when $default != null: case _SnAuthChallenge() when $default != null:
return $default(_that.id,_that.expiredAt,_that.stepRemain,_that.stepTotal,_that.failedAttempts,_that.platform,_that.type,_that.blacklistFactors,_that.audiences,_that.scopes,_that.ipAddress,_that.userAgent,_that.deviceId,_that.nonce,_that.location,_that.accountId,_that.createdAt,_that.updatedAt,_that.deletedAt);case _: return $default(_that.id,_that.expiredAt,_that.stepRemain,_that.stepTotal,_that.failedAttempts,_that.type,_that.blacklistFactors,_that.audiences,_that.scopes,_that.ipAddress,_that.userAgent,_that.nonce,_that.location,_that.accountId,_that.createdAt,_that.updatedAt,_that.deletedAt);case _:
return null; return null;
} }
@@ -478,7 +476,7 @@ return $default(_that.id,_that.expiredAt,_that.stepRemain,_that.stepTotal,_that.
@JsonSerializable() @JsonSerializable()
class _SnAuthChallenge implements SnAuthChallenge { class _SnAuthChallenge implements SnAuthChallenge {
const _SnAuthChallenge({required this.id, required this.expiredAt, required this.stepRemain, required this.stepTotal, required this.failedAttempts, required this.platform, required this.type, required final List<String> blacklistFactors, required final List<dynamic> audiences, required final List<dynamic> scopes, required this.ipAddress, required this.userAgent, required this.deviceId, required this.nonce, required this.location, required this.accountId, required this.createdAt, required this.updatedAt, required this.deletedAt}): _blacklistFactors = blacklistFactors,_audiences = audiences,_scopes = scopes; const _SnAuthChallenge({required this.id, required this.expiredAt, required this.stepRemain, required this.stepTotal, required this.failedAttempts, required this.type, required final List<String> blacklistFactors, required final List<dynamic> audiences, required final List<dynamic> scopes, required this.ipAddress, required this.userAgent, required this.nonce, required this.location, required this.accountId, required this.createdAt, required this.updatedAt, required this.deletedAt}): _blacklistFactors = blacklistFactors,_audiences = audiences,_scopes = scopes;
factory _SnAuthChallenge.fromJson(Map<String, dynamic> json) => _$SnAuthChallengeFromJson(json); factory _SnAuthChallenge.fromJson(Map<String, dynamic> json) => _$SnAuthChallengeFromJson(json);
@override final String id; @override final String id;
@@ -486,7 +484,6 @@ class _SnAuthChallenge implements SnAuthChallenge {
@override final int stepRemain; @override final int stepRemain;
@override final int stepTotal; @override final int stepTotal;
@override final int failedAttempts; @override final int failedAttempts;
@override final int platform;
@override final int type; @override final int type;
final List<String> _blacklistFactors; final List<String> _blacklistFactors;
@override List<String> get blacklistFactors { @override List<String> get blacklistFactors {
@@ -511,7 +508,6 @@ class _SnAuthChallenge implements SnAuthChallenge {
@override final String ipAddress; @override final String ipAddress;
@override final String userAgent; @override final String userAgent;
@override final String deviceId;
@override final String? nonce; @override final String? nonce;
@override final String? location; @override final String? location;
@override final String accountId; @override final String accountId;
@@ -532,16 +528,16 @@ Map<String, dynamic> toJson() {
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnAuthChallenge&&(identical(other.id, id) || other.id == id)&&(identical(other.expiredAt, expiredAt) || other.expiredAt == expiredAt)&&(identical(other.stepRemain, stepRemain) || other.stepRemain == stepRemain)&&(identical(other.stepTotal, stepTotal) || other.stepTotal == stepTotal)&&(identical(other.failedAttempts, failedAttempts) || other.failedAttempts == failedAttempts)&&(identical(other.platform, platform) || other.platform == platform)&&(identical(other.type, type) || other.type == type)&&const DeepCollectionEquality().equals(other._blacklistFactors, _blacklistFactors)&&const DeepCollectionEquality().equals(other._audiences, _audiences)&&const DeepCollectionEquality().equals(other._scopes, _scopes)&&(identical(other.ipAddress, ipAddress) || other.ipAddress == ipAddress)&&(identical(other.userAgent, userAgent) || other.userAgent == userAgent)&&(identical(other.deviceId, deviceId) || other.deviceId == deviceId)&&(identical(other.nonce, nonce) || other.nonce == nonce)&&(identical(other.location, location) || other.location == location)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)); return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnAuthChallenge&&(identical(other.id, id) || other.id == id)&&(identical(other.expiredAt, expiredAt) || other.expiredAt == expiredAt)&&(identical(other.stepRemain, stepRemain) || other.stepRemain == stepRemain)&&(identical(other.stepTotal, stepTotal) || other.stepTotal == stepTotal)&&(identical(other.failedAttempts, failedAttempts) || other.failedAttempts == failedAttempts)&&(identical(other.type, type) || other.type == type)&&const DeepCollectionEquality().equals(other._blacklistFactors, _blacklistFactors)&&const DeepCollectionEquality().equals(other._audiences, _audiences)&&const DeepCollectionEquality().equals(other._scopes, _scopes)&&(identical(other.ipAddress, ipAddress) || other.ipAddress == ipAddress)&&(identical(other.userAgent, userAgent) || other.userAgent == userAgent)&&(identical(other.nonce, nonce) || other.nonce == nonce)&&(identical(other.location, location) || other.location == location)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt));
} }
@JsonKey(includeFromJson: false, includeToJson: false) @JsonKey(includeFromJson: false, includeToJson: false)
@override @override
int get hashCode => Object.hashAll([runtimeType,id,expiredAt,stepRemain,stepTotal,failedAttempts,platform,type,const DeepCollectionEquality().hash(_blacklistFactors),const DeepCollectionEquality().hash(_audiences),const DeepCollectionEquality().hash(_scopes),ipAddress,userAgent,deviceId,nonce,location,accountId,createdAt,updatedAt,deletedAt]); int get hashCode => Object.hash(runtimeType,id,expiredAt,stepRemain,stepTotal,failedAttempts,type,const DeepCollectionEquality().hash(_blacklistFactors),const DeepCollectionEquality().hash(_audiences),const DeepCollectionEquality().hash(_scopes),ipAddress,userAgent,nonce,location,accountId,createdAt,updatedAt,deletedAt);
@override @override
String toString() { String toString() {
return 'SnAuthChallenge(id: $id, expiredAt: $expiredAt, stepRemain: $stepRemain, stepTotal: $stepTotal, failedAttempts: $failedAttempts, platform: $platform, type: $type, blacklistFactors: $blacklistFactors, audiences: $audiences, scopes: $scopes, ipAddress: $ipAddress, userAgent: $userAgent, deviceId: $deviceId, nonce: $nonce, location: $location, accountId: $accountId, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; return 'SnAuthChallenge(id: $id, expiredAt: $expiredAt, stepRemain: $stepRemain, stepTotal: $stepTotal, failedAttempts: $failedAttempts, type: $type, blacklistFactors: $blacklistFactors, audiences: $audiences, scopes: $scopes, ipAddress: $ipAddress, userAgent: $userAgent, nonce: $nonce, location: $location, accountId: $accountId, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)';
} }
@@ -552,7 +548,7 @@ abstract mixin class _$SnAuthChallengeCopyWith<$Res> implements $SnAuthChallenge
factory _$SnAuthChallengeCopyWith(_SnAuthChallenge value, $Res Function(_SnAuthChallenge) _then) = __$SnAuthChallengeCopyWithImpl; factory _$SnAuthChallengeCopyWith(_SnAuthChallenge value, $Res Function(_SnAuthChallenge) _then) = __$SnAuthChallengeCopyWithImpl;
@override @useResult @override @useResult
$Res call({ $Res call({
String id, DateTime expiredAt, int stepRemain, int stepTotal, int failedAttempts, int platform, int type, List<String> blacklistFactors, List<dynamic> audiences, List<dynamic> scopes, String ipAddress, String userAgent, String deviceId, String? nonce, String? location, String accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt String id, DateTime expiredAt, int stepRemain, int stepTotal, int failedAttempts, int type, List<String> blacklistFactors, List<dynamic> audiences, List<dynamic> scopes, String ipAddress, String userAgent, String? nonce, String? location, String accountId, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt
}); });
@@ -569,21 +565,19 @@ class __$SnAuthChallengeCopyWithImpl<$Res>
/// Create a copy of SnAuthChallenge /// Create a copy of SnAuthChallenge
/// with the given fields replaced by the non-null parameter values. /// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? expiredAt = null,Object? stepRemain = null,Object? stepTotal = null,Object? failedAttempts = null,Object? platform = null,Object? type = null,Object? blacklistFactors = null,Object? audiences = null,Object? scopes = null,Object? ipAddress = null,Object? userAgent = null,Object? deviceId = null,Object? nonce = freezed,Object? location = freezed,Object? accountId = null,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { @override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? expiredAt = null,Object? stepRemain = null,Object? stepTotal = null,Object? failedAttempts = null,Object? type = null,Object? blacklistFactors = null,Object? audiences = null,Object? scopes = null,Object? ipAddress = null,Object? userAgent = null,Object? nonce = freezed,Object? location = freezed,Object? accountId = null,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) {
return _then(_SnAuthChallenge( return _then(_SnAuthChallenge(
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
as String,expiredAt: null == expiredAt ? _self.expiredAt : expiredAt // ignore: cast_nullable_to_non_nullable as String,expiredAt: null == expiredAt ? _self.expiredAt : expiredAt // ignore: cast_nullable_to_non_nullable
as DateTime,stepRemain: null == stepRemain ? _self.stepRemain : stepRemain // ignore: cast_nullable_to_non_nullable as DateTime,stepRemain: null == stepRemain ? _self.stepRemain : stepRemain // ignore: cast_nullable_to_non_nullable
as int,stepTotal: null == stepTotal ? _self.stepTotal : stepTotal // ignore: cast_nullable_to_non_nullable as int,stepTotal: null == stepTotal ? _self.stepTotal : stepTotal // ignore: cast_nullable_to_non_nullable
as int,failedAttempts: null == failedAttempts ? _self.failedAttempts : failedAttempts // ignore: cast_nullable_to_non_nullable as int,failedAttempts: null == failedAttempts ? _self.failedAttempts : failedAttempts // ignore: cast_nullable_to_non_nullable
as int,platform: null == platform ? _self.platform : platform // ignore: cast_nullable_to_non_nullable
as int,type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable as int,type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable
as int,blacklistFactors: null == blacklistFactors ? _self._blacklistFactors : blacklistFactors // ignore: cast_nullable_to_non_nullable as int,blacklistFactors: null == blacklistFactors ? _self._blacklistFactors : blacklistFactors // ignore: cast_nullable_to_non_nullable
as List<String>,audiences: null == audiences ? _self._audiences : audiences // ignore: cast_nullable_to_non_nullable as List<String>,audiences: null == audiences ? _self._audiences : audiences // ignore: cast_nullable_to_non_nullable
as List<dynamic>,scopes: null == scopes ? _self._scopes : scopes // ignore: cast_nullable_to_non_nullable as List<dynamic>,scopes: null == scopes ? _self._scopes : scopes // ignore: cast_nullable_to_non_nullable
as List<dynamic>,ipAddress: null == ipAddress ? _self.ipAddress : ipAddress // ignore: cast_nullable_to_non_nullable as List<dynamic>,ipAddress: null == ipAddress ? _self.ipAddress : ipAddress // ignore: cast_nullable_to_non_nullable
as String,userAgent: null == userAgent ? _self.userAgent : userAgent // ignore: cast_nullable_to_non_nullable as String,userAgent: null == userAgent ? _self.userAgent : userAgent // ignore: cast_nullable_to_non_nullable
as String,deviceId: null == deviceId ? _self.deviceId : deviceId // ignore: cast_nullable_to_non_nullable
as String,nonce: freezed == nonce ? _self.nonce : nonce // ignore: cast_nullable_to_non_nullable as String,nonce: freezed == nonce ? _self.nonce : nonce // ignore: cast_nullable_to_non_nullable
as String?,location: freezed == location ? _self.location : location // ignore: cast_nullable_to_non_nullable as String?,location: freezed == location ? _self.location : location // ignore: cast_nullable_to_non_nullable
as String?,accountId: null == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable as String?,accountId: null == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable
@@ -1189,286 +1183,6 @@ as Map<String, dynamic>?,
} }
/// @nodoc
mixin _$SnAuthDevice {
dynamic get label; String get userAgent; String get deviceId; int get platform; List<SnAuthSession> get sessions;// Not from backend, used for UI
bool get isCurrent;
/// Create a copy of SnAuthDevice
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$SnAuthDeviceCopyWith<SnAuthDevice> get copyWith => _$SnAuthDeviceCopyWithImpl<SnAuthDevice>(this as SnAuthDevice, _$identity);
/// Serializes this SnAuthDevice to a JSON map.
Map<String, dynamic> toJson();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnAuthDevice&&const DeepCollectionEquality().equals(other.label, label)&&(identical(other.userAgent, userAgent) || other.userAgent == userAgent)&&(identical(other.deviceId, deviceId) || other.deviceId == deviceId)&&(identical(other.platform, platform) || other.platform == platform)&&const DeepCollectionEquality().equals(other.sessions, sessions)&&(identical(other.isCurrent, isCurrent) || other.isCurrent == isCurrent));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(label),userAgent,deviceId,platform,const DeepCollectionEquality().hash(sessions),isCurrent);
@override
String toString() {
return 'SnAuthDevice(label: $label, userAgent: $userAgent, deviceId: $deviceId, platform: $platform, sessions: $sessions, isCurrent: $isCurrent)';
}
}
/// @nodoc
abstract mixin class $SnAuthDeviceCopyWith<$Res> {
factory $SnAuthDeviceCopyWith(SnAuthDevice value, $Res Function(SnAuthDevice) _then) = _$SnAuthDeviceCopyWithImpl;
@useResult
$Res call({
dynamic label, String userAgent, String deviceId, int platform, List<SnAuthSession> sessions, bool isCurrent
});
}
/// @nodoc
class _$SnAuthDeviceCopyWithImpl<$Res>
implements $SnAuthDeviceCopyWith<$Res> {
_$SnAuthDeviceCopyWithImpl(this._self, this._then);
final SnAuthDevice _self;
final $Res Function(SnAuthDevice) _then;
/// Create a copy of SnAuthDevice
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? label = freezed,Object? userAgent = null,Object? deviceId = null,Object? platform = null,Object? sessions = null,Object? isCurrent = null,}) {
return _then(_self.copyWith(
label: freezed == label ? _self.label : label // ignore: cast_nullable_to_non_nullable
as dynamic,userAgent: null == userAgent ? _self.userAgent : userAgent // ignore: cast_nullable_to_non_nullable
as String,deviceId: null == deviceId ? _self.deviceId : deviceId // ignore: cast_nullable_to_non_nullable
as String,platform: null == platform ? _self.platform : platform // ignore: cast_nullable_to_non_nullable
as int,sessions: null == sessions ? _self.sessions : sessions // ignore: cast_nullable_to_non_nullable
as List<SnAuthSession>,isCurrent: null == isCurrent ? _self.isCurrent : isCurrent // ignore: cast_nullable_to_non_nullable
as bool,
));
}
}
/// Adds pattern-matching-related methods to [SnAuthDevice].
extension SnAuthDevicePatterns on SnAuthDevice {
/// A variant of `map` that fallback to returning `orElse`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _SnAuthDevice value)? $default,{required TResult orElse(),}){
final _that = this;
switch (_that) {
case _SnAuthDevice() when $default != null:
return $default(_that);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// Callbacks receives the raw object, upcasted.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case final Subclass2 value:
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _SnAuthDevice value) $default,){
final _that = this;
switch (_that) {
case _SnAuthDevice():
return $default(_that);}
}
/// A variant of `map` that fallback to returning `null`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _SnAuthDevice value)? $default,){
final _that = this;
switch (_that) {
case _SnAuthDevice() when $default != null:
return $default(_that);case _:
return null;
}
}
/// A variant of `when` that fallback to an `orElse` callback.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( dynamic label, String userAgent, String deviceId, int platform, List<SnAuthSession> sessions, bool isCurrent)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _SnAuthDevice() when $default != null:
return $default(_that.label,_that.userAgent,_that.deviceId,_that.platform,_that.sessions,_that.isCurrent);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// As opposed to `map`, this offers destructuring.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case Subclass2(:final field2):
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( dynamic label, String userAgent, String deviceId, int platform, List<SnAuthSession> sessions, bool isCurrent) $default,) {final _that = this;
switch (_that) {
case _SnAuthDevice():
return $default(_that.label,_that.userAgent,_that.deviceId,_that.platform,_that.sessions,_that.isCurrent);}
}
/// A variant of `when` that fallback to returning `null`
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( dynamic label, String userAgent, String deviceId, int platform, List<SnAuthSession> sessions, bool isCurrent)? $default,) {final _that = this;
switch (_that) {
case _SnAuthDevice() when $default != null:
return $default(_that.label,_that.userAgent,_that.deviceId,_that.platform,_that.sessions,_that.isCurrent);case _:
return null;
}
}
}
/// @nodoc
@JsonSerializable()
class _SnAuthDevice implements SnAuthDevice {
const _SnAuthDevice({required this.label, required this.userAgent, required this.deviceId, required this.platform, required final List<SnAuthSession> sessions, this.isCurrent = false}): _sessions = sessions;
factory _SnAuthDevice.fromJson(Map<String, dynamic> json) => _$SnAuthDeviceFromJson(json);
@override final dynamic label;
@override final String userAgent;
@override final String deviceId;
@override final int platform;
final List<SnAuthSession> _sessions;
@override List<SnAuthSession> get sessions {
if (_sessions is EqualUnmodifiableListView) return _sessions;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_sessions);
}
// Not from backend, used for UI
@override@JsonKey() final bool isCurrent;
/// Create a copy of SnAuthDevice
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$SnAuthDeviceCopyWith<_SnAuthDevice> get copyWith => __$SnAuthDeviceCopyWithImpl<_SnAuthDevice>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$SnAuthDeviceToJson(this, );
}
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnAuthDevice&&const DeepCollectionEquality().equals(other.label, label)&&(identical(other.userAgent, userAgent) || other.userAgent == userAgent)&&(identical(other.deviceId, deviceId) || other.deviceId == deviceId)&&(identical(other.platform, platform) || other.platform == platform)&&const DeepCollectionEquality().equals(other._sessions, _sessions)&&(identical(other.isCurrent, isCurrent) || other.isCurrent == isCurrent));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(label),userAgent,deviceId,platform,const DeepCollectionEquality().hash(_sessions),isCurrent);
@override
String toString() {
return 'SnAuthDevice(label: $label, userAgent: $userAgent, deviceId: $deviceId, platform: $platform, sessions: $sessions, isCurrent: $isCurrent)';
}
}
/// @nodoc
abstract mixin class _$SnAuthDeviceCopyWith<$Res> implements $SnAuthDeviceCopyWith<$Res> {
factory _$SnAuthDeviceCopyWith(_SnAuthDevice value, $Res Function(_SnAuthDevice) _then) = __$SnAuthDeviceCopyWithImpl;
@override @useResult
$Res call({
dynamic label, String userAgent, String deviceId, int platform, List<SnAuthSession> sessions, bool isCurrent
});
}
/// @nodoc
class __$SnAuthDeviceCopyWithImpl<$Res>
implements _$SnAuthDeviceCopyWith<$Res> {
__$SnAuthDeviceCopyWithImpl(this._self, this._then);
final _SnAuthDevice _self;
final $Res Function(_SnAuthDevice) _then;
/// Create a copy of SnAuthDevice
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? label = freezed,Object? userAgent = null,Object? deviceId = null,Object? platform = null,Object? sessions = null,Object? isCurrent = null,}) {
return _then(_SnAuthDevice(
label: freezed == label ? _self.label : label // ignore: cast_nullable_to_non_nullable
as dynamic,userAgent: null == userAgent ? _self.userAgent : userAgent // ignore: cast_nullable_to_non_nullable
as String,deviceId: null == deviceId ? _self.deviceId : deviceId // ignore: cast_nullable_to_non_nullable
as String,platform: null == platform ? _self.platform : platform // ignore: cast_nullable_to_non_nullable
as int,sessions: null == sessions ? _self._sessions : sessions // ignore: cast_nullable_to_non_nullable
as List<SnAuthSession>,isCurrent: null == isCurrent ? _self.isCurrent : isCurrent // ignore: cast_nullable_to_non_nullable
as bool,
));
}
}
/// @nodoc /// @nodoc
mixin _$SnAccountConnection { mixin _$SnAccountConnection {

View File

@@ -20,7 +20,6 @@ _SnAuthChallenge _$SnAuthChallengeFromJson(Map<String, dynamic> json) =>
stepRemain: (json['step_remain'] as num).toInt(), stepRemain: (json['step_remain'] as num).toInt(),
stepTotal: (json['step_total'] as num).toInt(), stepTotal: (json['step_total'] as num).toInt(),
failedAttempts: (json['failed_attempts'] as num).toInt(), failedAttempts: (json['failed_attempts'] as num).toInt(),
platform: (json['platform'] as num).toInt(),
type: (json['type'] as num).toInt(), type: (json['type'] as num).toInt(),
blacklistFactors: blacklistFactors:
(json['blacklist_factors'] as List<dynamic>) (json['blacklist_factors'] as List<dynamic>)
@@ -30,7 +29,6 @@ _SnAuthChallenge _$SnAuthChallengeFromJson(Map<String, dynamic> json) =>
scopes: json['scopes'] as List<dynamic>, scopes: json['scopes'] as List<dynamic>,
ipAddress: json['ip_address'] as String, ipAddress: json['ip_address'] as String,
userAgent: json['user_agent'] as String, userAgent: json['user_agent'] as String,
deviceId: json['device_id'] as String,
nonce: json['nonce'] as String?, nonce: json['nonce'] as String?,
location: json['location'] as String?, location: json['location'] as String?,
accountId: json['account_id'] as String, accountId: json['account_id'] as String,
@@ -49,14 +47,12 @@ Map<String, dynamic> _$SnAuthChallengeToJson(_SnAuthChallenge instance) =>
'step_remain': instance.stepRemain, 'step_remain': instance.stepRemain,
'step_total': instance.stepTotal, 'step_total': instance.stepTotal,
'failed_attempts': instance.failedAttempts, 'failed_attempts': instance.failedAttempts,
'platform': instance.platform,
'type': instance.type, 'type': instance.type,
'blacklist_factors': instance.blacklistFactors, 'blacklist_factors': instance.blacklistFactors,
'audiences': instance.audiences, 'audiences': instance.audiences,
'scopes': instance.scopes, 'scopes': instance.scopes,
'ip_address': instance.ipAddress, 'ip_address': instance.ipAddress,
'user_agent': instance.userAgent, 'user_agent': instance.userAgent,
'device_id': instance.deviceId,
'nonce': instance.nonce, 'nonce': instance.nonce,
'location': instance.location, 'location': instance.location,
'account_id': instance.accountId, 'account_id': instance.accountId,
@@ -133,29 +129,6 @@ Map<String, dynamic> _$SnAuthFactorToJson(_SnAuthFactor instance) =>
'created_response': instance.createdResponse, 'created_response': instance.createdResponse,
}; };
_SnAuthDevice _$SnAuthDeviceFromJson(Map<String, dynamic> json) =>
_SnAuthDevice(
label: json['label'],
userAgent: json['user_agent'] as String,
deviceId: json['device_id'] as String,
platform: (json['platform'] as num).toInt(),
sessions:
(json['sessions'] as List<dynamic>)
.map((e) => SnAuthSession.fromJson(e as Map<String, dynamic>))
.toList(),
isCurrent: json['is_current'] as bool? ?? false,
);
Map<String, dynamic> _$SnAuthDeviceToJson(_SnAuthDevice instance) =>
<String, dynamic>{
'label': instance.label,
'user_agent': instance.userAgent,
'device_id': instance.deviceId,
'platform': instance.platform,
'sessions': instance.sessions.map((e) => e.toJson()).toList(),
'is_current': instance.isCurrent,
};
_SnAccountConnection _$SnAccountConnectionFromJson(Map<String, dynamic> json) => _SnAccountConnection _$SnAccountConnectionFromJson(Map<String, dynamic> json) =>
_SnAccountConnection( _SnAccountConnection(
id: json['id'] as String, id: json['id'] as String,

View File

@@ -1,7 +1,7 @@
import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:island/models/file.dart'; import 'package:island/models/file.dart';
import 'package:island/models/realm.dart'; import 'package:island/models/realm.dart';
import 'package:island/models/user.dart'; import 'package:island/models/account.dart';
part 'chat.freezed.dart'; part 'chat.freezed.dart';
part 'chat.g.dart'; part 'chat.g.dart';
@@ -91,6 +91,7 @@ sealed class SnChatMember with _$SnChatMember {
required DateTime? breakUntil, required DateTime? breakUntil,
required DateTime? timeoutUntil, required DateTime? timeoutUntil,
required bool isBot, required bool isBot,
required SnAccountStatus? status,
// Frontend data // Frontend data
DateTime? lastTyped, DateTime? lastTyped,
}) = _SnChatMember; }) = _SnChatMember;

View File

@@ -1037,7 +1037,7 @@ $SnChatMemberCopyWith<$Res> get sender {
/// @nodoc /// @nodoc
mixin _$SnChatMember { mixin _$SnChatMember {
DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; String get id; String get chatRoomId; SnChatRoom? get chatRoom; String get accountId; SnAccount get account; String? get nick; int get role; int get notify; DateTime? get joinedAt; DateTime? get breakUntil; DateTime? get timeoutUntil; bool get isBot;// Frontend data DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; String get id; String get chatRoomId; SnChatRoom? get chatRoom; String get accountId; SnAccount get account; String? get nick; int get role; int get notify; DateTime? get joinedAt; DateTime? get breakUntil; DateTime? get timeoutUntil; bool get isBot; SnAccountStatus? get status;// Frontend data
DateTime? get lastTyped; DateTime? get lastTyped;
/// Create a copy of SnChatMember /// Create a copy of SnChatMember
/// with the given fields replaced by the non-null parameter values. /// with the given fields replaced by the non-null parameter values.
@@ -1051,16 +1051,16 @@ $SnChatMemberCopyWith<SnChatMember> get copyWith => _$SnChatMemberCopyWithImpl<S
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnChatMember&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.id, id) || other.id == id)&&(identical(other.chatRoomId, chatRoomId) || other.chatRoomId == chatRoomId)&&(identical(other.chatRoom, chatRoom) || other.chatRoom == chatRoom)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.account, account) || other.account == account)&&(identical(other.nick, nick) || other.nick == nick)&&(identical(other.role, role) || other.role == role)&&(identical(other.notify, notify) || other.notify == notify)&&(identical(other.joinedAt, joinedAt) || other.joinedAt == joinedAt)&&(identical(other.breakUntil, breakUntil) || other.breakUntil == breakUntil)&&(identical(other.timeoutUntil, timeoutUntil) || other.timeoutUntil == timeoutUntil)&&(identical(other.isBot, isBot) || other.isBot == isBot)&&(identical(other.lastTyped, lastTyped) || other.lastTyped == lastTyped)); return identical(this, other) || (other.runtimeType == runtimeType&&other is SnChatMember&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.id, id) || other.id == id)&&(identical(other.chatRoomId, chatRoomId) || other.chatRoomId == chatRoomId)&&(identical(other.chatRoom, chatRoom) || other.chatRoom == chatRoom)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.account, account) || other.account == account)&&(identical(other.nick, nick) || other.nick == nick)&&(identical(other.role, role) || other.role == role)&&(identical(other.notify, notify) || other.notify == notify)&&(identical(other.joinedAt, joinedAt) || other.joinedAt == joinedAt)&&(identical(other.breakUntil, breakUntil) || other.breakUntil == breakUntil)&&(identical(other.timeoutUntil, timeoutUntil) || other.timeoutUntil == timeoutUntil)&&(identical(other.isBot, isBot) || other.isBot == isBot)&&(identical(other.status, status) || other.status == status)&&(identical(other.lastTyped, lastTyped) || other.lastTyped == lastTyped));
} }
@JsonKey(includeFromJson: false, includeToJson: false) @JsonKey(includeFromJson: false, includeToJson: false)
@override @override
int get hashCode => Object.hash(runtimeType,createdAt,updatedAt,deletedAt,id,chatRoomId,chatRoom,accountId,account,nick,role,notify,joinedAt,breakUntil,timeoutUntil,isBot,lastTyped); int get hashCode => Object.hash(runtimeType,createdAt,updatedAt,deletedAt,id,chatRoomId,chatRoom,accountId,account,nick,role,notify,joinedAt,breakUntil,timeoutUntil,isBot,status,lastTyped);
@override @override
String toString() { String toString() {
return 'SnChatMember(createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, id: $id, chatRoomId: $chatRoomId, chatRoom: $chatRoom, accountId: $accountId, account: $account, nick: $nick, role: $role, notify: $notify, joinedAt: $joinedAt, breakUntil: $breakUntil, timeoutUntil: $timeoutUntil, isBot: $isBot, lastTyped: $lastTyped)'; return 'SnChatMember(createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, id: $id, chatRoomId: $chatRoomId, chatRoom: $chatRoom, accountId: $accountId, account: $account, nick: $nick, role: $role, notify: $notify, joinedAt: $joinedAt, breakUntil: $breakUntil, timeoutUntil: $timeoutUntil, isBot: $isBot, status: $status, lastTyped: $lastTyped)';
} }
@@ -1071,11 +1071,11 @@ abstract mixin class $SnChatMemberCopyWith<$Res> {
factory $SnChatMemberCopyWith(SnChatMember value, $Res Function(SnChatMember) _then) = _$SnChatMemberCopyWithImpl; factory $SnChatMemberCopyWith(SnChatMember value, $Res Function(SnChatMember) _then) = _$SnChatMemberCopyWithImpl;
@useResult @useResult
$Res call({ $Res call({
DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, String id, String chatRoomId, SnChatRoom? chatRoom, String accountId, SnAccount account, String? nick, int role, int notify, DateTime? joinedAt, DateTime? breakUntil, DateTime? timeoutUntil, bool isBot, DateTime? lastTyped DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, String id, String chatRoomId, SnChatRoom? chatRoom, String accountId, SnAccount account, String? nick, int role, int notify, DateTime? joinedAt, DateTime? breakUntil, DateTime? timeoutUntil, bool isBot, SnAccountStatus? status, DateTime? lastTyped
}); });
$SnChatRoomCopyWith<$Res>? get chatRoom;$SnAccountCopyWith<$Res> get account; $SnChatRoomCopyWith<$Res>? get chatRoom;$SnAccountCopyWith<$Res> get account;$SnAccountStatusCopyWith<$Res>? get status;
} }
/// @nodoc /// @nodoc
@@ -1088,7 +1088,7 @@ class _$SnChatMemberCopyWithImpl<$Res>
/// Create a copy of SnChatMember /// Create a copy of SnChatMember
/// with the given fields replaced by the non-null parameter values. /// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,Object? id = null,Object? chatRoomId = null,Object? chatRoom = freezed,Object? accountId = null,Object? account = null,Object? nick = freezed,Object? role = null,Object? notify = null,Object? joinedAt = freezed,Object? breakUntil = freezed,Object? timeoutUntil = freezed,Object? isBot = null,Object? lastTyped = freezed,}) { @pragma('vm:prefer-inline') @override $Res call({Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,Object? id = null,Object? chatRoomId = null,Object? chatRoom = freezed,Object? accountId = null,Object? account = null,Object? nick = freezed,Object? role = null,Object? notify = null,Object? joinedAt = freezed,Object? breakUntil = freezed,Object? timeoutUntil = freezed,Object? isBot = null,Object? status = freezed,Object? lastTyped = freezed,}) {
return _then(_self.copyWith( return _then(_self.copyWith(
createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable
@@ -1105,7 +1105,8 @@ as int,joinedAt: freezed == joinedAt ? _self.joinedAt : joinedAt // ignore: cast
as DateTime?,breakUntil: freezed == breakUntil ? _self.breakUntil : breakUntil // ignore: cast_nullable_to_non_nullable as DateTime?,breakUntil: freezed == breakUntil ? _self.breakUntil : breakUntil // ignore: cast_nullable_to_non_nullable
as DateTime?,timeoutUntil: freezed == timeoutUntil ? _self.timeoutUntil : timeoutUntil // ignore: cast_nullable_to_non_nullable as DateTime?,timeoutUntil: freezed == timeoutUntil ? _self.timeoutUntil : timeoutUntil // ignore: cast_nullable_to_non_nullable
as DateTime?,isBot: null == isBot ? _self.isBot : isBot // ignore: cast_nullable_to_non_nullable as DateTime?,isBot: null == isBot ? _self.isBot : isBot // ignore: cast_nullable_to_non_nullable
as bool,lastTyped: freezed == lastTyped ? _self.lastTyped : lastTyped // ignore: cast_nullable_to_non_nullable as bool,status: freezed == status ? _self.status : status // ignore: cast_nullable_to_non_nullable
as SnAccountStatus?,lastTyped: freezed == lastTyped ? _self.lastTyped : lastTyped // ignore: cast_nullable_to_non_nullable
as DateTime?, as DateTime?,
)); ));
} }
@@ -1130,6 +1131,18 @@ $SnAccountCopyWith<$Res> get account {
return $SnAccountCopyWith<$Res>(_self.account, (value) { return $SnAccountCopyWith<$Res>(_self.account, (value) {
return _then(_self.copyWith(account: value)); return _then(_self.copyWith(account: value));
}); });
}/// Create a copy of SnChatMember
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$SnAccountStatusCopyWith<$Res>? get status {
if (_self.status == null) {
return null;
}
return $SnAccountStatusCopyWith<$Res>(_self.status!, (value) {
return _then(_self.copyWith(status: value));
});
} }
} }
@@ -1209,10 +1222,10 @@ return $default(_that);case _:
/// } /// }
/// ``` /// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, String id, String chatRoomId, SnChatRoom? chatRoom, String accountId, SnAccount account, String? nick, int role, int notify, DateTime? joinedAt, DateTime? breakUntil, DateTime? timeoutUntil, bool isBot, DateTime? lastTyped)? $default,{required TResult orElse(),}) {final _that = this; @optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, String id, String chatRoomId, SnChatRoom? chatRoom, String accountId, SnAccount account, String? nick, int role, int notify, DateTime? joinedAt, DateTime? breakUntil, DateTime? timeoutUntil, bool isBot, SnAccountStatus? status, DateTime? lastTyped)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) { switch (_that) {
case _SnChatMember() when $default != null: case _SnChatMember() when $default != null:
return $default(_that.createdAt,_that.updatedAt,_that.deletedAt,_that.id,_that.chatRoomId,_that.chatRoom,_that.accountId,_that.account,_that.nick,_that.role,_that.notify,_that.joinedAt,_that.breakUntil,_that.timeoutUntil,_that.isBot,_that.lastTyped);case _: return $default(_that.createdAt,_that.updatedAt,_that.deletedAt,_that.id,_that.chatRoomId,_that.chatRoom,_that.accountId,_that.account,_that.nick,_that.role,_that.notify,_that.joinedAt,_that.breakUntil,_that.timeoutUntil,_that.isBot,_that.status,_that.lastTyped);case _:
return orElse(); return orElse();
} }
@@ -1230,10 +1243,10 @@ return $default(_that.createdAt,_that.updatedAt,_that.deletedAt,_that.id,_that.c
/// } /// }
/// ``` /// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, String id, String chatRoomId, SnChatRoom? chatRoom, String accountId, SnAccount account, String? nick, int role, int notify, DateTime? joinedAt, DateTime? breakUntil, DateTime? timeoutUntil, bool isBot, DateTime? lastTyped) $default,) {final _that = this; @optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, String id, String chatRoomId, SnChatRoom? chatRoom, String accountId, SnAccount account, String? nick, int role, int notify, DateTime? joinedAt, DateTime? breakUntil, DateTime? timeoutUntil, bool isBot, SnAccountStatus? status, DateTime? lastTyped) $default,) {final _that = this;
switch (_that) { switch (_that) {
case _SnChatMember(): case _SnChatMember():
return $default(_that.createdAt,_that.updatedAt,_that.deletedAt,_that.id,_that.chatRoomId,_that.chatRoom,_that.accountId,_that.account,_that.nick,_that.role,_that.notify,_that.joinedAt,_that.breakUntil,_that.timeoutUntil,_that.isBot,_that.lastTyped);} return $default(_that.createdAt,_that.updatedAt,_that.deletedAt,_that.id,_that.chatRoomId,_that.chatRoom,_that.accountId,_that.account,_that.nick,_that.role,_that.notify,_that.joinedAt,_that.breakUntil,_that.timeoutUntil,_that.isBot,_that.status,_that.lastTyped);}
} }
/// A variant of `when` that fallback to returning `null` /// A variant of `when` that fallback to returning `null`
/// ///
@@ -1247,10 +1260,10 @@ return $default(_that.createdAt,_that.updatedAt,_that.deletedAt,_that.id,_that.c
/// } /// }
/// ``` /// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, String id, String chatRoomId, SnChatRoom? chatRoom, String accountId, SnAccount account, String? nick, int role, int notify, DateTime? joinedAt, DateTime? breakUntil, DateTime? timeoutUntil, bool isBot, DateTime? lastTyped)? $default,) {final _that = this; @optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, String id, String chatRoomId, SnChatRoom? chatRoom, String accountId, SnAccount account, String? nick, int role, int notify, DateTime? joinedAt, DateTime? breakUntil, DateTime? timeoutUntil, bool isBot, SnAccountStatus? status, DateTime? lastTyped)? $default,) {final _that = this;
switch (_that) { switch (_that) {
case _SnChatMember() when $default != null: case _SnChatMember() when $default != null:
return $default(_that.createdAt,_that.updatedAt,_that.deletedAt,_that.id,_that.chatRoomId,_that.chatRoom,_that.accountId,_that.account,_that.nick,_that.role,_that.notify,_that.joinedAt,_that.breakUntil,_that.timeoutUntil,_that.isBot,_that.lastTyped);case _: return $default(_that.createdAt,_that.updatedAt,_that.deletedAt,_that.id,_that.chatRoomId,_that.chatRoom,_that.accountId,_that.account,_that.nick,_that.role,_that.notify,_that.joinedAt,_that.breakUntil,_that.timeoutUntil,_that.isBot,_that.status,_that.lastTyped);case _:
return null; return null;
} }
@@ -1262,7 +1275,7 @@ return $default(_that.createdAt,_that.updatedAt,_that.deletedAt,_that.id,_that.c
@JsonSerializable() @JsonSerializable()
class _SnChatMember implements SnChatMember { class _SnChatMember implements SnChatMember {
const _SnChatMember({required this.createdAt, required this.updatedAt, required this.deletedAt, required this.id, required this.chatRoomId, required this.chatRoom, required this.accountId, required this.account, required this.nick, required this.role, required this.notify, required this.joinedAt, required this.breakUntil, required this.timeoutUntil, required this.isBot, this.lastTyped}); const _SnChatMember({required this.createdAt, required this.updatedAt, required this.deletedAt, required this.id, required this.chatRoomId, required this.chatRoom, required this.accountId, required this.account, required this.nick, required this.role, required this.notify, required this.joinedAt, required this.breakUntil, required this.timeoutUntil, required this.isBot, required this.status, this.lastTyped});
factory _SnChatMember.fromJson(Map<String, dynamic> json) => _$SnChatMemberFromJson(json); factory _SnChatMember.fromJson(Map<String, dynamic> json) => _$SnChatMemberFromJson(json);
@override final DateTime createdAt; @override final DateTime createdAt;
@@ -1280,6 +1293,7 @@ class _SnChatMember implements SnChatMember {
@override final DateTime? breakUntil; @override final DateTime? breakUntil;
@override final DateTime? timeoutUntil; @override final DateTime? timeoutUntil;
@override final bool isBot; @override final bool isBot;
@override final SnAccountStatus? status;
// Frontend data // Frontend data
@override final DateTime? lastTyped; @override final DateTime? lastTyped;
@@ -1296,16 +1310,16 @@ Map<String, dynamic> toJson() {
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnChatMember&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.id, id) || other.id == id)&&(identical(other.chatRoomId, chatRoomId) || other.chatRoomId == chatRoomId)&&(identical(other.chatRoom, chatRoom) || other.chatRoom == chatRoom)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.account, account) || other.account == account)&&(identical(other.nick, nick) || other.nick == nick)&&(identical(other.role, role) || other.role == role)&&(identical(other.notify, notify) || other.notify == notify)&&(identical(other.joinedAt, joinedAt) || other.joinedAt == joinedAt)&&(identical(other.breakUntil, breakUntil) || other.breakUntil == breakUntil)&&(identical(other.timeoutUntil, timeoutUntil) || other.timeoutUntil == timeoutUntil)&&(identical(other.isBot, isBot) || other.isBot == isBot)&&(identical(other.lastTyped, lastTyped) || other.lastTyped == lastTyped)); return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnChatMember&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.id, id) || other.id == id)&&(identical(other.chatRoomId, chatRoomId) || other.chatRoomId == chatRoomId)&&(identical(other.chatRoom, chatRoom) || other.chatRoom == chatRoom)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.account, account) || other.account == account)&&(identical(other.nick, nick) || other.nick == nick)&&(identical(other.role, role) || other.role == role)&&(identical(other.notify, notify) || other.notify == notify)&&(identical(other.joinedAt, joinedAt) || other.joinedAt == joinedAt)&&(identical(other.breakUntil, breakUntil) || other.breakUntil == breakUntil)&&(identical(other.timeoutUntil, timeoutUntil) || other.timeoutUntil == timeoutUntil)&&(identical(other.isBot, isBot) || other.isBot == isBot)&&(identical(other.status, status) || other.status == status)&&(identical(other.lastTyped, lastTyped) || other.lastTyped == lastTyped));
} }
@JsonKey(includeFromJson: false, includeToJson: false) @JsonKey(includeFromJson: false, includeToJson: false)
@override @override
int get hashCode => Object.hash(runtimeType,createdAt,updatedAt,deletedAt,id,chatRoomId,chatRoom,accountId,account,nick,role,notify,joinedAt,breakUntil,timeoutUntil,isBot,lastTyped); int get hashCode => Object.hash(runtimeType,createdAt,updatedAt,deletedAt,id,chatRoomId,chatRoom,accountId,account,nick,role,notify,joinedAt,breakUntil,timeoutUntil,isBot,status,lastTyped);
@override @override
String toString() { String toString() {
return 'SnChatMember(createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, id: $id, chatRoomId: $chatRoomId, chatRoom: $chatRoom, accountId: $accountId, account: $account, nick: $nick, role: $role, notify: $notify, joinedAt: $joinedAt, breakUntil: $breakUntil, timeoutUntil: $timeoutUntil, isBot: $isBot, lastTyped: $lastTyped)'; return 'SnChatMember(createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, id: $id, chatRoomId: $chatRoomId, chatRoom: $chatRoom, accountId: $accountId, account: $account, nick: $nick, role: $role, notify: $notify, joinedAt: $joinedAt, breakUntil: $breakUntil, timeoutUntil: $timeoutUntil, isBot: $isBot, status: $status, lastTyped: $lastTyped)';
} }
@@ -1316,11 +1330,11 @@ abstract mixin class _$SnChatMemberCopyWith<$Res> implements $SnChatMemberCopyWi
factory _$SnChatMemberCopyWith(_SnChatMember value, $Res Function(_SnChatMember) _then) = __$SnChatMemberCopyWithImpl; factory _$SnChatMemberCopyWith(_SnChatMember value, $Res Function(_SnChatMember) _then) = __$SnChatMemberCopyWithImpl;
@override @useResult @override @useResult
$Res call({ $Res call({
DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, String id, String chatRoomId, SnChatRoom? chatRoom, String accountId, SnAccount account, String? nick, int role, int notify, DateTime? joinedAt, DateTime? breakUntil, DateTime? timeoutUntil, bool isBot, DateTime? lastTyped DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, String id, String chatRoomId, SnChatRoom? chatRoom, String accountId, SnAccount account, String? nick, int role, int notify, DateTime? joinedAt, DateTime? breakUntil, DateTime? timeoutUntil, bool isBot, SnAccountStatus? status, DateTime? lastTyped
}); });
@override $SnChatRoomCopyWith<$Res>? get chatRoom;@override $SnAccountCopyWith<$Res> get account; @override $SnChatRoomCopyWith<$Res>? get chatRoom;@override $SnAccountCopyWith<$Res> get account;@override $SnAccountStatusCopyWith<$Res>? get status;
} }
/// @nodoc /// @nodoc
@@ -1333,7 +1347,7 @@ class __$SnChatMemberCopyWithImpl<$Res>
/// Create a copy of SnChatMember /// Create a copy of SnChatMember
/// with the given fields replaced by the non-null parameter values. /// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,Object? id = null,Object? chatRoomId = null,Object? chatRoom = freezed,Object? accountId = null,Object? account = null,Object? nick = freezed,Object? role = null,Object? notify = null,Object? joinedAt = freezed,Object? breakUntil = freezed,Object? timeoutUntil = freezed,Object? isBot = null,Object? lastTyped = freezed,}) { @override @pragma('vm:prefer-inline') $Res call({Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,Object? id = null,Object? chatRoomId = null,Object? chatRoom = freezed,Object? accountId = null,Object? account = null,Object? nick = freezed,Object? role = null,Object? notify = null,Object? joinedAt = freezed,Object? breakUntil = freezed,Object? timeoutUntil = freezed,Object? isBot = null,Object? status = freezed,Object? lastTyped = freezed,}) {
return _then(_SnChatMember( return _then(_SnChatMember(
createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable
@@ -1350,7 +1364,8 @@ as int,joinedAt: freezed == joinedAt ? _self.joinedAt : joinedAt // ignore: cast
as DateTime?,breakUntil: freezed == breakUntil ? _self.breakUntil : breakUntil // ignore: cast_nullable_to_non_nullable as DateTime?,breakUntil: freezed == breakUntil ? _self.breakUntil : breakUntil // ignore: cast_nullable_to_non_nullable
as DateTime?,timeoutUntil: freezed == timeoutUntil ? _self.timeoutUntil : timeoutUntil // ignore: cast_nullable_to_non_nullable as DateTime?,timeoutUntil: freezed == timeoutUntil ? _self.timeoutUntil : timeoutUntil // ignore: cast_nullable_to_non_nullable
as DateTime?,isBot: null == isBot ? _self.isBot : isBot // ignore: cast_nullable_to_non_nullable as DateTime?,isBot: null == isBot ? _self.isBot : isBot // ignore: cast_nullable_to_non_nullable
as bool,lastTyped: freezed == lastTyped ? _self.lastTyped : lastTyped // ignore: cast_nullable_to_non_nullable as bool,status: freezed == status ? _self.status : status // ignore: cast_nullable_to_non_nullable
as SnAccountStatus?,lastTyped: freezed == lastTyped ? _self.lastTyped : lastTyped // ignore: cast_nullable_to_non_nullable
as DateTime?, as DateTime?,
)); ));
} }
@@ -1376,6 +1391,18 @@ $SnAccountCopyWith<$Res> get account {
return $SnAccountCopyWith<$Res>(_self.account, (value) { return $SnAccountCopyWith<$Res>(_self.account, (value) {
return _then(_self.copyWith(account: value)); return _then(_self.copyWith(account: value));
}); });
}/// Create a copy of SnChatMember
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$SnAccountStatusCopyWith<$Res>? get status {
if (_self.status == null) {
return null;
}
return $SnAccountStatusCopyWith<$Res>(_self.status!, (value) {
return _then(_self.copyWith(status: value));
});
} }
} }

View File

@@ -177,6 +177,12 @@ _SnChatMember _$SnChatMemberFromJson(Map<String, dynamic> json) =>
? null ? null
: DateTime.parse(json['timeout_until'] as String), : DateTime.parse(json['timeout_until'] as String),
isBot: json['is_bot'] as bool, isBot: json['is_bot'] as bool,
status:
json['status'] == null
? null
: SnAccountStatus.fromJson(
json['status'] as Map<String, dynamic>,
),
lastTyped: lastTyped:
json['last_typed'] == null json['last_typed'] == null
? null ? null
@@ -200,6 +206,7 @@ Map<String, dynamic> _$SnChatMemberToJson(_SnChatMember instance) =>
'break_until': instance.breakUntil?.toIso8601String(), 'break_until': instance.breakUntil?.toIso8601String(),
'timeout_until': instance.timeoutUntil?.toIso8601String(), 'timeout_until': instance.timeoutUntil?.toIso8601String(),
'is_bot': instance.isBot, 'is_bot': instance.isBot,
'status': instance.status?.toJson(),
'last_typed': instance.lastTyped?.toIso8601String(), 'last_typed': instance.lastTyped?.toIso8601String(),
}; };

View File

@@ -1,6 +1,6 @@
import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:island/models/file.dart'; import 'package:island/models/file.dart';
import 'package:island/models/user.dart'; import 'package:island/models/account.dart';
part 'custom_app.freezed.dart'; part 'custom_app.freezed.dart';
part 'custom_app.g.dart'; part 'custom_app.g.dart';

View File

@@ -11,8 +11,8 @@ sealed class SnScrappedLink with _$SnScrappedLink {
required String title, required String title,
required String? description, required String? description,
required String? imageUrl, required String? imageUrl,
required String faviconUrl, required String? faviconUrl,
required String siteName, required String? siteName,
required String? contentType, required String? contentType,
required String? author, required String? author,
required DateTime? publishedDate, required DateTime? publishedDate,

View File

@@ -15,7 +15,7 @@ T _$identity<T>(T value) => value;
/// @nodoc /// @nodoc
mixin _$SnScrappedLink { 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 /// Create a copy of SnScrappedLink
/// with the given fields replaced by the non-null parameter values. /// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false) @JsonKey(includeFromJson: false, includeToJson: false)
@@ -48,7 +48,7 @@ abstract mixin class $SnScrappedLinkCopyWith<$Res> {
factory $SnScrappedLinkCopyWith(SnScrappedLink value, $Res Function(SnScrappedLink) _then) = _$SnScrappedLinkCopyWithImpl; factory $SnScrappedLinkCopyWith(SnScrappedLink value, $Res Function(SnScrappedLink) _then) = _$SnScrappedLinkCopyWithImpl;
@useResult @useResult
$Res call({ $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 /// Create a copy of SnScrappedLink
/// with the given fields replaced by the non-null parameter values. /// 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( return _then(_self.copyWith(
type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable 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,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,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,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?,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?,faviconUrl: freezed == 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?,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?,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?,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 String?,publishedDate: freezed == publishedDate ? _self.publishedDate : publishedDate // ignore: cast_nullable_to_non_nullable
as DateTime?, 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) { switch (_that) {
case _SnScrappedLink() when $default != null: 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 _: 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) { switch (_that) {
case _SnScrappedLink(): case _SnScrappedLink():
return $default(_that.type,_that.url,_that.title,_that.description,_that.imageUrl,_that.faviconUrl,_that.siteName,_that.contentType,_that.author,_that.publishedDate);} 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) { switch (_that) {
case _SnScrappedLink() when $default != null: 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 _: 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 title;
@override final String? description; @override final String? description;
@override final String? imageUrl; @override final String? imageUrl;
@override final String faviconUrl; @override final String? faviconUrl;
@override final String siteName; @override final String? siteName;
@override final String? contentType; @override final String? contentType;
@override final String? author; @override final String? author;
@override final DateTime? publishedDate; @override final DateTime? publishedDate;
@@ -259,7 +259,7 @@ abstract mixin class _$SnScrappedLinkCopyWith<$Res> implements $SnScrappedLinkCo
factory _$SnScrappedLinkCopyWith(_SnScrappedLink value, $Res Function(_SnScrappedLink) _then) = __$SnScrappedLinkCopyWithImpl; factory _$SnScrappedLinkCopyWith(_SnScrappedLink value, $Res Function(_SnScrappedLink) _then) = __$SnScrappedLinkCopyWithImpl;
@override @useResult @override @useResult
$Res call({ $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 /// Create a copy of SnScrappedLink
/// with the given fields replaced by the non-null parameter values. /// 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( return _then(_SnScrappedLink(
type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable 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,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,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,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?,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?,faviconUrl: freezed == 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?,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?,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?,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 String?,publishedDate: freezed == publishedDate ? _self.publishedDate : publishedDate // ignore: cast_nullable_to_non_nullable
as DateTime?, as DateTime?,

View File

@@ -13,8 +13,8 @@ _SnScrappedLink _$SnScrappedLinkFromJson(Map<String, dynamic> json) =>
title: json['title'] as String, title: json['title'] as String,
description: json['description'] as String?, description: json['description'] as String?,
imageUrl: json['image_url'] as String?, imageUrl: json['image_url'] as String?,
faviconUrl: json['favicon_url'] as String, faviconUrl: json['favicon_url'] as String?,
siteName: json['site_name'] as String, siteName: json['site_name'] as String?,
contentType: json['content_type'] as String?, contentType: json['content_type'] as String?,
author: json['author'] as String?, author: json['author'] as String?,
publishedDate: publishedDate:

View File

@@ -3,6 +3,7 @@ import 'package:island/models/file.dart';
import 'package:island/models/post_category.dart'; import 'package:island/models/post_category.dart';
import 'package:island/models/post_tag.dart'; import 'package:island/models/post_tag.dart';
import 'package:island/models/publisher.dart'; import 'package:island/models/publisher.dart';
import 'package:island/models/realm.dart';
part 'post.freezed.dart'; part 'post.freezed.dart';
part 'post.g.dart'; part 'post.g.dart';
@@ -18,6 +19,7 @@ sealed class SnPost with _$SnPost {
@Default(null) DateTime? publishedAt, @Default(null) DateTime? publishedAt,
@Default(0) int visibility, @Default(0) int visibility,
String? content, String? content,
String? slug,
@Default(0) int type, @Default(0) int type,
Map<String, dynamic>? meta, Map<String, dynamic>? meta,
@Default(0) int viewsUnique, @Default(0) int viewsUnique,
@@ -31,6 +33,8 @@ sealed class SnPost with _$SnPost {
SnPost? repliedPost, SnPost? repliedPost,
String? forwardedPostId, String? forwardedPostId,
SnPost? forwardedPost, SnPost? forwardedPost,
String? realmId,
SnRealm? realm,
@Default([]) List<SnCloudFile> attachments, @Default([]) List<SnCloudFile> attachments,
required SnPublisher publisher, required SnPublisher publisher,
@Default({}) Map<String, int> reactionsCount, @Default({}) Map<String, int> reactionsCount,

View File

@@ -15,7 +15,7 @@ T _$identity<T>(T value) => value;
/// @nodoc /// @nodoc
mixin _$SnPost { 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 /// Create a copy of SnPost
/// with the given fields replaced by the non-null parameter values. /// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false) @JsonKey(includeFromJson: false, includeToJson: false)
@@ -28,16 +28,16 @@ $SnPostCopyWith<SnPost> get copyWith => _$SnPostCopyWithImpl<SnPost>(this as SnP
@override @override
bool operator ==(Object other) { 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) @JsonKey(includeFromJson: false, includeToJson: false)
@override @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 @override
String toString() { 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; factory $SnPostCopyWith(SnPost value, $Res Function(SnPost) _then) = _$SnPostCopyWithImpl;
@useResult @useResult
$Res call({ $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 /// @nodoc
@@ -65,7 +65,7 @@ class _$SnPostCopyWithImpl<$Res>
/// Create a copy of SnPost /// Create a copy of SnPost
/// with the given fields replaced by the non-null parameter values. /// 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( return _then(_self.copyWith(
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable 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 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?,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 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 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 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 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 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 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 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 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 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 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 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. /// with the given fields replaced by the non-null parameter values.
@override @override
@pragma('vm:prefer-inline') @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 { $SnPublisherCopyWith<$Res> get publisher {
return $SnPublisherCopyWith<$Res>(_self.publisher, (value) { 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) { switch (_that) {
case _SnPost() when $default != null: 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(); 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) { switch (_that) {
case _SnPost(): 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` /// 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) { switch (_that) {
case _SnPost() when $default != null: 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; return null;
} }
@@ -280,7 +295,7 @@ return $default(_that.id,_that.title,_that.description,_that.language,_that.edit
@JsonSerializable() @JsonSerializable()
class _SnPost implements SnPost { 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); factory _SnPost.fromJson(Map<String, dynamic> json) => _$SnPostFromJson(json);
@override final String id; @override final String id;
@@ -291,6 +306,7 @@ class _SnPost implements SnPost {
@override@JsonKey() final DateTime? publishedAt; @override@JsonKey() final DateTime? publishedAt;
@override@JsonKey() final int visibility; @override@JsonKey() final int visibility;
@override final String? content; @override final String? content;
@override final String? slug;
@override@JsonKey() final int type; @override@JsonKey() final int type;
final Map<String, dynamic>? _meta; final Map<String, dynamic>? _meta;
@override Map<String, dynamic>? get meta { @override Map<String, dynamic>? get meta {
@@ -312,6 +328,8 @@ class _SnPost implements SnPost {
@override final SnPost? repliedPost; @override final SnPost? repliedPost;
@override final String? forwardedPostId; @override final String? forwardedPostId;
@override final SnPost? forwardedPost; @override final SnPost? forwardedPost;
@override final String? realmId;
@override final SnRealm? realm;
final List<SnCloudFile> _attachments; final List<SnCloudFile> _attachments;
@override@JsonKey() List<SnCloudFile> get attachments { @override@JsonKey() List<SnCloudFile> get attachments {
if (_attachments is EqualUnmodifiableListView) return _attachments; if (_attachments is EqualUnmodifiableListView) return _attachments;
@@ -380,16 +398,16 @@ Map<String, dynamic> toJson() {
@override @override
bool operator ==(Object other) { 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) @JsonKey(includeFromJson: false, includeToJson: false)
@override @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 @override
String toString() { 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; factory _$SnPostCopyWith(_SnPost value, $Res Function(_SnPost) _then) = __$SnPostCopyWithImpl;
@override @useResult @override @useResult
$Res call({ $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 /// @nodoc
@@ -417,7 +435,7 @@ class __$SnPostCopyWithImpl<$Res>
/// Create a copy of SnPost /// Create a copy of SnPost
/// with the given fields replaced by the non-null parameter values. /// 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( return _then(_SnPost(
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable 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 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?,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 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 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 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 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 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 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 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 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 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 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 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. /// with the given fields replaced by the non-null parameter values.
@override @override
@pragma('vm:prefer-inline') @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 { $SnPublisherCopyWith<$Res> get publisher {
return $SnPublisherCopyWith<$Res>(_self.publisher, (value) { return $SnPublisherCopyWith<$Res>(_self.publisher, (value) {

View File

@@ -21,6 +21,7 @@ _SnPost _$SnPostFromJson(Map<String, dynamic> json) => _SnPost(
: DateTime.parse(json['published_at'] as String), : DateTime.parse(json['published_at'] as String),
visibility: (json['visibility'] as num?)?.toInt() ?? 0, visibility: (json['visibility'] as num?)?.toInt() ?? 0,
content: json['content'] as String?, content: json['content'] as String?,
slug: json['slug'] as String?,
type: (json['type'] as num?)?.toInt() ?? 0, type: (json['type'] as num?)?.toInt() ?? 0,
meta: json['meta'] as Map<String, dynamic>?, meta: json['meta'] as Map<String, dynamic>?,
viewsUnique: (json['views_unique'] as num?)?.toInt() ?? 0, viewsUnique: (json['views_unique'] as num?)?.toInt() ?? 0,
@@ -43,6 +44,11 @@ _SnPost _$SnPostFromJson(Map<String, dynamic> json) => _SnPost(
json['forwarded_post'] == null json['forwarded_post'] == null
? null ? null
: SnPost.fromJson(json['forwarded_post'] as Map<String, dynamic>), : 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: attachments:
(json['attachments'] as List<dynamic>?) (json['attachments'] as List<dynamic>?)
?.map((e) => SnCloudFile.fromJson(e as Map<String, 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(), 'published_at': instance.publishedAt?.toIso8601String(),
'visibility': instance.visibility, 'visibility': instance.visibility,
'content': instance.content, 'content': instance.content,
'slug': instance.slug,
'type': instance.type, 'type': instance.type,
'meta': instance.meta, 'meta': instance.meta,
'views_unique': instance.viewsUnique, 'views_unique': instance.viewsUnique,
@@ -108,6 +115,8 @@ Map<String, dynamic> _$SnPostToJson(_SnPost instance) => <String, dynamic>{
'replied_post': instance.repliedPost?.toJson(), 'replied_post': instance.repliedPost?.toJson(),
'forwarded_post_id': instance.forwardedPostId, 'forwarded_post_id': instance.forwardedPostId,
'forwarded_post': instance.forwardedPost?.toJson(), 'forwarded_post': instance.forwardedPost?.toJson(),
'realm_id': instance.realmId,
'realm': instance.realm?.toJson(),
'attachments': instance.attachments.map((e) => e.toJson()).toList(), 'attachments': instance.attachments.map((e) => e.toJson()).toList(),
'publisher': instance.publisher.toJson(), 'publisher': instance.publisher.toJson(),
'reactions_count': instance.reactionsCount, 'reactions_count': instance.reactionsCount,

View File

@@ -1,6 +1,6 @@
import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:island/models/file.dart'; import 'package:island/models/file.dart';
import 'package:island/models/user.dart'; import 'package:island/models/account.dart';
part 'publisher.freezed.dart'; part 'publisher.freezed.dart';
part 'publisher.g.dart'; part 'publisher.g.dart';

View File

@@ -1,6 +1,6 @@
import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:island/models/file.dart'; import 'package:island/models/file.dart';
import 'package:island/models/user.dart'; import 'package:island/models/account.dart';
part 'realm.freezed.dart'; part 'realm.freezed.dart';
part 'realm.g.dart'; part 'realm.g.dart';
@@ -40,6 +40,7 @@ sealed class SnRealmMember with _$SnRealmMember {
required DateTime createdAt, required DateTime createdAt,
required DateTime updatedAt, required DateTime updatedAt,
required DateTime? deletedAt, required DateTime? deletedAt,
required SnAccountStatus? status,
}) = _SnRealmMember; }) = _SnRealmMember;
factory SnRealmMember.fromJson(Map<String, dynamic> json) => factory SnRealmMember.fromJson(Map<String, dynamic> json) =>

View File

@@ -359,7 +359,7 @@ $SnCloudFileCopyWith<$Res>? get background {
/// @nodoc /// @nodoc
mixin _$SnRealmMember { mixin _$SnRealmMember {
String get realmId; SnRealm? get realm; String get accountId; SnAccount? get account; int get role; DateTime? get joinedAt; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; String get realmId; SnRealm? get realm; String get accountId; SnAccount? get account; int get role; DateTime? get joinedAt; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; SnAccountStatus? get status;
/// Create a copy of SnRealmMember /// Create a copy of SnRealmMember
/// with the given fields replaced by the non-null parameter values. /// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false) @JsonKey(includeFromJson: false, includeToJson: false)
@@ -372,16 +372,16 @@ $SnRealmMemberCopyWith<SnRealmMember> get copyWith => _$SnRealmMemberCopyWithImp
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnRealmMember&&(identical(other.realmId, realmId) || other.realmId == realmId)&&(identical(other.realm, realm) || other.realm == realm)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.account, account) || other.account == account)&&(identical(other.role, role) || other.role == role)&&(identical(other.joinedAt, joinedAt) || other.joinedAt == joinedAt)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)); return identical(this, other) || (other.runtimeType == runtimeType&&other is SnRealmMember&&(identical(other.realmId, realmId) || other.realmId == realmId)&&(identical(other.realm, realm) || other.realm == realm)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.account, account) || other.account == account)&&(identical(other.role, role) || other.role == role)&&(identical(other.joinedAt, joinedAt) || other.joinedAt == joinedAt)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.status, status) || other.status == status));
} }
@JsonKey(includeFromJson: false, includeToJson: false) @JsonKey(includeFromJson: false, includeToJson: false)
@override @override
int get hashCode => Object.hash(runtimeType,realmId,realm,accountId,account,role,joinedAt,createdAt,updatedAt,deletedAt); int get hashCode => Object.hash(runtimeType,realmId,realm,accountId,account,role,joinedAt,createdAt,updatedAt,deletedAt,status);
@override @override
String toString() { String toString() {
return 'SnRealmMember(realmId: $realmId, realm: $realm, accountId: $accountId, account: $account, role: $role, joinedAt: $joinedAt, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; return 'SnRealmMember(realmId: $realmId, realm: $realm, accountId: $accountId, account: $account, role: $role, joinedAt: $joinedAt, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, status: $status)';
} }
@@ -392,11 +392,11 @@ abstract mixin class $SnRealmMemberCopyWith<$Res> {
factory $SnRealmMemberCopyWith(SnRealmMember value, $Res Function(SnRealmMember) _then) = _$SnRealmMemberCopyWithImpl; factory $SnRealmMemberCopyWith(SnRealmMember value, $Res Function(SnRealmMember) _then) = _$SnRealmMemberCopyWithImpl;
@useResult @useResult
$Res call({ $Res call({
String realmId, SnRealm? realm, String accountId, SnAccount? account, int role, DateTime? joinedAt, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt String realmId, SnRealm? realm, String accountId, SnAccount? account, int role, DateTime? joinedAt, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, SnAccountStatus? status
}); });
$SnRealmCopyWith<$Res>? get realm;$SnAccountCopyWith<$Res>? get account; $SnRealmCopyWith<$Res>? get realm;$SnAccountCopyWith<$Res>? get account;$SnAccountStatusCopyWith<$Res>? get status;
} }
/// @nodoc /// @nodoc
@@ -409,7 +409,7 @@ class _$SnRealmMemberCopyWithImpl<$Res>
/// Create a copy of SnRealmMember /// Create a copy of SnRealmMember
/// with the given fields replaced by the non-null parameter values. /// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? realmId = null,Object? realm = freezed,Object? accountId = null,Object? account = freezed,Object? role = null,Object? joinedAt = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { @pragma('vm:prefer-inline') @override $Res call({Object? realmId = null,Object? realm = freezed,Object? accountId = null,Object? account = freezed,Object? role = null,Object? joinedAt = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,Object? status = freezed,}) {
return _then(_self.copyWith( return _then(_self.copyWith(
realmId: null == realmId ? _self.realmId : realmId // ignore: cast_nullable_to_non_nullable realmId: null == 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 String,realm: freezed == realm ? _self.realm : realm // ignore: cast_nullable_to_non_nullable
@@ -420,7 +420,8 @@ as int,joinedAt: freezed == joinedAt ? _self.joinedAt : joinedAt // ignore: cast
as DateTime?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable as DateTime?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable
as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable
as DateTime?, as DateTime?,status: freezed == status ? _self.status : status // ignore: cast_nullable_to_non_nullable
as SnAccountStatus?,
)); ));
} }
/// Create a copy of SnRealmMember /// Create a copy of SnRealmMember
@@ -447,6 +448,18 @@ $SnAccountCopyWith<$Res>? get account {
return $SnAccountCopyWith<$Res>(_self.account!, (value) { return $SnAccountCopyWith<$Res>(_self.account!, (value) {
return _then(_self.copyWith(account: value)); return _then(_self.copyWith(account: value));
}); });
}/// Create a copy of SnRealmMember
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$SnAccountStatusCopyWith<$Res>? get status {
if (_self.status == null) {
return null;
}
return $SnAccountStatusCopyWith<$Res>(_self.status!, (value) {
return _then(_self.copyWith(status: value));
});
} }
} }
@@ -526,10 +539,10 @@ return $default(_that);case _:
/// } /// }
/// ``` /// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String realmId, SnRealm? realm, String accountId, SnAccount? account, int role, DateTime? joinedAt, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,{required TResult orElse(),}) {final _that = this; @optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String realmId, SnRealm? realm, String accountId, SnAccount? account, int role, DateTime? joinedAt, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, SnAccountStatus? status)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) { switch (_that) {
case _SnRealmMember() when $default != null: case _SnRealmMember() when $default != null:
return $default(_that.realmId,_that.realm,_that.accountId,_that.account,_that.role,_that.joinedAt,_that.createdAt,_that.updatedAt,_that.deletedAt);case _: return $default(_that.realmId,_that.realm,_that.accountId,_that.account,_that.role,_that.joinedAt,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.status);case _:
return orElse(); return orElse();
} }
@@ -547,10 +560,10 @@ return $default(_that.realmId,_that.realm,_that.accountId,_that.account,_that.ro
/// } /// }
/// ``` /// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String realmId, SnRealm? realm, String accountId, SnAccount? account, int role, DateTime? joinedAt, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt) $default,) {final _that = this; @optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String realmId, SnRealm? realm, String accountId, SnAccount? account, int role, DateTime? joinedAt, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, SnAccountStatus? status) $default,) {final _that = this;
switch (_that) { switch (_that) {
case _SnRealmMember(): case _SnRealmMember():
return $default(_that.realmId,_that.realm,_that.accountId,_that.account,_that.role,_that.joinedAt,_that.createdAt,_that.updatedAt,_that.deletedAt);} return $default(_that.realmId,_that.realm,_that.accountId,_that.account,_that.role,_that.joinedAt,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.status);}
} }
/// A variant of `when` that fallback to returning `null` /// A variant of `when` that fallback to returning `null`
/// ///
@@ -564,10 +577,10 @@ return $default(_that.realmId,_that.realm,_that.accountId,_that.account,_that.ro
/// } /// }
/// ``` /// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String realmId, SnRealm? realm, String accountId, SnAccount? account, int role, DateTime? joinedAt, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,) {final _that = this; @optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String realmId, SnRealm? realm, String accountId, SnAccount? account, int role, DateTime? joinedAt, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, SnAccountStatus? status)? $default,) {final _that = this;
switch (_that) { switch (_that) {
case _SnRealmMember() when $default != null: case _SnRealmMember() when $default != null:
return $default(_that.realmId,_that.realm,_that.accountId,_that.account,_that.role,_that.joinedAt,_that.createdAt,_that.updatedAt,_that.deletedAt);case _: return $default(_that.realmId,_that.realm,_that.accountId,_that.account,_that.role,_that.joinedAt,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.status);case _:
return null; return null;
} }
@@ -579,7 +592,7 @@ return $default(_that.realmId,_that.realm,_that.accountId,_that.account,_that.ro
@JsonSerializable() @JsonSerializable()
class _SnRealmMember implements SnRealmMember { class _SnRealmMember implements SnRealmMember {
const _SnRealmMember({required this.realmId, required this.realm, required this.accountId, required this.account, required this.role, required this.joinedAt, required this.createdAt, required this.updatedAt, required this.deletedAt}); const _SnRealmMember({required this.realmId, required this.realm, required this.accountId, required this.account, required this.role, required this.joinedAt, required this.createdAt, required this.updatedAt, required this.deletedAt, required this.status});
factory _SnRealmMember.fromJson(Map<String, dynamic> json) => _$SnRealmMemberFromJson(json); factory _SnRealmMember.fromJson(Map<String, dynamic> json) => _$SnRealmMemberFromJson(json);
@override final String realmId; @override final String realmId;
@@ -591,6 +604,7 @@ class _SnRealmMember implements SnRealmMember {
@override final DateTime createdAt; @override final DateTime createdAt;
@override final DateTime updatedAt; @override final DateTime updatedAt;
@override final DateTime? deletedAt; @override final DateTime? deletedAt;
@override final SnAccountStatus? status;
/// Create a copy of SnRealmMember /// Create a copy of SnRealmMember
/// with the given fields replaced by the non-null parameter values. /// with the given fields replaced by the non-null parameter values.
@@ -605,16 +619,16 @@ Map<String, dynamic> toJson() {
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnRealmMember&&(identical(other.realmId, realmId) || other.realmId == realmId)&&(identical(other.realm, realm) || other.realm == realm)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.account, account) || other.account == account)&&(identical(other.role, role) || other.role == role)&&(identical(other.joinedAt, joinedAt) || other.joinedAt == joinedAt)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)); return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnRealmMember&&(identical(other.realmId, realmId) || other.realmId == realmId)&&(identical(other.realm, realm) || other.realm == realm)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.account, account) || other.account == account)&&(identical(other.role, role) || other.role == role)&&(identical(other.joinedAt, joinedAt) || other.joinedAt == joinedAt)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.status, status) || other.status == status));
} }
@JsonKey(includeFromJson: false, includeToJson: false) @JsonKey(includeFromJson: false, includeToJson: false)
@override @override
int get hashCode => Object.hash(runtimeType,realmId,realm,accountId,account,role,joinedAt,createdAt,updatedAt,deletedAt); int get hashCode => Object.hash(runtimeType,realmId,realm,accountId,account,role,joinedAt,createdAt,updatedAt,deletedAt,status);
@override @override
String toString() { String toString() {
return 'SnRealmMember(realmId: $realmId, realm: $realm, accountId: $accountId, account: $account, role: $role, joinedAt: $joinedAt, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)'; return 'SnRealmMember(realmId: $realmId, realm: $realm, accountId: $accountId, account: $account, role: $role, joinedAt: $joinedAt, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, status: $status)';
} }
@@ -625,11 +639,11 @@ abstract mixin class _$SnRealmMemberCopyWith<$Res> implements $SnRealmMemberCopy
factory _$SnRealmMemberCopyWith(_SnRealmMember value, $Res Function(_SnRealmMember) _then) = __$SnRealmMemberCopyWithImpl; factory _$SnRealmMemberCopyWith(_SnRealmMember value, $Res Function(_SnRealmMember) _then) = __$SnRealmMemberCopyWithImpl;
@override @useResult @override @useResult
$Res call({ $Res call({
String realmId, SnRealm? realm, String accountId, SnAccount? account, int role, DateTime? joinedAt, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt String realmId, SnRealm? realm, String accountId, SnAccount? account, int role, DateTime? joinedAt, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, SnAccountStatus? status
}); });
@override $SnRealmCopyWith<$Res>? get realm;@override $SnAccountCopyWith<$Res>? get account; @override $SnRealmCopyWith<$Res>? get realm;@override $SnAccountCopyWith<$Res>? get account;@override $SnAccountStatusCopyWith<$Res>? get status;
} }
/// @nodoc /// @nodoc
@@ -642,7 +656,7 @@ class __$SnRealmMemberCopyWithImpl<$Res>
/// Create a copy of SnRealmMember /// Create a copy of SnRealmMember
/// with the given fields replaced by the non-null parameter values. /// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? realmId = null,Object? realm = freezed,Object? accountId = null,Object? account = freezed,Object? role = null,Object? joinedAt = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) { @override @pragma('vm:prefer-inline') $Res call({Object? realmId = null,Object? realm = freezed,Object? accountId = null,Object? account = freezed,Object? role = null,Object? joinedAt = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,Object? status = freezed,}) {
return _then(_SnRealmMember( return _then(_SnRealmMember(
realmId: null == realmId ? _self.realmId : realmId // ignore: cast_nullable_to_non_nullable realmId: null == 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 String,realm: freezed == realm ? _self.realm : realm // ignore: cast_nullable_to_non_nullable
@@ -653,7 +667,8 @@ as int,joinedAt: freezed == joinedAt ? _self.joinedAt : joinedAt // ignore: cast
as DateTime?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable as DateTime?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable
as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable
as DateTime?, as DateTime?,status: freezed == status ? _self.status : status // ignore: cast_nullable_to_non_nullable
as SnAccountStatus?,
)); ));
} }
@@ -681,6 +696,18 @@ $SnAccountCopyWith<$Res>? get account {
return $SnAccountCopyWith<$Res>(_self.account!, (value) { return $SnAccountCopyWith<$Res>(_self.account!, (value) {
return _then(_self.copyWith(account: value)); return _then(_self.copyWith(account: value));
}); });
}/// Create a copy of SnRealmMember
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$SnAccountStatusCopyWith<$Res>? get status {
if (_self.status == null) {
return null;
}
return $SnAccountStatusCopyWith<$Res>(_self.status!, (value) {
return _then(_self.copyWith(status: value));
});
} }
} }

View File

@@ -75,6 +75,12 @@ _SnRealmMember _$SnRealmMemberFromJson(Map<String, dynamic> json) =>
json['deleted_at'] == null json['deleted_at'] == null
? null ? null
: DateTime.parse(json['deleted_at'] as String), : DateTime.parse(json['deleted_at'] as String),
status:
json['status'] == null
? null
: SnAccountStatus.fromJson(
json['status'] as Map<String, dynamic>,
),
); );
Map<String, dynamic> _$SnRealmMemberToJson(_SnRealmMember instance) => Map<String, dynamic> _$SnRealmMemberToJson(_SnRealmMember instance) =>
@@ -88,4 +94,5 @@ Map<String, dynamic> _$SnRealmMemberToJson(_SnRealmMember instance) =>
'created_at': instance.createdAt.toIso8601String(), 'created_at': instance.createdAt.toIso8601String(),
'updated_at': instance.updatedAt.toIso8601String(), 'updated_at': instance.updatedAt.toIso8601String(),
'deleted_at': instance.deletedAt?.toIso8601String(), 'deleted_at': instance.deletedAt?.toIso8601String(),
'status': instance.status?.toJson(),
}; };

View File

@@ -1,6 +1,6 @@
import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:island/models/user.dart'; import 'package:island/models/account.dart';
part 'relationship.freezed.dart'; part 'relationship.freezed.dart';
part 'relationship.g.dart'; part 'relationship.g.dart';

View File

@@ -1,5 +1,5 @@
import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:island/models/user.dart'; import 'package:island/models/account.dart';
part 'wallet.freezed.dart'; part 'wallet.freezed.dart';
part 'wallet.g.dart'; part 'wallet.g.dart';

View File

@@ -23,6 +23,8 @@ const kAppSoundEffects = 'app_sound_effects';
const kAppAprilFoolFeatures = 'app_april_fool_features'; const kAppAprilFoolFeatures = 'app_april_fool_features';
const kAppWindowSize = 'app_window_size'; const kAppWindowSize = 'app_window_size';
const kAppEnterToSend = 'app_enter_to_send'; 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 = { const Map<String, FilterQuality> kImageQualityLevel = {
'settingsImageQualityLowest': FilterQuality.none, 'settingsImageQualityLowest': FilterQuality.none,

View File

@@ -1,9 +1,14 @@
import 'dart:convert';
import 'dart:developer'; import 'dart:developer';
import 'package:dio/dio.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:firebase_analytics/firebase_analytics.dart'; import 'package:firebase_analytics/firebase_analytics.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_platform_alert/flutter_platform_alert.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/models/user.dart'; import 'package:island/models/account.dart';
import 'package:island/pods/config.dart'; import 'package:island/pods/config.dart';
import 'package:island/pods/network.dart'; import 'package:island/pods/network.dart';
@@ -13,6 +18,11 @@ class UserInfoNotifier extends StateNotifier<AsyncValue<SnAccount?>> {
UserInfoNotifier(this._ref) : super(const AsyncValue.data(null)); UserInfoNotifier(this._ref) : super(const AsyncValue.data(null));
Future<void> fetchUser() async { Future<void> fetchUser() async {
final token = _ref.watch(tokenProvider);
if (token == null) {
log('[UserInfo] No token found, not going to fetch...');
return;
}
try { try {
final client = _ref.read(apiClientProvider); final client = _ref.read(apiClientProvider);
final response = await client.get('/id/accounts/me'); final response = await client.get('/id/accounts/me');
@@ -20,6 +30,44 @@ class UserInfoNotifier extends StateNotifier<AsyncValue<SnAccount?>> {
state = AsyncValue.data(user); state = AsyncValue.data(user);
FirebaseAnalytics.instance.setUserId(id: user.id); FirebaseAnalytics.instance.setUserId(id: user.id);
} catch (error, stackTrace) { } catch (error, stackTrace) {
if (!kIsWeb) {
if (error is DioException) {
FlutterPlatformAlert.showCustomAlert(
windowTitle: 'failedToLoadUserInfo'.tr(),
text: [
(error.response?.statusCode == 401
? 'failedToLoadUserInfoUnauthorized'
: 'failedToLoadUserInfoNetwork')
.tr()
.trim(),
'${error.response!.statusCode}\n${error.response?.headers}',
jsonEncode(error.response?.data),
].join('\n\n'),
iconStyle: IconStyle.error,
neutralButtonTitle: 'retry'.tr(),
negativeButtonTitle: 'okay'.tr(),
).then((value) {
if (value == CustomButton.neutralButton) {
fetchUser();
}
});
}
FlutterPlatformAlert.showCustomAlert(
windowTitle: 'failedToLoadUserInfo'.tr(),
text:
[
'failedToLoadUserInfoNetwork'.tr(),
error.toString(),
].join('\n\n').trim(),
iconStyle: IconStyle.error,
neutralButtonTitle: 'retry'.tr(),
negativeButtonTitle: 'okay'.tr(),
).then((value) {
if (value == CustomButton.neutralButton) {
fetchUser();
}
});
}
log( log(
"[UserInfo] Failed to fetch user info...", "[UserInfo] Failed to fetch user info...",
name: 'UserInfoNotifier', name: 'UserInfoNotifier',

View File

@@ -1,6 +1,8 @@
import 'dart:io' show Platform;
import 'package:animations/animations.dart';
import 'package:firebase_analytics/firebase_analytics.dart'; import 'package:firebase_analytics/firebase_analytics.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/screens/about.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/wallet.dart';
import 'package:island/screens/account/relationship.dart'; import 'package:island/screens/account/relationship.dart';
import 'package:island/screens/account/profile.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/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/chat.dart';
import 'package:island/screens/chat/room.dart'; import 'package:island/screens/chat/room.dart';
import 'package:island/screens/chat/room_detail.dart'; import 'package:island/screens/chat/room_detail.dart';
@@ -56,13 +58,35 @@ final rootNavigatorKey = GlobalKey<NavigatorState>();
final _shellNavigatorKey = GlobalKey<NavigatorState>(); final _shellNavigatorKey = GlobalKey<NavigatorState>();
final _tabsShellKey = 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 // Provider for the router
final routerProvider = Provider<GoRouter>((ref) { final routerProvider = Provider<GoRouter>((ref) {
return GoRouter( return GoRouter(
navigatorKey: rootNavigatorKey, navigatorKey: rootNavigatorKey,
initialLocation: '/', initialLocation: '/',
observers: [ observers: [
FirebaseAnalyticsObserver(analytics: FirebaseAnalytics.instance), if (_supportsAnalytics)
FirebaseAnalyticsObserver(analytics: FirebaseAnalytics.instance),
], ],
routes: [ routes: [
ShellRoute( ShellRoute(
@@ -339,7 +363,12 @@ final routerProvider = Provider<GoRouter>((ref) {
GoRoute( GoRoute(
name: 'explore', name: 'explore',
path: '/', path: '/',
builder: (context, state) => const ExploreScreen(), pageBuilder:
(context, state) => CustomTransitionPage(
key: const ValueKey('explore'),
child: const ExploreScreen(),
transitionsBuilder: _tabPagesTransitionBuilder,
),
), ),
GoRoute( GoRoute(
name: 'postSearch', name: 'postSearch',
@@ -389,8 +418,12 @@ final routerProvider = Provider<GoRouter>((ref) {
// Chat tab // Chat tab
ShellRoute( ShellRoute(
builder: pageBuilder:
(context, state, child) => ChatShellScreen(child: child), (context, state, child) => CustomTransitionPage(
key: const ValueKey('chat'),
child: ChatShellScreen(child: child),
transitionsBuilder: _tabPagesTransitionBuilder,
),
routes: [ routes: [
GoRoute( GoRoute(
name: 'chatList', name: 'chatList',
@@ -433,7 +466,12 @@ final routerProvider = Provider<GoRouter>((ref) {
GoRoute( GoRoute(
name: 'realmList', name: 'realmList',
path: '/realms', path: '/realms',
builder: (context, state) => const RealmListScreen(), pageBuilder:
(context, state) => CustomTransitionPage(
key: const ValueKey('realms'),
child: const RealmListScreen(),
transitionsBuilder: _tabPagesTransitionBuilder,
),
routes: [ routes: [
GoRoute( GoRoute(
name: 'realmNew', name: 'realmNew',
@@ -461,8 +499,12 @@ final routerProvider = Provider<GoRouter>((ref) {
// Account tab // Account tab
ShellRoute( ShellRoute(
builder: pageBuilder:
(context, state, child) => AccountShellScreen(child: child), (context, state, child) => CustomTransitionPage(
key: const ValueKey('account'),
child: AccountShellScreen(child: child),
transitionsBuilder: _tabPagesTransitionBuilder,
),
routes: [ routes: [
GoRoute( GoRoute(
name: 'account', name: 'account',

View File

@@ -178,7 +178,8 @@ class _AboutScreenState extends ConsumerState<AboutScreen> {
context, context,
icon: Symbols.label, icon: Symbols.label,
label: 'aboutDeviceName'.tr(), label: 'aboutDeviceName'.tr(),
value: _deviceInfo?.data['name'], value:
_deviceInfo?.data['name'] ?? 'unknown'.tr(),
), ),
_buildInfoItem( _buildInfoItem(
context, context,

View File

@@ -3,12 +3,14 @@ import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:gap/gap.dart'; import 'package:gap/gap.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/pods/network.dart';
import 'package:island/pods/userinfo.dart'; import 'package:island/pods/userinfo.dart';
import 'package:island/screens/notification.dart'; import 'package:island/screens/notification.dart';
import 'package:island/services/responsive.dart'; import 'package:island/services/responsive.dart';
import 'package:island/widgets/account/account_name.dart'; import 'package:island/widgets/account/account_name.dart';
import 'package:island/widgets/account/status.dart'; import 'package:island/widgets/account/status.dart';
import 'package:island/widgets/account/leveling_progress.dart'; import 'package:island/widgets/account/leveling_progress.dart';
import 'package:island/widgets/alert.dart';
import 'package:island/widgets/app_scaffold.dart'; import 'package:island/widgets/app_scaffold.dart';
import 'package:island/widgets/content/cloud_files.dart'; import 'package:island/widgets/content/cloud_files.dart';
import 'package:island/widgets/debug_sheet.dart'; import 'package:island/widgets/debug_sheet.dart';
@@ -303,7 +305,12 @@ class AccountScreen extends HookConsumerWidget {
trailing: const Icon(Symbols.chevron_right), trailing: const Icon(Symbols.chevron_right),
contentPadding: EdgeInsets.symmetric(horizontal: 24), contentPadding: EdgeInsets.symmetric(horizontal: 24),
title: Text('logout').tr(), title: Text('logout').tr(),
onTap: () { onTap: () async {
final apiClient = ref.watch(apiClientProvider);
showLoadingModal(context);
await apiClient.delete('/id/accounts/me/sessions/current');
if (!context.mounted) return;
hideLoadingModal(context);
final userNotifier = ref.read(userInfoProvider.notifier); final userNotifier = ref.read(userInfoProvider.notifier);
userNotifier.logOut(); userNotifier.logOut();
}, },

View File

@@ -6,7 +6,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/models/auth.dart'; import 'package:island/models/auth.dart';
import 'package:island/models/user.dart'; import 'package:island/models/account.dart';
import 'package:island/pods/network.dart'; import 'package:island/pods/network.dart';
import 'package:island/pods/userinfo.dart'; import 'package:island/pods/userinfo.dart';
import 'package:island/screens/account/me/settings_auth_factors.dart'; import 'package:island/screens/account/me/settings_auth_factors.dart';
@@ -15,7 +15,7 @@ import 'package:island/screens/account/me/settings_contacts.dart';
import 'package:island/screens/auth/captcha.dart'; import 'package:island/screens/auth/captcha.dart';
import 'package:island/screens/auth/login.dart'; import 'package:island/screens/auth/login.dart';
import 'package:island/services/responsive.dart'; import 'package:island/services/responsive.dart';
import 'package:island/widgets/account/account_session_sheet.dart'; import 'package:island/widgets/account/account_devices.dart';
import 'package:island/widgets/alert.dart'; import 'package:island/widgets/alert.dart';
import 'package:island/widgets/app_scaffold.dart'; import 'package:island/widgets/app_scaffold.dart';
import 'package:island/widgets/response.dart'; import 'package:island/widgets/response.dart';
@@ -23,7 +23,7 @@ import 'package:material_symbols_icons/symbols.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:styled_widget/styled_widget.dart'; import 'package:styled_widget/styled_widget.dart';
part 'settings.g.dart'; part 'account_settings.g.dart';
@riverpod @riverpod
Future<List<SnAuthFactor>> authFactors(Ref ref) async { Future<List<SnAuthFactor>> authFactors(Ref ref) async {

View File

@@ -1,6 +1,6 @@
// GENERATED CODE - DO NOT MODIFY BY HAND // GENERATED CODE - DO NOT MODIFY BY HAND
part of 'settings.dart'; part of 'account_settings.dart';
// ************************************************************************** // **************************************************************************
// RiverpodGenerator // RiverpodGenerator

View File

@@ -1,3 +1,4 @@
import 'package:collection/collection.dart';
import 'package:croppy/croppy.dart' hide cropImage; import 'package:croppy/croppy.dart' hide cropImage;
import 'package:dropdown_button2/dropdown_button2.dart'; import 'package:dropdown_button2/dropdown_button2.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
@@ -7,7 +8,7 @@ import 'package:gap/gap.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:image_picker/image_picker.dart'; import 'package:image_picker/image_picker.dart';
import 'package:island/models/file.dart'; import 'package:island/models/file.dart';
import 'package:island/models/user.dart'; import 'package:island/models/account.dart';
import 'package:island/pods/config.dart'; import 'package:island/pods/config.dart';
import 'package:island/pods/network.dart'; import 'package:island/pods/network.dart';
import 'package:island/pods/userinfo.dart'; import 'package:island/pods/userinfo.dart';
@@ -168,11 +169,18 @@ class UpdateProfileScreen extends HookConsumerWidget {
'location': locationController.text, 'location': locationController.text,
'time_zone': timeZoneController.text, 'time_zone': timeZoneController.text,
'birthday': birthday.value?.toUtc().toIso8601String(), '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); final userNotifier = ref.read(userInfoProvider.notifier);
userNotifier.fetchUser(); userNotifier.fetchUser();
links.value =
links.value
.where((e) => e.name.isNotEmpty && e.url.isNotEmpty)
.toList();
} catch (err) { } catch (err) {
showErrorAlert(err); showErrorAlert(err);
} finally { } finally {
@@ -568,6 +576,7 @@ class UpdateProfileScreen extends HookConsumerWidget {
children: [ children: [
for (var i = 0; i < links.value.length; i++) for (var i = 0; i < links.value.length; i++)
Row( Row(
key: ValueKey(links.value[i].hashCode),
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
children: [ children: [
Expanded( Expanded(
@@ -610,8 +619,10 @@ class UpdateProfileScreen extends HookConsumerWidget {
IconButton( IconButton(
icon: const Icon(Symbols.delete), icon: const Icon(Symbols.delete),
onPressed: () { onPressed: () {
links.value = List.from(links.value) links.value =
..removeAt(i); links.value
.whereIndexed((idx, _) => idx != i)
.toList();
}, },
), ),
], ],

View File

@@ -6,7 +6,7 @@ import 'package:gap/gap.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/models/auth.dart'; import 'package:island/models/auth.dart';
import 'package:island/pods/network.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/screens/auth/oidc.native.dart';
import 'package:island/services/text.dart'; import 'package:island/services/text.dart';
import 'package:island/services/time.dart'; import 'package:island/services/time.dart';

View File

@@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:gap/gap.dart'; import 'package:gap/gap.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/models/user.dart'; import 'package:island/models/account.dart';
import 'package:island/pods/network.dart'; import 'package:island/pods/network.dart';
import 'package:island/widgets/alert.dart'; import 'package:island/widgets/alert.dart';
import 'package:island/widgets/content/sheet.dart'; import 'package:island/widgets/content/sheet.dart';

View File

@@ -8,7 +8,7 @@ import 'package:gap/gap.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/models/chat.dart'; import 'package:island/models/chat.dart';
import 'package:island/models/relationship.dart'; import 'package:island/models/relationship.dart';
import 'package:island/models/user.dart'; import 'package:island/models/account.dart';
import 'package:island/pods/config.dart'; import 'package:island/pods/config.dart';
import 'package:island/pods/event_calendar.dart'; import 'package:island/pods/event_calendar.dart';
import 'package:island/pods/network.dart'; import 'package:island/pods/network.dart';

View File

@@ -6,7 +6,7 @@ import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:gap/gap.dart'; import 'package:gap/gap.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/pods/network.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/alert.dart';
import 'package:island/widgets/app_scaffold.dart'; import 'package:island/widgets/app_scaffold.dart';
import 'package:material_symbols_icons/symbols.dart'; import 'package:material_symbols_icons/symbols.dart';

View File

@@ -42,6 +42,22 @@ final Map<int, (String, String, IconData)> kFactorTypes = {
4: ('authFactorPin', 'authFactorPinDescription', Symbols.nest_secure_alarm), 4: ('authFactorPin', 'authFactorPinDescription', Symbols.nest_secure_alarm),
}; };
Future<String?> getDeviceName() async {
if (kIsWeb) return null;
String? name;
if (Platform.isIOS) {
final deviceInfo = await DeviceInfoPlugin().iosInfo;
name = deviceInfo.name;
} else if (Platform.isAndroid) {
final deviceInfo = await DeviceInfoPlugin().androidInfo;
name = deviceInfo.name;
} else if (Platform.isWindows) {
final deviceInfo = await DeviceInfoPlugin().windowsInfo;
name = deviceInfo.computerName;
}
return name;
}
class LoginScreen extends HookConsumerWidget { class LoginScreen extends HookConsumerWidget {
const LoginScreen({super.key}); const LoginScreen({super.key});
@@ -198,28 +214,6 @@ class _LoginCheckScreen extends HookConsumerWidget {
wsNotifier.connect(); wsNotifier.connect();
if (context.mounted) Navigator.pop(context, true); if (context.mounted) Navigator.pop(context, true);
}); });
// Update the sessions' device name is available
if (!kIsWeb) {
String? name;
if (Platform.isIOS) {
final deviceInfo = await DeviceInfoPlugin().iosInfo;
name = deviceInfo.name;
} else if (Platform.isAndroid) {
final deviceInfo = await DeviceInfoPlugin().androidInfo;
name = deviceInfo.name;
} else if (Platform.isWindows) {
final deviceInfo = await DeviceInfoPlugin().windowsInfo;
name = deviceInfo.computerName;
}
if (name != null) {
final client = ref.watch(apiClientProvider);
await client.patch(
'/id/accounts/me/sessions/current/label',
data: jsonEncode(name),
);
}
}
} }
useEffect(() { useEffect(() {
@@ -578,6 +572,7 @@ class _LoginLookupScreen extends HookConsumerWidget {
data: { data: {
'account': uname, 'account': uname,
'device_id': await getUdid(), 'device_id': await getUdid(),
'device_name': await getDeviceName(),
'platform': 'platform':
kIsWeb kIsWeb
? 1 ? 1
@@ -628,6 +623,7 @@ class _LoginLookupScreen extends HookConsumerWidget {
'identity_token': credential.identityToken!, 'identity_token': credential.identityToken!,
'authorization_code': credential.authorizationCode, 'authorization_code': credential.authorizationCode,
'device_id': await getUdid(), 'device_id': await getUdid(),
'device_name': await getDeviceName(),
}, },
); );

View File

@@ -23,7 +23,7 @@ import 'package:island/widgets/alert.dart';
import 'package:island/widgets/app_scaffold.dart'; import 'package:island/widgets/app_scaffold.dart';
import 'package:island/widgets/content/cloud_files.dart'; import 'package:island/widgets/content/cloud_files.dart';
import 'package:island/widgets/content/sheet.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/widgets/response.dart';
import 'package:island/screens/tabs.dart'; import 'package:island/screens/tabs.dart';
import 'package:material_symbols_icons/symbols.dart'; import 'package:material_symbols_icons/symbols.dart';
@@ -80,10 +80,12 @@ class ChatRoomListTile extends HookConsumerWidget {
), ),
), ),
Row( Row(
spacing: 4,
children: [ children: [
Text( Badge(
'${data.lastMessage.sender.account.name}: ', label: Text(data.lastMessage.sender.account.nick),
style: Theme.of(context).textTheme.bodySmall, textColor: Theme.of(context).colorScheme.onPrimary,
backgroundColor: Theme.of(context).colorScheme.primary,
), ),
Expanded( Expanded(
child: Text( child: Text(

File diff suppressed because it is too large Load Diff

View File

@@ -6,7 +6,7 @@ part of 'room.dart';
// RiverpodGenerator // RiverpodGenerator
// ************************************************************************** // **************************************************************************
String _$messagesNotifierHash() => r'afc4d43f4948ec571118cef0321838a6cefc89c0'; String _$messagesNotifierHash() => r'32afe6ea24086d869cc47bd3389c8fd734409ca0';
/// Copied from Dart SDK /// Copied from Dart SDK
class _SystemHash { class _SystemHash {

View File

@@ -10,6 +10,7 @@ import 'package:island/models/chat.dart';
import 'package:island/pods/network.dart'; import 'package:island/pods/network.dart';
import 'package:island/screens/chat/chat.dart'; import 'package:island/screens/chat/chat.dart';
import 'package:island/widgets/account/account_picker.dart'; import 'package:island/widgets/account/account_picker.dart';
import 'package:island/widgets/account/status.dart';
import 'package:island/widgets/alert.dart'; import 'package:island/widgets/alert.dart';
import 'package:island/widgets/app_scaffold.dart'; import 'package:island/widgets/app_scaffold.dart';
import 'package:island/widgets/content/cloud_files.dart'; import 'package:island/widgets/content/cloud_files.dart';
@@ -544,7 +545,7 @@ class ChatMemberListNotifier extends _$ChatMemberListNotifier
final apiClient = ref.watch(apiClientProvider); final apiClient = ref.watch(apiClientProvider);
final response = await apiClient.get( final response = await apiClient.get(
'/sphere/chat/$roomId/members', '/sphere/chat/$roomId/members',
queryParameters: {'offset': offset, 'take': take}, queryParameters: {'offset': offset, 'take': take, 'withStatus': true},
); );
final total = int.parse(response.headers.value('X-Total') ?? '0'); final total = int.parse(response.headers.value('X-Total') ?? '0');
@@ -672,6 +673,8 @@ class _ChatMemberListSheet extends HookConsumerWidget {
spacing: 6, spacing: 6,
children: [ children: [
Flexible(child: Text(member.account.nick)), Flexible(child: Text(member.account.nick)),
if (member.status != null)
AccountStatusLabel(status: member.status!),
if (member.joinedAt == null) if (member.joinedAt == null)
const Icon(Symbols.pending_actions, size: 20), const Icon(Symbols.pending_actions, size: 20),
], ],

View File

@@ -212,30 +212,6 @@ class CreatorHubScreen extends HookConsumerWidget {
leading: !isWide ? const PageBackButton() : null, leading: !isWide ? const PageBackButton() : null,
title: Text('creatorHub').tr(), title: Text('creatorHub').tr(),
actions: [ actions: [
IconButton(
icon: Badge(
label: Text(
publisherInvites.when(
data: (invites) => invites.length.toString(),
error: (_, _) => '0',
loading: () => '0',
),
),
isLabelVisible: publisherInvites.when(
data: (invites) => invites.isNotEmpty,
error: (_, _) => false,
loading: () => false,
),
child: const Icon(Symbols.email),
),
onPressed: () {
showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (_) => const _PublisherInviteSheet(),
);
},
),
DropdownButtonHideUnderline( DropdownButtonHideUnderline(
child: DropdownButton2<SnPublisher>( child: DropdownButton2<SnPublisher>(
alignment: Alignment.centerRight, alignment: Alignment.centerRight,
@@ -323,6 +299,23 @@ class CreatorHubScreen extends HookConsumerWidget {
), ),
) ?? ) ??
[]), []),
ListTile(
leading: const CircleAvatar(
child: Icon(Symbols.mail),
),
title: Text('publisherCollabInvitation').tr(),
subtitle: Text(
'publisherCollabInvitationCount',
).plural(publisherInvites.value?.length ?? 0),
trailing: const Icon(Symbols.chevron_right),
onTap: () {
showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (_) => const _PublisherInviteSheet(),
);
},
),
ListTile( ListTile(
leading: const CircleAvatar( leading: const CircleAvatar(
child: Icon(Symbols.add), child: Icon(Symbols.add),

View File

@@ -19,7 +19,7 @@ import 'package:island/services/responsive.dart';
import 'package:island/widgets/alert.dart'; import 'package:island/widgets/alert.dart';
import 'package:island/widgets/app_scaffold.dart'; import 'package:island/widgets/app_scaffold.dart';
import 'package:island/widgets/content/cloud_files.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:material_symbols_icons/symbols.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:styled_widget/styled_widget.dart'; import 'package:styled_widget/styled_widget.dart';

View File

@@ -11,6 +11,7 @@ import 'package:island/models/realm.dart';
import 'package:island/models/webfeed.dart'; import 'package:island/models/webfeed.dart';
import 'package:island/pods/event_calendar.dart'; import 'package:island/pods/event_calendar.dart';
import 'package:island/pods/userinfo.dart'; import 'package:island/pods/userinfo.dart';
import 'package:island/screens/notification.dart';
import 'package:island/services/responsive.dart'; import 'package:island/services/responsive.dart';
import 'package:island/widgets/account/fortune_graph.dart'; import 'package:island/widgets/account/fortune_graph.dart';
import 'package:island/widgets/app_scaffold.dart'; import 'package:island/widgets/app_scaffold.dart';
@@ -30,6 +31,33 @@ import 'package:styled_widget/styled_widget.dart';
part 'explore.g.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 { class ExploreScreen extends HookConsumerWidget {
const ExploreScreen({super.key}); const ExploreScreen({super.key});
@@ -77,6 +105,10 @@ class ExploreScreen extends HookConsumerWidget {
final user = ref.watch(userInfoProvider); final user = ref.watch(userInfoProvider);
final notificationCount = ref.watch(
notificationUnreadCountNotifierProvider,
);
return AppScaffold( return AppScaffold(
isNoBackground: false, isNoBackground: false,
appBar: AppBar( appBar: AppBar(
@@ -185,7 +217,7 @@ class ExploreScreen extends HookConsumerWidget {
floatingActionButtonLocation: TabbedFabLocation(context), floatingActionButtonLocation: TabbedFabLocation(context),
body: Builder( body: Builder(
builder: (context) { builder: (context) {
final isWider = isWiderScreen(context); final isWide = isWideScreen(context);
final bodyView = _buildActivityList( final bodyView = _buildActivityList(
context, context,
@@ -193,40 +225,58 @@ class ExploreScreen extends HookConsumerWidget {
currentFilter.value, currentFilter.value,
); );
if (isWider) { if (isWide) {
return Row( return Row(
children: [ children: [
Flexible(flex: 3, child: bodyView.padding(left: 8)), Flexible(flex: 3, child: bodyView.padding(left: 8)),
if (user.value != null) if (user.value != null)
Flexible( Flexible(
flex: 2, flex: 2,
child: SingleChildScrollView( child: Align(
child: Column( alignment: Alignment.topCenter,
children: [ child: SingleChildScrollView(
CheckInWidget( child: Column(
margin: EdgeInsets.only( children: [
CheckInWidget(
margin: EdgeInsets.only(
left: 8,
right: 12,
top: 16,
),
onChecked: () {
ref.invalidate(
eventCalendarProvider(query.value),
);
},
),
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, left: 8,
right: 12, right: 12,
top: 16, top: 8,
), ),
onChecked: () { FortuneGraphWidget(
ref.invalidate( margin: EdgeInsets.only(
eventCalendarProvider(query.value), left: 8,
); right: 12,
}, top: 8,
), ),
PostFeaturedList().padding( events: events,
left: 8, constrainWidth: true,
right: 12, onPointSelected: onDaySelected,
top: 8, ),
), ],
FortuneGraphWidget( ),
margin: EdgeInsets.only(left: 8, right: 12, top: 8),
events: events,
constrainWidth: true,
onPointSelected: onDaySelected,
),
],
), ),
), ),
) )
@@ -268,7 +318,7 @@ class ExploreScreen extends HookConsumerWidget {
activityListNotifierProvider(filter).notifier, activityListNotifierProvider(filter).notifier,
); );
final isWider = isWiderScreen(context); final isWide = isWideScreen(context);
return RefreshIndicator( return RefreshIndicator(
onRefresh: () => Future.sync(activitiesNotifier.forceRefresh), onRefresh: () => Future.sync(activitiesNotifier.forceRefresh),
@@ -283,7 +333,7 @@ class ExploreScreen extends HookConsumerWidget {
widgetCount: widgetCount, widgetCount: widgetCount,
endItemView: endItemView, endItemView: endItemView,
activitiesNotifier: activitiesNotifier, activitiesNotifier: activitiesNotifier,
contentOnly: isWider || filter != null, contentOnly: isWide || filter != null,
), ),
), ),
), ),
@@ -380,6 +430,10 @@ class _ActivityListView extends HookConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final user = ref.watch(userInfoProvider); final user = ref.watch(userInfoProvider);
final notificationCount = ref.watch(
notificationUnreadCountNotifierProvider,
);
return CustomScrollView( return CustomScrollView(
slivers: [ slivers: [
SliverGap(12), SliverGap(12),
@@ -393,6 +447,14 @@ class _ActivityListView extends HookConsumerWidget {
SliverToBoxAdapter( SliverToBoxAdapter(
child: PostFeaturedList().padding(horizontal: 8, bottom: 4, top: 4), child: PostFeaturedList().padding(horizontal: 8, bottom: 4, top: 4),
), ),
if (!contentOnly && (notificationCount.value ?? 0) > 0)
SliverToBoxAdapter(
child: notificationIndicatorWidget(
context,
count: notificationCount.value ?? 0,
margin: EdgeInsets.only(left: 8, right: 8, top: 4, bottom: 4),
),
),
SliverList.builder( SliverList.builder(
itemCount: widgetCount, itemCount: widgetCount,
itemBuilder: (context, index) { itemBuilder: (context, index) {

View File

@@ -3,14 +3,17 @@ import 'dart:math' as math;
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/models/user.dart'; import 'package:island/models/account.dart';
import 'package:island/pods/network.dart'; import 'package:island/pods/network.dart';
import 'package:island/pods/websocket.dart'; import 'package:island/pods/websocket.dart';
import 'package:island/route.dart'; import 'package:island/route.dart';
import 'package:island/widgets/alert.dart';
import 'package:island/widgets/app_scaffold.dart'; import 'package:island/widgets/app_scaffold.dart';
import 'package:island/widgets/content/markdown.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:relative_time/relative_time.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:riverpod_paging_utils/riverpod_paging_utils.dart'; import 'package:riverpod_paging_utils/riverpod_paging_utils.dart';
@@ -62,6 +65,10 @@ class NotificationUnreadCountNotifier
final current = await future; final current = await future;
state = AsyncData(math.max(current - count, 0)); state = AsyncData(math.max(current - count, 0));
} }
void clear() async {
state = AsyncData(0);
}
} }
@riverpod @riverpod
@@ -111,8 +118,28 @@ class NotificationScreen extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { 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( return AppScaffold(
appBar: AppBar(title: const Text('notifications').tr()), appBar: AppBar(
leading: const PageBackButton(),
title: const Text('notifications').tr(),
actions: [
IconButton(
onPressed: markAllRead,
icon: const Icon(Symbols.mark_as_unread),
),
const Gap(8),
],
),
body: PagingHelperView( body: PagingHelperView(
provider: notificationListNotifierProvider, provider: notificationListNotifierProvider,
futureRefreshable: notificationListNotifierProvider.future, futureRefreshable: notificationListNotifierProvider.future,

View File

@@ -7,7 +7,7 @@ part of 'notification.dart';
// ************************************************************************** // **************************************************************************
String _$notificationUnreadCountNotifierHash() => String _$notificationUnreadCountNotifierHash() =>
r'd199abf0d16944587e747798399a267a790341f3'; r'0763b66bd64e5a9b7c317887e109ab367515dfa4';
/// See also [NotificationUnreadCountNotifier]. /// See also [NotificationUnreadCountNotifier].
@ProviderFor(NotificationUnreadCountNotifier) @ProviderFor(NotificationUnreadCountNotifier)

View File

@@ -89,6 +89,9 @@ class ArticleComposeScreen extends HookConsumerWidget {
}, [state]); }, [state]);
final showPreview = useState(false); final showPreview = useState(false);
final isAttachmentsExpanded = useState(
true,
); // New state for attachments section
// Initialize publisher once when data is available // Initialize publisher once when data is available
useEffect(() { useEffect(() {
@@ -297,71 +300,88 @@ class ArticleComposeScreen extends HookConsumerWidget {
valueListenable: state.attachments, valueListenable: state.attachments,
builder: (context, attachments, _) { builder: (context, attachments, _) {
if (attachments.isEmpty) return const SizedBox.shrink(); if (attachments.isEmpty) return const SizedBox.shrink();
return Column( return Theme(
crossAxisAlignment: CrossAxisAlignment.start, data: Theme.of(
children: [ context,
const Gap(16), ).copyWith(dividerColor: Colors.transparent),
Text( child: ExpansionTile(
'articleAttachmentHint'.tr(), initiallyExpanded: isAttachmentsExpanded.value,
style: Theme.of(context).textTheme.bodySmall?.copyWith( onExpansionChanged: (expanded) {
color: Theme.of(context).colorScheme.onSurfaceVariant, isAttachmentsExpanded.value = expanded;
), },
).padding(bottom: 8), collapsedBackgroundColor:
ValueListenableBuilder<Map<int, double>>( Theme.of(context).colorScheme.surfaceContainer,
valueListenable: state.attachmentProgress, title: Column(
builder: (context, progressMap, _) { crossAxisAlignment: CrossAxisAlignment.start,
return Wrap( children: [
spacing: 8, Text('attachments').tr(),
runSpacing: 8, Text(
children: [ 'articleAttachmentHint'.tr(),
for (var idx = 0; idx < attachments.length; idx++) style: Theme.of(
SizedBox( context,
width: 280, ).textTheme.bodySmall?.copyWith(
height: 280, color:
child: AttachmentPreview( Theme.of(
item: attachments[idx], context,
progress: progressMap[idx], ).colorScheme.onSurfaceVariant,
onRequestUpload: ),
() => ComposeLogic.uploadAttachment( ),
ref, ],
state,
idx,
),
onUpdate:
(value) =>
ComposeLogic.updateAttachment(
state,
value,
idx,
),
onDelete:
() => ComposeLogic.deleteAttachment(
ref,
state,
idx,
),
onMove: (delta) {
state
.attachments
.value = ComposeLogic.moveAttachment(
state.attachments.value,
idx,
delta,
);
},
onInsert:
() => ComposeLogic.insertAttachment(
ref,
state,
idx,
),
),
),
],
);
},
), ),
], children: [
ValueListenableBuilder<Map<int, double>>(
valueListenable: state.attachmentProgress,
builder: (context, progressMap, _) {
return Wrap(
runSpacing: 8,
spacing: 8,
children: [
for (
var idx = 0;
idx < attachments.length;
idx++
)
SizedBox(
width: 180,
height: 180,
child: AttachmentPreview(
isCompact: true,
item: attachments[idx],
progress: progressMap[idx],
onRequestUpload:
() => ComposeLogic.uploadAttachment(
ref,
state,
idx,
),
onUpdate:
(value) =>
ComposeLogic.updateAttachment(
state,
value,
idx,
),
onDelete:
() => ComposeLogic.deleteAttachment(
ref,
state,
idx,
),
onInsert:
() => ComposeLogic.insertAttachment(
ref,
state,
idx,
),
),
),
],
);
},
),
Gap(16),
],
),
); );
}, },
), ),

View File

@@ -51,12 +51,12 @@ class PostSearchNotifier
final offset = cursor == null ? 0 : int.parse(cursor); final offset = cursor == null ? 0 : int.parse(cursor);
final response = await client.get( final response = await client.get(
'/sphere/posts/search', '/sphere/posts',
queryParameters: { queryParameters: {
'query': _currentQuery, 'query': _currentQuery,
'offset': offset, 'offset': offset,
'take': _pageSize, 'take': _pageSize,
'useVector': false, 'vector': false,
}, },
); );

View File

@@ -7,7 +7,7 @@ import 'package:gap/gap.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/models/post.dart'; import 'package:island/models/post.dart';
import 'package:island/models/publisher.dart'; import 'package:island/models/publisher.dart';
import 'package:island/models/user.dart'; import 'package:island/models/account.dart';
import 'package:island/pods/config.dart'; import 'package:island/pods/config.dart';
import 'package:island/pods/network.dart'; import 'package:island/pods/network.dart';
import 'package:island/services/color.dart'; import 'package:island/services/color.dart';
@@ -147,7 +147,11 @@ class PublisherProfileScreen extends HookConsumerWidget {
), ),
backgroundColor: Theme.of(context).colorScheme.primary, backgroundColor: Theme.of(context).colorScheme.primary,
offset: Offset(0, 48), 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: () { onTap: () {
Navigator.pop(context, true); Navigator.pop(context, true);

View File

@@ -4,6 +4,9 @@ import 'package:island/screens/chat/chat.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:island/models/chat.dart'; import 'package:island/models/chat.dart';
import 'package:island/services/color.dart'; import 'package:island/services/color.dart';
import 'package:island/services/responsive.dart';
import 'package:island/widgets/account/status.dart';
import 'package:island/widgets/post/post_list.dart';
import 'package:palette_generator/palette_generator.dart'; import 'package:palette_generator/palette_generator.dart';
import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:gap/gap.dart'; import 'package:gap/gap.dart';
@@ -78,155 +81,287 @@ class RealmDetailScreen extends HookConsumerWidget {
offset: Offset(1.0, 1.0), offset: Offset(1.0, 1.0),
); );
final realmIdentity = ref.watch(realmIdentityProvider(slug));
final realmChatRooms = ref.watch(realmChatRoomsProvider(slug));
Widget realmDescriptionWidget(SnRealm realm) => Card(
margin: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
child: Theme(
data: Theme.of(context).copyWith(dividerColor: Colors.transparent),
child: ExpansionTile(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(8)),
),
collapsedShape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(8)),
),
title: const Text('description').tr(),
initiallyExpanded:
realmIdentity.hasValue && realmIdentity.value == null,
tilePadding: EdgeInsets.only(left: 24, right: 20),
expandedCrossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
realm.description,
style: const TextStyle(fontSize: 16),
).padding(horizontal: 20, bottom: 16, top: 8),
],
),
),
);
Widget realmActionWidget(SnRealm realm) => Card(
margin: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
child: FilledButton.tonalIcon(
onPressed: () async {
try {
final apiClient = ref.read(apiClientProvider);
await apiClient.post('/sphere/realms/$slug/members/me');
ref.invalidate(realmIdentityProvider(slug));
ref.invalidate(realmsJoinedProvider);
showSnackBar('realmJoinSuccess'.tr());
} catch (err) {
showErrorAlert(err);
}
},
icon: const Icon(Symbols.add),
label: const Text('realmJoin').tr(),
).padding(all: 16),
);
Widget realmChatRoomListWidget(SnRealm realm) => Card(
margin: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
'chatTabGroup',
).tr().bold().padding(horizontal: 24, top: 12, bottom: 4),
realmChatRooms.when(
loading: () => Center(child: CircularProgressIndicator()),
error: (error, _) => Center(child: Text('Error: $error')),
data: (rooms) {
if (rooms.isEmpty) {
return Text(
'dataEmpty',
).tr().padding(horizontal: 24, bottom: 12);
}
return Column(
children: [
for (final room in rooms)
ChatRoomListTile(
room: room,
onTap: () {
context.pushNamed(
'chatRoom',
pathParameters: {'id': room.id},
);
},
),
],
);
},
),
],
),
);
return AppScaffold( return AppScaffold(
isNoBackground: false, isNoBackground: false,
appBar:
isWideScreen(context)
? realmState.when(
data:
(realm) => AppBar(
foregroundColor: appbarColor.value,
leading: PageBackButton(
color: appbarColor.value,
shadows: [iconShadow],
),
flexibleSpace: Stack(
children: [
Positioned.fill(
child:
realm!.background?.id != null
? CloudImageWidget(
fileId: realm.background!.id,
)
: Container(
color:
Theme.of(
context,
).appBarTheme.backgroundColor,
),
),
FlexibleSpaceBar(
title: Text(
realm.name,
style: TextStyle(
color:
appbarColor.value ??
Theme.of(
context,
).appBarTheme.foregroundColor,
shadows: [iconShadow],
),
),
background: Container(),
),
],
),
actions: [
IconButton(
icon: Icon(Icons.people, shadows: [iconShadow]),
onPressed: () {
showModalBottomSheet(
isScrollControlled: true,
context: context,
builder:
(context) =>
_RealmMemberListSheet(realmSlug: slug),
);
},
),
_RealmActionMenu(
realmSlug: slug,
iconShadow: iconShadow,
),
const Gap(8),
],
),
error: (_, _) => AppBar(leading: PageBackButton()),
loading: () => AppBar(leading: PageBackButton()),
)
: null,
body: realmState.when( body: realmState.when(
loading: () => const Center(child: CircularProgressIndicator()), loading: () => const Center(child: CircularProgressIndicator()),
error: (error, _) => Center(child: Text('Error: $error')), error: (error, _) => Center(child: Text('Error: $error')),
data: data:
(realm) => CustomScrollView( (realm) =>
slivers: [ isWideScreen(context)
SliverAppBar( ? Row(
expandedHeight: 180, children: [
pinned: true, Flexible(
foregroundColor: appbarColor.value, flex: 3,
leading: PageBackButton( child: CustomScrollView(
color: appbarColor.value, slivers: [SliverPostList(realm: slug)],
shadows: [iconShadow], ),
), ),
flexibleSpace: FlexibleSpaceBar( Flexible(
background: flex: 2,
realm!.background?.id != null child: Column(
? CloudImageWidget(fileId: realm.background!.id) children: [
: Container( realmIdentity.when(
color: loading: () => const SizedBox.shrink(),
Theme.of(context).appBarTheme.backgroundColor, error: (_, _) => const SizedBox.shrink(),
), data:
title: Text( (identity) => Column(
realm.name, crossAxisAlignment:
style: TextStyle( CrossAxisAlignment.stretch,
color: children: [
appbarColor.value ?? realmDescriptionWidget(realm!),
Theme.of(context).appBarTheme.foregroundColor, if (identity == null &&
shadows: [iconShadow], realm.isCommunity)
), realmActionWidget(realm)
), else
), const SizedBox.shrink(),
actions: [ ],
IconButton(
icon: Icon(Icons.people, shadows: [iconShadow]),
onPressed: () {
showModalBottomSheet(
isScrollControlled: true,
context: context,
builder:
(context) =>
_RealmMemberListSheet(realmSlug: slug),
);
},
),
_RealmActionMenu(realmSlug: slug, iconShadow: iconShadow),
const Gap(8),
],
),
SliverToBoxAdapter(
child: ref
.watch(realmIdentityProvider(slug))
.when(
loading: () => const SizedBox.shrink(),
error: (_, _) => const SizedBox.shrink(),
data:
(identity) => Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
ExpansionTile(
title: const Text('description').tr(),
initiallyExpanded: identity == null,
tilePadding: EdgeInsets.symmetric(
horizontal: 20,
),
expandedCrossAxisAlignment:
CrossAxisAlignment.stretch,
children: [
Text(
realm.description,
style: const TextStyle(fontSize: 16),
).padding(
horizontal: 20,
bottom: 16,
top: 8,
), ),
], ),
realmChatRoomListWidget(realm!),
],
),
),
],
).padding(horizontal: 8, top: 8)
: CustomScrollView(
slivers: [
SliverAppBar(
expandedHeight: 180,
pinned: true,
foregroundColor: appbarColor.value,
leading: PageBackButton(
color: appbarColor.value,
shadows: [iconShadow],
),
flexibleSpace: Stack(
children: [
Positioned.fill(
child:
realm!.background?.id != null
? CloudImageWidget(
fileId: realm.background!.id,
)
: Container(
color:
Theme.of(
context,
).appBarTheme.backgroundColor,
),
),
FlexibleSpaceBar(
title: Text(
realm.name,
style: TextStyle(
color:
appbarColor.value ??
Theme.of(
context,
).appBarTheme.foregroundColor,
shadows: [iconShadow],
),
), ),
if (identity == null && realm.isCommunity) background:
FilledButton.tonalIcon( Container(), // Empty container since background is handled by Stack
onPressed: () async { ),
try { ],
final apiClient = ref.read(
apiClientProvider,
);
await apiClient.post(
'/sphere/realms/$slug/members/me',
);
ref.invalidate(
realmIdentityProvider(slug),
);
ref.invalidate(realmsJoinedProvider);
showSnackBar('realmJoinSuccess'.tr());
} catch (err) {
showErrorAlert(err);
}
},
icon: const Icon(Symbols.add),
label: const Text('realmJoin').tr(),
).padding(horizontal: 16, vertical: 16)
else
const SizedBox.shrink(),
],
),
),
),
const SliverToBoxAdapter(child: Divider(height: 1)),
Consumer(
builder: (context, ref, _) {
final chatRooms = ref.watch(realmChatRoomsProvider(slug));
return chatRooms.when(
loading:
() => const SliverToBoxAdapter(
child: Center(child: CircularProgressIndicator()),
), ),
error: actions: [
(error, _) => SliverToBoxAdapter( IconButton(
child: Center(child: Text('Error: $error')), icon: Icon(Icons.people, shadows: [iconShadow]),
), onPressed: () {
data: (rooms) { showModalBottomSheet(
if (rooms.isEmpty) { isScrollControlled: true,
return const SliverToBoxAdapter( context: context,
child: SizedBox.shrink(), builder:
); (context) => _RealmMemberListSheet(
} realmSlug: slug,
return SliverList( ),
delegate: SliverChildBuilderDelegate((
context,
index,
) {
return ChatRoomListTile(
room: rooms[index],
onTap: () {
context.pushNamed(
'chatRoom',
pathParameters: {'id': rooms[index].id},
); );
}, },
); ),
}, childCount: rooms.length), _RealmActionMenu(
); realmSlug: slug,
}, iconShadow: iconShadow,
); ),
}, const Gap(8),
), ],
], ),
), SliverGap(4),
SliverToBoxAdapter(
child: realmIdentity.when(
loading: () => const SizedBox.shrink(),
error: (_, _) => const SizedBox.shrink(),
data:
(identity) => Column(
crossAxisAlignment:
CrossAxisAlignment.stretch,
children: [
realmDescriptionWidget(realm),
if (identity == null && realm.isCommunity)
realmActionWidget(realm)
else
const SizedBox.shrink(),
],
),
),
),
SliverToBoxAdapter(
child: realmChatRoomListWidget(realm),
),
SliverPostList(realm: slug),
],
),
), ),
); );
} }
@@ -398,7 +533,11 @@ class RealmMemberListNotifier extends _$RealmMemberListNotifier
final response = await apiClient.get( final response = await apiClient.get(
'/sphere/realms/$realmSlug/members', '/sphere/realms/$realmSlug/members',
queryParameters: {'offset': offset, 'take': _pageSize}, queryParameters: {
'offset': offset,
'take': _pageSize,
'withStatus': true,
},
); );
final total = int.parse(response.headers.value('X-Total') ?? '0'); final total = int.parse(response.headers.value('X-Total') ?? '0');
@@ -441,7 +580,7 @@ class RealmMemberNotifier extends StateNotifier<RealmMemberState> {
try { try {
final response = await _apiClient.get( final response = await _apiClient.get(
'/sphere/realms/$realmSlug/members', '/sphere/realms/$realmSlug/members',
queryParameters: {'offset': offset, 'take': take}, queryParameters: {'offset': offset, 'take': take, 'withStatus': true},
); );
final total = int.parse(response.headers.value('X-Total') ?? '0'); final total = int.parse(response.headers.value('X-Total') ?? '0');
@@ -508,146 +647,154 @@ class _RealmMemberListSheet extends HookConsumerWidget {
} }
} }
Widget buildMemberListHeader() {
return Padding(
padding: EdgeInsets.only(top: 16, left: 20, right: 16, bottom: 12),
child: Row(
children: [
Text(
'members'.plural(memberState.total),
style: Theme.of(context).textTheme.headlineSmall?.copyWith(
fontWeight: FontWeight.w600,
letterSpacing: -0.5,
),
),
const Spacer(),
IconButton(
icon: const Icon(Symbols.person_add),
onPressed: invitePerson,
style: IconButton.styleFrom(minimumSize: const Size(36, 36)),
),
IconButton(
icon: const Icon(Symbols.refresh),
onPressed: () {
// Refresh both providers
memberNotifier.reset();
memberNotifier.loadMore();
ref.invalidate(memberListProvider);
},
),
IconButton(
icon: const Icon(Symbols.close),
onPressed: () => Navigator.pop(context),
style: IconButton.styleFrom(minimumSize: const Size(36, 36)),
),
],
),
);
}
Widget buildMemberListContent() {
return Expanded(
child: PagingHelperView(
provider: memberListProvider,
futureRefreshable: memberListProvider.future,
notifierRefreshable: memberListProvider.notifier,
contentBuilder: (data, widgetCount, endItemView) {
return ListView.builder(
itemCount: widgetCount,
itemBuilder: (context, index) {
if (index == data.items.length) {
return endItemView;
}
final member = data.items[index];
return ListTile(
contentPadding: EdgeInsets.only(left: 16, right: 12),
leading: ProfilePictureWidget(
fileId: member.account!.profile.picture?.id,
),
title: Row(
spacing: 6,
children: [
Flexible(child: Text(member.account!.nick)),
if (member.status != null)
AccountStatusLabel(status: member.status!),
if (member.joinedAt == null)
const Icon(Symbols.pending_actions, size: 20),
],
),
subtitle: Row(
children: [
Text(
member.role >= 100
? 'permissionOwner'
: member.role >= 50
? 'permissionModerator'
: 'permissionMember',
).tr(),
Text('·').bold().padding(horizontal: 6),
Expanded(child: Text("@${member.account!.name}")),
],
),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
if ((realmIdentity.value?.role ?? 0) >= 50)
IconButton(
icon: const Icon(Symbols.edit),
onPressed: () {
showModalBottomSheet(
isScrollControlled: true,
context: context,
builder:
(context) => _RealmMemberRoleSheet(
realmSlug: realmSlug,
member: member,
),
).then((value) {
if (value != null) {
// Refresh both providers
memberNotifier.reset();
memberNotifier.loadMore();
ref.invalidate(memberListProvider);
}
});
},
),
if ((realmIdentity.value?.role ?? 0) >= 50)
IconButton(
icon: const Icon(Symbols.delete),
onPressed: () {
showConfirmAlert(
'removeRealmMemberHint'.tr(),
'removeRealmMember'.tr(),
).then((confirm) async {
if (confirm != true) return;
try {
final apiClient = ref.watch(apiClientProvider);
await apiClient.delete(
'/sphere/realms/$realmSlug/members/${member.accountId}',
);
// Refresh both providers
memberNotifier.reset();
memberNotifier.loadMore();
ref.invalidate(memberListProvider);
} catch (err) {
showErrorAlert(err);
}
});
},
),
],
),
);
},
);
},
),
);
}
return Container( return Container(
constraints: BoxConstraints( constraints: BoxConstraints(
maxHeight: MediaQuery.of(context).size.height * 0.8, maxHeight: MediaQuery.of(context).size.height * 0.8,
), ),
child: Column( child: Column(
children: [ children: [
Padding( buildMemberListHeader(),
padding: EdgeInsets.only(top: 16, left: 20, right: 16, bottom: 12),
child: Row(
children: [
Text(
'members'.plural(memberState.total),
style: Theme.of(context).textTheme.headlineSmall?.copyWith(
fontWeight: FontWeight.w600,
letterSpacing: -0.5,
),
),
const Spacer(),
IconButton(
icon: const Icon(Symbols.person_add),
onPressed: invitePerson,
style: IconButton.styleFrom(minimumSize: const Size(36, 36)),
),
IconButton(
icon: const Icon(Symbols.refresh),
onPressed: () {
// Refresh both providers
memberNotifier.reset();
memberNotifier.loadMore();
ref.invalidate(memberListProvider);
},
),
IconButton(
icon: const Icon(Symbols.close),
onPressed: () => Navigator.pop(context),
style: IconButton.styleFrom(minimumSize: const Size(36, 36)),
),
],
),
),
const Divider(height: 1), const Divider(height: 1),
Expanded( buildMemberListContent(),
child: PagingHelperView(
provider: memberListProvider,
futureRefreshable: memberListProvider.future,
notifierRefreshable: memberListProvider.notifier,
contentBuilder: (data, widgetCount, endItemView) {
return ListView.builder(
itemCount: widgetCount,
itemBuilder: (context, index) {
if (index == data.items.length) {
return endItemView;
}
final member = data.items[index];
return ListTile(
contentPadding: EdgeInsets.only(left: 16, right: 12),
leading: ProfilePictureWidget(
fileId: member.account!.profile.picture?.id,
),
title: Row(
spacing: 6,
children: [
Flexible(child: Text(member.account!.nick)),
if (member.joinedAt == null)
const Icon(Symbols.pending_actions, size: 20),
],
),
subtitle: Row(
children: [
Text(
member.role >= 100
? 'permissionOwner'
: member.role >= 50
? 'permissionModerator'
: 'permissionMember',
).tr(),
Text('·').bold().padding(horizontal: 6),
Expanded(child: Text("@${member.account!.name}")),
],
),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
if ((realmIdentity.value?.role ?? 0) >= 50)
IconButton(
icon: const Icon(Symbols.edit),
onPressed: () {
showModalBottomSheet(
isScrollControlled: true,
context: context,
builder:
(context) => _RealmMemberRoleSheet(
realmSlug: realmSlug,
member: member,
),
).then((value) {
if (value != null) {
// Refresh both providers
memberNotifier.reset();
memberNotifier.loadMore();
ref.invalidate(memberListProvider);
}
});
},
),
if ((realmIdentity.value?.role ?? 0) >= 50)
IconButton(
icon: const Icon(Symbols.delete),
onPressed: () {
showConfirmAlert(
'removeRealmMemberHint'.tr(),
'removeRealmMember'.tr(),
).then((confirm) async {
if (confirm != true) return;
try {
final apiClient = ref.watch(
apiClientProvider,
);
await apiClient.delete(
'/sphere/realms/$realmSlug/members/${member.accountId}',
);
// Refresh both providers
memberNotifier.reset();
memberNotifier.loadMore();
ref.invalidate(memberListProvider);
} catch (err) {
showErrorAlert(err);
}
});
},
),
],
),
);
},
);
},
),
),
], ],
), ),
); );

View File

@@ -22,6 +22,7 @@ import 'package:island/screens/tabs.dart';
import 'package:material_symbols_icons/symbols.dart'; import 'package:material_symbols_icons/symbols.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:styled_widget/styled_widget.dart'; import 'package:styled_widget/styled_widget.dart';
import 'package:island/widgets/realm/realm_list_tile.dart';
part 'realms.g.dart'; part 'realms.g.dart';
@@ -95,32 +96,19 @@ class RealmListScreen extends HookConsumerWidget {
(value) => Column( (value) => Column(
children: [ children: [
Expanded( Expanded(
child: ListView.builder( child: ListView.separated(
padding: getTabbedPadding(context), padding: EdgeInsets.only(
top: 8,
bottom: getTabbedPadding(context).bottom + 8,
),
itemCount: value.length, itemCount: value.length,
itemBuilder: (context, item) { itemBuilder: (context, item) {
return ListTile( return ConstrainedBox(
isThreeLine: true, constraints: const BoxConstraints(maxWidth: 540),
leading: ProfilePictureWidget( child: RealmListTile(realm: value[item]),
fileId: value[item].picture?.id, ).center();
fallbackIcon: Symbols.group,
),
title: Text(value[item].name),
subtitle: Text(value[item].description),
onTap: () {
context.pushNamed(
'realmDetail',
pathParameters: {'slug': value[item].slug},
);
},
contentPadding: const EdgeInsets.only(
left: 16,
right: 14,
top: 8,
bottom: 8,
),
);
}, },
separatorBuilder: (_, _) => const Gap(8),
), ),
), ),
], ],

View File

@@ -10,7 +10,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:island/main.dart'; import 'package:island/main.dart';
import 'package:island/route.dart'; import 'package:island/route.dart';
import 'package:island/models/user.dart'; import 'package:island/models/account.dart';
import 'package:island/pods/websocket.dart'; import 'package:island/pods/websocket.dart';
import 'package:island/widgets/app_notification.dart'; import 'package:island/widgets/app_notification.dart';
import 'package:top_snackbar_flutter/top_snack_bar.dart'; import 'package:top_snackbar_flutter/top_snack_bar.dart';
@@ -26,7 +26,12 @@ StreamSubscription<WebSocketPacket> setupNotificationListener(
final notification = SnNotification.fromJson(pkt.data!); final notification = SnNotification.fromJson(pkt.data!);
showTopSnackBar( showTopSnackBar(
globalOverlay.currentState!, globalOverlay.currentState!,
NotificationCard(notification: notification), Center(
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 480),
child: NotificationCard(notification: notification),
),
),
onTap: () { onTap: () {
if (notification.meta['action_uri'] != null) { if (notification.meta['action_uri'] != null) {
var uri = notification.meta['action_uri'] as String; var uri = notification.meta['action_uri'] as String;
@@ -53,9 +58,9 @@ StreamSubscription<WebSocketPacket> setupNotificationListener(
(Platform.isMacOS || (Platform.isMacOS ||
Platform.isWindows || Platform.isWindows ||
Platform.isLinux)) Platform.isLinux))
? 24 ? 28
// ignore: use_build_context_synchronously // ignore: use_build_context_synchronously
: MediaQuery.of(context).padding.top + 8, : MediaQuery.of(context).padding.top + 16,
bottom: 16, bottom: 16,
), ),
); );
@@ -67,7 +72,7 @@ Future<void> subscribePushNotification(
Dio apiClient, { Dio apiClient, {
bool detailedErrors = false, bool detailedErrors = false,
}) async { }) async {
if (Platform.isLinux){ if (Platform.isLinux) {
return; return;
} }
await FirebaseMessaging.instance.requestPermission( await FirebaseMessaging.instance.requestPermission(

View File

@@ -3,33 +3,34 @@ import 'dart:convert';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/models/auth.dart'; import 'package:island/models/account.dart';
import 'package:island/pods/network.dart'; import 'package:island/pods/network.dart';
import 'package:island/services/responsive.dart'; import 'package:island/services/responsive.dart';
import 'package:island/services/udid.dart';
import 'package:island/widgets/alert.dart'; import 'package:island/widgets/alert.dart';
import 'package:island/widgets/content/sheet.dart'; import 'package:island/widgets/content/sheet.dart';
import 'package:island/widgets/response.dart'; import 'package:island/widgets/response.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:styled_widget/styled_widget.dart'; import 'package:styled_widget/styled_widget.dart';
part 'account_session_sheet.g.dart'; part 'account_devices.g.dart';
@riverpod @riverpod
Future<List<SnAuthDevice>> authDevices(Ref ref) async { Future<List<SnAuthDeviceWithChallenge>> authDevices(Ref ref) async {
final resp = await ref final resp = await ref
.watch(apiClientProvider) .watch(apiClientProvider)
.get('/id/accounts/me/devices'); .get('/id/accounts/me/devices');
final sessionId = resp.headers.value('x-auth-session'); final currentId = await getUdid();
final data = final data =
resp.data.map<SnAuthDevice>((e) { resp.data.map<SnAuthDeviceWithChallenge>((e) {
final ele = SnAuthDevice.fromJson(e); final ele = SnAuthDeviceWithChallenge.fromJson(e);
return ele.copyWith(isCurrent: ele.sessions.first.id == sessionId); return ele.copyWith(isCurrent: ele.deviceId == currentId);
}).toList(); }).toList();
return data; return data;
} }
class _DeviceListTile extends StatelessWidget { class _DeviceListTile extends StatelessWidget {
final SnAuthDevice device; final SnAuthDeviceWithChallenge device;
final Function(String) updateDeviceLabel; final Function(String) updateDeviceLabel;
final Function(String) logoutDevice; final Function(String) logoutDevice;
@@ -57,17 +58,16 @@ class _DeviceListTile extends StatelessWidget {
subtitle: Column( subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [
Text('authSessionsCount'.plural(device.sessions.length)),
Text( Text(
'lastActiveAt'.tr( 'lastActiveAt'.tr(
args: [ args: [
DateFormat().format( DateFormat().format(
device.sessions.first.lastGrantedAt.toLocal(), device.challenges.first.createdAt.toLocal(),
), ),
], ],
), ),
), ),
Text(device.sessions.first.challenge.ipAddress), Text(device.challenges.first.ipAddress),
if (device.isCurrent) if (device.isCurrent)
Row( Row(
children: [ children: [
@@ -84,7 +84,7 @@ class _DeviceListTile extends StatelessWidget {
).padding(top: 4), ).padding(top: 4),
], ],
), ),
title: Text(device.label ?? device.sessions.first.challenge.userAgent), title: Text(device.deviceLabel ?? device.deviceName),
trailing: trailing:
isWideScreen(context) isWideScreen(context)
? Row( ? Row(
@@ -93,14 +93,13 @@ class _DeviceListTile extends StatelessWidget {
IconButton( IconButton(
icon: Icon(Icons.edit), icon: Icon(Icons.edit),
tooltip: 'authDeviceEditLabel'.tr(), tooltip: 'authDeviceEditLabel'.tr(),
onPressed: onPressed: () => updateDeviceLabel(device.deviceId),
() => updateDeviceLabel(device.sessions.first.id),
), ),
if (!device.isCurrent) if (!device.isCurrent)
IconButton( IconButton(
icon: Icon(Icons.logout), icon: Icon(Icons.logout),
tooltip: 'authDeviceLogout'.tr(), tooltip: 'authDeviceLogout'.tr(),
onPressed: () => logoutDevice(device.sessions.first.id), onPressed: () => logoutDevice(device.deviceId),
), ),
], ],
) )
@@ -124,7 +123,7 @@ class AccountSessionSheet extends HookConsumerWidget {
if (!confirm || !context.mounted) return; if (!confirm || !context.mounted) return;
try { try {
final apiClient = ref.watch(apiClientProvider); final apiClient = ref.watch(apiClientProvider);
await apiClient.delete('/id/accounts/me/sessions/$sessionId'); await apiClient.delete('/id/accounts/me/devices/$sessionId');
ref.invalidate(authDevicesProvider); ref.invalidate(authDevicesProvider);
} catch (err) { } catch (err) {
showErrorAlert(err); showErrorAlert(err);
@@ -163,7 +162,7 @@ class AccountSessionSheet extends HookConsumerWidget {
try { try {
final apiClient = ref.watch(apiClientProvider); final apiClient = ref.watch(apiClientProvider);
await apiClient.patch( await apiClient.patch(
'/accounts/me/sessions/$sessionId/label', '/id/accounts/me/devices/$sessionId/label',
data: jsonEncode(label), data: jsonEncode(label),
); );
ref.invalidate(authDevicesProvider); ref.invalidate(authDevicesProvider);
@@ -194,7 +193,7 @@ class AccountSessionSheet extends HookConsumerWidget {
); );
} else { } else {
return Dismissible( return Dismissible(
key: Key('device-${device.sessions.first.id}'), key: Key('device-${device.id}'),
direction: direction:
device.isCurrent device.isCurrent
? DismissDirection.startToEnd ? DismissDirection.startToEnd
@@ -213,7 +212,7 @@ class AccountSessionSheet extends HookConsumerWidget {
), ),
confirmDismiss: (direction) async { confirmDismiss: (direction) async {
if (direction == DismissDirection.startToEnd) { if (direction == DismissDirection.startToEnd) {
updateDeviceLabel(device.sessions.first.id); updateDeviceLabel(device.deviceId);
return false; return false;
} else { } else {
final confirm = await showConfirmAlert( final confirm = await showConfirmAlert(
@@ -221,7 +220,7 @@ class AccountSessionSheet extends HookConsumerWidget {
'authDeviceLogout'.tr(), 'authDeviceLogout'.tr(),
); );
if (confirm && context.mounted) { if (confirm && context.mounted) {
logoutDevice(device.sessions.first.id); logoutDevice(device.deviceId);
} }
return false; // Don't dismiss return false; // Don't dismiss
} }

View File

@@ -1,17 +1,17 @@
// GENERATED CODE - DO NOT MODIFY BY HAND // GENERATED CODE - DO NOT MODIFY BY HAND
part of 'account_session_sheet.dart'; part of 'account_devices.dart';
// ************************************************************************** // **************************************************************************
// RiverpodGenerator // RiverpodGenerator
// ************************************************************************** // **************************************************************************
String _$authDevicesHash() => r'8bc41a1ffc37df8e757c977b4ddae11db8faaeb5'; String _$authDevicesHash() => r'feb19238f759921e51c888f8b443a3d7761e68da';
/// See also [authDevices]. /// See also [authDevices].
@ProviderFor(authDevices) @ProviderFor(authDevices)
final authDevicesProvider = final authDevicesProvider =
AutoDisposeFutureProvider<List<SnAuthDevice>>.internal( AutoDisposeFutureProvider<List<SnAuthDeviceWithChallenge>>.internal(
authDevices, authDevices,
name: r'authDevicesProvider', name: r'authDevicesProvider',
debugGetCreateSourceHash: debugGetCreateSourceHash:
@@ -24,6 +24,7 @@ final authDevicesProvider =
@Deprecated('Will be removed in 3.0. Use Ref instead') @Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element // ignore: unused_element
typedef AuthDevicesRef = AutoDisposeFutureProviderRef<List<SnAuthDevice>>; typedef AuthDevicesRef =
AutoDisposeFutureProviderRef<List<SnAuthDeviceWithChallenge>>;
// ignore_for_file: type=lint // ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package

View File

@@ -1,7 +1,7 @@
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:gap/gap.dart'; import 'package:gap/gap.dart';
import 'package:island/models/user.dart'; import 'package:island/models/account.dart';
import 'package:island/models/wallet.dart'; import 'package:island/models/wallet.dart';
import 'package:material_symbols_icons/symbols.dart'; import 'package:material_symbols_icons/symbols.dart';
import 'package:styled_widget/styled_widget.dart'; import 'package:styled_widget/styled_widget.dart';

View File

@@ -4,7 +4,7 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/models/user.dart'; import 'package:island/models/account.dart';
import 'package:island/pods/network.dart'; import 'package:island/pods/network.dart';
import 'package:island/widgets/content/cloud_files.dart'; import 'package:island/widgets/content/cloud_files.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart';

View File

@@ -1,6 +1,6 @@
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:island/models/user.dart'; import 'package:island/models/account.dart';
import 'package:island/models/badge.dart'; import 'package:island/models/badge.dart';
class BadgeList extends StatelessWidget { class BadgeList extends StatelessWidget {

View File

@@ -2,7 +2,7 @@ import 'package:dio/dio.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/models/user.dart'; import 'package:island/models/account.dart';
import 'package:island/pods/network.dart'; import 'package:island/pods/network.dart';
import 'package:island/screens/account/profile.dart'; import 'package:island/screens/account/profile.dart';
import 'package:island/services/time.dart'; import 'package:island/services/time.dart';
@@ -158,3 +158,42 @@ class AccountStatusWidget extends HookConsumerWidget {
).opacity((status.value?.isCustomized ?? false) ? 1 : 0.85); ).opacity((status.value?.isCustomized ?? false) ? 1 : 0.85);
} }
} }
class AccountStatusLabel extends StatelessWidget {
final SnAccountStatus status;
final TextStyle? style;
final int maxLines;
final TextOverflow overflow;
const AccountStatusLabel({
super.key,
required this.status,
this.style,
this.maxLines = 1,
this.overflow = TextOverflow.ellipsis,
});
@override
Widget build(BuildContext context) {
return Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Icon(
Symbols.circle,
fill: 1,
color: status.isOnline ? Colors.green : Colors.grey,
size: 14,
).padding(right: 4),
Flexible(
child: Text(
status.label,
style: style,
maxLines: maxLines,
overflow: overflow,
).fontSize(13),
),
],
);
}
}

View File

@@ -4,7 +4,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:gap/gap.dart'; import 'package:gap/gap.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/models/user.dart'; import 'package:island/models/account.dart';
import 'package:island/pods/network.dart'; import 'package:island/pods/network.dart';
import 'package:island/pods/userinfo.dart'; import 'package:island/pods/userinfo.dart';
import 'package:island/widgets/account/status.dart'; import 'package:island/widgets/account/status.dart';

View File

@@ -11,7 +11,12 @@ export 'content/alert.native.dart'
void showSnackBar(String message, {SnackBarAction? action}) { void showSnackBar(String message, {SnackBarAction? action}) {
showTopSnackBar( showTopSnackBar(
globalOverlay.currentState!, 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, snackBarPosition: SnackBarPosition.bottom,
); );
} }

View File

@@ -1,6 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/models/user.dart'; import 'package:island/models/account.dart';
import 'package:island/widgets/content/cloud_files.dart'; import 'package:island/widgets/content/cloud_files.dart';
import 'package:material_symbols_icons/material_symbols_icons.dart'; import 'package:material_symbols_icons/material_symbols_icons.dart';
import 'package:styled_widget/styled_widget.dart'; import 'package:styled_widget/styled_widget.dart';

View File

@@ -546,6 +546,26 @@ class _MessageItemContent extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
switch (item.type) { switch (item.type) {
case 'deleted':
return Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Icon(
Symbols.delete,
size: 14,
color: Theme.of(context).colorScheme.onSurfaceVariant.withOpacity(0.6),
),
const Gap(4),
Text(
item.content!,
style: Theme.of(context).textTheme.bodySmall?.copyWith(
color: Theme.of(context).colorScheme.onSurfaceVariant.withOpacity(0.6),
fontStyle: FontStyle.italic,
),
),
],
);
case 'call.start': case 'call.start':
case 'call.ended': case 'call.ended':
return _MessageContentCall( return _MessageContentCall(

View File

@@ -88,6 +88,7 @@ class AttachmentPreview extends HookConsumerWidget {
final Function? onInsert; final Function? onInsert;
final Function(UniversalFile)? onUpdate; final Function(UniversalFile)? onUpdate;
final Function? onRequestUpload; final Function? onRequestUpload;
final bool isCompact;
const AttachmentPreview({ const AttachmentPreview({
super.key, super.key,
@@ -98,6 +99,7 @@ class AttachmentPreview extends HookConsumerWidget {
this.onDelete, this.onDelete,
this.onUpdate, this.onUpdate,
this.onInsert, this.onInsert,
this.isCompact = false,
}); });
// GlobalKey for selector // GlobalKey for selector
@@ -361,7 +363,7 @@ class AttachmentPreview extends HookConsumerWidget {
), ),
], ],
), ),
), ).center(),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
@@ -458,11 +460,12 @@ class AttachmentPreview extends HookConsumerWidget {
size: 16, size: 16,
color: Colors.white, color: Colors.white,
), ),
const Gap(8), if (!isCompact) const Gap(8),
Text( if (!isCompact)
'On-cloud', Text(
style: TextStyle(color: Colors.white), 'attachmentOnCloud'.tr(),
), style: TextStyle(color: Colors.white),
),
], ],
) )
: Row( : Row(
@@ -473,11 +476,12 @@ class AttachmentPreview extends HookConsumerWidget {
size: 16, size: 16,
color: Colors.white, color: Colors.white,
), ),
const Gap(8), if (!isCompact) const Gap(8),
Text( if (!isCompact)
'On-device', Text(
style: TextStyle(color: Colors.white), 'attachmentOnDevice'.tr(),
), style: TextStyle(color: Colors.white),
),
], ],
), ),
), ),

View File

@@ -256,6 +256,7 @@ class ProfilePictureWidget extends ConsumerWidget {
final String? fileId; final String? fileId;
final SnCloudFile? file; final SnCloudFile? file;
final double radius; final double radius;
final double? borderRadius;
final IconData? fallbackIcon; final IconData? fallbackIcon;
final Color? fallbackColor; final Color? fallbackColor;
const ProfilePictureWidget({ const ProfilePictureWidget({
@@ -263,6 +264,7 @@ class ProfilePictureWidget extends ConsumerWidget {
this.fileId, this.fileId,
this.file, this.file,
this.radius = 20, this.radius = 20,
this.borderRadius,
this.fallbackIcon, this.fallbackIcon,
this.fallbackColor, this.fallbackColor,
}); });
@@ -273,7 +275,10 @@ class ProfilePictureWidget extends ConsumerWidget {
final uri = '$serverUrl/drive/files/${file?.id ?? fileId}'; final uri = '$serverUrl/drive/files/${file?.id ?? fileId}';
return ClipRRect( return ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(radius)), borderRadius:
borderRadius == null
? BorderRadius.all(Radius.circular(radius))
: BorderRadius.all(Radius.circular(borderRadius!)),
child: Container( child: Container(
width: radius * 2, width: radius * 2,
height: radius * 2, height: radius * 2,

View File

@@ -57,11 +57,11 @@ class EmbedLinkWidget extends StatelessWidget {
Row( Row(
children: [ children: [
// Favicon // Favicon
if (link.faviconUrl.isNotEmpty) ...[ if (link.faviconUrl?.isNotEmpty ?? false) ...[
ClipRRect( ClipRRect(
borderRadius: BorderRadius.circular(4), borderRadius: BorderRadius.circular(4),
child: UniversalImage( child: UniversalImage(
uri: link.faviconUrl, uri: link.faviconUrl!,
width: 16, width: 16,
height: 16, height: 16,
fit: BoxFit.cover, fit: BoxFit.cover,
@@ -80,8 +80,8 @@ class EmbedLinkWidget extends StatelessWidget {
// Site name // Site name
Expanded( Expanded(
child: Text( child: Text(
link.siteName.isNotEmpty (link.siteName?.isNotEmpty ?? false)
? link.siteName ? link.siteName!
: Uri.parse(link.url).host, : Uri.parse(link.url).host,
style: theme.textTheme.bodySmall?.copyWith( style: theme.textTheme.bodySmall?.copyWith(
color: colorScheme.onSurfaceVariant, color: colorScheme.onSurfaceVariant,

View File

@@ -51,9 +51,13 @@ class UniversalImage extends StatelessWidget {
); );
}, },
errorWidget: (context, url, error) { errorWidget: (context, url, error) {
return const Center( return Image.asset(
child: Icon(Icons.broken_image, color: Colors.white, size: 16), 'assets/images/media-offline.png',
fit: BoxFit.cover,
); );
// return const Center(
// child: Icon(Icons.broken_image, color: Colors.white, size: 16),
// );
}, },
), ),
], ],

View File

@@ -183,9 +183,15 @@ class MarkdownTextContent extends HookConsumerWidget {
); );
} }
} }
final content = ConstrainedBox( final content = ClipRRect(
constraints: BoxConstraints(maxHeight: 360), borderRadius: const BorderRadius.all(Radius.circular(8)),
child: UniversalImage(uri: uri.toString(), fit: BoxFit.contain), child: ConstrainedBox(
constraints: BoxConstraints(maxHeight: 360),
child: UniversalImage(
uri: uri.toString(),
fit: BoxFit.contain,
),
),
); );
return content; return content;
}, },

View File

@@ -73,6 +73,7 @@ class _UniversalVideoState extends ConsumerState<UniversalVideo> {
return Video( return Video(
controller: _videoController!, controller: _videoController!,
aspectRatio: widget.aspectRatio != 1 ? widget.aspectRatio : null, aspectRatio: widget.aspectRatio != 1 ? widget.aspectRatio : null,
fit: BoxFit.contain,
controls: controls:
!kIsWeb && (Platform.isAndroid || Platform.isIOS) !kIsWeb && (Platform.isAndroid || Platform.isIOS)
? MaterialVideoControls ? MaterialVideoControls

View File

@@ -5,11 +5,15 @@ import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:gap/gap.dart'; import 'package:gap/gap.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/models/post_category.dart'; import 'package:island/models/post_category.dart';
import 'package:island/models/realm.dart';
import 'package:island/pods/network.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/content/sheet.dart';
import 'package:island/widgets/post/compose_shared.dart'; import 'package:island/widgets/post/compose_shared.dart';
import 'package:material_symbols_icons/symbols.dart'; import 'package:material_symbols_icons/symbols.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:styled_widget/styled_widget.dart';
import 'package:textfield_tags/textfield_tags.dart'; import 'package:textfield_tags/textfield_tags.dart';
part 'compose_settings_sheet.g.dart'; part 'compose_settings_sheet.g.dart';
@@ -129,7 +133,9 @@ class ComposeSettingsSheet extends HookConsumerWidget {
// Listen to visibility changes to trigger rebuilds // Listen to visibility changes to trigger rebuilds
final currentVisibility = useValueListenable(state.visibility); final currentVisibility = useValueListenable(state.visibility);
final currentCategories = useValueListenable(state.categories); final currentCategories = useValueListenable(state.categories);
final currentRealm = useValueListenable(state.realm);
final postCategories = ref.watch(postCategoriesProvider); final postCategories = ref.watch(postCategoriesProvider);
final userRealms = ref.watch(realmsJoinedProvider);
IconData getVisibilityIcon(int visibilityValue) { IconData getVisibilityIcon(int visibilityValue) {
switch (visibilityValue) { switch (visibilityValue) {
@@ -223,6 +229,24 @@ class ComposeSettingsSheet extends HookConsumerWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
spacing: 16, spacing: 16,
children: [ children: [
// Slug field
TextField(
controller: state.slugController,
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 // Tags field
TextFieldTags( TextFieldTags(
textfieldTagsController: state.tagsController, textfieldTagsController: state.tagsController,
@@ -244,7 +268,6 @@ class ComposeSettingsSheet extends HookConsumerWidget {
), ),
// Categories field // 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>( DropdownButtonFormField2<SnPostCategory>(
isExpanded: true, isExpanded: true,
decoration: InputDecoration( decoration: InputDecoration(
@@ -306,7 +329,7 @@ class ComposeSettingsSheet extends HookConsumerWidget {
value: currentCategories.isEmpty ? null : currentCategories.last, value: currentCategories.isEmpty ? null : currentCategories.last,
onChanged: (_) {}, onChanged: (_) {},
selectedItemBuilder: (context) { selectedItemBuilder: (context) {
return currentCategories.map((item) { return (postCategories.value ?? []).map((item) {
return SingleChildScrollView( return SingleChildScrollView(
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
child: Row( child: Row(
@@ -335,12 +358,89 @@ class ComposeSettingsSheet extends HookConsumerWidget {
); );
}).toList(); }).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( buttonStyleData: const ButtonStyleData(
padding: EdgeInsets.only(left: 16, right: 8), padding: EdgeInsets.only(left: 16, right: 8),
height: 40, height: 40,
), ),
menuItemStyleData: const MenuItemStyleData( menuItemStyleData: const MenuItemStyleData(
height: 40, height: 56,
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
), ),
), ),

View File

@@ -9,6 +9,7 @@ import 'package:island/models/file.dart';
import 'package:island/models/post.dart'; import 'package:island/models/post.dart';
import 'package:island/models/post_category.dart'; import 'package:island/models/post_category.dart';
import 'package:island/models/publisher.dart'; import 'package:island/models/publisher.dart';
import 'package:island/models/realm.dart';
import 'package:island/pods/config.dart'; import 'package:island/pods/config.dart';
import 'package:island/pods/network.dart'; import 'package:island/pods/network.dart';
import 'package:island/services/file.dart'; import 'package:island/services/file.dart';
@@ -26,6 +27,7 @@ class ComposeState {
final TextEditingController titleController; final TextEditingController titleController;
final TextEditingController descriptionController; final TextEditingController descriptionController;
final TextEditingController contentController; final TextEditingController contentController;
final TextEditingController slugController;
final ValueNotifier<int> visibility; final ValueNotifier<int> visibility;
final ValueNotifier<List<UniversalFile>> attachments; final ValueNotifier<List<UniversalFile>> attachments;
final ValueNotifier<Map<int, double>> attachmentProgress; final ValueNotifier<Map<int, double>> attachmentProgress;
@@ -33,6 +35,7 @@ class ComposeState {
final ValueNotifier<bool> submitting; final ValueNotifier<bool> submitting;
final ValueNotifier<List<SnPostCategory>> categories; final ValueNotifier<List<SnPostCategory>> categories;
StringTagController tagsController; StringTagController tagsController;
final ValueNotifier<SnRealm?> realm;
final String draftId; final String draftId;
int postType; int postType;
// Linked poll id for this compose session (nullable) // Linked poll id for this compose session (nullable)
@@ -43,6 +46,7 @@ class ComposeState {
required this.titleController, required this.titleController,
required this.descriptionController, required this.descriptionController,
required this.contentController, required this.contentController,
required this.slugController,
required this.visibility, required this.visibility,
required this.attachments, required this.attachments,
required this.attachmentProgress, required this.attachmentProgress,
@@ -50,6 +54,7 @@ class ComposeState {
required this.submitting, required this.submitting,
required this.tagsController, required this.tagsController,
required this.categories, required this.categories,
required this.realm,
required this.draftId, required this.draftId,
this.postType = 0, this.postType = 0,
String? pollId, String? pollId,
@@ -104,6 +109,7 @@ class ComposeLogic {
text: originalPost?.description, text: originalPost?.description,
), ),
contentController: TextEditingController(text: originalPost?.content), contentController: TextEditingController(text: originalPost?.content),
slugController: TextEditingController(text: originalPost?.slug),
visibility: ValueNotifier<int>(originalPost?.visibility ?? 0), visibility: ValueNotifier<int>(originalPost?.visibility ?? 0),
submitting: ValueNotifier<bool>(false), submitting: ValueNotifier<bool>(false),
attachmentProgress: ValueNotifier<Map<int, double>>({}), attachmentProgress: ValueNotifier<Map<int, double>>({}),
@@ -112,6 +118,7 @@ class ComposeLogic {
categories: ValueNotifier<List<SnPostCategory>>( categories: ValueNotifier<List<SnPostCategory>>(
originalPost?.categories ?? [], originalPost?.categories ?? [],
), ),
realm: ValueNotifier(originalPost?.realm),
draftId: id, draftId: id,
postType: postType, postType: postType,
// initialize without poll by default // initialize without poll by default
@@ -135,12 +142,14 @@ class ComposeLogic {
titleController: TextEditingController(text: draft.title), titleController: TextEditingController(text: draft.title),
descriptionController: TextEditingController(text: draft.description), descriptionController: TextEditingController(text: draft.description),
contentController: TextEditingController(text: draft.content), contentController: TextEditingController(text: draft.content),
slugController: TextEditingController(text: draft.slug),
visibility: ValueNotifier<int>(draft.visibility), visibility: ValueNotifier<int>(draft.visibility),
submitting: ValueNotifier<bool>(false), submitting: ValueNotifier<bool>(false),
attachmentProgress: ValueNotifier<Map<int, double>>({}), attachmentProgress: ValueNotifier<Map<int, double>>({}),
currentPublisher: ValueNotifier<SnPublisher?>(null), currentPublisher: ValueNotifier<SnPublisher?>(null),
tagsController: tagsController, tagsController: tagsController,
categories: ValueNotifier<List<SnPostCategory>>([]), categories: ValueNotifier<List<SnPostCategory>>([]),
realm: ValueNotifier(null),
draftId: draft.id, draftId: draft.id,
postType: postType, postType: postType,
pollId: null, pollId: null,
@@ -629,6 +638,8 @@ class ComposeLogic {
'title': state.titleController.text, 'title': state.titleController.text,
'description': state.descriptionController.text, 'description': state.descriptionController.text,
'content': state.contentController.text, 'content': state.contentController.text,
if (state.slugController.text.isNotEmpty)
'slug': state.slugController.text,
'visibility': state.visibility.value, 'visibility': state.visibility.value,
'attachments': 'attachments':
state.attachments.value state.attachments.value
@@ -640,6 +651,7 @@ class ComposeLogic {
if (forwardedPost != null) 'forwarded_post_id': forwardedPost.id, if (forwardedPost != null) 'forwarded_post_id': forwardedPost.id,
'tags': state.tagsController.getTags, 'tags': state.tagsController.getTags,
'categories': state.categories.value.map((e) => e.slug).toList(), '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, if (state.pollId.value != null) 'poll_id': state.pollId.value,
}; };
@@ -733,6 +745,7 @@ class ComposeLogic {
state.currentPublisher.dispose(); state.currentPublisher.dispose();
state.tagsController.dispose(); state.tagsController.dispose();
state.categories.dispose(); state.categories.dispose();
state.realm.dispose();
state.pollId.dispose(); state.pollId.dispose();
} }
} }

View File

@@ -7,6 +7,7 @@ import 'package:material_symbols_icons/symbols.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:island/widgets/post/post_item.dart'; import 'package:island/widgets/post/post_item.dart';
import 'package:styled_widget/styled_widget.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'; part 'post_featured.g.dart';
@@ -25,7 +26,13 @@ class PostFeaturedList extends HookConsumerWidget {
final featuredPostsAsync = ref.watch(featuredPostsProvider); final featuredPostsAsync = ref.watch(featuredPostsProvider);
final pageViewController = usePageController(); final pageViewController = usePageController();
final prefs = ref.watch(sharedPreferencesProvider);
final pageViewCurrent = useState(0); final pageViewCurrent = useState(0);
final previousFirstPostId = useState<String?>(null);
final storedCollapsedId = useState<String?>(
prefs.getString(kFeaturedPostsCollapsedId),
);
final isCollapsed = useState(false);
useEffect(() { useEffect(() {
pageViewController.addListener(() { pageViewController.addListener(() {
@@ -34,6 +41,59 @@ class PostFeaturedList extends HookConsumerWidget {
return null; return null;
}, [pageViewController]); }, [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( return ClipRRect(
borderRadius: const BorderRadius.all(Radius.circular(8)), borderRadius: const BorderRadius.all(Radius.circular(8)),
child: Card( child: Card(
@@ -73,29 +133,69 @@ class PostFeaturedList extends HookConsumerWidget {
}, },
icon: const Icon(Symbols.arrow_right), 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), ).padding(horizontal: 16, vertical: 8),
featuredPostsAsync.when( AnimatedSize(
loading: () => const Center(child: CircularProgressIndicator()), duration: const Duration(milliseconds: 300),
error: (error, stack) => Center(child: Text('Error: $error')), curve: Curves.easeInOut,
data: (posts) { child: Visibility(
return SizedBox( visible: !isCollapsed.value,
height: 320, child: featuredPostsAsync.when(
child: PageView.builder( loading:
controller: pageViewController, () => const Center(child: CircularProgressIndicator()),
scrollDirection: Axis.horizontal, error: (error, stack) => Center(child: Text('Error: $error')),
itemCount: posts.length, data: (posts) {
itemBuilder: (context, index) { return SizedBox(
return SingleChildScrollView( height: 320,
child: PostActionableItem( child: PageView.builder(
item: posts[index], controller: pageViewController,
borderRadius: 8, scrollDirection: Axis.horizontal,
), itemCount: posts.length,
); itemBuilder: (context, index) {
}, return SingleChildScrollView(
), child: PostActionableItem(
); item: posts[index],
}, borderRadius: 8,
),
);
},
),
);
},
),
),
), ),
], ],
), ),

View File

@@ -117,8 +117,12 @@ class PostActionableItem extends HookConsumerWidget {
await File('${directory.path}/image.png').create(); await File('${directory.path}/image.png').create();
await imagePath.writeAsBytes(image); await imagePath.writeAsBytes(image);
if (context.mounted) hideLoadingModal(context); if (!context.mounted) return;
await Share.shareXFiles([XFile(imagePath.path)]); hideLoadingModal(context);
final box = context.findRenderObject() as RenderBox?;
await Share.shareXFiles([
XFile(imagePath.path),
], sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size);
}) })
.catchError((err) { .catchError((err) {
if (context.mounted) hideLoadingModal(context); if (context.mounted) hideLoadingModal(context);
@@ -174,7 +178,7 @@ class PostActionableItem extends HookConsumerWidget {
image: MenuImage.icon(Symbols.link), image: MenuImage.icon(Symbols.link),
callback: () { callback: () {
Clipboard.setData( Clipboard.setData(
ClipboardData(text: 'https://solsynth.dev/posts/${item.id}'), ClipboardData(text: 'https://solian.app/posts/${item.id}'),
); );
}, },
), ),

View File

@@ -15,8 +15,9 @@ class PostListNotifier extends _$PostListNotifier
static const int _pageSize = 20; static const int _pageSize = 20;
@override @override
Future<CursorPagingData<SnPost>> build( Future<CursorPagingData<SnPost>> build({
String? pubName, { String? pubName,
String? realm,
int? type, int? type,
List<String>? categories, List<String>? categories,
List<String>? tags, List<String>? tags,
@@ -33,6 +34,7 @@ class PostListNotifier extends _$PostListNotifier
'offset': offset, 'offset': offset,
'take': _pageSize, 'take': _pageSize,
if (pubName != null) 'pub': pubName, if (pubName != null) 'pub': pubName,
if (realm != null) 'realm': realm,
if (type != null) 'type': type, if (type != null) 'type': type,
if (tags != null) 'tags': tags, if (tags != null) 'tags': tags,
if (categories != null) 'categories': categories, if (categories != null) 'categories': categories,
@@ -68,6 +70,7 @@ enum PostItemType {
class SliverPostList extends HookConsumerWidget { class SliverPostList extends HookConsumerWidget {
final String? pubName; final String? pubName;
final String? realm;
final int? type; final int? type;
final List<String>? categories; final List<String>? categories;
final List<String>? tags; final List<String>? tags;
@@ -81,6 +84,7 @@ class SliverPostList extends HookConsumerWidget {
const SliverPostList({ const SliverPostList({
super.key, super.key,
this.pubName, this.pubName,
this.realm,
this.type, this.type,
this.categories, this.categories,
this.tags, this.tags,
@@ -96,21 +100,24 @@ class SliverPostList extends HookConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
return PagingHelperSliverView( return PagingHelperSliverView(
provider: postListNotifierProvider( provider: postListNotifierProvider(
pubName, pubName: pubName,
realm: realm,
type: type, type: type,
categories: categories, categories: categories,
tags: tags, tags: tags,
), ),
futureRefreshable: futureRefreshable:
postListNotifierProvider( postListNotifierProvider(
pubName, pubName: pubName,
realm: realm,
type: type, type: type,
categories: categories, categories: categories,
tags: tags, tags: tags,
).future, ).future,
notifierRefreshable: notifierRefreshable:
postListNotifierProvider( postListNotifierProvider(
pubName, pubName: pubName,
realm: realm,
type: type, type: type,
categories: categories, categories: categories,
tags: tags, tags: tags,

View File

@@ -6,7 +6,7 @@ part of 'post_list.dart';
// RiverpodGenerator // RiverpodGenerator
// ************************************************************************** // **************************************************************************
String _$postListNotifierHash() => r'2ca4f3cfbbcd04f3cc32e7f7bd511a5811042829'; String _$postListNotifierHash() => r'9784b282b3ee14b7109e263c5841a082cf0be78e';
/// Copied from Dart SDK /// Copied from Dart SDK
class _SystemHash { class _SystemHash {
@@ -32,12 +32,14 @@ class _SystemHash {
abstract class _$PostListNotifier abstract class _$PostListNotifier
extends BuildlessAutoDisposeAsyncNotifier<CursorPagingData<SnPost>> { extends BuildlessAutoDisposeAsyncNotifier<CursorPagingData<SnPost>> {
late final String? pubName; late final String? pubName;
late final String? realm;
late final int? type; late final int? type;
late final List<String>? categories; late final List<String>? categories;
late final List<String>? tags; late final List<String>? tags;
FutureOr<CursorPagingData<SnPost>> build( FutureOr<CursorPagingData<SnPost>> build({
String? pubName, { String? pubName,
String? realm,
int? type, int? type,
List<String>? categories, List<String>? categories,
List<String>? tags, List<String>? tags,
@@ -55,14 +57,16 @@ class PostListNotifierFamily
const PostListNotifierFamily(); const PostListNotifierFamily();
/// See also [PostListNotifier]. /// See also [PostListNotifier].
PostListNotifierProvider call( PostListNotifierProvider call({
String? pubName, { String? pubName,
String? realm,
int? type, int? type,
List<String>? categories, List<String>? categories,
List<String>? tags, List<String>? tags,
}) { }) {
return PostListNotifierProvider( return PostListNotifierProvider(
pubName, pubName: pubName,
realm: realm,
type: type, type: type,
categories: categories, categories: categories,
tags: tags, tags: tags,
@@ -74,7 +78,8 @@ class PostListNotifierFamily
covariant PostListNotifierProvider provider, covariant PostListNotifierProvider provider,
) { ) {
return call( return call(
provider.pubName, pubName: provider.pubName,
realm: provider.realm,
type: provider.type, type: provider.type,
categories: provider.categories, categories: provider.categories,
tags: provider.tags, tags: provider.tags,
@@ -104,8 +109,9 @@ class PostListNotifierProvider
CursorPagingData<SnPost> CursorPagingData<SnPost>
> { > {
/// See also [PostListNotifier]. /// See also [PostListNotifier].
PostListNotifierProvider( PostListNotifierProvider({
String? pubName, { String? pubName,
String? realm,
int? type, int? type,
List<String>? categories, List<String>? categories,
List<String>? tags, List<String>? tags,
@@ -113,6 +119,7 @@ class PostListNotifierProvider
() => () =>
PostListNotifier() PostListNotifier()
..pubName = pubName ..pubName = pubName
..realm = realm
..type = type ..type = type
..categories = categories ..categories = categories
..tags = tags, ..tags = tags,
@@ -126,6 +133,7 @@ class PostListNotifierProvider
allTransitiveDependencies: allTransitiveDependencies:
PostListNotifierFamily._allTransitiveDependencies, PostListNotifierFamily._allTransitiveDependencies,
pubName: pubName, pubName: pubName,
realm: realm,
type: type, type: type,
categories: categories, categories: categories,
tags: tags, tags: tags,
@@ -139,12 +147,14 @@ class PostListNotifierProvider
required super.debugGetCreateSourceHash, required super.debugGetCreateSourceHash,
required super.from, required super.from,
required this.pubName, required this.pubName,
required this.realm,
required this.type, required this.type,
required this.categories, required this.categories,
required this.tags, required this.tags,
}) : super.internal(); }) : super.internal();
final String? pubName; final String? pubName;
final String? realm;
final int? type; final int? type;
final List<String>? categories; final List<String>? categories;
final List<String>? tags; final List<String>? tags;
@@ -154,7 +164,8 @@ class PostListNotifierProvider
covariant PostListNotifier notifier, covariant PostListNotifier notifier,
) { ) {
return notifier.build( return notifier.build(
pubName, pubName: pubName,
realm: realm,
type: type, type: type,
categories: categories, categories: categories,
tags: tags, tags: tags,
@@ -169,6 +180,7 @@ class PostListNotifierProvider
() => () =>
create() create()
..pubName = pubName ..pubName = pubName
..realm = realm
..type = type ..type = type
..categories = categories ..categories = categories
..tags = tags, ..tags = tags,
@@ -178,6 +190,7 @@ class PostListNotifierProvider
allTransitiveDependencies: null, allTransitiveDependencies: null,
debugGetCreateSourceHash: null, debugGetCreateSourceHash: null,
pubName: pubName, pubName: pubName,
realm: realm,
type: type, type: type,
categories: categories, categories: categories,
tags: tags, tags: tags,
@@ -198,6 +211,7 @@ class PostListNotifierProvider
bool operator ==(Object other) { bool operator ==(Object other) {
return other is PostListNotifierProvider && return other is PostListNotifierProvider &&
other.pubName == pubName && other.pubName == pubName &&
other.realm == realm &&
other.type == type && other.type == type &&
other.categories == categories && other.categories == categories &&
other.tags == tags; other.tags == tags;
@@ -207,6 +221,7 @@ class PostListNotifierProvider
int get hashCode { int get hashCode {
var hash = _SystemHash.combine(0, runtimeType.hashCode); var hash = _SystemHash.combine(0, runtimeType.hashCode);
hash = _SystemHash.combine(hash, pubName.hashCode); hash = _SystemHash.combine(hash, pubName.hashCode);
hash = _SystemHash.combine(hash, realm.hashCode);
hash = _SystemHash.combine(hash, type.hashCode); hash = _SystemHash.combine(hash, type.hashCode);
hash = _SystemHash.combine(hash, categories.hashCode); hash = _SystemHash.combine(hash, categories.hashCode);
hash = _SystemHash.combine(hash, tags.hashCode); hash = _SystemHash.combine(hash, tags.hashCode);
@@ -222,6 +237,9 @@ mixin PostListNotifierRef
/// The parameter `pubName` of this provider. /// The parameter `pubName` of this provider.
String? get pubName; String? get pubName;
/// The parameter `realm` of this provider.
String? get realm;
/// The parameter `type` of this provider. /// The parameter `type` of this provider.
int? get type; int? get type;
@@ -244,6 +262,8 @@ class _PostListNotifierProviderElement
@override @override
String? get pubName => (origin as PostListNotifierProvider).pubName; String? get pubName => (origin as PostListNotifierProvider).pubName;
@override @override
String? get realm => (origin as PostListNotifierProvider).realm;
@override
int? get type => (origin as PostListNotifierProvider).type; int? get type => (origin as PostListNotifierProvider).type;
@override @override
List<String>? get categories => List<String>? get categories =>

View File

@@ -559,7 +559,11 @@ class PostHeader extends StatelessWidget {
); );
} }
: null, : 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( Expanded(
child: Column( child: Column(
@@ -567,12 +571,46 @@ class PostHeader extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Row( Row(
crossAxisAlignment: CrossAxisAlignment.center,
spacing: 4, spacing: 4,
children: [ children: [
Text(item.publisher.nick).bold(), Text(item.publisher.nick).bold(),
if (item.publisher.verification != null) if (item.publisher.verification != null)
VerificationMark(mark: item.publisher.verification!), 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),
Flexible(
child: InkWell(
child: Row(
mainAxisSize: MainAxisSize.min,
spacing: 5,
children: [
Flexible(
child: Text(
item.realm!.name,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
ProfilePictureWidget(
file: item.realm!.picture,
fallbackIcon: Symbols.group,
radius: 9,
),
],
),
onTap: () {
GoRouter.of(context).pushNamed(
'realmDetail',
pathParameters: {'slug': item.realm!.slug},
);
},
),
),
]),
], ],
), ),
Row( Row(

View File

@@ -6,6 +6,7 @@ import 'package:island/pods/network.dart';
import 'package:island/widgets/realm/realm_card.dart'; import 'package:island/widgets/realm/realm_card.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:riverpod_paging_utils/riverpod_paging_utils.dart'; import 'package:riverpod_paging_utils/riverpod_paging_utils.dart';
import 'package:styled_widget/styled_widget.dart';
part 'realm_list.g.dart'; part 'realm_list.g.dart';
@@ -78,7 +79,11 @@ class SliverRealmList extends HookConsumerWidget {
horizontal: 16, horizontal: 16,
vertical: 8, vertical: 8,
), ),
child: RealmCard(realm: realm), child:
ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 540),
child: RealmCard(realm: realm),
).center(),
); );
}, },
separatorBuilder: (_, _) => const Gap(8), separatorBuilder: (_, _) => const Gap(8),

View File

@@ -0,0 +1,76 @@
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:go_router/go_router.dart';
import 'package:island/models/realm.dart';
import 'package:island/widgets/content/cloud_files.dart';
import 'package:material_symbols_icons/symbols.dart';
import 'package:styled_widget/styled_widget.dart';
class RealmListTile extends StatelessWidget {
const RealmListTile({super.key, required this.realm});
final SnRealm realm;
@override
Widget build(BuildContext context) {
return Card(
margin: EdgeInsets.zero,
child: InkWell(
borderRadius: const BorderRadius.all(Radius.circular(8)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
AspectRatio(
aspectRatio: 16 / 7,
child: Stack(
clipBehavior: Clip.none,
fit: StackFit.expand,
children: [
ClipRRect(
borderRadius: const BorderRadius.all(Radius.circular(8)),
child: Container(
color: Theme.of(context).colorScheme.surfaceContainer,
child:
realm.background == null
? const SizedBox.shrink()
: CloudImageWidget(file: realm.background),
),
),
Positioned(
bottom: -30,
left: 18,
child: ProfilePictureWidget(
fileId: realm.picture?.id,
fallbackIcon: Symbols.group,
radius: 24,
),
),
],
),
),
const Gap(20 + 12),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
realm.name,
).textStyle(Theme.of(context).textTheme.titleMedium!),
Text(
realm.description,
maxLines: 2,
overflow: TextOverflow.ellipsis,
).textStyle(Theme.of(context).textTheme.bodySmall!),
],
).padding(horizontal: 24, bottom: 14),
],
),
onTap: () {
context.pushNamed(
'realmDetail',
pathParameters: {'slug': realm.slug},
);
},
),
);
}
}

View File

@@ -340,22 +340,33 @@ class _ShareSheetState extends ConsumerState<ShareSheet> {
Future<void> _shareToSystem() async { Future<void> _shareToSystem() async {
if (!widget.toSystem) return; if (!widget.toSystem) return;
final box = context.findRenderObject() as RenderBox?;
setState(() => _isLoading = true); setState(() => _isLoading = true);
try { try {
switch (widget.content.type) { switch (widget.content.type) {
case ShareContentType.text: case ShareContentType.text:
if (widget.content.text?.isNotEmpty == true) { 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; break;
case ShareContentType.link: case ShareContentType.link:
if (widget.content.link?.isNotEmpty == true) { 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; break;
case ShareContentType.file: case ShareContentType.file:
if (widget.content.files?.isNotEmpty == true) { 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; break;
} }
@@ -879,7 +890,8 @@ class _LinkPreview extends ConsumerWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
// Favicon and image // Favicon and image
if (embed.imageUrl != null || embed.faviconUrl.isNotEmpty) if (embed.imageUrl != null ||
(embed.faviconUrl?.isNotEmpty ?? false))
Container( Container(
width: 60, width: 60,
height: 60, height: 60,
@@ -899,11 +911,14 @@ class _LinkPreview extends ConsumerWidget {
errorBuilder: (context, error, stackTrace) { errorBuilder: (context, error, stackTrace) {
return _buildFaviconFallback( return _buildFaviconFallback(
context, context,
embed.faviconUrl, embed.faviconUrl ?? '',
); );
}, },
) )
: _buildFaviconFallback(context, embed.faviconUrl), : _buildFaviconFallback(
context,
embed.faviconUrl ?? '',
),
), ),
), ),
// Content // Content
@@ -912,9 +927,9 @@ class _LinkPreview extends ConsumerWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
// Site name // Site name
if (embed.siteName.isNotEmpty) if (embed.siteName?.isNotEmpty ?? false)
Text( Text(
embed.siteName, embed.siteName!,
style: Theme.of(context).textTheme.labelSmall?.copyWith( style: Theme.of(context).textTheme.labelSmall?.copyWith(
color: Theme.of(context).colorScheme.primary, color: Theme.of(context).colorScheme.primary,
), ),

View File

@@ -41,7 +41,7 @@ endif()
# of modifying this function. # of modifying this function.
function(APPLY_STANDARD_SETTINGS TARGET) function(APPLY_STANDARD_SETTINGS TARGET)
target_compile_features(${TARGET} PUBLIC cxx_std_14) 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_options(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-O3>")
target_compile_definitions(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:NDEBUG>") target_compile_definitions(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:NDEBUG>")
endfunction() endfunction()

View File

@@ -195,7 +195,7 @@ PODS:
- PromisesObjC (2.4.0) - PromisesObjC (2.4.0)
- PromisesSwift (2.4.0): - PromisesSwift (2.4.0):
- PromisesObjC (= 2.4.0) - PromisesObjC (= 2.4.0)
- record_macos (1.0.0): - record_macos (1.1.0):
- FlutterMacOS - FlutterMacOS
- SAMKeychain (1.5.3) - SAMKeychain (1.5.3)
- share_plus (0.0.1): - share_plus (0.0.1):
@@ -422,7 +422,7 @@ SPEC CHECKSUMS:
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564 path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851 PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851
record_macos: 295d70bd5fb47145df78df7b80e6697cd18403c0 record_macos: 43194b6c06ca6f8fa132e2acea72b202b92a0f5b
SAMKeychain: 483e1c9f32984d50ca961e26818a534283b4cd5c SAMKeychain: 483e1c9f32984d50ca961e26818a534283b4cd5c
share_plus: 510bf0af1a42cd602274b4629920c9649c52f4cc share_plus: 510bf0af1a42cd602274b4629920c9649c52f4cc
shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7 shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7

View File

@@ -301,10 +301,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: connectivity_plus name: connectivity_plus
sha256: "051849e2bd7c7b3bc5844ea0d096609ddc3a859890ec3a9ac4a65a2620cc1f99" sha256: b5e72753cf63becce2c61fd04dfe0f1c430cc5278b53a1342dc5ad839eab29ec
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.1.4" version: "6.1.5"
connectivity_plus_platform_interface: connectivity_plus_platform_interface:
dependency: transitive dependency: transitive
description: description:
@@ -413,10 +413,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: dart_webrtc name: dart_webrtc
sha256: a2ae542cdadc21359022adedc26138fa3487cc3b3547c24ff4f556681869e28c sha256: "3bfa069a8b14a53ba506f6dd529e9b88c878ba0cc238f311051a39bf1e53d075"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.5.3+hotfix.4" version: "1.5.3+hotfix.5"
dbus: dbus:
dependency: transitive dependency: transitive
description: description:
@@ -565,10 +565,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: file_picker name: file_picker
sha256: "970d33d79e1da667b6da222575fd7f2e30e323ca76251504477e6d51405b2d9a" sha256: ef7d2a085c1b1d69d17b6842d0734aad90156de08df6bd3c12496d0bd6ddf8e2
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "10.2.4" version: "10.3.1"
file_selector_linux: file_selector_linux:
dependency: transitive dependency: transitive
description: description:
@@ -581,10 +581,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: file_selector_macos name: file_selector_macos
sha256: "8c9250b2bd2d8d4268e39c82543bacbaca0fda7d29e0728c3c4bbb7c820fd711" sha256: "19124ff4a3d8864fdc62072b6a2ef6c222d55a3404fe14893a3c02744907b60c"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.9.4+3" version: "0.9.4+4"
file_selector_platform_interface: file_selector_platform_interface:
dependency: transitive dependency: transitive
description: description:
@@ -754,10 +754,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: flutter_hooks name: flutter_hooks
sha256: b772e710d16d7a20c0740c4f855095026b31c7eb5ba3ab67d2bd52021cd9461d sha256: c3df76c62bb3a9f9bee75c57cdab40abab6123b734c1cd7e9b26a5dbd436eceb
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.21.2" version: "0.21.3"
flutter_inappwebview: flutter_inappwebview:
dependency: "direct main" dependency: "direct main"
description: description:
@@ -1073,10 +1073,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: font_awesome_flutter name: font_awesome_flutter
sha256: f50ce90dbe26d977415b9540400d6778bef00894aced6358ae578abd92b14b10 sha256: b738e35f8bb4957896c34957baf922f99c5d415b38ddc8b070d14b7fa95715d4
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "10.9.0" version: "10.9.1"
freezed: freezed:
dependency: "direct dev" dependency: "direct dev"
description: description:
@@ -1233,66 +1233,66 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: image_picker name: image_picker
sha256: "021834d9c0c3de46bf0fe40341fa07168407f694d9b2bb18d532dc1261867f7a" sha256: "736eb56a911cf24d1859315ad09ddec0b66104bc41a7f8c5b96b4e2620cf5041"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.2" version: "1.2.0"
image_picker_android: image_picker_android:
dependency: "direct main" dependency: "direct main"
description: description:
name: image_picker_android name: image_picker_android
sha256: b08e9a04d0f8d91f4a6e767a745b9871bfbc585410205c311d0492de20a7ccd6 sha256: e83b2b05141469c5e19d77e1dfa11096b6b1567d09065b2265d7c6904560050c
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.8.12+25" version: "0.8.13"
image_picker_for_web: image_picker_for_web:
dependency: transitive dependency: transitive
description: description:
name: image_picker_for_web name: image_picker_for_web
sha256: "717eb042ab08c40767684327be06a5d8dbb341fe791d514e4b92c7bbe1b7bb83" sha256: "40c2a6a0da15556dc0f8e38a3246064a971a9f512386c3339b89f76db87269b6"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.6" version: "3.1.0"
image_picker_ios: image_picker_ios:
dependency: transitive dependency: transitive
description: description:
name: image_picker_ios name: image_picker_ios
sha256: "05da758e67bc7839e886b3959848aa6b44ff123ab4b28f67891008afe8ef9100" sha256: eb06fe30bab4c4497bad449b66448f50edcc695f1c59408e78aa3a8059eb8f0e
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.8.12+2" version: "0.8.13"
image_picker_linux: image_picker_linux:
dependency: transitive dependency: transitive
description: description:
name: image_picker_linux name: image_picker_linux
sha256: "34a65f6740df08bbbeb0a1abd8e6d32107941fd4868f67a507b25601651022c9" sha256: "1f81c5f2046b9ab724f85523e4af65be1d47b038160a8c8deed909762c308ed4"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.2.1+2" version: "0.2.2"
image_picker_macos: image_picker_macos:
dependency: transitive dependency: transitive
description: description:
name: image_picker_macos name: image_picker_macos
sha256: "1b90ebbd9dcf98fb6c1d01427e49a55bd96b5d67b8c67cf955d60a5de74207c1" sha256: d58cd9d67793d52beefd6585b12050af0a7663c0c2a6ece0fb110a35d6955e04
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.2.1+2" version: "0.2.2"
image_picker_platform_interface: image_picker_platform_interface:
dependency: "direct main" dependency: "direct main"
description: description:
name: image_picker_platform_interface name: image_picker_platform_interface
sha256: "886d57f0be73c4b140004e78b9f28a8914a09e50c2d816bdd0520051a71236a0" sha256: "9f143b0dba3e459553209e20cc425c9801af48e6dfa4f01a0fcf927be3f41665"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.10.1" version: "2.11.0"
image_picker_windows: image_picker_windows:
dependency: transitive dependency: transitive
description: description:
name: image_picker_windows name: image_picker_windows
sha256: "6ad07afc4eb1bc25f3a01084d28520496c4a3bb0cb13685435838167c9dcedeb" sha256: d248c86554a72b5495a31c56f060cf73a41c7ff541689327b1a7dbccc33adfae
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.2.1+1" version: "0.2.2"
intl: intl:
dependency: transitive dependency: transitive
description: description:
@@ -1649,18 +1649,18 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: package_info_plus name: package_info_plus
sha256: "7976bfe4c583170d6cdc7077e3237560b364149fcd268b5f53d95a991963b191" sha256: "16eee997588c60225bda0488b6dcfac69280a6b7a3cf02c741895dd370a02968"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "8.3.0" version: "8.3.1"
package_info_plus_platform_interface: package_info_plus_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: package_info_plus_platform_interface name: package_info_plus_platform_interface
sha256: "6c935fb612dff8e3cc9632c2b301720c77450a126114126ffaafe28d2e87956c" sha256: "202a487f08836a592a6bd4f901ac69b3a8f146af552bbd14407b6b41e1c3f086"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.2.0" version: "3.2.1"
palette_generator: palette_generator:
dependency: "direct main" dependency: "direct main"
description: description:
@@ -1713,10 +1713,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: path_provider_foundation name: path_provider_foundation
sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942" sha256: "16eef174aacb07e09c351502740fa6254c165757638eba1e9116b0a781201bbd"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.4.1" version: "2.4.2"
path_provider_linux: path_provider_linux:
dependency: transitive dependency: transitive
description: description:
@@ -1833,10 +1833,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: protobuf name: protobuf
sha256: "6153efcc92a06910918f3db8231fd2cf828ac81e50ebd87adc8f8a8cb3caff0e" sha256: de9c9eb2c33f8e933a42932fe1dc504800ca45ebc3d673e6ed7f39754ee4053e
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.1.1" version: "4.2.0"
provider: provider:
dependency: transitive dependency: transitive
description: description:
@@ -1897,58 +1897,58 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: record name: record
sha256: daeb3f9b3fea9797094433fe6e49a879d8e4ca4207740bc6dc7e4a58764f0817 sha256: "3d08502b77edf2a864aa6e4cd7874b983d42a80f3689431da053cc5e85c1ad21"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.0.0" version: "6.1.0"
record_android: record_android:
dependency: transitive dependency: transitive
description: description:
name: record_android name: record_android
sha256: "97d7122455f30de89a01c6c244c839085be6b12abca251fc0e78f67fed73628b" sha256: "8b170e33d9866f9b51e01a767d7e1ecb97b9ecd629950bd87a47c79359ec57f8"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.3" version: "1.4.0"
record_ios: record_ios:
dependency: transitive dependency: transitive
description: description:
name: record_ios name: record_ios
sha256: "73706ebbece6150654c9d6f57897cf9b622c581148304132ba85dba15df0fdfb" sha256: ad97d0a75933c44bcf5aff648e86e32fc05eb61f8fbef190f14968c8eaf86692
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.0" version: "1.1.0"
record_linux: record_linux:
dependency: transitive dependency: transitive
description: description:
name: record_linux name: record_linux
sha256: "0626678a092c75ce6af1e32fe7fd1dea709b92d308bc8e3b6d6348e2430beb95" sha256: "785e8e8d6db109aa606d0669d95aaae416458aaa39782bb0abe0bee74eee17d7"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.1" version: "1.2.0"
record_macos: record_macos:
dependency: transitive dependency: transitive
description: description:
name: record_macos name: record_macos
sha256: "02240833fde16c33fcf2c589f3e08d4394b704761b4a3bb609d872ff3043fbbd" sha256: f1399bca76a1634da109e5b0cba764ed8332a2b4da49c704c66d2c553405ed81
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.0" version: "1.1.0"
record_platform_interface: record_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: record_platform_interface name: record_platform_interface
sha256: c1ad38f51e4af88a085b3e792a22c685cb3e7c23fc37aa7ce44c4cf18f25fe89 sha256: b0065fdf1ec28f5a634d676724d388a77e43ce7646fb049949f58c69f3fcb4ed
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.0" version: "1.4.0"
record_web: record_web:
dependency: transitive dependency: transitive
description: description:
name: record_web name: record_web
sha256: a12856d0b3dd03d336b4b10d7520a8b3e21649a06a8f95815318feaa8f07adbb sha256: "4f0adf20c9ccafcc02d71111fd91fba1ca7b17a7453902593e5a9b25b74a5c56"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.9" version: "1.2.0"
record_windows: record_windows:
dependency: transitive dependency: transitive
description: description:
@@ -2073,18 +2073,18 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: share_plus name: share_plus
sha256: b2961506569e28948d75ec346c28775bb111986bb69dc6a20754a457e3d97fa0 sha256: d7dc0630a923883c6328ca31b89aa682bacbf2f8304162d29f7c6aaff03a27a1
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "11.0.0" version: "11.1.0"
share_plus_platform_interface: share_plus_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: share_plus_platform_interface name: share_plus_platform_interface
sha256: "1032d392bc5d2095a77447a805aa3f804d2ae6a4d5eef5e6ebb3bd94c1bc19ef" sha256: "88023e53a13429bd65d8e85e11a9b484f49d4c190abbd96c7932b74d6927cc9a"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.0.0" version: "6.1.0"
shared_preferences: shared_preferences:
dependency: "direct main" dependency: "direct main"
description: description:
@@ -2206,10 +2206,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: source_helper name: source_helper
sha256: "4f81479fe5194a622cdd1713fe1ecb683a6e6c85cd8cec8e2e35ee5ab3fdf2a1" sha256: a447acb083d3a5ef17f983dd36201aeea33fedadb3228fa831f2f0c92f0f3aca
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.6" version: "1.3.7"
source_span: source_span:
dependency: transitive dependency: transitive
description: description:
@@ -2496,10 +2496,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_ios name: url_launcher_ios
sha256: "7f2022359d4c099eea7df3fdf739f7d3d3b9faf3166fb1dd390775176e0b76cb" sha256: d80b3f567a617cb923546034cc94bfe44eb15f989fe670b37f26abdb9d939cb7
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.3.3" version: "6.3.4"
url_launcher_linux: url_launcher_linux:
dependency: transitive dependency: transitive
description: description:
@@ -2512,10 +2512,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_macos name: url_launcher_macos
sha256: "17ba2000b847f334f16626a574c702b196723af2a289e7a93ffcb79acff855c2" sha256: c043a77d6600ac9c38300567f33ef12b0ef4f4783a2c1f00231d2b1941fea13f
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.2.2" version: "3.2.3"
url_launcher_platform_interface: url_launcher_platform_interface:
dependency: transitive dependency: transitive
description: description:
@@ -2568,10 +2568,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: vector_graphics_compiler name: vector_graphics_compiler
sha256: "557a315b7d2a6dbb0aaaff84d857967ce6bdc96a63dc6ee2a57ce5a6ee5d3331" sha256: ca81fdfaf62a5ab45d7296614aea108d2c7d0efca8393e96174bf4d51e6725b0
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.17" version: "1.1.18"
vector_math: vector_math:
dependency: transitive dependency: transitive
description: description:
@@ -2718,4 +2718,4 @@ packages:
version: "3.1.3" version: "3.1.3"
sdks: sdks:
dart: ">=3.8.0 <4.0.0" dart: ">=3.8.0 <4.0.0"
flutter: ">=3.29.0" flutter: ">=3.32.0"

View File

@@ -16,7 +16,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts # In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix. # of the product and file versions while build-number is used as the build suffix.
version: 3.2.0+124 version: 3.2.0+127
environment: environment:
sdk: ^3.7.2 sdk: ^3.7.2
@@ -36,7 +36,7 @@ dependencies:
# The following adds the Cupertino Icons font to your application. # The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons. # Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.8 cupertino_icons: ^1.0.8
flutter_hooks: ^0.21.2 flutter_hooks: ^0.21.3
hooks_riverpod: ^2.6.1 hooks_riverpod: ^2.6.1
bitsdojo_window: ^0.1.6 bitsdojo_window: ^0.1.6
go_router: ^16.1.0 go_router: ^16.1.0
@@ -67,16 +67,16 @@ dependencies:
easy_localization: ^3.0.8 easy_localization: ^3.0.8
flutter_inappwebview: ^6.1.5 flutter_inappwebview: ^6.1.5
animations: ^2.0.11 animations: ^2.0.11
package_info_plus: ^8.3.0 package_info_plus: ^8.3.1
device_info_plus: ^11.5.0 device_info_plus: ^11.5.0
tus_client_dart: tus_client_dart:
git: https://github.com/LittleSheep2Code/tus_client.git git: https://github.com/LittleSheep2Code/tus_client.git
cross_file: ^0.3.4+2 cross_file: ^0.3.4+2
image_picker: ^1.1.2 image_picker: ^1.2.0
file_picker: ^10.2.4 file_picker: ^10.3.1
riverpod_annotation: ^2.6.1 riverpod_annotation: ^2.6.1
image_picker_platform_interface: ^2.10.1 image_picker_platform_interface: ^2.11.0
image_picker_android: ^0.8.12+25 image_picker_android: ^0.8.13
super_context_menu: ^0.9.1 super_context_menu: ^0.9.1
modal_bottom_sheet: ^3.0.0 modal_bottom_sheet: ^3.0.0
firebase_messaging: ^16.0.0 firebase_messaging: ^16.0.0
@@ -107,7 +107,7 @@ dependencies:
livekit_client: ^2.5.0+hotfix.1 livekit_client: ^2.5.0+hotfix.1
pasteboard: ^0.4.0 pasteboard: ^0.4.0
flutter_colorpicker: ^1.1.0 flutter_colorpicker: ^1.1.0
record: ^6.0.0 record: ^6.1.0
qr_flutter: ^4.1.0 qr_flutter: ^4.1.0
flutter_otp_text_field: ^1.5.1+1 flutter_otp_text_field: ^1.5.1+1
palette_generator: ^0.3.3+7 palette_generator: ^0.3.3+7
@@ -121,7 +121,7 @@ dependencies:
local_auth: ^2.3.0 local_auth: ^2.3.0
flutter_secure_storage: ^9.2.4 flutter_secure_storage: ^9.2.4
flutter_math_fork: ^0.7.4 flutter_math_fork: ^0.7.4
share_plus: ^11.0.0 share_plus: ^11.1.0
receive_sharing_intent: ^1.8.1 receive_sharing_intent: ^1.8.1
top_snackbar_flutter: ^3.3.0 top_snackbar_flutter: ^3.3.0
textfield_tags: textfield_tags:

View File

@@ -1,19 +1,52 @@
[Setup] ; ==================================================
AppName=Solian #define AppVersion "3.2.0"
AppVersion=3.2.0 #define BuildNumber "124"
DefaultDirName={pf}\Solian ; ==================================================
DefaultGroupName=Solian
OutputDir=C:\Development\Solian\Installer
OutputBaseFilename=Solian
Compression=lzma
SolidCompression=yes
[Files] #define FullVersion AppVersion + "." + BuildNumber
Source: "C:\Development\Solian\build\windows\x64\runner\Release\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
[Icons] [Setup]
Name: "{group}\Solian"; Filename: "{app}\Solian.exe" AppName=Solian
Name: "{group}\Uninstall Solian"; Filename: "{uninstallexe}" AppVersion={#AppVersion}
AppPublisher=Solsynth
AppPublisherURL=https://solsynth.dev
AppSupportURL=https://kb.solsynth.dev/zh/solar-network
AppUpdatesURL=https://github.com/Solsynth/Solian/releases
AppCopyright=Copyright © 2025 Solsynth
VersionInfoVersion={#FullVersion}
UninstallDisplayName=Solian
UninstallDisplayIcon={app}\Solian.exe
[Run] DefaultDirName={commonpf}\Solian
Filename: "{app}\Solian.exe"; Description: "Launch Solian"; Flags: nowait postinstall skipifsilent UsePreviousAppDir=no
OutputDir=.\Installer
OutputBaseFilename=windows-x86_64-setup
SetupIconFile=.\assets\icons\icon.ico
Compression=lzma2/ultra64
SolidCompression=yes
LZMAUseSeparateProcess=yes
LZMANumBlockThreads=4
ArchitecturesAllowed=x64compatible
PrivilegesRequired=admin
[Files]
Source: ".\build\windows\x64\runner\Release\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
[Icons]
Name: "{group}\Solian"; Filename: "{app}\Solian.exe";IconFilename: "{app}\Solian.exe"
Name: "{group}\{cm:UninstallProgram,Solian}"; Filename: "{uninstallexe}"
Name: "{autodesktop}\Solian"; Filename: "{app}\Solian.exe"; Tasks: desktopicon
[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
[Run]
Filename: "{app}\Solian.exe"; Description: "Launch Solian"; Flags: nowait postinstall skipifsilent
[UninstallDelete]
Type: filesandordirs; Name: "{userappdata}\dev.solsynth\Solian"
Type: files; Name: "{group}\Solian.lnk" ;
Type: files; Name: "{autodesktop}\Solian.lnk" ;