Compare commits

..

39 Commits

Author SHA1 Message Date
188b6821a2 🚀 Launch 3.5.0+159 2026-01-02 20:46:18 +08:00
0ebbe0bd5a 💄 Optimize shuffle post 2026-01-02 20:34:09 +08:00
46a826ff86 👽 Update the articles url to new 2026-01-02 20:33:04 +08:00
1d99ac6441 💄 Adjust post detail screen 2026-01-02 19:57:16 +08:00
e2efdc4064 🐛 Fix chat input didn't count safe area 2026-01-02 19:27:17 +08:00
cba1a3884b 💄 Change EXIF info overlay alignment 2026-01-02 19:26:58 +08:00
7147ce1efa Better EXIF overlay 2026-01-02 19:22:47 +08:00
78c1a284a5 ♻️ Better image loading animation and more commonly used blurhash 2026-01-02 18:32:37 +08:00
f1f5113b01 💄 Swipe style post shuffle 2026-01-02 17:49:14 +08:00
a44552f105 🗑️ Remove unused activitypub screens 2026-01-02 17:02:04 +08:00
8c1ad94555 🐛 Fix route bug 2026-01-02 16:59:46 +08:00
84f5677260 🐛 Fix reference post displaying issue 2026-01-02 16:24:23 +08:00
aa1ffdbf10 ⬆️ Upgrade dependecies 2026-01-02 16:24:14 +08:00
c24d13461b 🐛 Fixes in chat subscribe 2026-01-02 16:14:55 +08:00
3b60fcb87c 💄 Optimize universal search 2026-01-02 16:14:24 +08:00
3605b997b1 💄 Optimize floating action button 2026-01-02 14:44:36 +08:00
800815c721 💄 Optimize unauthorized status 2026-01-02 14:33:41 +08:00
3b13a63e7b 💄 Optimize fediverse mention rendering, etc 2026-01-02 14:04:16 +08:00
81d69ce10f 🗑️ Remove unused stuff 2026-01-02 12:46:42 +08:00
c16d8a5912 🚀 Launch 3.5.0+158 (SNAPSHOT) 2026-01-02 03:13:37 +08:00
cb9eca0424 Better fediverse content 2026-01-02 03:08:50 +08:00
d7858bab67 🐛 Fix some bugs 2026-01-02 02:34:45 +08:00
5ce590029b 👽 Fix realm chat API didn't move 2026-01-02 00:15:32 +08:00
4d92dec45c 👽 Changes to API path since sphere no longer handle messages 2026-01-01 23:59:21 +08:00
0a4e797eec ♻️ Update the way to render total counts of data in UI, close #220 2026-01-01 11:44:10 +08:00
38dffa414f ♻️ Rebuilt fetching state machine 2026-01-01 11:40:28 +08:00
eea56a742e 🐛 Fix the paging refreshing issue 2026-01-01 11:10:04 +08:00
56b7ee1d69 🐛 Fix style mismatch 2026-01-01 02:44:25 +08:00
3b564f7e7f Able to render fediverse reactions (likes) 2026-01-01 02:37:05 +08:00
93d2670063 Able to manage publisher actor 2026-01-01 02:29:27 +08:00
788165ac5b 🐛 Fix poll feedback, close #224 2026-01-01 02:02:12 +08:00
ec71125fa9 Able to render offsite media 2026-01-01 02:00:09 +08:00
adb231278c Able to render fediverse posts 2026-01-01 01:47:09 +08:00
b3ae4ab36f 👽 Update the models to match API 2025-12-31 01:43:23 +08:00
3670fe0f10 👽 Update according to AP api changes 2025-12-29 01:43:00 +08:00
bb1a5155ed ActivityPub service impl basis 2025-12-29 01:01:47 +08:00
eb90dbbc5a 🐛 Fix fab 2025-12-28 17:19:27 +08:00
a73d9f8ec0 ♻️ Improve file viewing experience 2025-12-28 15:32:00 +08:00
4c8f2e3251 🐛 Fix tabs padding cause background color missing, close #221 2025-12-28 14:10:42 +08:00
194 changed files with 9086 additions and 9299 deletions

View File

@@ -255,6 +255,24 @@
"walletCurrencyShortGolds": "NSD",
"retry": "Retry",
"creatorHubUnselectedHint": "Pick / create a publisher to get started.",
"publisherFediverse": "Fediverse Actor",
"publisherFediverseDescription": "Configure your publisher's ActivityPub actor for federated social networking",
"publisherFediverseEnabled": "Enabled",
"publisherFediverseDisabled": "Disabled",
"publisherFediverseNotConfigured": "Not configured",
"publisherFediverseEnableHint": "Enable your publisher to interact with fediverse",
"publisherFediverseDisableHint": "Disable your publisher's fediverse actor",
"publisherFediverseEnableConfirm": "Enable fediverse actor?",
"publisherFediverseDisableConfirm": "Disable fediverse actor?",
"publisherFediverseEnabledSuccess": "Fediverse actor enabled successfully",
"publisherFediverseDisabledSuccess": "Fediverse actor disabled successfully",
"publisherFediverseFailedToEnable": "Failed to enable fediverse actor",
"publisherFediverseFailedToDisable": "Failed to disable fediverse actor",
"publisherFediverseWhatIs": "What is Fediverse?",
"publisherFediverseAbout": "The fediverse is a federated network of social platforms. Enabling this feature allows your publisher to interact with users across different ActivityPub-compatible services like Mastodon, PeerTube, and more.",
"publisherFediverseActorUri": "Actor URI",
"publisherFediverseFollowerCount": "Followers",
"publisherFediverseNoFollowers": "No followers yet",
"relationships": "Relationships",
"addFriend": "Send a Friend Request",
"addFriendShort": "Add as Friend",
@@ -340,7 +358,7 @@
"accountSettingsHelp": "Account Settings Help",
"accountSettingsHelpContent": "This page allows you to manage your account security, privacy, and other settings. If you need assistance, please contact support.",
"unauthorized": "Unauthorized",
"unauthorizedHint": "You're not signed in or session expired, please sign in again.",
"unauthorizedHint": "You're not signed in or session expired, please sign in and try again.",
"publisherBelongsTo": "Belongs to {}",
"postContent": "Content",
"postSettings": "Settings",
@@ -906,6 +924,7 @@
"fileHash": "File Hash",
"exifData": "EXIF Data",
"postShuffle": "Shuffle Posts",
"swipeToExplore": "Swipe to explore",
"leveling": "Leveling",
"levelingHistory": "Leveling History",
"stellarProgram": "Stellar Program",
@@ -1546,5 +1565,24 @@
"embedLinks": {
"one": "{} link",
"other": "{} links"
}
},
"searchFediverse": "Search Fediverse",
"searchFediverseHint": "Search by address, e.g. {}",
"searchFediverseEmpty": "Search for users on other ActivityPub instances",
"searchFediverseNoResults": "No users found for this search",
"fediverseUsers": "Fediverse Users",
"following": "Following",
"followers": "Followers",
"follow": "Follow",
"unfollow": "Unfollow",
"followedUser": "Followed @{}",
"unfollowedUser": "Unfollowed @{}",
"followingEmpty": "You're not following anyone yet",
"followersEmpty": "No followers yet",
"followingEmptyHint": "Start by searching for users or explore other instances",
"fediversePost": "Fediverse Post",
"fediversePostDescribe": "Post from the Fediverse Network",
"settingsShowFediverseContent": "Show Fediverse Content",
"universalSearch": "Universal Search",
"universalSearchDescription": "Search content across the Solar Network and the fediverse network."
}

View File

@@ -34,7 +34,7 @@ class NotifyDelegate: UIResponder, UNUserNotificationCenterDelegate {
}
let serverUrl = UserDefaults.standard.getServerUrl()
let url = "\(serverUrl)/sphere/chat/\(metadata["room_id"] ?? "")/messages"
let url = "\(serverUrl)/messager/chat/\(metadata["room_id"] ?? "")/messages"
let parameters: [String: Any?] = [
"content": textResponse.userText,

View File

@@ -261,7 +261,7 @@ class NetworkService {
guard let baseURL = URL(string: serverUrl) else {
throw URLError(.badURL)
}
let url = baseURL.appendingPathComponent("/sphere/chat")
let url = baseURL.appendingPathComponent("/messager/chat")
var request = URLRequest(url: url)
request.httpMethod = "GET"
@@ -283,7 +283,7 @@ class NetworkService {
guard let baseURL = URL(string: serverUrl) else {
throw URLError(.badURL)
}
let url = baseURL.appendingPathComponent("/sphere/chat/\(identifier)")
let url = baseURL.appendingPathComponent("/messager/chat/\(identifier)")
var request = URLRequest(url: url)
request.httpMethod = "GET"
@@ -308,7 +308,7 @@ class NetworkService {
guard let baseURL = URL(string: serverUrl) else {
throw URLError(.badURL)
}
let url = baseURL.appendingPathComponent("/sphere/chat/invites")
let url = baseURL.appendingPathComponent("/messager/chat/invites")
var request = URLRequest(url: url)
request.httpMethod = "GET"
@@ -330,7 +330,7 @@ class NetworkService {
guard let baseURL = URL(string: serverUrl) else {
throw URLError(.badURL)
}
let url = baseURL.appendingPathComponent("/sphere/chat/invites/\(chatRoomId)/accept")
let url = baseURL.appendingPathComponent("/messager/chat/invites/\(chatRoomId)/accept")
var request = URLRequest(url: url)
request.httpMethod = "POST"
@@ -351,7 +351,7 @@ class NetworkService {
guard let baseURL = URL(string: serverUrl) else {
throw URLError(.badURL)
}
let url = baseURL.appendingPathComponent("/sphere/chat/invites/\(chatRoomId)/decline")
let url = baseURL.appendingPathComponent("/messager/chat/invites/\(chatRoomId)/decline")
var request = URLRequest(url: url)
request.httpMethod = "POST"
@@ -375,9 +375,9 @@ class NetworkService {
throw URLError(.badURL)
}
// Try a different pattern: /sphere/chat/messages with roomId as query param
// Try a different pattern: /messager/chat/messages with roomId as query param
var components = URLComponents(
url: baseURL.appendingPathComponent("/sphere/chat/\(chatRoomId)/messages"),
url: baseURL.appendingPathComponent("/messager/chat/\(chatRoomId)/messages"),
resolvingAgainstBaseURL: false
)!
var queryItems = [

View File

@@ -455,7 +455,7 @@ struct ChatRoomView: View {
]
// Create the URL
guard let url = URL(string: "\(serverUrl)/sphere/chat/\(room.id)/messages") else {
guard let url = URL(string: "\(serverUrl)/messager/chat/\(room.id)/messages") else {
throw URLError(.badURL)
}

108
lib/models/activitypub.dart Normal file
View File

@@ -0,0 +1,108 @@
import 'package:freezed_annotation/freezed_annotation.dart';
part 'activitypub.freezed.dart';
part 'activitypub.g.dart';
@freezed
sealed class SnActivityPubInstance with _$SnActivityPubInstance {
const factory SnActivityPubInstance({
required String id,
required String domain,
String? name,
String? description,
String? software,
String? version,
String? iconUrl,
String? thumbnailUrl,
String? contactEmail,
String? contactAccountUsername,
int? activeUsers,
@Default(false) bool isBlocked,
@Default(false) bool isSilenced,
String? blockReason,
Map<String, dynamic>? metadata,
DateTime? lastFetchedAt,
DateTime? lastActivityAt,
DateTime? metadataFetchedAt,
}) = _SnActivityPubInstance;
factory SnActivityPubInstance.fromJson(Map<String, dynamic> json) =>
_$SnActivityPubInstanceFromJson(json);
}
@freezed
sealed class SnActivityPubUser with _$SnActivityPubUser {
const factory SnActivityPubUser({
required String actorUri,
required String username,
required String displayName,
required String bio,
required String avatarUrl,
required DateTime followedAt,
required bool isLocal,
required String instanceDomain,
}) = _SnActivityPubUser;
factory SnActivityPubUser.fromJson(Map<String, dynamic> json) =>
_$SnActivityPubUserFromJson(json);
}
@freezed
sealed class SnActivityPubActor with _$SnActivityPubActor {
const factory SnActivityPubActor({
required String id,
required String uri,
@Default('') String type,
String? displayName,
String? username,
String? summary,
String? inboxUri,
String? outboxUri,
String? followersUri,
String? followingUri,
String? featuredUri,
String? avatarUrl,
String? headerUrl,
String? publicKeyId,
String? publicKey,
@Default(false) bool isBot,
@Default(false) bool isLocked,
@Default(true) bool discoverable,
@Default(false) bool manuallyApprovesFollowers,
Map<String, dynamic>? endpoints,
Map<String, dynamic>? publicKeyData,
Map<String, dynamic>? metadata,
DateTime? lastFetchedAt,
DateTime? lastActivityAt,
required SnActivityPubInstance instance,
required String instanceId,
bool? isFollowing,
}) = _SnActivityPubActor;
factory SnActivityPubActor.fromJson(Map<String, dynamic> json) =>
_$SnActivityPubActorFromJson(json);
}
@freezed
sealed class SnActivityPubFollowResponse with _$SnActivityPubFollowResponse {
const factory SnActivityPubFollowResponse({
required bool success,
required String message,
}) = _SnActivityPubFollowResponse;
factory SnActivityPubFollowResponse.fromJson(Map<String, dynamic> json) =>
_$SnActivityPubFollowResponseFromJson(json);
}
@freezed
sealed class SnActorStatusResponse with _$SnActorStatusResponse {
const factory SnActorStatusResponse({
required bool enabled,
@Default(0) int followerCount,
SnActivityPubActor? actor,
String? actorUri,
}) = _SnActorStatusResponse;
factory SnActorStatusResponse.fromJson(Map<String, dynamic> json) =>
_$SnActorStatusResponseFromJson(json);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,186 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'activitypub.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_SnActivityPubInstance _$SnActivityPubInstanceFromJson(
Map<String, dynamic> json,
) => _SnActivityPubInstance(
id: json['id'] as String,
domain: json['domain'] as String,
name: json['name'] as String?,
description: json['description'] as String?,
software: json['software'] as String?,
version: json['version'] as String?,
iconUrl: json['icon_url'] as String?,
thumbnailUrl: json['thumbnail_url'] as String?,
contactEmail: json['contact_email'] as String?,
contactAccountUsername: json['contact_account_username'] as String?,
activeUsers: (json['active_users'] as num?)?.toInt(),
isBlocked: json['is_blocked'] as bool? ?? false,
isSilenced: json['is_silenced'] as bool? ?? false,
blockReason: json['block_reason'] as String?,
metadata: json['metadata'] as Map<String, dynamic>?,
lastFetchedAt: json['last_fetched_at'] == null
? null
: DateTime.parse(json['last_fetched_at'] as String),
lastActivityAt: json['last_activity_at'] == null
? null
: DateTime.parse(json['last_activity_at'] as String),
metadataFetchedAt: json['metadata_fetched_at'] == null
? null
: DateTime.parse(json['metadata_fetched_at'] as String),
);
Map<String, dynamic> _$SnActivityPubInstanceToJson(
_SnActivityPubInstance instance,
) => <String, dynamic>{
'id': instance.id,
'domain': instance.domain,
'name': instance.name,
'description': instance.description,
'software': instance.software,
'version': instance.version,
'icon_url': instance.iconUrl,
'thumbnail_url': instance.thumbnailUrl,
'contact_email': instance.contactEmail,
'contact_account_username': instance.contactAccountUsername,
'active_users': instance.activeUsers,
'is_blocked': instance.isBlocked,
'is_silenced': instance.isSilenced,
'block_reason': instance.blockReason,
'metadata': instance.metadata,
'last_fetched_at': instance.lastFetchedAt?.toIso8601String(),
'last_activity_at': instance.lastActivityAt?.toIso8601String(),
'metadata_fetched_at': instance.metadataFetchedAt?.toIso8601String(),
};
_SnActivityPubUser _$SnActivityPubUserFromJson(Map<String, dynamic> json) =>
_SnActivityPubUser(
actorUri: json['actor_uri'] as String,
username: json['username'] as String,
displayName: json['display_name'] as String,
bio: json['bio'] as String,
avatarUrl: json['avatar_url'] as String,
followedAt: DateTime.parse(json['followed_at'] as String),
isLocal: json['is_local'] as bool,
instanceDomain: json['instance_domain'] as String,
);
Map<String, dynamic> _$SnActivityPubUserToJson(_SnActivityPubUser instance) =>
<String, dynamic>{
'actor_uri': instance.actorUri,
'username': instance.username,
'display_name': instance.displayName,
'bio': instance.bio,
'avatar_url': instance.avatarUrl,
'followed_at': instance.followedAt.toIso8601String(),
'is_local': instance.isLocal,
'instance_domain': instance.instanceDomain,
};
_SnActivityPubActor _$SnActivityPubActorFromJson(Map<String, dynamic> json) =>
_SnActivityPubActor(
id: json['id'] as String,
uri: json['uri'] as String,
type: json['type'] as String? ?? '',
displayName: json['display_name'] as String?,
username: json['username'] as String?,
summary: json['summary'] as String?,
inboxUri: json['inbox_uri'] as String?,
outboxUri: json['outbox_uri'] as String?,
followersUri: json['followers_uri'] as String?,
followingUri: json['following_uri'] as String?,
featuredUri: json['featured_uri'] as String?,
avatarUrl: json['avatar_url'] as String?,
headerUrl: json['header_url'] as String?,
publicKeyId: json['public_key_id'] as String?,
publicKey: json['public_key'] as String?,
isBot: json['is_bot'] as bool? ?? false,
isLocked: json['is_locked'] as bool? ?? false,
discoverable: json['discoverable'] as bool? ?? true,
manuallyApprovesFollowers:
json['manually_approves_followers'] as bool? ?? false,
endpoints: json['endpoints'] as Map<String, dynamic>?,
publicKeyData: json['public_key_data'] as Map<String, dynamic>?,
metadata: json['metadata'] as Map<String, dynamic>?,
lastFetchedAt: json['last_fetched_at'] == null
? null
: DateTime.parse(json['last_fetched_at'] as String),
lastActivityAt: json['last_activity_at'] == null
? null
: DateTime.parse(json['last_activity_at'] as String),
instance: SnActivityPubInstance.fromJson(
json['instance'] as Map<String, dynamic>,
),
instanceId: json['instance_id'] as String,
isFollowing: json['is_following'] as bool?,
);
Map<String, dynamic> _$SnActivityPubActorToJson(_SnActivityPubActor instance) =>
<String, dynamic>{
'id': instance.id,
'uri': instance.uri,
'type': instance.type,
'display_name': instance.displayName,
'username': instance.username,
'summary': instance.summary,
'inbox_uri': instance.inboxUri,
'outbox_uri': instance.outboxUri,
'followers_uri': instance.followersUri,
'following_uri': instance.followingUri,
'featured_uri': instance.featuredUri,
'avatar_url': instance.avatarUrl,
'header_url': instance.headerUrl,
'public_key_id': instance.publicKeyId,
'public_key': instance.publicKey,
'is_bot': instance.isBot,
'is_locked': instance.isLocked,
'discoverable': instance.discoverable,
'manually_approves_followers': instance.manuallyApprovesFollowers,
'endpoints': instance.endpoints,
'public_key_data': instance.publicKeyData,
'metadata': instance.metadata,
'last_fetched_at': instance.lastFetchedAt?.toIso8601String(),
'last_activity_at': instance.lastActivityAt?.toIso8601String(),
'instance': instance.instance.toJson(),
'instance_id': instance.instanceId,
'is_following': instance.isFollowing,
};
_SnActivityPubFollowResponse _$SnActivityPubFollowResponseFromJson(
Map<String, dynamic> json,
) => _SnActivityPubFollowResponse(
success: json['success'] as bool,
message: json['message'] as String,
);
Map<String, dynamic> _$SnActivityPubFollowResponseToJson(
_SnActivityPubFollowResponse instance,
) => <String, dynamic>{
'success': instance.success,
'message': instance.message,
};
_SnActorStatusResponse _$SnActorStatusResponseFromJson(
Map<String, dynamic> json,
) => _SnActorStatusResponse(
enabled: json['enabled'] as bool,
followerCount: (json['follower_count'] as num?)?.toInt() ?? 0,
actor: json['actor'] == null
? null
: SnActivityPubActor.fromJson(json['actor'] as Map<String, dynamic>),
actorUri: json['actor_uri'] as String?,
);
Map<String, dynamic> _$SnActorStatusResponseToJson(
_SnActorStatusResponse instance,
) => <String, dynamic>{
'enabled': instance.enabled,
'follower_count': instance.followerCount,
'actor': instance.actor?.toJson(),
'actor_uri': instance.actorUri,
};

View File

@@ -55,6 +55,7 @@ sealed class SnCloudFile with _$SnCloudFile {
required DateTime createdAt,
required DateTime updatedAt,
required DateTime? deletedAt,
String? url,
}) = _SnCloudFile;
factory SnCloudFile.fromJson(Map<String, dynamic> json) =>

View File

@@ -281,7 +281,7 @@ as String?,
/// @nodoc
mixin _$SnCloudFile {
String get id; String get name; String? get description; Map<String, dynamic>? get fileMeta; Map<String, dynamic>? get userMeta; SnFilePool? get pool; List<int> get sensitiveMarks; String? get mimeType; String? get hash; int get size; DateTime? get uploadedAt; String? get uploadedTo; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt;
String get id; String get name; String? get description; Map<String, dynamic>? get fileMeta; Map<String, dynamic>? get userMeta; SnFilePool? get pool; List<int> get sensitiveMarks; String? get mimeType; String? get hash; int get size; DateTime? get uploadedAt; String? get uploadedTo; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt; String? get url;
/// Create a copy of SnCloudFile
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@@ -294,16 +294,16 @@ $SnCloudFileCopyWith<SnCloudFile> get copyWith => _$SnCloudFileCopyWithImpl<SnCl
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnCloudFile&&(identical(other.id, id) || other.id == id)&&(identical(other.name, name) || other.name == name)&&(identical(other.description, description) || other.description == description)&&const DeepCollectionEquality().equals(other.fileMeta, fileMeta)&&const DeepCollectionEquality().equals(other.userMeta, userMeta)&&(identical(other.pool, pool) || other.pool == pool)&&const DeepCollectionEquality().equals(other.sensitiveMarks, sensitiveMarks)&&(identical(other.mimeType, mimeType) || other.mimeType == mimeType)&&(identical(other.hash, hash) || other.hash == hash)&&(identical(other.size, size) || other.size == size)&&(identical(other.uploadedAt, uploadedAt) || other.uploadedAt == uploadedAt)&&(identical(other.uploadedTo, uploadedTo) || other.uploadedTo == uploadedTo)&&(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 SnCloudFile&&(identical(other.id, id) || other.id == id)&&(identical(other.name, name) || other.name == name)&&(identical(other.description, description) || other.description == description)&&const DeepCollectionEquality().equals(other.fileMeta, fileMeta)&&const DeepCollectionEquality().equals(other.userMeta, userMeta)&&(identical(other.pool, pool) || other.pool == pool)&&const DeepCollectionEquality().equals(other.sensitiveMarks, sensitiveMarks)&&(identical(other.mimeType, mimeType) || other.mimeType == mimeType)&&(identical(other.hash, hash) || other.hash == hash)&&(identical(other.size, size) || other.size == size)&&(identical(other.uploadedAt, uploadedAt) || other.uploadedAt == uploadedAt)&&(identical(other.uploadedTo, uploadedTo) || other.uploadedTo == uploadedTo)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.url, url) || other.url == url));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,id,name,description,const DeepCollectionEquality().hash(fileMeta),const DeepCollectionEquality().hash(userMeta),pool,const DeepCollectionEquality().hash(sensitiveMarks),mimeType,hash,size,uploadedAt,uploadedTo,createdAt,updatedAt,deletedAt);
int get hashCode => Object.hash(runtimeType,id,name,description,const DeepCollectionEquality().hash(fileMeta),const DeepCollectionEquality().hash(userMeta),pool,const DeepCollectionEquality().hash(sensitiveMarks),mimeType,hash,size,uploadedAt,uploadedTo,createdAt,updatedAt,deletedAt,url);
@override
String toString() {
return 'SnCloudFile(id: $id, name: $name, description: $description, fileMeta: $fileMeta, userMeta: $userMeta, pool: $pool, sensitiveMarks: $sensitiveMarks, mimeType: $mimeType, hash: $hash, size: $size, uploadedAt: $uploadedAt, uploadedTo: $uploadedTo, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)';
return 'SnCloudFile(id: $id, name: $name, description: $description, fileMeta: $fileMeta, userMeta: $userMeta, pool: $pool, sensitiveMarks: $sensitiveMarks, mimeType: $mimeType, hash: $hash, size: $size, uploadedAt: $uploadedAt, uploadedTo: $uploadedTo, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, url: $url)';
}
@@ -314,7 +314,7 @@ abstract mixin class $SnCloudFileCopyWith<$Res> {
factory $SnCloudFileCopyWith(SnCloudFile value, $Res Function(SnCloudFile) _then) = _$SnCloudFileCopyWithImpl;
@useResult
$Res call({
String id, String name, String? description, Map<String, dynamic>? fileMeta, Map<String, dynamic>? userMeta, SnFilePool? pool, List<int> sensitiveMarks, String? mimeType, String? hash, int size, DateTime? uploadedAt, String? uploadedTo, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt
String id, String name, String? description, Map<String, dynamic>? fileMeta, Map<String, dynamic>? userMeta, SnFilePool? pool, List<int> sensitiveMarks, String? mimeType, String? hash, int size, DateTime? uploadedAt, String? uploadedTo, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, String? url
});
@@ -331,7 +331,7 @@ class _$SnCloudFileCopyWithImpl<$Res>
/// Create a copy of SnCloudFile
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? name = null,Object? description = freezed,Object? fileMeta = freezed,Object? userMeta = freezed,Object? pool = freezed,Object? sensitiveMarks = null,Object? mimeType = freezed,Object? hash = freezed,Object? size = null,Object? uploadedAt = freezed,Object? uploadedTo = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) {
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? name = null,Object? description = freezed,Object? fileMeta = freezed,Object? userMeta = freezed,Object? pool = freezed,Object? sensitiveMarks = null,Object? mimeType = freezed,Object? hash = freezed,Object? size = null,Object? uploadedAt = freezed,Object? uploadedTo = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,Object? url = freezed,}) {
return _then(_self.copyWith(
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
as String,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable
@@ -348,7 +348,8 @@ as DateTime?,uploadedTo: freezed == uploadedTo ? _self.uploadedTo : uploadedTo /
as String?,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,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable
as DateTime?,
as DateTime?,url: freezed == url ? _self.url : url // ignore: cast_nullable_to_non_nullable
as String?,
));
}
/// Create a copy of SnCloudFile
@@ -442,10 +443,10 @@ return $default(_that);case _:
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String name, String? description, Map<String, dynamic>? fileMeta, Map<String, dynamic>? userMeta, SnFilePool? pool, List<int> sensitiveMarks, String? mimeType, String? hash, int size, DateTime? uploadedAt, String? uploadedTo, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,{required TResult orElse(),}) {final _that = this;
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String name, String? description, Map<String, dynamic>? fileMeta, Map<String, dynamic>? userMeta, SnFilePool? pool, List<int> sensitiveMarks, String? mimeType, String? hash, int size, DateTime? uploadedAt, String? uploadedTo, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, String? url)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _SnCloudFile() when $default != null:
return $default(_that.id,_that.name,_that.description,_that.fileMeta,_that.userMeta,_that.pool,_that.sensitiveMarks,_that.mimeType,_that.hash,_that.size,_that.uploadedAt,_that.uploadedTo,_that.createdAt,_that.updatedAt,_that.deletedAt);case _:
return $default(_that.id,_that.name,_that.description,_that.fileMeta,_that.userMeta,_that.pool,_that.sensitiveMarks,_that.mimeType,_that.hash,_that.size,_that.uploadedAt,_that.uploadedTo,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.url);case _:
return orElse();
}
@@ -463,10 +464,10 @@ return $default(_that.id,_that.name,_that.description,_that.fileMeta,_that.userM
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String name, String? description, Map<String, dynamic>? fileMeta, Map<String, dynamic>? userMeta, SnFilePool? pool, List<int> sensitiveMarks, String? mimeType, String? hash, int size, DateTime? uploadedAt, String? uploadedTo, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt) $default,) {final _that = this;
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String name, String? description, Map<String, dynamic>? fileMeta, Map<String, dynamic>? userMeta, SnFilePool? pool, List<int> sensitiveMarks, String? mimeType, String? hash, int size, DateTime? uploadedAt, String? uploadedTo, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, String? url) $default,) {final _that = this;
switch (_that) {
case _SnCloudFile():
return $default(_that.id,_that.name,_that.description,_that.fileMeta,_that.userMeta,_that.pool,_that.sensitiveMarks,_that.mimeType,_that.hash,_that.size,_that.uploadedAt,_that.uploadedTo,_that.createdAt,_that.updatedAt,_that.deletedAt);}
return $default(_that.id,_that.name,_that.description,_that.fileMeta,_that.userMeta,_that.pool,_that.sensitiveMarks,_that.mimeType,_that.hash,_that.size,_that.uploadedAt,_that.uploadedTo,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.url);}
}
/// A variant of `when` that fallback to returning `null`
///
@@ -480,10 +481,10 @@ return $default(_that.id,_that.name,_that.description,_that.fileMeta,_that.userM
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String name, String? description, Map<String, dynamic>? fileMeta, Map<String, dynamic>? userMeta, SnFilePool? pool, List<int> sensitiveMarks, String? mimeType, String? hash, int size, DateTime? uploadedAt, String? uploadedTo, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,) {final _that = this;
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String name, String? description, Map<String, dynamic>? fileMeta, Map<String, dynamic>? userMeta, SnFilePool? pool, List<int> sensitiveMarks, String? mimeType, String? hash, int size, DateTime? uploadedAt, String? uploadedTo, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, String? url)? $default,) {final _that = this;
switch (_that) {
case _SnCloudFile() when $default != null:
return $default(_that.id,_that.name,_that.description,_that.fileMeta,_that.userMeta,_that.pool,_that.sensitiveMarks,_that.mimeType,_that.hash,_that.size,_that.uploadedAt,_that.uploadedTo,_that.createdAt,_that.updatedAt,_that.deletedAt);case _:
return $default(_that.id,_that.name,_that.description,_that.fileMeta,_that.userMeta,_that.pool,_that.sensitiveMarks,_that.mimeType,_that.hash,_that.size,_that.uploadedAt,_that.uploadedTo,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.url);case _:
return null;
}
@@ -495,7 +496,7 @@ return $default(_that.id,_that.name,_that.description,_that.fileMeta,_that.userM
@JsonSerializable()
class _SnCloudFile implements SnCloudFile {
const _SnCloudFile({required this.id, required this.name, required this.description, required final Map<String, dynamic>? fileMeta, required final Map<String, dynamic>? userMeta, required this.pool, final List<int> sensitiveMarks = const [], required this.mimeType, required this.hash, required this.size, required this.uploadedAt, required this.uploadedTo, required this.createdAt, required this.updatedAt, required this.deletedAt}): _fileMeta = fileMeta,_userMeta = userMeta,_sensitiveMarks = sensitiveMarks;
const _SnCloudFile({required this.id, required this.name, required this.description, required final Map<String, dynamic>? fileMeta, required final Map<String, dynamic>? userMeta, required this.pool, final List<int> sensitiveMarks = const [], required this.mimeType, required this.hash, required this.size, required this.uploadedAt, required this.uploadedTo, required this.createdAt, required this.updatedAt, required this.deletedAt, this.url}): _fileMeta = fileMeta,_userMeta = userMeta,_sensitiveMarks = sensitiveMarks;
factory _SnCloudFile.fromJson(Map<String, dynamic> json) => _$SnCloudFileFromJson(json);
@override final String id;
@@ -535,6 +536,7 @@ class _SnCloudFile implements SnCloudFile {
@override final DateTime createdAt;
@override final DateTime updatedAt;
@override final DateTime? deletedAt;
@override final String? url;
/// Create a copy of SnCloudFile
/// with the given fields replaced by the non-null parameter values.
@@ -549,16 +551,16 @@ Map<String, dynamic> toJson() {
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnCloudFile&&(identical(other.id, id) || other.id == id)&&(identical(other.name, name) || other.name == name)&&(identical(other.description, description) || other.description == description)&&const DeepCollectionEquality().equals(other._fileMeta, _fileMeta)&&const DeepCollectionEquality().equals(other._userMeta, _userMeta)&&(identical(other.pool, pool) || other.pool == pool)&&const DeepCollectionEquality().equals(other._sensitiveMarks, _sensitiveMarks)&&(identical(other.mimeType, mimeType) || other.mimeType == mimeType)&&(identical(other.hash, hash) || other.hash == hash)&&(identical(other.size, size) || other.size == size)&&(identical(other.uploadedAt, uploadedAt) || other.uploadedAt == uploadedAt)&&(identical(other.uploadedTo, uploadedTo) || other.uploadedTo == uploadedTo)&&(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 _SnCloudFile&&(identical(other.id, id) || other.id == id)&&(identical(other.name, name) || other.name == name)&&(identical(other.description, description) || other.description == description)&&const DeepCollectionEquality().equals(other._fileMeta, _fileMeta)&&const DeepCollectionEquality().equals(other._userMeta, _userMeta)&&(identical(other.pool, pool) || other.pool == pool)&&const DeepCollectionEquality().equals(other._sensitiveMarks, _sensitiveMarks)&&(identical(other.mimeType, mimeType) || other.mimeType == mimeType)&&(identical(other.hash, hash) || other.hash == hash)&&(identical(other.size, size) || other.size == size)&&(identical(other.uploadedAt, uploadedAt) || other.uploadedAt == uploadedAt)&&(identical(other.uploadedTo, uploadedTo) || other.uploadedTo == uploadedTo)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.url, url) || other.url == url));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,id,name,description,const DeepCollectionEquality().hash(_fileMeta),const DeepCollectionEquality().hash(_userMeta),pool,const DeepCollectionEquality().hash(_sensitiveMarks),mimeType,hash,size,uploadedAt,uploadedTo,createdAt,updatedAt,deletedAt);
int get hashCode => Object.hash(runtimeType,id,name,description,const DeepCollectionEquality().hash(_fileMeta),const DeepCollectionEquality().hash(_userMeta),pool,const DeepCollectionEquality().hash(_sensitiveMarks),mimeType,hash,size,uploadedAt,uploadedTo,createdAt,updatedAt,deletedAt,url);
@override
String toString() {
return 'SnCloudFile(id: $id, name: $name, description: $description, fileMeta: $fileMeta, userMeta: $userMeta, pool: $pool, sensitiveMarks: $sensitiveMarks, mimeType: $mimeType, hash: $hash, size: $size, uploadedAt: $uploadedAt, uploadedTo: $uploadedTo, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)';
return 'SnCloudFile(id: $id, name: $name, description: $description, fileMeta: $fileMeta, userMeta: $userMeta, pool: $pool, sensitiveMarks: $sensitiveMarks, mimeType: $mimeType, hash: $hash, size: $size, uploadedAt: $uploadedAt, uploadedTo: $uploadedTo, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, url: $url)';
}
@@ -569,7 +571,7 @@ abstract mixin class _$SnCloudFileCopyWith<$Res> implements $SnCloudFileCopyWith
factory _$SnCloudFileCopyWith(_SnCloudFile value, $Res Function(_SnCloudFile) _then) = __$SnCloudFileCopyWithImpl;
@override @useResult
$Res call({
String id, String name, String? description, Map<String, dynamic>? fileMeta, Map<String, dynamic>? userMeta, SnFilePool? pool, List<int> sensitiveMarks, String? mimeType, String? hash, int size, DateTime? uploadedAt, String? uploadedTo, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt
String id, String name, String? description, Map<String, dynamic>? fileMeta, Map<String, dynamic>? userMeta, SnFilePool? pool, List<int> sensitiveMarks, String? mimeType, String? hash, int size, DateTime? uploadedAt, String? uploadedTo, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt, String? url
});
@@ -586,7 +588,7 @@ class __$SnCloudFileCopyWithImpl<$Res>
/// Create a copy of SnCloudFile
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? name = null,Object? description = freezed,Object? fileMeta = freezed,Object? userMeta = freezed,Object? pool = freezed,Object? sensitiveMarks = null,Object? mimeType = freezed,Object? hash = freezed,Object? size = null,Object? uploadedAt = freezed,Object? uploadedTo = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) {
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? name = null,Object? description = freezed,Object? fileMeta = freezed,Object? userMeta = freezed,Object? pool = freezed,Object? sensitiveMarks = null,Object? mimeType = freezed,Object? hash = freezed,Object? size = null,Object? uploadedAt = freezed,Object? uploadedTo = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,Object? url = freezed,}) {
return _then(_SnCloudFile(
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
as String,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable
@@ -603,7 +605,8 @@ as DateTime?,uploadedTo: freezed == uploadedTo ? _self.uploadedTo : uploadedTo /
as String?,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,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable
as DateTime?,
as DateTime?,url: freezed == url ? _self.url : url // ignore: cast_nullable_to_non_nullable
as String?,
));
}

View File

@@ -55,6 +55,7 @@ _SnCloudFile _$SnCloudFileFromJson(Map<String, dynamic> json) => _SnCloudFile(
deletedAt: json['deleted_at'] == null
? null
: DateTime.parse(json['deleted_at'] as String),
url: json['url'] as String?,
);
Map<String, dynamic> _$SnCloudFileToJson(_SnCloudFile instance) =>
@@ -74,6 +75,7 @@ Map<String, dynamic> _$SnCloudFileToJson(_SnCloudFile instance) =>
'created_at': instance.createdAt.toIso8601String(),
'updated_at': instance.updatedAt.toIso8601String(),
'deleted_at': instance.deletedAt?.toIso8601String(),
'url': instance.url,
};
_SnCloudFileIndex _$SnCloudFileIndexFromJson(Map<String, dynamic> json) =>

View File

@@ -1,5 +1,6 @@
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:island/models/account.dart';
import 'package:island/models/activitypub.dart';
import 'package:island/models/file.dart';
import 'package:island/models/post_category.dart';
import 'package:island/models/post_tag.dart';
@@ -39,8 +40,14 @@ sealed class SnPost with _$SnPost {
SnPost? forwardedPost,
String? realmId,
SnRealm? realm,
String? publisherId,
SnPublisher? publisher,
String? actorid,
SnActivityPubActor? actor,
String? fediverseUri,
int? fediverseType,
@Default(0) int contentType,
@Default([]) List<SnCloudFile> attachments,
required SnPublisher publisher,
@Default({}) Map<String, int> reactionsCount,
@Default({}) Map<String, bool> reactionsMade,
@Default([]) List<dynamic> reactions,
@@ -155,10 +162,12 @@ sealed class SnPostReaction with _$SnPostReaction {
required String symbol,
required int attitude,
required String postId,
required String accountId,
required DateTime createdAt,
required DateTime updatedAt,
@Default(null) SnAccount? account,
String? actorId,
SnActivityPubActor? actor,
String? accountId,
SnAccount? account,
DateTime? deletedAt,
}) = _SnPostReaction;

View File

@@ -15,7 +15,7 @@ T _$identity<T>(T value) => value;
/// @nodoc
mixin _$SnPost {
String get id; String? get title; String? get description; String? get language; DateTime? get editedAt; DateTime? get publishedAt; int get visibility; String? get content; String? get slug; int get type; Map<String, dynamic>? get meta; SnPostEmbedView? get embedView; int get viewsUnique; int get viewsTotal; int get upvotes; int get downvotes; int get repliesCount; int get awardedScore; int? get pinMode; 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; List<SnPostFeaturedRecord> get featuredRecords; DateTime? get createdAt; DateTime? get updatedAt; DateTime? get deletedAt; bool get repliedGone; bool get forwardedGone; 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; SnPostEmbedView? get embedView; int get viewsUnique; int get viewsTotal; int get upvotes; int get downvotes; int get repliesCount; int get awardedScore; int? get pinMode; String? get threadedPostId; SnPost? get threadedPost; String? get repliedPostId; SnPost? get repliedPost; String? get forwardedPostId; SnPost? get forwardedPost; String? get realmId; SnRealm? get realm; String? get publisherId; SnPublisher? get publisher; String? get actorid; SnActivityPubActor? get actor; String? get fediverseUri; int? get fediverseType; int get contentType; List<SnCloudFile> get attachments; 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; List<SnPostFeaturedRecord> get featuredRecords; DateTime? get createdAt; DateTime? get updatedAt; DateTime? get deletedAt; bool get repliedGone; bool get forwardedGone; bool get isTruncated;
/// Create a copy of SnPost
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@@ -28,16 +28,16 @@ $SnPostCopyWith<SnPost> get copyWith => _$SnPostCopyWithImpl<SnPost>(this as SnP
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnPost&&(identical(other.id, id) || other.id == id)&&(identical(other.title, title) || other.title == title)&&(identical(other.description, description) || other.description == description)&&(identical(other.language, language) || other.language == language)&&(identical(other.editedAt, editedAt) || other.editedAt == editedAt)&&(identical(other.publishedAt, publishedAt) || other.publishedAt == publishedAt)&&(identical(other.visibility, visibility) || other.visibility == visibility)&&(identical(other.content, content) || other.content == content)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.type, type) || other.type == type)&&const DeepCollectionEquality().equals(other.meta, meta)&&(identical(other.embedView, embedView) || other.embedView == embedView)&&(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.awardedScore, awardedScore) || other.awardedScore == awardedScore)&&(identical(other.pinMode, pinMode) || other.pinMode == pinMode)&&(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)&&const DeepCollectionEquality().equals(other.featuredRecords, featuredRecords)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.repliedGone, repliedGone) || other.repliedGone == repliedGone)&&(identical(other.forwardedGone, forwardedGone) || other.forwardedGone == forwardedGone)&&(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.embedView, embedView) || other.embedView == embedView)&&(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.awardedScore, awardedScore) || other.awardedScore == awardedScore)&&(identical(other.pinMode, pinMode) || other.pinMode == pinMode)&&(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)&&(identical(other.publisherId, publisherId) || other.publisherId == publisherId)&&(identical(other.publisher, publisher) || other.publisher == publisher)&&(identical(other.actorid, actorid) || other.actorid == actorid)&&(identical(other.actor, actor) || other.actor == actor)&&(identical(other.fediverseUri, fediverseUri) || other.fediverseUri == fediverseUri)&&(identical(other.fediverseType, fediverseType) || other.fediverseType == fediverseType)&&(identical(other.contentType, contentType) || other.contentType == contentType)&&const DeepCollectionEquality().equals(other.attachments, attachments)&&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)&&const DeepCollectionEquality().equals(other.featuredRecords, featuredRecords)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.repliedGone, repliedGone) || other.repliedGone == repliedGone)&&(identical(other.forwardedGone, forwardedGone) || other.forwardedGone == forwardedGone)&&(identical(other.isTruncated, isTruncated) || other.isTruncated == isTruncated));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hashAll([runtimeType,id,title,description,language,editedAt,publishedAt,visibility,content,slug,type,const DeepCollectionEquality().hash(meta),embedView,viewsUnique,viewsTotal,upvotes,downvotes,repliesCount,awardedScore,pinMode,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),const DeepCollectionEquality().hash(featuredRecords),createdAt,updatedAt,deletedAt,repliedGone,forwardedGone,isTruncated]);
int get hashCode => Object.hashAll([runtimeType,id,title,description,language,editedAt,publishedAt,visibility,content,slug,type,const DeepCollectionEquality().hash(meta),embedView,viewsUnique,viewsTotal,upvotes,downvotes,repliesCount,awardedScore,pinMode,threadedPostId,threadedPost,repliedPostId,repliedPost,forwardedPostId,forwardedPost,realmId,realm,publisherId,publisher,actorid,actor,fediverseUri,fediverseType,contentType,const DeepCollectionEquality().hash(attachments),const DeepCollectionEquality().hash(reactionsCount),const DeepCollectionEquality().hash(reactionsMade),const DeepCollectionEquality().hash(reactions),const DeepCollectionEquality().hash(tags),const DeepCollectionEquality().hash(categories),const DeepCollectionEquality().hash(collections),const DeepCollectionEquality().hash(featuredRecords),createdAt,updatedAt,deletedAt,repliedGone,forwardedGone,isTruncated]);
@override
String toString() {
return 'SnPost(id: $id, title: $title, description: $description, language: $language, editedAt: $editedAt, publishedAt: $publishedAt, visibility: $visibility, content: $content, slug: $slug, type: $type, meta: $meta, embedView: $embedView, viewsUnique: $viewsUnique, viewsTotal: $viewsTotal, upvotes: $upvotes, downvotes: $downvotes, repliesCount: $repliesCount, awardedScore: $awardedScore, pinMode: $pinMode, 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, featuredRecords: $featuredRecords, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, repliedGone: $repliedGone, forwardedGone: $forwardedGone, 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, embedView: $embedView, viewsUnique: $viewsUnique, viewsTotal: $viewsTotal, upvotes: $upvotes, downvotes: $downvotes, repliesCount: $repliesCount, awardedScore: $awardedScore, pinMode: $pinMode, threadedPostId: $threadedPostId, threadedPost: $threadedPost, repliedPostId: $repliedPostId, repliedPost: $repliedPost, forwardedPostId: $forwardedPostId, forwardedPost: $forwardedPost, realmId: $realmId, realm: $realm, publisherId: $publisherId, publisher: $publisher, actorid: $actorid, actor: $actor, fediverseUri: $fediverseUri, fediverseType: $fediverseType, contentType: $contentType, attachments: $attachments, reactionsCount: $reactionsCount, reactionsMade: $reactionsMade, reactions: $reactions, tags: $tags, categories: $categories, collections: $collections, featuredRecords: $featuredRecords, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, repliedGone: $repliedGone, forwardedGone: $forwardedGone, isTruncated: $isTruncated)';
}
@@ -48,11 +48,11 @@ abstract mixin class $SnPostCopyWith<$Res> {
factory $SnPostCopyWith(SnPost value, $Res Function(SnPost) _then) = _$SnPostCopyWithImpl;
@useResult
$Res call({
String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map<String, dynamic>? meta, SnPostEmbedView? embedView, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, int awardedScore, int? pinMode, 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, List<SnPostFeaturedRecord> featuredRecords, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool repliedGone, bool forwardedGone, 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, SnPostEmbedView? embedView, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, int awardedScore, int? pinMode, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, String? realmId, SnRealm? realm, String? publisherId, SnPublisher? publisher, String? actorid, SnActivityPubActor? actor, String? fediverseUri, int? fediverseType, int contentType, List<SnCloudFile> attachments, Map<String, int> reactionsCount, Map<String, bool> reactionsMade, List<dynamic> reactions, List<SnPostTag> tags, List<SnPostCategory> categories, List<dynamic> collections, List<SnPostFeaturedRecord> featuredRecords, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool repliedGone, bool forwardedGone, bool isTruncated
});
$SnPostEmbedViewCopyWith<$Res>? get embedView;$SnPostCopyWith<$Res>? get threadedPost;$SnPostCopyWith<$Res>? get repliedPost;$SnPostCopyWith<$Res>? get forwardedPost;$SnRealmCopyWith<$Res>? get realm;$SnPublisherCopyWith<$Res> get publisher;
$SnPostEmbedViewCopyWith<$Res>? get embedView;$SnPostCopyWith<$Res>? get threadedPost;$SnPostCopyWith<$Res>? get repliedPost;$SnPostCopyWith<$Res>? get forwardedPost;$SnRealmCopyWith<$Res>? get realm;$SnPublisherCopyWith<$Res>? get publisher;$SnActivityPubActorCopyWith<$Res>? get actor;
}
/// @nodoc
@@ -65,7 +65,7 @@ class _$SnPostCopyWithImpl<$Res>
/// Create a copy of SnPost
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? title = freezed,Object? description = freezed,Object? language = freezed,Object? editedAt = freezed,Object? publishedAt = freezed,Object? visibility = null,Object? content = freezed,Object? slug = freezed,Object? type = null,Object? meta = freezed,Object? embedView = freezed,Object? viewsUnique = null,Object? viewsTotal = null,Object? upvotes = null,Object? downvotes = null,Object? repliesCount = null,Object? awardedScore = null,Object? pinMode = freezed,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? featuredRecords = null,Object? createdAt = freezed,Object? updatedAt = freezed,Object? deletedAt = freezed,Object? repliedGone = null,Object? forwardedGone = null,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? embedView = freezed,Object? viewsUnique = null,Object? viewsTotal = null,Object? upvotes = null,Object? downvotes = null,Object? repliesCount = null,Object? awardedScore = null,Object? pinMode = freezed,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? publisherId = freezed,Object? publisher = freezed,Object? actorid = freezed,Object? actor = freezed,Object? fediverseUri = freezed,Object? fediverseType = freezed,Object? contentType = null,Object? attachments = null,Object? reactionsCount = null,Object? reactionsMade = null,Object? reactions = null,Object? tags = null,Object? categories = null,Object? collections = null,Object? featuredRecords = null,Object? createdAt = freezed,Object? updatedAt = freezed,Object? deletedAt = freezed,Object? repliedGone = null,Object? forwardedGone = null,Object? isTruncated = null,}) {
return _then(_self.copyWith(
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
as String,title: freezed == title ? _self.title : title // ignore: cast_nullable_to_non_nullable
@@ -94,9 +94,15 @@ as SnPost?,forwardedPostId: freezed == forwardedPostId ? _self.forwardedPostId :
as String?,forwardedPost: freezed == forwardedPost ? _self.forwardedPost : forwardedPost // ignore: cast_nullable_to_non_nullable
as SnPost?,realmId: freezed == realmId ? _self.realmId : realmId // ignore: cast_nullable_to_non_nullable
as String?,realm: freezed == realm ? _self.realm : realm // ignore: cast_nullable_to_non_nullable
as SnRealm?,attachments: null == attachments ? _self.attachments : attachments // ignore: cast_nullable_to_non_nullable
as List<SnCloudFile>,publisher: null == publisher ? _self.publisher : publisher // ignore: cast_nullable_to_non_nullable
as SnPublisher,reactionsCount: null == reactionsCount ? _self.reactionsCount : reactionsCount // ignore: cast_nullable_to_non_nullable
as SnRealm?,publisherId: freezed == publisherId ? _self.publisherId : publisherId // ignore: cast_nullable_to_non_nullable
as String?,publisher: freezed == publisher ? _self.publisher : publisher // ignore: cast_nullable_to_non_nullable
as SnPublisher?,actorid: freezed == actorid ? _self.actorid : actorid // ignore: cast_nullable_to_non_nullable
as String?,actor: freezed == actor ? _self.actor : actor // ignore: cast_nullable_to_non_nullable
as SnActivityPubActor?,fediverseUri: freezed == fediverseUri ? _self.fediverseUri : fediverseUri // ignore: cast_nullable_to_non_nullable
as String?,fediverseType: freezed == fediverseType ? _self.fediverseType : fediverseType // ignore: cast_nullable_to_non_nullable
as int?,contentType: null == contentType ? _self.contentType : contentType // ignore: cast_nullable_to_non_nullable
as int,attachments: null == attachments ? _self.attachments : attachments // ignore: cast_nullable_to_non_nullable
as List<SnCloudFile>,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, bool>,reactions: null == reactions ? _self.reactions : reactions // ignore: cast_nullable_to_non_nullable
as List<dynamic>,tags: null == tags ? _self.tags : tags // ignore: cast_nullable_to_non_nullable
@@ -176,11 +182,26 @@ $SnRealmCopyWith<$Res>? get realm {
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$SnPublisherCopyWith<$Res> get publisher {
return $SnPublisherCopyWith<$Res>(_self.publisher, (value) {
$SnPublisherCopyWith<$Res>? get publisher {
if (_self.publisher == null) {
return null;
}
return $SnPublisherCopyWith<$Res>(_self.publisher!, (value) {
return _then(_self.copyWith(publisher: value));
});
}/// Create a copy of SnPost
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$SnActivityPubActorCopyWith<$Res>? get actor {
if (_self.actor == null) {
return null;
}
return $SnActivityPubActorCopyWith<$Res>(_self.actor!, (value) {
return _then(_self.copyWith(actor: value));
});
}
}
@@ -260,10 +281,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, String? slug, int type, Map<String, dynamic>? meta, SnPostEmbedView? embedView, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, int awardedScore, int? pinMode, 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, List<SnPostFeaturedRecord> featuredRecords, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool repliedGone, bool forwardedGone, 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, SnPostEmbedView? embedView, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, int awardedScore, int? pinMode, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, String? realmId, SnRealm? realm, String? publisherId, SnPublisher? publisher, String? actorid, SnActivityPubActor? actor, String? fediverseUri, int? fediverseType, int contentType, List<SnCloudFile> attachments, Map<String, int> reactionsCount, Map<String, bool> reactionsMade, List<dynamic> reactions, List<SnPostTag> tags, List<SnPostCategory> categories, List<dynamic> collections, List<SnPostFeaturedRecord> featuredRecords, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool repliedGone, bool forwardedGone, bool isTruncated)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _SnPost() when $default != null:
return $default(_that.id,_that.title,_that.description,_that.language,_that.editedAt,_that.publishedAt,_that.visibility,_that.content,_that.slug,_that.type,_that.meta,_that.embedView,_that.viewsUnique,_that.viewsTotal,_that.upvotes,_that.downvotes,_that.repliesCount,_that.awardedScore,_that.pinMode,_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.featuredRecords,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.repliedGone,_that.forwardedGone,_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.embedView,_that.viewsUnique,_that.viewsTotal,_that.upvotes,_that.downvotes,_that.repliesCount,_that.awardedScore,_that.pinMode,_that.threadedPostId,_that.threadedPost,_that.repliedPostId,_that.repliedPost,_that.forwardedPostId,_that.forwardedPost,_that.realmId,_that.realm,_that.publisherId,_that.publisher,_that.actorid,_that.actor,_that.fediverseUri,_that.fediverseType,_that.contentType,_that.attachments,_that.reactionsCount,_that.reactionsMade,_that.reactions,_that.tags,_that.categories,_that.collections,_that.featuredRecords,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.repliedGone,_that.forwardedGone,_that.isTruncated);case _:
return orElse();
}
@@ -281,10 +302,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, String? slug, int type, Map<String, dynamic>? meta, SnPostEmbedView? embedView, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, int awardedScore, int? pinMode, 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, List<SnPostFeaturedRecord> featuredRecords, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool repliedGone, bool forwardedGone, 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, SnPostEmbedView? embedView, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, int awardedScore, int? pinMode, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, String? realmId, SnRealm? realm, String? publisherId, SnPublisher? publisher, String? actorid, SnActivityPubActor? actor, String? fediverseUri, int? fediverseType, int contentType, List<SnCloudFile> attachments, Map<String, int> reactionsCount, Map<String, bool> reactionsMade, List<dynamic> reactions, List<SnPostTag> tags, List<SnPostCategory> categories, List<dynamic> collections, List<SnPostFeaturedRecord> featuredRecords, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool repliedGone, bool forwardedGone, bool isTruncated) $default,) {final _that = this;
switch (_that) {
case _SnPost():
return $default(_that.id,_that.title,_that.description,_that.language,_that.editedAt,_that.publishedAt,_that.visibility,_that.content,_that.slug,_that.type,_that.meta,_that.embedView,_that.viewsUnique,_that.viewsTotal,_that.upvotes,_that.downvotes,_that.repliesCount,_that.awardedScore,_that.pinMode,_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.featuredRecords,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.repliedGone,_that.forwardedGone,_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.embedView,_that.viewsUnique,_that.viewsTotal,_that.upvotes,_that.downvotes,_that.repliesCount,_that.awardedScore,_that.pinMode,_that.threadedPostId,_that.threadedPost,_that.repliedPostId,_that.repliedPost,_that.forwardedPostId,_that.forwardedPost,_that.realmId,_that.realm,_that.publisherId,_that.publisher,_that.actorid,_that.actor,_that.fediverseUri,_that.fediverseType,_that.contentType,_that.attachments,_that.reactionsCount,_that.reactionsMade,_that.reactions,_that.tags,_that.categories,_that.collections,_that.featuredRecords,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.repliedGone,_that.forwardedGone,_that.isTruncated);}
}
/// A variant of `when` that fallback to returning `null`
///
@@ -298,10 +319,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, String? slug, int type, Map<String, dynamic>? meta, SnPostEmbedView? embedView, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, int awardedScore, int? pinMode, 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, List<SnPostFeaturedRecord> featuredRecords, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool repliedGone, bool forwardedGone, 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, SnPostEmbedView? embedView, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, int awardedScore, int? pinMode, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, String? realmId, SnRealm? realm, String? publisherId, SnPublisher? publisher, String? actorid, SnActivityPubActor? actor, String? fediverseUri, int? fediverseType, int contentType, List<SnCloudFile> attachments, Map<String, int> reactionsCount, Map<String, bool> reactionsMade, List<dynamic> reactions, List<SnPostTag> tags, List<SnPostCategory> categories, List<dynamic> collections, List<SnPostFeaturedRecord> featuredRecords, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool repliedGone, bool forwardedGone, bool isTruncated)? $default,) {final _that = this;
switch (_that) {
case _SnPost() when $default != null:
return $default(_that.id,_that.title,_that.description,_that.language,_that.editedAt,_that.publishedAt,_that.visibility,_that.content,_that.slug,_that.type,_that.meta,_that.embedView,_that.viewsUnique,_that.viewsTotal,_that.upvotes,_that.downvotes,_that.repliesCount,_that.awardedScore,_that.pinMode,_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.featuredRecords,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.repliedGone,_that.forwardedGone,_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.embedView,_that.viewsUnique,_that.viewsTotal,_that.upvotes,_that.downvotes,_that.repliesCount,_that.awardedScore,_that.pinMode,_that.threadedPostId,_that.threadedPost,_that.repliedPostId,_that.repliedPost,_that.forwardedPostId,_that.forwardedPost,_that.realmId,_that.realm,_that.publisherId,_that.publisher,_that.actorid,_that.actor,_that.fediverseUri,_that.fediverseType,_that.contentType,_that.attachments,_that.reactionsCount,_that.reactionsMade,_that.reactions,_that.tags,_that.categories,_that.collections,_that.featuredRecords,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.repliedGone,_that.forwardedGone,_that.isTruncated);case _:
return null;
}
@@ -313,7 +334,7 @@ return $default(_that.id,_that.title,_that.description,_that.language,_that.edit
@JsonSerializable()
class _SnPost implements SnPost {
const _SnPost({required this.id, this.title, this.description, this.language, this.editedAt, this.publishedAt = null, this.visibility = 0, this.content, this.slug, this.type = 0, final Map<String, dynamic>? meta, this.embedView, this.viewsUnique = 0, this.viewsTotal = 0, this.upvotes = 0, this.downvotes = 0, this.repliesCount = 0, this.awardedScore = 0, this.pinMode, 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 [], final List<SnPostFeaturedRecord> featuredRecords = const [], this.createdAt = null, this.updatedAt = null, this.deletedAt, this.repliedGone = false, this.forwardedGone = false, this.isTruncated = false}): _meta = meta,_attachments = attachments,_reactionsCount = reactionsCount,_reactionsMade = reactionsMade,_reactions = reactions,_tags = tags,_categories = categories,_collections = collections,_featuredRecords = featuredRecords;
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.embedView, this.viewsUnique = 0, this.viewsTotal = 0, this.upvotes = 0, this.downvotes = 0, this.repliesCount = 0, this.awardedScore = 0, this.pinMode, this.threadedPostId, this.threadedPost, this.repliedPostId, this.repliedPost, this.forwardedPostId, this.forwardedPost, this.realmId, this.realm, this.publisherId, this.publisher, this.actorid, this.actor, this.fediverseUri, this.fediverseType, this.contentType = 0, final List<SnCloudFile> attachments = const [], 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 [], final List<SnPostFeaturedRecord> featuredRecords = const [], this.createdAt = null, this.updatedAt = null, this.deletedAt, this.repliedGone = false, this.forwardedGone = false, this.isTruncated = false}): _meta = meta,_attachments = attachments,_reactionsCount = reactionsCount,_reactionsMade = reactionsMade,_reactions = reactions,_tags = tags,_categories = categories,_collections = collections,_featuredRecords = featuredRecords;
factory _SnPost.fromJson(Map<String, dynamic> json) => _$SnPostFromJson(json);
@override final String id;
@@ -351,6 +372,13 @@ class _SnPost implements SnPost {
@override final SnPost? forwardedPost;
@override final String? realmId;
@override final SnRealm? realm;
@override final String? publisherId;
@override final SnPublisher? publisher;
@override final String? actorid;
@override final SnActivityPubActor? actor;
@override final String? fediverseUri;
@override final int? fediverseType;
@override@JsonKey() final int contentType;
final List<SnCloudFile> _attachments;
@override@JsonKey() List<SnCloudFile> get attachments {
if (_attachments is EqualUnmodifiableListView) return _attachments;
@@ -358,7 +386,6 @@ class _SnPost implements SnPost {
return EqualUnmodifiableListView(_attachments);
}
@override final SnPublisher publisher;
final Map<String, int> _reactionsCount;
@override@JsonKey() Map<String, int> get reactionsCount {
if (_reactionsCount is EqualUnmodifiableMapView) return _reactionsCount;
@@ -428,16 +455,16 @@ Map<String, dynamic> toJson() {
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnPost&&(identical(other.id, id) || other.id == id)&&(identical(other.title, title) || other.title == title)&&(identical(other.description, description) || other.description == description)&&(identical(other.language, language) || other.language == language)&&(identical(other.editedAt, editedAt) || other.editedAt == editedAt)&&(identical(other.publishedAt, publishedAt) || other.publishedAt == publishedAt)&&(identical(other.visibility, visibility) || other.visibility == visibility)&&(identical(other.content, content) || other.content == content)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.type, type) || other.type == type)&&const DeepCollectionEquality().equals(other._meta, _meta)&&(identical(other.embedView, embedView) || other.embedView == embedView)&&(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.awardedScore, awardedScore) || other.awardedScore == awardedScore)&&(identical(other.pinMode, pinMode) || other.pinMode == pinMode)&&(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)&&const DeepCollectionEquality().equals(other._featuredRecords, _featuredRecords)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.repliedGone, repliedGone) || other.repliedGone == repliedGone)&&(identical(other.forwardedGone, forwardedGone) || other.forwardedGone == forwardedGone)&&(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.embedView, embedView) || other.embedView == embedView)&&(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.awardedScore, awardedScore) || other.awardedScore == awardedScore)&&(identical(other.pinMode, pinMode) || other.pinMode == pinMode)&&(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)&&(identical(other.publisherId, publisherId) || other.publisherId == publisherId)&&(identical(other.publisher, publisher) || other.publisher == publisher)&&(identical(other.actorid, actorid) || other.actorid == actorid)&&(identical(other.actor, actor) || other.actor == actor)&&(identical(other.fediverseUri, fediverseUri) || other.fediverseUri == fediverseUri)&&(identical(other.fediverseType, fediverseType) || other.fediverseType == fediverseType)&&(identical(other.contentType, contentType) || other.contentType == contentType)&&const DeepCollectionEquality().equals(other._attachments, _attachments)&&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)&&const DeepCollectionEquality().equals(other._featuredRecords, _featuredRecords)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.repliedGone, repliedGone) || other.repliedGone == repliedGone)&&(identical(other.forwardedGone, forwardedGone) || other.forwardedGone == forwardedGone)&&(identical(other.isTruncated, isTruncated) || other.isTruncated == isTruncated));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hashAll([runtimeType,id,title,description,language,editedAt,publishedAt,visibility,content,slug,type,const DeepCollectionEquality().hash(_meta),embedView,viewsUnique,viewsTotal,upvotes,downvotes,repliesCount,awardedScore,pinMode,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),const DeepCollectionEquality().hash(_featuredRecords),createdAt,updatedAt,deletedAt,repliedGone,forwardedGone,isTruncated]);
int get hashCode => Object.hashAll([runtimeType,id,title,description,language,editedAt,publishedAt,visibility,content,slug,type,const DeepCollectionEquality().hash(_meta),embedView,viewsUnique,viewsTotal,upvotes,downvotes,repliesCount,awardedScore,pinMode,threadedPostId,threadedPost,repliedPostId,repliedPost,forwardedPostId,forwardedPost,realmId,realm,publisherId,publisher,actorid,actor,fediverseUri,fediverseType,contentType,const DeepCollectionEquality().hash(_attachments),const DeepCollectionEquality().hash(_reactionsCount),const DeepCollectionEquality().hash(_reactionsMade),const DeepCollectionEquality().hash(_reactions),const DeepCollectionEquality().hash(_tags),const DeepCollectionEquality().hash(_categories),const DeepCollectionEquality().hash(_collections),const DeepCollectionEquality().hash(_featuredRecords),createdAt,updatedAt,deletedAt,repliedGone,forwardedGone,isTruncated]);
@override
String toString() {
return 'SnPost(id: $id, title: $title, description: $description, language: $language, editedAt: $editedAt, publishedAt: $publishedAt, visibility: $visibility, content: $content, slug: $slug, type: $type, meta: $meta, embedView: $embedView, viewsUnique: $viewsUnique, viewsTotal: $viewsTotal, upvotes: $upvotes, downvotes: $downvotes, repliesCount: $repliesCount, awardedScore: $awardedScore, pinMode: $pinMode, 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, featuredRecords: $featuredRecords, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, repliedGone: $repliedGone, forwardedGone: $forwardedGone, 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, embedView: $embedView, viewsUnique: $viewsUnique, viewsTotal: $viewsTotal, upvotes: $upvotes, downvotes: $downvotes, repliesCount: $repliesCount, awardedScore: $awardedScore, pinMode: $pinMode, threadedPostId: $threadedPostId, threadedPost: $threadedPost, repliedPostId: $repliedPostId, repliedPost: $repliedPost, forwardedPostId: $forwardedPostId, forwardedPost: $forwardedPost, realmId: $realmId, realm: $realm, publisherId: $publisherId, publisher: $publisher, actorid: $actorid, actor: $actor, fediverseUri: $fediverseUri, fediverseType: $fediverseType, contentType: $contentType, attachments: $attachments, reactionsCount: $reactionsCount, reactionsMade: $reactionsMade, reactions: $reactions, tags: $tags, categories: $categories, collections: $collections, featuredRecords: $featuredRecords, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, repliedGone: $repliedGone, forwardedGone: $forwardedGone, isTruncated: $isTruncated)';
}
@@ -448,11 +475,11 @@ abstract mixin class _$SnPostCopyWith<$Res> implements $SnPostCopyWith<$Res> {
factory _$SnPostCopyWith(_SnPost value, $Res Function(_SnPost) _then) = __$SnPostCopyWithImpl;
@override @useResult
$Res call({
String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map<String, dynamic>? meta, SnPostEmbedView? embedView, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, int awardedScore, int? pinMode, 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, List<SnPostFeaturedRecord> featuredRecords, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool repliedGone, bool forwardedGone, 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, SnPostEmbedView? embedView, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, int awardedScore, int? pinMode, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, String? realmId, SnRealm? realm, String? publisherId, SnPublisher? publisher, String? actorid, SnActivityPubActor? actor, String? fediverseUri, int? fediverseType, int contentType, List<SnCloudFile> attachments, Map<String, int> reactionsCount, Map<String, bool> reactionsMade, List<dynamic> reactions, List<SnPostTag> tags, List<SnPostCategory> categories, List<dynamic> collections, List<SnPostFeaturedRecord> featuredRecords, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool repliedGone, bool forwardedGone, bool isTruncated
});
@override $SnPostEmbedViewCopyWith<$Res>? get embedView;@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;
@override $SnPostEmbedViewCopyWith<$Res>? get embedView;@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;@override $SnActivityPubActorCopyWith<$Res>? get actor;
}
/// @nodoc
@@ -465,7 +492,7 @@ class __$SnPostCopyWithImpl<$Res>
/// Create a copy of SnPost
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? title = freezed,Object? description = freezed,Object? language = freezed,Object? editedAt = freezed,Object? publishedAt = freezed,Object? visibility = null,Object? content = freezed,Object? slug = freezed,Object? type = null,Object? meta = freezed,Object? embedView = freezed,Object? viewsUnique = null,Object? viewsTotal = null,Object? upvotes = null,Object? downvotes = null,Object? repliesCount = null,Object? awardedScore = null,Object? pinMode = freezed,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? featuredRecords = null,Object? createdAt = freezed,Object? updatedAt = freezed,Object? deletedAt = freezed,Object? repliedGone = null,Object? forwardedGone = null,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? embedView = freezed,Object? viewsUnique = null,Object? viewsTotal = null,Object? upvotes = null,Object? downvotes = null,Object? repliesCount = null,Object? awardedScore = null,Object? pinMode = freezed,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? publisherId = freezed,Object? publisher = freezed,Object? actorid = freezed,Object? actor = freezed,Object? fediverseUri = freezed,Object? fediverseType = freezed,Object? contentType = null,Object? attachments = null,Object? reactionsCount = null,Object? reactionsMade = null,Object? reactions = null,Object? tags = null,Object? categories = null,Object? collections = null,Object? featuredRecords = null,Object? createdAt = freezed,Object? updatedAt = freezed,Object? deletedAt = freezed,Object? repliedGone = null,Object? forwardedGone = null,Object? isTruncated = null,}) {
return _then(_SnPost(
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
as String,title: freezed == title ? _self.title : title // ignore: cast_nullable_to_non_nullable
@@ -494,9 +521,15 @@ as SnPost?,forwardedPostId: freezed == forwardedPostId ? _self.forwardedPostId :
as String?,forwardedPost: freezed == forwardedPost ? _self.forwardedPost : forwardedPost // ignore: cast_nullable_to_non_nullable
as SnPost?,realmId: freezed == realmId ? _self.realmId : realmId // ignore: cast_nullable_to_non_nullable
as String?,realm: freezed == realm ? _self.realm : realm // ignore: cast_nullable_to_non_nullable
as SnRealm?,attachments: null == attachments ? _self._attachments : attachments // ignore: cast_nullable_to_non_nullable
as List<SnCloudFile>,publisher: null == publisher ? _self.publisher : publisher // ignore: cast_nullable_to_non_nullable
as SnPublisher,reactionsCount: null == reactionsCount ? _self._reactionsCount : reactionsCount // ignore: cast_nullable_to_non_nullable
as SnRealm?,publisherId: freezed == publisherId ? _self.publisherId : publisherId // ignore: cast_nullable_to_non_nullable
as String?,publisher: freezed == publisher ? _self.publisher : publisher // ignore: cast_nullable_to_non_nullable
as SnPublisher?,actorid: freezed == actorid ? _self.actorid : actorid // ignore: cast_nullable_to_non_nullable
as String?,actor: freezed == actor ? _self.actor : actor // ignore: cast_nullable_to_non_nullable
as SnActivityPubActor?,fediverseUri: freezed == fediverseUri ? _self.fediverseUri : fediverseUri // ignore: cast_nullable_to_non_nullable
as String?,fediverseType: freezed == fediverseType ? _self.fediverseType : fediverseType // ignore: cast_nullable_to_non_nullable
as int?,contentType: null == contentType ? _self.contentType : contentType // ignore: cast_nullable_to_non_nullable
as int,attachments: null == attachments ? _self._attachments : attachments // ignore: cast_nullable_to_non_nullable
as List<SnCloudFile>,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, bool>,reactions: null == reactions ? _self._reactions : reactions // ignore: cast_nullable_to_non_nullable
as List<dynamic>,tags: null == tags ? _self._tags : tags // ignore: cast_nullable_to_non_nullable
@@ -577,11 +610,26 @@ $SnRealmCopyWith<$Res>? get realm {
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$SnPublisherCopyWith<$Res> get publisher {
return $SnPublisherCopyWith<$Res>(_self.publisher, (value) {
$SnPublisherCopyWith<$Res>? get publisher {
if (_self.publisher == null) {
return null;
}
return $SnPublisherCopyWith<$Res>(_self.publisher!, (value) {
return _then(_self.copyWith(publisher: value));
});
}/// Create a copy of SnPost
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$SnActivityPubActorCopyWith<$Res>? get actor {
if (_self.actor == null) {
return null;
}
return $SnActivityPubActorCopyWith<$Res>(_self.actor!, (value) {
return _then(_self.copyWith(actor: value));
});
}
}
@@ -1937,7 +1985,7 @@ as DateTime?,
/// @nodoc
mixin _$SnPostReaction {
String get id; String get symbol; int get attitude; String get postId; String get accountId; DateTime get createdAt; DateTime get updatedAt; SnAccount? get account; DateTime? get deletedAt;
String get id; String get symbol; int get attitude; String get postId; DateTime get createdAt; DateTime get updatedAt; String? get actorId; SnActivityPubActor? get actor; String? get accountId; SnAccount? get account; DateTime? get deletedAt;
/// Create a copy of SnPostReaction
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@@ -1950,16 +1998,16 @@ $SnPostReactionCopyWith<SnPostReaction> get copyWith => _$SnPostReactionCopyWith
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnPostReaction&&(identical(other.id, id) || other.id == id)&&(identical(other.symbol, symbol) || other.symbol == symbol)&&(identical(other.attitude, attitude) || other.attitude == attitude)&&(identical(other.postId, postId) || other.postId == postId)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.account, account) || other.account == account)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt));
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnPostReaction&&(identical(other.id, id) || other.id == id)&&(identical(other.symbol, symbol) || other.symbol == symbol)&&(identical(other.attitude, attitude) || other.attitude == attitude)&&(identical(other.postId, postId) || other.postId == postId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.actorId, actorId) || other.actorId == actorId)&&(identical(other.actor, actor) || other.actor == actor)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.account, account) || other.account == account)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,id,symbol,attitude,postId,accountId,createdAt,updatedAt,account,deletedAt);
int get hashCode => Object.hash(runtimeType,id,symbol,attitude,postId,createdAt,updatedAt,actorId,actor,accountId,account,deletedAt);
@override
String toString() {
return 'SnPostReaction(id: $id, symbol: $symbol, attitude: $attitude, postId: $postId, accountId: $accountId, createdAt: $createdAt, updatedAt: $updatedAt, account: $account, deletedAt: $deletedAt)';
return 'SnPostReaction(id: $id, symbol: $symbol, attitude: $attitude, postId: $postId, createdAt: $createdAt, updatedAt: $updatedAt, actorId: $actorId, actor: $actor, accountId: $accountId, account: $account, deletedAt: $deletedAt)';
}
@@ -1970,11 +2018,11 @@ abstract mixin class $SnPostReactionCopyWith<$Res> {
factory $SnPostReactionCopyWith(SnPostReaction value, $Res Function(SnPostReaction) _then) = _$SnPostReactionCopyWithImpl;
@useResult
$Res call({
String id, String symbol, int attitude, String postId, String accountId, DateTime createdAt, DateTime updatedAt, SnAccount? account, DateTime? deletedAt
String id, String symbol, int attitude, String postId, DateTime createdAt, DateTime updatedAt, String? actorId, SnActivityPubActor? actor, String? accountId, SnAccount? account, DateTime? deletedAt
});
$SnAccountCopyWith<$Res>? get account;
$SnActivityPubActorCopyWith<$Res>? get actor;$SnAccountCopyWith<$Res>? get account;
}
/// @nodoc
@@ -1987,16 +2035,18 @@ class _$SnPostReactionCopyWithImpl<$Res>
/// Create a copy of SnPostReaction
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? symbol = null,Object? attitude = null,Object? postId = null,Object? accountId = null,Object? createdAt = null,Object? updatedAt = null,Object? account = freezed,Object? deletedAt = freezed,}) {
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? symbol = null,Object? attitude = null,Object? postId = null,Object? createdAt = null,Object? updatedAt = null,Object? actorId = freezed,Object? actor = freezed,Object? accountId = freezed,Object? account = freezed,Object? deletedAt = freezed,}) {
return _then(_self.copyWith(
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
as String,symbol: null == symbol ? _self.symbol : symbol // ignore: cast_nullable_to_non_nullable
as String,attitude: null == attitude ? _self.attitude : attitude // ignore: cast_nullable_to_non_nullable
as int,postId: null == postId ? _self.postId : postId // ignore: cast_nullable_to_non_nullable
as String,accountId: null == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable
as String,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,account: freezed == account ? _self.account : account // ignore: cast_nullable_to_non_nullable
as DateTime,actorId: freezed == actorId ? _self.actorId : actorId // ignore: cast_nullable_to_non_nullable
as String?,actor: freezed == actor ? _self.actor : actor // ignore: cast_nullable_to_non_nullable
as SnActivityPubActor?,accountId: freezed == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable
as String?,account: freezed == account ? _self.account : account // ignore: cast_nullable_to_non_nullable
as SnAccount?,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable
as DateTime?,
));
@@ -2005,6 +2055,18 @@ as DateTime?,
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$SnActivityPubActorCopyWith<$Res>? get actor {
if (_self.actor == null) {
return null;
}
return $SnActivityPubActorCopyWith<$Res>(_self.actor!, (value) {
return _then(_self.copyWith(actor: value));
});
}/// Create a copy of SnPostReaction
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$SnAccountCopyWith<$Res>? get account {
if (_self.account == null) {
return null;
@@ -2092,10 +2154,10 @@ return $default(_that);case _:
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String symbol, int attitude, String postId, String accountId, DateTime createdAt, DateTime updatedAt, SnAccount? account, DateTime? deletedAt)? $default,{required TResult orElse(),}) {final _that = this;
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String symbol, int attitude, String postId, DateTime createdAt, DateTime updatedAt, String? actorId, SnActivityPubActor? actor, String? accountId, SnAccount? account, DateTime? deletedAt)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _SnPostReaction() when $default != null:
return $default(_that.id,_that.symbol,_that.attitude,_that.postId,_that.accountId,_that.createdAt,_that.updatedAt,_that.account,_that.deletedAt);case _:
return $default(_that.id,_that.symbol,_that.attitude,_that.postId,_that.createdAt,_that.updatedAt,_that.actorId,_that.actor,_that.accountId,_that.account,_that.deletedAt);case _:
return orElse();
}
@@ -2113,10 +2175,10 @@ return $default(_that.id,_that.symbol,_that.attitude,_that.postId,_that.accountI
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String symbol, int attitude, String postId, String accountId, DateTime createdAt, DateTime updatedAt, SnAccount? account, DateTime? deletedAt) $default,) {final _that = this;
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String symbol, int attitude, String postId, DateTime createdAt, DateTime updatedAt, String? actorId, SnActivityPubActor? actor, String? accountId, SnAccount? account, DateTime? deletedAt) $default,) {final _that = this;
switch (_that) {
case _SnPostReaction():
return $default(_that.id,_that.symbol,_that.attitude,_that.postId,_that.accountId,_that.createdAt,_that.updatedAt,_that.account,_that.deletedAt);}
return $default(_that.id,_that.symbol,_that.attitude,_that.postId,_that.createdAt,_that.updatedAt,_that.actorId,_that.actor,_that.accountId,_that.account,_that.deletedAt);}
}
/// A variant of `when` that fallback to returning `null`
///
@@ -2130,10 +2192,10 @@ return $default(_that.id,_that.symbol,_that.attitude,_that.postId,_that.accountI
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String symbol, int attitude, String postId, String accountId, DateTime createdAt, DateTime updatedAt, SnAccount? account, DateTime? deletedAt)? $default,) {final _that = this;
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String symbol, int attitude, String postId, DateTime createdAt, DateTime updatedAt, String? actorId, SnActivityPubActor? actor, String? accountId, SnAccount? account, DateTime? deletedAt)? $default,) {final _that = this;
switch (_that) {
case _SnPostReaction() when $default != null:
return $default(_that.id,_that.symbol,_that.attitude,_that.postId,_that.accountId,_that.createdAt,_that.updatedAt,_that.account,_that.deletedAt);case _:
return $default(_that.id,_that.symbol,_that.attitude,_that.postId,_that.createdAt,_that.updatedAt,_that.actorId,_that.actor,_that.accountId,_that.account,_that.deletedAt);case _:
return null;
}
@@ -2145,17 +2207,19 @@ return $default(_that.id,_that.symbol,_that.attitude,_that.postId,_that.accountI
@JsonSerializable()
class _SnPostReaction implements SnPostReaction {
const _SnPostReaction({required this.id, required this.symbol, required this.attitude, required this.postId, required this.accountId, required this.createdAt, required this.updatedAt, this.account = null, this.deletedAt});
const _SnPostReaction({required this.id, required this.symbol, required this.attitude, required this.postId, required this.createdAt, required this.updatedAt, this.actorId, this.actor, this.accountId, this.account, this.deletedAt});
factory _SnPostReaction.fromJson(Map<String, dynamic> json) => _$SnPostReactionFromJson(json);
@override final String id;
@override final String symbol;
@override final int attitude;
@override final String postId;
@override final String accountId;
@override final DateTime createdAt;
@override final DateTime updatedAt;
@override@JsonKey() final SnAccount? account;
@override final String? actorId;
@override final SnActivityPubActor? actor;
@override final String? accountId;
@override final SnAccount? account;
@override final DateTime? deletedAt;
/// Create a copy of SnPostReaction
@@ -2171,16 +2235,16 @@ Map<String, dynamic> toJson() {
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnPostReaction&&(identical(other.id, id) || other.id == id)&&(identical(other.symbol, symbol) || other.symbol == symbol)&&(identical(other.attitude, attitude) || other.attitude == attitude)&&(identical(other.postId, postId) || other.postId == postId)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.account, account) || other.account == account)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt));
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnPostReaction&&(identical(other.id, id) || other.id == id)&&(identical(other.symbol, symbol) || other.symbol == symbol)&&(identical(other.attitude, attitude) || other.attitude == attitude)&&(identical(other.postId, postId) || other.postId == postId)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.actorId, actorId) || other.actorId == actorId)&&(identical(other.actor, actor) || other.actor == actor)&&(identical(other.accountId, accountId) || other.accountId == accountId)&&(identical(other.account, account) || other.account == account)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,id,symbol,attitude,postId,accountId,createdAt,updatedAt,account,deletedAt);
int get hashCode => Object.hash(runtimeType,id,symbol,attitude,postId,createdAt,updatedAt,actorId,actor,accountId,account,deletedAt);
@override
String toString() {
return 'SnPostReaction(id: $id, symbol: $symbol, attitude: $attitude, postId: $postId, accountId: $accountId, createdAt: $createdAt, updatedAt: $updatedAt, account: $account, deletedAt: $deletedAt)';
return 'SnPostReaction(id: $id, symbol: $symbol, attitude: $attitude, postId: $postId, createdAt: $createdAt, updatedAt: $updatedAt, actorId: $actorId, actor: $actor, accountId: $accountId, account: $account, deletedAt: $deletedAt)';
}
@@ -2191,11 +2255,11 @@ abstract mixin class _$SnPostReactionCopyWith<$Res> implements $SnPostReactionCo
factory _$SnPostReactionCopyWith(_SnPostReaction value, $Res Function(_SnPostReaction) _then) = __$SnPostReactionCopyWithImpl;
@override @useResult
$Res call({
String id, String symbol, int attitude, String postId, String accountId, DateTime createdAt, DateTime updatedAt, SnAccount? account, DateTime? deletedAt
String id, String symbol, int attitude, String postId, DateTime createdAt, DateTime updatedAt, String? actorId, SnActivityPubActor? actor, String? accountId, SnAccount? account, DateTime? deletedAt
});
@override $SnAccountCopyWith<$Res>? get account;
@override $SnActivityPubActorCopyWith<$Res>? get actor;@override $SnAccountCopyWith<$Res>? get account;
}
/// @nodoc
@@ -2208,16 +2272,18 @@ class __$SnPostReactionCopyWithImpl<$Res>
/// Create a copy of SnPostReaction
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? symbol = null,Object? attitude = null,Object? postId = null,Object? accountId = null,Object? createdAt = null,Object? updatedAt = null,Object? account = freezed,Object? deletedAt = freezed,}) {
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? symbol = null,Object? attitude = null,Object? postId = null,Object? createdAt = null,Object? updatedAt = null,Object? actorId = freezed,Object? actor = freezed,Object? accountId = freezed,Object? account = freezed,Object? deletedAt = freezed,}) {
return _then(_SnPostReaction(
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
as String,symbol: null == symbol ? _self.symbol : symbol // ignore: cast_nullable_to_non_nullable
as String,attitude: null == attitude ? _self.attitude : attitude // ignore: cast_nullable_to_non_nullable
as int,postId: null == postId ? _self.postId : postId // ignore: cast_nullable_to_non_nullable
as String,accountId: null == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable
as String,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,account: freezed == account ? _self.account : account // ignore: cast_nullable_to_non_nullable
as DateTime,actorId: freezed == actorId ? _self.actorId : actorId // ignore: cast_nullable_to_non_nullable
as String?,actor: freezed == actor ? _self.actor : actor // ignore: cast_nullable_to_non_nullable
as SnActivityPubActor?,accountId: freezed == accountId ? _self.accountId : accountId // ignore: cast_nullable_to_non_nullable
as String?,account: freezed == account ? _self.account : account // ignore: cast_nullable_to_non_nullable
as SnAccount?,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable
as DateTime?,
));
@@ -2227,6 +2293,18 @@ as DateTime?,
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$SnActivityPubActorCopyWith<$Res>? get actor {
if (_self.actor == null) {
return null;
}
return $SnActivityPubActorCopyWith<$Res>(_self.actor!, (value) {
return _then(_self.copyWith(actor: value));
});
}/// Create a copy of SnPostReaction
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$SnAccountCopyWith<$Res>? get account {
if (_self.account == null) {
return null;

View File

@@ -48,12 +48,22 @@ _SnPost _$SnPostFromJson(Map<String, dynamic> json) => _SnPost(
realm: json['realm'] == null
? null
: SnRealm.fromJson(json['realm'] as Map<String, dynamic>),
publisherId: json['publisher_id'] as String?,
publisher: json['publisher'] == null
? null
: SnPublisher.fromJson(json['publisher'] as Map<String, dynamic>),
actorid: json['actorid'] as String?,
actor: json['actor'] == null
? null
: SnActivityPubActor.fromJson(json['actor'] as Map<String, dynamic>),
fediverseUri: json['fediverse_uri'] as String?,
fediverseType: (json['fediverse_type'] as num?)?.toInt(),
contentType: (json['content_type'] as num?)?.toInt() ?? 0,
attachments:
(json['attachments'] as List<dynamic>?)
?.map((e) => SnCloudFile.fromJson(e as Map<String, dynamic>))
.toList() ??
const [],
publisher: SnPublisher.fromJson(json['publisher'] as Map<String, dynamic>),
reactionsCount:
(json['reactions_count'] as Map<String, dynamic>?)?.map(
(k, e) => MapEntry(k, (e as num).toInt()),
@@ -123,8 +133,14 @@ Map<String, dynamic> _$SnPostToJson(_SnPost instance) => <String, dynamic>{
'forwarded_post': instance.forwardedPost?.toJson(),
'realm_id': instance.realmId,
'realm': instance.realm?.toJson(),
'publisher_id': instance.publisherId,
'publisher': instance.publisher?.toJson(),
'actorid': instance.actorid,
'actor': instance.actor?.toJson(),
'fediverse_uri': instance.fediverseUri,
'fediverse_type': instance.fediverseType,
'content_type': instance.contentType,
'attachments': instance.attachments.map((e) => e.toJson()).toList(),
'publisher': instance.publisher.toJson(),
'reactions_count': instance.reactionsCount,
'reactions_made': instance.reactionsMade,
'reactions': instance.reactions,
@@ -232,9 +248,13 @@ _SnPostReaction _$SnPostReactionFromJson(Map<String, dynamic> json) =>
symbol: json['symbol'] as String,
attitude: (json['attitude'] as num).toInt(),
postId: json['post_id'] as String,
accountId: json['account_id'] as String,
createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String),
actorId: json['actor_id'] as String?,
actor: json['actor'] == null
? null
: SnActivityPubActor.fromJson(json['actor'] as Map<String, dynamic>),
accountId: json['account_id'] as String?,
account: json['account'] == null
? null
: SnAccount.fromJson(json['account'] as Map<String, dynamic>),
@@ -249,9 +269,11 @@ Map<String, dynamic> _$SnPostReactionToJson(_SnPostReaction instance) =>
'symbol': instance.symbol,
'attitude': instance.attitude,
'post_id': instance.postId,
'account_id': instance.accountId,
'created_at': instance.createdAt.toIso8601String(),
'updated_at': instance.updatedAt.toIso8601String(),
'actor_id': instance.actorId,
'actor': instance.actor?.toJson(),
'account_id': instance.accountId,
'account': instance.account?.toJson(),
'deleted_at': instance.deletedAt?.toIso8601String(),
};

View File

@@ -32,10 +32,10 @@ final List<RouteItem> kAvailableRoutes = [
icon: Symbols.explore,
),
RouteItem(
name: 'searchPosts'.tr(),
path: '/posts/search',
description: 'searchPostsDescription'.tr(),
searchableAliases: ['search', 'posts'],
name: 'universalSearch'.tr(),
path: '/search',
description: 'universalSearchDescription'.tr(),
searchableAliases: ['search', 'universal', 'fediverse'],
icon: Symbols.search,
),
RouteItem(

View File

@@ -10,7 +10,7 @@ part of 'activity_rpc.dart';
// ignore_for_file: type=lint, type=warning
@ProviderFor(presenceActivities)
const presenceActivitiesProvider = PresenceActivitiesFamily._();
final presenceActivitiesProvider = PresenceActivitiesFamily._();
final class PresenceActivitiesProvider
extends
@@ -22,7 +22,7 @@ final class PresenceActivitiesProvider
with
$FutureModifier<List<SnPresenceActivity>>,
$FutureProvider<List<SnPresenceActivity>> {
const PresenceActivitiesProvider._({
PresenceActivitiesProvider._({
required PresenceActivitiesFamily super.from,
required String super.argument,
}) : super(
@@ -71,7 +71,7 @@ String _$presenceActivitiesHash() =>
final class PresenceActivitiesFamily extends $Family
with $FunctionalFamilyOverride<FutureOr<List<SnPresenceActivity>>, String> {
const PresenceActivitiesFamily._()
PresenceActivitiesFamily._()
: super(
retry: null,
name: r'presenceActivitiesProvider',

View File

@@ -10,7 +10,7 @@ final articleDetailProvider = FutureProvider.autoDispose
try {
final response = await dio.get<Map<String, dynamic>>(
'/sphere/feeds/articles/$articleId',
'/insight/feeds/articles/$articleId',
);
if (response.statusCode == 200 && response.data != null) {

View File

@@ -245,7 +245,7 @@ class CallNotifier extends _$CallNotifier {
final apiClient = ref.read(apiClientProvider);
final ongoingCall = await ref.read(ongoingCallProvider(roomId).future);
final response = await apiClient.get(
'/sphere/chat/realtime/$roomId/join',
'/messager/chat/realtime/$roomId/join',
);
if (response.statusCode == 200 && response.data != null) {
final data = response.data;

View File

@@ -10,11 +10,11 @@ part of 'call.dart';
// ignore_for_file: type=lint, type=warning
@ProviderFor(CallNotifier)
const callProvider = CallNotifierProvider._();
final callProvider = CallNotifierProvider._();
final class CallNotifierProvider
extends $NotifierProvider<CallNotifier, CallState> {
const CallNotifierProvider._()
CallNotifierProvider._()
: super(
from: null,
argument: null,
@@ -41,14 +41,13 @@ final class CallNotifierProvider
}
}
String _$callNotifierHash() => r'40bd884d3918b8e817329589c921774ab3c62ea2';
String _$callNotifierHash() => r'caa03913d98c6d98448af44059db5ef72b5d58f6';
abstract class _$CallNotifier extends $Notifier<CallState> {
CallState build();
@$mustCallSuper
@override
void runBuild() {
final created = build();
final ref = this.ref as $Ref<CallState, CallState>;
final element =
ref.element
@@ -58,6 +57,6 @@ abstract class _$CallNotifier extends $Notifier<CallState> {
Object?,
Object?
>;
element.handleValue(ref, created);
element.handleCreate(ref, build);
}
}

View File

@@ -15,7 +15,7 @@ class ChatOnlineCountNotifier extends _$ChatOnlineCountNotifier {
// Fetch initial online count
final response = await apiClient.get(
'/sphere/chat/$chatroomId/members/online',
'/messager/chat/$chatroomId/members/online',
);
final initialCount = response.data as int;

View File

@@ -10,11 +10,11 @@ part of 'chat_online_count.dart';
// ignore_for_file: type=lint, type=warning
@ProviderFor(ChatOnlineCountNotifier)
const chatOnlineCountProvider = ChatOnlineCountNotifierFamily._();
final chatOnlineCountProvider = ChatOnlineCountNotifierFamily._();
final class ChatOnlineCountNotifierProvider
extends $AsyncNotifierProvider<ChatOnlineCountNotifier, int> {
const ChatOnlineCountNotifierProvider._({
ChatOnlineCountNotifierProvider._({
required ChatOnlineCountNotifierFamily super.from,
required String super.argument,
}) : super(
@@ -52,7 +52,7 @@ final class ChatOnlineCountNotifierProvider
}
String _$chatOnlineCountNotifierHash() =>
r'19af8fd0e9f62c65e12a68215406776085235fa3';
r'b2f9f17bfece1937ec90590b8f11db2bec923156';
final class ChatOnlineCountNotifierFamily extends $Family
with
@@ -63,7 +63,7 @@ final class ChatOnlineCountNotifierFamily extends $Family
FutureOr<int>,
String
> {
const ChatOnlineCountNotifierFamily._()
ChatOnlineCountNotifierFamily._()
: super(
retry: null,
name: r'chatOnlineCountProvider',
@@ -87,7 +87,6 @@ abstract class _$ChatOnlineCountNotifier extends $AsyncNotifier<int> {
@$mustCallSuper
@override
void runBuild() {
final created = build(_$args);
final ref = this.ref as $Ref<AsyncValue<int>, int>;
final element =
ref.element
@@ -97,6 +96,6 @@ abstract class _$ChatOnlineCountNotifier extends $AsyncNotifier<int> {
Object?,
Object?
>;
element.handleValue(ref, created);
element.handleCreate(ref, () => build(_$args));
}
}

View File

@@ -105,7 +105,7 @@ class ChatRoomJoinedNotifier extends _$ChatRoomJoinedNotifier {
Future(() async {
try {
final client = ref.read(apiClientProvider);
final resp = await client.get('/sphere/chat');
final resp = await client.get('/messager/chat');
final remoteRooms = resp.data
.map((e) => SnChatRoom.fromJson(e))
.cast<SnChatRoom>()
@@ -122,7 +122,7 @@ class ChatRoomJoinedNotifier extends _$ChatRoomJoinedNotifier {
// Fallback to API
final client = ref.watch(apiClientProvider);
final resp = await client.get('/sphere/chat');
final resp = await client.get('/messager/chat');
final rooms = resp.data
.map((e) => SnChatRoom.fromJson(e))
.cast<SnChatRoom>()
@@ -306,7 +306,7 @@ class ChatRoomNotifier extends _$ChatRoomNotifier {
Future(() async {
try {
final client = ref.read(apiClientProvider);
final resp = await client.get('/sphere/chat/$identifier');
final resp = await client.get('/messager/chat/$identifier');
final remoteRoom = SnChatRoom.fromJson(resp.data);
// Update state with fresh data directly without saving to DB
// DB will be updated by ChatRoomJoinedNotifier's full sync
@@ -321,7 +321,7 @@ class ChatRoomNotifier extends _$ChatRoomNotifier {
// Fallback to API
try {
final client = ref.watch(apiClientProvider);
final resp = await client.get('/sphere/chat/$identifier');
final resp = await client.get('/messager/chat/$identifier');
final room = SnChatRoom.fromJson(resp.data);
await db.saveChatRooms([room]);
return room;
@@ -375,7 +375,7 @@ class ChatRoomIdentityNotifier extends _$ChatRoomIdentityNotifier {
try {
final client = ref.read(apiClientProvider);
final resp = await client.get(
'/sphere/chat/$identifier/members/me',
'/messager/chat/$identifier/members/me',
);
final remoteMember = SnChatMember.fromJson(resp.data);
await db.saveMember(remoteMember);
@@ -396,7 +396,7 @@ class ChatRoomIdentityNotifier extends _$ChatRoomIdentityNotifier {
// Fallback to API
try {
final client = ref.watch(apiClientProvider);
final resp = await client.get('/sphere/chat/$identifier/members/me');
final resp = await client.get('/messager/chat/$identifier/members/me');
final member = SnChatMember.fromJson(resp.data);
await db.saveMember(member);
return member;
@@ -444,7 +444,7 @@ class ChatRoomIdentityNotifier extends _$ChatRoomIdentityNotifier {
@riverpod
Future<List<SnChatMember>> chatroomInvites(Ref ref) async {
final client = ref.watch(apiClientProvider);
final resp = await client.get('/sphere/chat/invites');
final resp = await client.get('/messager/chat/invites');
return resp.data
.map((e) => SnChatMember.fromJson(e))
.cast<SnChatMember>()

View File

@@ -10,11 +10,11 @@ part of 'chat_room.dart';
// ignore_for_file: type=lint, type=warning
@ProviderFor(ChatRoomJoinedNotifier)
const chatRoomJoinedProvider = ChatRoomJoinedNotifierProvider._();
final chatRoomJoinedProvider = ChatRoomJoinedNotifierProvider._();
final class ChatRoomJoinedNotifierProvider
extends $AsyncNotifierProvider<ChatRoomJoinedNotifier, List<SnChatRoom>> {
const ChatRoomJoinedNotifierProvider._()
ChatRoomJoinedNotifierProvider._()
: super(
from: null,
argument: null,
@@ -34,7 +34,7 @@ final class ChatRoomJoinedNotifierProvider
}
String _$chatRoomJoinedNotifierHash() =>
r'e69955be56ef2c04a8062a8a65925e0a23bfcbaa';
r'b3726e10298b99a8529c5e28a5c402b95016f096';
abstract class _$ChatRoomJoinedNotifier
extends $AsyncNotifier<List<SnChatRoom>> {
@@ -42,7 +42,6 @@ abstract class _$ChatRoomJoinedNotifier
@$mustCallSuper
@override
void runBuild() {
final created = build();
final ref =
this.ref as $Ref<AsyncValue<List<SnChatRoom>>, List<SnChatRoom>>;
final element =
@@ -53,16 +52,16 @@ abstract class _$ChatRoomJoinedNotifier
Object?,
Object?
>;
element.handleValue(ref, created);
element.handleCreate(ref, build);
}
}
@ProviderFor(ChatRoomNotifier)
const chatRoomProvider = ChatRoomNotifierFamily._();
final chatRoomProvider = ChatRoomNotifierFamily._();
final class ChatRoomNotifierProvider
extends $AsyncNotifierProvider<ChatRoomNotifier, SnChatRoom?> {
const ChatRoomNotifierProvider._({
ChatRoomNotifierProvider._({
required ChatRoomNotifierFamily super.from,
required String? super.argument,
}) : super(
@@ -98,7 +97,7 @@ final class ChatRoomNotifierProvider
}
}
String _$chatRoomNotifierHash() => r'1e6391e2ab4eeb114fa001aaa6b06ab2bd646f38';
String _$chatRoomNotifierHash() => r'9f7a8bdd4af381c6b60e65e74363a0af3c1a650e';
final class ChatRoomNotifierFamily extends $Family
with
@@ -109,7 +108,7 @@ final class ChatRoomNotifierFamily extends $Family
FutureOr<SnChatRoom?>,
String?
> {
const ChatRoomNotifierFamily._()
ChatRoomNotifierFamily._()
: super(
retry: null,
name: r'chatRoomProvider',
@@ -133,7 +132,6 @@ abstract class _$ChatRoomNotifier extends $AsyncNotifier<SnChatRoom?> {
@$mustCallSuper
@override
void runBuild() {
final created = build(_$args);
final ref = this.ref as $Ref<AsyncValue<SnChatRoom?>, SnChatRoom?>;
final element =
ref.element
@@ -143,16 +141,16 @@ abstract class _$ChatRoomNotifier extends $AsyncNotifier<SnChatRoom?> {
Object?,
Object?
>;
element.handleValue(ref, created);
element.handleCreate(ref, () => build(_$args));
}
}
@ProviderFor(ChatRoomIdentityNotifier)
const chatRoomIdentityProvider = ChatRoomIdentityNotifierFamily._();
final chatRoomIdentityProvider = ChatRoomIdentityNotifierFamily._();
final class ChatRoomIdentityNotifierProvider
extends $AsyncNotifierProvider<ChatRoomIdentityNotifier, SnChatMember?> {
const ChatRoomIdentityNotifierProvider._({
ChatRoomIdentityNotifierProvider._({
required ChatRoomIdentityNotifierFamily super.from,
required String? super.argument,
}) : super(
@@ -190,7 +188,7 @@ final class ChatRoomIdentityNotifierProvider
}
String _$chatRoomIdentityNotifierHash() =>
r'27c17d55366d39be81d7209837e5c01f80a68a24';
r'1ce75462a19cc037c97ee6084a30fee1f5335875';
final class ChatRoomIdentityNotifierFamily extends $Family
with
@@ -201,7 +199,7 @@ final class ChatRoomIdentityNotifierFamily extends $Family
FutureOr<SnChatMember?>,
String?
> {
const ChatRoomIdentityNotifierFamily._()
ChatRoomIdentityNotifierFamily._()
: super(
retry: null,
name: r'chatRoomIdentityProvider',
@@ -226,7 +224,6 @@ abstract class _$ChatRoomIdentityNotifier
@$mustCallSuper
@override
void runBuild() {
final created = build(_$args);
final ref = this.ref as $Ref<AsyncValue<SnChatMember?>, SnChatMember?>;
final element =
ref.element
@@ -236,12 +233,12 @@ abstract class _$ChatRoomIdentityNotifier
Object?,
Object?
>;
element.handleValue(ref, created);
element.handleCreate(ref, () => build(_$args));
}
}
@ProviderFor(chatroomInvites)
const chatroomInvitesProvider = ChatroomInvitesProvider._();
final chatroomInvitesProvider = ChatroomInvitesProvider._();
final class ChatroomInvitesProvider
extends
@@ -253,7 +250,7 @@ final class ChatroomInvitesProvider
with
$FutureModifier<List<SnChatMember>>,
$FutureProvider<List<SnChatMember>> {
const ChatroomInvitesProvider._()
ChatroomInvitesProvider._()
: super(
from: null,
argument: null,
@@ -279,4 +276,4 @@ final class ChatroomInvitesProvider
}
}
String _$chatroomInvitesHash() => r'5cd6391b09c5517ede19bacce43b45c8d71dd087';
String _$chatroomInvitesHash() => r'fc23231d5f111b1c3796ffae2b471384b951861a';

View File

@@ -7,6 +7,7 @@ import "package:island/pods/chat/chat_room.dart";
import "package:island/pods/lifecycle.dart";
import "package:island/pods/chat/messages_notifier.dart";
import "package:island/pods/websocket.dart";
import "package:island/talker.dart";
import "package:island/widgets/chat/call_button.dart";
import "package:riverpod_annotation/riverpod_annotation.dart";
@@ -35,6 +36,22 @@ class ChatSubscribeNotifier extends _$ChatSubscribeNotifier {
Timer? _typingCooldownTimer;
Timer? _periodicSubscribeTimer;
StreamSubscription? _wsSubscription;
Function? _sendMessage;
void _cleanupResources() {
if (_wsSubscription != null) {
_wsSubscription!.cancel();
_wsSubscription = null;
}
if (_typingCleanupTimer != null) {
_typingCleanupTimer!.cancel();
_typingCleanupTimer = null;
}
if (_periodicSubscribeTimer != null) {
_periodicSubscribeTimer!.cancel();
_periodicSubscribeTimer = null;
}
}
@override
List<SnChatMember> build(String roomId) {
@@ -43,6 +60,8 @@ class ChatSubscribeNotifier extends _$ChatSubscribeNotifier {
final chatIdentityAsync = ref.watch(chatRoomIdentityProvider(roomId));
_messagesNotifier = ref.watch(messagesProvider(roomId).notifier);
_cleanupResources();
if (chatRoomAsync.isLoading || chatIdentityAsync.isLoading) {
return [];
}
@@ -56,12 +75,14 @@ class ChatSubscribeNotifier extends _$ChatSubscribeNotifier {
// Subscribe to messages
final wsState = ref.read(websocketStateProvider.notifier);
wsState.sendMessage(
_sendMessage = wsState.sendMessage;
talker.info('[MessageSubscriber] Subscribing room $roomId');
_sendMessage!(
jsonEncode(
WebSocketPacket(
type: 'messages.subscribe',
data: {'chat_room_id': roomId},
endpoint: 'sphere',
endpoint: 'messager',
),
),
);
@@ -93,64 +114,85 @@ class ChatSubscribeNotifier extends _$ChatSubscribeNotifier {
// Set up periodic subscribe timer (every 5 minutes)
_periodicSubscribeTimer = Timer.periodic(const Duration(minutes: 5), (_) {
wsState.sendMessage(
_sendMessage!(
jsonEncode(
WebSocketPacket(
type: 'messages.subscribe',
data: {'chat_room_id': roomId},
endpoint: 'sphere',
endpoint: 'messager',
),
),
);
});
// Listen to app lifecycle changes
ref.listen(appLifecycleStateProvider, (previous, next) {
final lifecycleState = next.value;
if (lifecycleState == AppLifecycleState.paused ||
lifecycleState == AppLifecycleState.inactive) {
// Unsubscribe when app goes to background
final wsState = ref.read(websocketStateProvider.notifier);
wsState.sendMessage(
talker.info('[MessageSubscriber] Unsubscribing room $roomId');
_sendMessage!(
jsonEncode(
WebSocketPacket(
type: 'messages.unsubscribe',
data: {'chat_room_id': roomId},
endpoint: 'sphere',
endpoint: 'messager',
),
),
);
} else if (lifecycleState == AppLifecycleState.resumed) {
// Resubscribe when app comes back to foreground
final wsState = ref.read(websocketStateProvider.notifier);
wsState.sendMessage(
talker.info('[MessageSubscriber] Subscribing room $roomId');
_sendMessage!(
jsonEncode(
WebSocketPacket(
type: 'messages.subscribe',
data: {'chat_room_id': roomId},
endpoint: 'sphere',
endpoint: 'messager',
),
),
);
}
});
// Cleanup on dispose
ref.onDispose(() {
ref.read(currentSubscribedChatIdProvider.notifier).set(null);
wsState.sendMessage(
jsonEncode(
WebSocketPacket(
type: 'messages.unsubscribe',
data: {'chat_room_id': roomId},
endpoint: 'sphere',
final subscribedNotifier = ref.watch(
currentSubscribedChatIdProvider.notifier,
);
ref.onCancel(() {
talker.info('[MessageSubscriber] Unsubscribing room $roomId');
subscribedNotifier.set(null);
try {
_sendMessage!(
jsonEncode(
WebSocketPacket(
type: 'messages.unsubscribe',
data: {'chat_room_id': roomId},
endpoint: 'messager',
),
),
),
);
_wsSubscription?.cancel();
_typingCleanupTimer?.cancel();
_typingCooldownTimer?.cancel();
_periodicSubscribeTimer?.cancel();
);
} catch (e, stackTrace) {
talker.error(
'[MessageSubscriber] Error sending unsubscribe message for room $roomId: $e\n$stackTrace',
);
}
try {
_cleanupResources();
} catch (e, stackTrace) {
talker.error(
'[MessageSubscriber] Error during cleanup for room $roomId: $e\n$stackTrace',
);
}
try {
if (_typingCooldownTimer != null) {
_typingCooldownTimer!.cancel();
}
} catch (e, stackTrace) {
talker.error(
'[MessageSubscriber] Error cancelling typing cooldown timer for room $roomId: $e\n$stackTrace',
);
}
});
return _typingStatuses;
@@ -201,13 +243,13 @@ class ChatSubscribeNotifier extends _$ChatSubscribeNotifier {
void sendReadReceipt() {
// Send websocket packet
final wsState = ref.read(websocketStateProvider.notifier);
wsState.sendMessage(
if (_sendMessage == null) return;
_sendMessage!(
jsonEncode(
WebSocketPacket(
type: 'messages.read',
data: {'chat_room_id': roomId},
endpoint: 'sphere',
endpoint: 'messager',
),
),
);
@@ -218,13 +260,13 @@ class ChatSubscribeNotifier extends _$ChatSubscribeNotifier {
if (_typingCooldownTimer != null) return;
// Send typing status immediately
final wsState = ref.read(websocketStateProvider.notifier);
wsState.sendMessage(
if (_sendMessage == null) return;
_sendMessage!(
jsonEncode(
WebSocketPacket(
type: 'messages.typing',
data: {'chat_room_id': roomId},
endpoint: 'sphere',
endpoint: 'messager',
),
),
);

View File

@@ -10,11 +10,11 @@ part of 'chat_subscribe.dart';
// ignore_for_file: type=lint, type=warning
@ProviderFor(ChatSubscribeNotifier)
const chatSubscribeProvider = ChatSubscribeNotifierFamily._();
final chatSubscribeProvider = ChatSubscribeNotifierFamily._();
final class ChatSubscribeNotifierProvider
extends $NotifierProvider<ChatSubscribeNotifier, List<SnChatMember>> {
const ChatSubscribeNotifierProvider._({
ChatSubscribeNotifierProvider._({
required ChatSubscribeNotifierFamily super.from,
required String super.argument,
}) : super(
@@ -59,7 +59,7 @@ final class ChatSubscribeNotifierProvider
}
String _$chatSubscribeNotifierHash() =>
r'1aa164429aaab1628b5edbae11e33b0860abdcdc';
r'b7624ae45ace2944a88f8b4d14ddce556c236371';
final class ChatSubscribeNotifierFamily extends $Family
with
@@ -70,7 +70,7 @@ final class ChatSubscribeNotifierFamily extends $Family
List<SnChatMember>,
String
> {
const ChatSubscribeNotifierFamily._()
ChatSubscribeNotifierFamily._()
: super(
retry: null,
name: r'chatSubscribeProvider',
@@ -94,7 +94,6 @@ abstract class _$ChatSubscribeNotifier extends $Notifier<List<SnChatMember>> {
@$mustCallSuper
@override
void runBuild() {
final created = build(_$args);
final ref = this.ref as $Ref<List<SnChatMember>, List<SnChatMember>>;
final element =
ref.element
@@ -104,6 +103,6 @@ abstract class _$ChatSubscribeNotifier extends $Notifier<List<SnChatMember>> {
Object?,
Object?
>;
element.handleValue(ref, created);
element.handleCreate(ref, () => build(_$args));
}
}

View File

@@ -24,7 +24,7 @@ class ChatUnreadCountNotifier extends _$ChatUnreadCountNotifier {
try {
final client = ref.read(apiClientProvider);
final response = await client.get('/sphere/chat/unread');
final response = await client.get('/messager/chat/unread');
return (response.data as num).toInt();
} catch (_) {
return 0;
@@ -65,7 +65,7 @@ class ChatSummary extends _$ChatSummary {
@override
Future<Map<String, SnChatSummary>> build() async {
final client = ref.watch(apiClientProvider);
final resp = await client.get('/sphere/chat/summary');
final resp = await client.get('/messager/chat/summary');
final Map<String, dynamic> data = resp.data;
final summaries = data.map(

View File

@@ -10,11 +10,11 @@ part of 'chat_summary.dart';
// ignore_for_file: type=lint, type=warning
@ProviderFor(ChatUnreadCountNotifier)
const chatUnreadCountProvider = ChatUnreadCountNotifierProvider._();
final chatUnreadCountProvider = ChatUnreadCountNotifierProvider._();
final class ChatUnreadCountNotifierProvider
extends $AsyncNotifierProvider<ChatUnreadCountNotifier, int> {
const ChatUnreadCountNotifierProvider._()
ChatUnreadCountNotifierProvider._()
: super(
from: null,
argument: null,
@@ -34,14 +34,13 @@ final class ChatUnreadCountNotifierProvider
}
String _$chatUnreadCountNotifierHash() =>
r'b8d93589dc37f772d4c3a07d9afd81c37026e57d';
r'169b28f8759ebd9de75f7de17f60d493737ee7a8';
abstract class _$ChatUnreadCountNotifier extends $AsyncNotifier<int> {
FutureOr<int> build();
@$mustCallSuper
@override
void runBuild() {
final created = build();
final ref = this.ref as $Ref<AsyncValue<int>, int>;
final element =
ref.element
@@ -51,16 +50,16 @@ abstract class _$ChatUnreadCountNotifier extends $AsyncNotifier<int> {
Object?,
Object?
>;
element.handleValue(ref, created);
element.handleCreate(ref, build);
}
}
@ProviderFor(ChatSummary)
const chatSummaryProvider = ChatSummaryProvider._();
final chatSummaryProvider = ChatSummaryProvider._();
final class ChatSummaryProvider
extends $AsyncNotifierProvider<ChatSummary, Map<String, SnChatSummary>> {
const ChatSummaryProvider._()
ChatSummaryProvider._()
: super(
from: null,
argument: null,
@@ -79,7 +78,7 @@ final class ChatSummaryProvider
ChatSummary create() => ChatSummary();
}
String _$chatSummaryHash() => r'dfa5e487586482ebdafef8d711f74db68ee86f84';
String _$chatSummaryHash() => r'82f516d4ce8b67dadb815523df57a3c30a33ef91';
abstract class _$ChatSummary
extends $AsyncNotifier<Map<String, SnChatSummary>> {
@@ -87,7 +86,6 @@ abstract class _$ChatSummary
@$mustCallSuper
@override
void runBuild() {
final created = build();
final ref =
this.ref
as $Ref<
@@ -105,6 +103,6 @@ abstract class _$ChatSummary
Object?,
Object?
>;
element.handleValue(ref, created);
element.handleCreate(ref, build);
}
}

View File

@@ -281,7 +281,7 @@ class MessagesNotifier extends _$MessagesNotifier {
talker.log('Fetching messages from API, offset $offset, take $take');
if (_totalCount == null) {
final response = await _apiClient.get(
'/sphere/chat/$roomId/messages',
'/messager/chat/$roomId/messages',
queryParameters: {'offset': 0, 'take': 1},
);
_totalCount = int.parse(response.headers['x-total']?.firstOrNull ?? '0');
@@ -293,7 +293,7 @@ class MessagesNotifier extends _$MessagesNotifier {
}
final response = await _apiClient.get(
'/sphere/chat/$roomId/messages',
'/messager/chat/$roomId/messages',
queryParameters: {'offset': offset, 'take': take},
);
@@ -373,7 +373,7 @@ class MessagesNotifier extends _$MessagesNotifier {
do {
final resp = await _apiClient.post(
'/sphere/chat/${_room.id}/sync',
'/messager/chat/${_room.id}/sync',
data: {'last_sync_timestamp': lastSyncTimestamp},
);
@@ -603,8 +603,8 @@ class MessagesNotifier extends _$MessagesNotifier {
final response = await _apiClient.request(
editingTo == null
? '/sphere/chat/$roomId/messages'
: '/sphere/chat/$roomId/messages/${editingTo.id}',
? '/messager/chat/$roomId/messages'
: '/messager/chat/$roomId/messages/${editingTo.id}',
data: {
'content': content,
'attachments_id': cloudAttachments.map((e) => e.id).toList(),
@@ -688,7 +688,7 @@ class MessagesNotifier extends _$MessagesNotifier {
try {
var remoteMessage = message.toRemoteMessage();
final response = await _apiClient.post(
'/sphere/chat/${message.roomId}/messages',
'/messager/chat/${message.roomId}/messages',
data: {
'content': remoteMessage.content,
'attachments_id': remoteMessage.attachments,
@@ -925,7 +925,7 @@ class MessagesNotifier extends _$MessagesNotifier {
}
try {
await _apiClient.delete('/sphere/chat/$roomId/messages/$messageId');
await _apiClient.delete('/messager/chat/$roomId/messages/$messageId');
await receiveMessageDeletion(messageId);
} catch (err, stackTrace) {
talker.log(
@@ -1033,7 +1033,7 @@ class MessagesNotifier extends _$MessagesNotifier {
}
final response = await _apiClient.get(
'/sphere/chat/$roomId/messages/$messageId',
'/messager/chat/$roomId/messages/$messageId',
);
final remoteMessage = SnChatMessage.fromJson(response.data);
final message = LocalChatMessage.fromRemoteMessage(

View File

@@ -10,11 +10,11 @@ part of 'messages_notifier.dart';
// ignore_for_file: type=lint, type=warning
@ProviderFor(MessagesNotifier)
const messagesProvider = MessagesNotifierFamily._();
final messagesProvider = MessagesNotifierFamily._();
final class MessagesNotifierProvider
extends $AsyncNotifierProvider<MessagesNotifier, List<LocalChatMessage>> {
const MessagesNotifierProvider._({
MessagesNotifierProvider._({
required MessagesNotifierFamily super.from,
required String super.argument,
}) : super(
@@ -50,7 +50,7 @@ final class MessagesNotifierProvider
}
}
String _$messagesNotifierHash() => r'c7e2cd7f5b8673af88f5076814393dbfbd0d43c5';
String _$messagesNotifierHash() => r'a721a4b92b48ee7c2289cdcd7130bbf1ca9dcb40';
final class MessagesNotifierFamily extends $Family
with
@@ -61,7 +61,7 @@ final class MessagesNotifierFamily extends $Family
FutureOr<List<LocalChatMessage>>,
String
> {
const MessagesNotifierFamily._()
MessagesNotifierFamily._()
: super(
retry: null,
name: r'messagesProvider',
@@ -86,7 +86,6 @@ abstract class _$MessagesNotifier
@$mustCallSuper
@override
void runBuild() {
final created = build(_$args);
final ref =
this.ref
as $Ref<AsyncValue<List<LocalChatMessage>>, List<LocalChatMessage>>;
@@ -101,6 +100,6 @@ abstract class _$MessagesNotifier
Object?,
Object?
>;
element.handleValue(ref, created);
element.handleCreate(ref, () => build(_$args));
}
}

View File

@@ -40,6 +40,7 @@ const kAppFirstLaunchAt = 'app_first_launch_at';
const kAppAskedReview = 'app_asked_review';
const kAppDashSearchEngine = 'app_dash_search_engine';
const kAppDefaultScreen = 'app_default_screen';
const kAppShowFediverseContent = 'app_show_fediverse_content';
// Will be overrided by the ProviderScope
final sharedPreferencesProvider = Provider<SharedPreferences>((ref) {
@@ -91,6 +92,7 @@ sealed class AppSettings with _$AppSettings {
required bool askedReview,
required String? dashSearchEngine,
required String? defaultScreen,
required bool showFediverseContent,
}) = _AppSettings;
}
@@ -122,6 +124,7 @@ class AppSettingsNotifier extends _$AppSettingsNotifier {
firstLaunchAt: prefs.getString(kAppFirstLaunchAt),
dashSearchEngine: prefs.getString(kAppDashSearchEngine),
defaultScreen: prefs.getString(kAppDefaultScreen),
showFediverseContent: prefs.getBool(kAppShowFediverseContent) ?? true,
);
}
@@ -311,6 +314,12 @@ class AppSettingsNotifier extends _$AppSettingsNotifier {
}
state = state.copyWith(dashSearchEngine: value);
}
void setShowFediverseContent(bool value) {
final prefs = ref.read(sharedPreferencesProvider);
prefs.setBool(kAppShowFediverseContent, value);
state = state.copyWith(showFediverseContent: value);
}
}
final updateInfoProvider =

View File

@@ -290,7 +290,7 @@ mixin _$AppSettings {
ThemeColors? get customColors; Size? get windowSize;// The window size for desktop platforms
double get windowOpacity;// The window opacity for desktop platforms
double get cardTransparency;// The card background opacity
String? get defaultPoolId; String get messageDisplayStyle; String? get themeMode; bool get disableAnimation; bool get groupedChatList; String? get firstLaunchAt; bool get askedReview; String? get dashSearchEngine; String? get defaultScreen;
String? get defaultPoolId; String get messageDisplayStyle; String? get themeMode; bool get disableAnimation; bool get groupedChatList; String? get firstLaunchAt; bool get askedReview; String? get dashSearchEngine; String? get defaultScreen; bool get showFediverseContent;
/// Create a copy of AppSettings
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@@ -301,16 +301,16 @@ $AppSettingsCopyWith<AppSettings> get copyWith => _$AppSettingsCopyWithImpl<AppS
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is AppSettings&&(identical(other.dataSavingMode, dataSavingMode) || other.dataSavingMode == dataSavingMode)&&(identical(other.soundEffects, soundEffects) || other.soundEffects == soundEffects)&&(identical(other.festivalFeatures, festivalFeatures) || other.festivalFeatures == festivalFeatures)&&(identical(other.enterToSend, enterToSend) || other.enterToSend == enterToSend)&&(identical(other.appBarTransparent, appBarTransparent) || other.appBarTransparent == appBarTransparent)&&(identical(other.showBackgroundImage, showBackgroundImage) || other.showBackgroundImage == showBackgroundImage)&&(identical(other.notifyWithHaptic, notifyWithHaptic) || other.notifyWithHaptic == notifyWithHaptic)&&(identical(other.customFonts, customFonts) || other.customFonts == customFonts)&&(identical(other.appColorScheme, appColorScheme) || other.appColorScheme == appColorScheme)&&(identical(other.customColors, customColors) || other.customColors == customColors)&&(identical(other.windowSize, windowSize) || other.windowSize == windowSize)&&(identical(other.windowOpacity, windowOpacity) || other.windowOpacity == windowOpacity)&&(identical(other.cardTransparency, cardTransparency) || other.cardTransparency == cardTransparency)&&(identical(other.defaultPoolId, defaultPoolId) || other.defaultPoolId == defaultPoolId)&&(identical(other.messageDisplayStyle, messageDisplayStyle) || other.messageDisplayStyle == messageDisplayStyle)&&(identical(other.themeMode, themeMode) || other.themeMode == themeMode)&&(identical(other.disableAnimation, disableAnimation) || other.disableAnimation == disableAnimation)&&(identical(other.groupedChatList, groupedChatList) || other.groupedChatList == groupedChatList)&&(identical(other.firstLaunchAt, firstLaunchAt) || other.firstLaunchAt == firstLaunchAt)&&(identical(other.askedReview, askedReview) || other.askedReview == askedReview)&&(identical(other.dashSearchEngine, dashSearchEngine) || other.dashSearchEngine == dashSearchEngine)&&(identical(other.defaultScreen, defaultScreen) || other.defaultScreen == defaultScreen));
return identical(this, other) || (other.runtimeType == runtimeType&&other is AppSettings&&(identical(other.dataSavingMode, dataSavingMode) || other.dataSavingMode == dataSavingMode)&&(identical(other.soundEffects, soundEffects) || other.soundEffects == soundEffects)&&(identical(other.festivalFeatures, festivalFeatures) || other.festivalFeatures == festivalFeatures)&&(identical(other.enterToSend, enterToSend) || other.enterToSend == enterToSend)&&(identical(other.appBarTransparent, appBarTransparent) || other.appBarTransparent == appBarTransparent)&&(identical(other.showBackgroundImage, showBackgroundImage) || other.showBackgroundImage == showBackgroundImage)&&(identical(other.notifyWithHaptic, notifyWithHaptic) || other.notifyWithHaptic == notifyWithHaptic)&&(identical(other.customFonts, customFonts) || other.customFonts == customFonts)&&(identical(other.appColorScheme, appColorScheme) || other.appColorScheme == appColorScheme)&&(identical(other.customColors, customColors) || other.customColors == customColors)&&(identical(other.windowSize, windowSize) || other.windowSize == windowSize)&&(identical(other.windowOpacity, windowOpacity) || other.windowOpacity == windowOpacity)&&(identical(other.cardTransparency, cardTransparency) || other.cardTransparency == cardTransparency)&&(identical(other.defaultPoolId, defaultPoolId) || other.defaultPoolId == defaultPoolId)&&(identical(other.messageDisplayStyle, messageDisplayStyle) || other.messageDisplayStyle == messageDisplayStyle)&&(identical(other.themeMode, themeMode) || other.themeMode == themeMode)&&(identical(other.disableAnimation, disableAnimation) || other.disableAnimation == disableAnimation)&&(identical(other.groupedChatList, groupedChatList) || other.groupedChatList == groupedChatList)&&(identical(other.firstLaunchAt, firstLaunchAt) || other.firstLaunchAt == firstLaunchAt)&&(identical(other.askedReview, askedReview) || other.askedReview == askedReview)&&(identical(other.dashSearchEngine, dashSearchEngine) || other.dashSearchEngine == dashSearchEngine)&&(identical(other.defaultScreen, defaultScreen) || other.defaultScreen == defaultScreen)&&(identical(other.showFediverseContent, showFediverseContent) || other.showFediverseContent == showFediverseContent));
}
@override
int get hashCode => Object.hashAll([runtimeType,dataSavingMode,soundEffects,festivalFeatures,enterToSend,appBarTransparent,showBackgroundImage,notifyWithHaptic,customFonts,appColorScheme,customColors,windowSize,windowOpacity,cardTransparency,defaultPoolId,messageDisplayStyle,themeMode,disableAnimation,groupedChatList,firstLaunchAt,askedReview,dashSearchEngine,defaultScreen]);
int get hashCode => Object.hashAll([runtimeType,dataSavingMode,soundEffects,festivalFeatures,enterToSend,appBarTransparent,showBackgroundImage,notifyWithHaptic,customFonts,appColorScheme,customColors,windowSize,windowOpacity,cardTransparency,defaultPoolId,messageDisplayStyle,themeMode,disableAnimation,groupedChatList,firstLaunchAt,askedReview,dashSearchEngine,defaultScreen,showFediverseContent]);
@override
String toString() {
return 'AppSettings(dataSavingMode: $dataSavingMode, soundEffects: $soundEffects, festivalFeatures: $festivalFeatures, enterToSend: $enterToSend, appBarTransparent: $appBarTransparent, showBackgroundImage: $showBackgroundImage, notifyWithHaptic: $notifyWithHaptic, customFonts: $customFonts, appColorScheme: $appColorScheme, customColors: $customColors, windowSize: $windowSize, windowOpacity: $windowOpacity, cardTransparency: $cardTransparency, defaultPoolId: $defaultPoolId, messageDisplayStyle: $messageDisplayStyle, themeMode: $themeMode, disableAnimation: $disableAnimation, groupedChatList: $groupedChatList, firstLaunchAt: $firstLaunchAt, askedReview: $askedReview, dashSearchEngine: $dashSearchEngine, defaultScreen: $defaultScreen)';
return 'AppSettings(dataSavingMode: $dataSavingMode, soundEffects: $soundEffects, festivalFeatures: $festivalFeatures, enterToSend: $enterToSend, appBarTransparent: $appBarTransparent, showBackgroundImage: $showBackgroundImage, notifyWithHaptic: $notifyWithHaptic, customFonts: $customFonts, appColorScheme: $appColorScheme, customColors: $customColors, windowSize: $windowSize, windowOpacity: $windowOpacity, cardTransparency: $cardTransparency, defaultPoolId: $defaultPoolId, messageDisplayStyle: $messageDisplayStyle, themeMode: $themeMode, disableAnimation: $disableAnimation, groupedChatList: $groupedChatList, firstLaunchAt: $firstLaunchAt, askedReview: $askedReview, dashSearchEngine: $dashSearchEngine, defaultScreen: $defaultScreen, showFediverseContent: $showFediverseContent)';
}
@@ -321,7 +321,7 @@ abstract mixin class $AppSettingsCopyWith<$Res> {
factory $AppSettingsCopyWith(AppSettings value, $Res Function(AppSettings) _then) = _$AppSettingsCopyWithImpl;
@useResult
$Res call({
bool dataSavingMode, bool soundEffects, bool festivalFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, bool notifyWithHaptic, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool disableAnimation, bool groupedChatList, String? firstLaunchAt, bool askedReview, String? dashSearchEngine, String? defaultScreen
bool dataSavingMode, bool soundEffects, bool festivalFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, bool notifyWithHaptic, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool disableAnimation, bool groupedChatList, String? firstLaunchAt, bool askedReview, String? dashSearchEngine, String? defaultScreen, bool showFediverseContent
});
@@ -338,7 +338,7 @@ class _$AppSettingsCopyWithImpl<$Res>
/// Create a copy of AppSettings
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? dataSavingMode = null,Object? soundEffects = null,Object? festivalFeatures = null,Object? enterToSend = null,Object? appBarTransparent = null,Object? showBackgroundImage = null,Object? notifyWithHaptic = null,Object? customFonts = freezed,Object? appColorScheme = freezed,Object? customColors = freezed,Object? windowSize = freezed,Object? windowOpacity = null,Object? cardTransparency = null,Object? defaultPoolId = freezed,Object? messageDisplayStyle = null,Object? themeMode = freezed,Object? disableAnimation = null,Object? groupedChatList = null,Object? firstLaunchAt = freezed,Object? askedReview = null,Object? dashSearchEngine = freezed,Object? defaultScreen = freezed,}) {
@pragma('vm:prefer-inline') @override $Res call({Object? dataSavingMode = null,Object? soundEffects = null,Object? festivalFeatures = null,Object? enterToSend = null,Object? appBarTransparent = null,Object? showBackgroundImage = null,Object? notifyWithHaptic = null,Object? customFonts = freezed,Object? appColorScheme = freezed,Object? customColors = freezed,Object? windowSize = freezed,Object? windowOpacity = null,Object? cardTransparency = null,Object? defaultPoolId = freezed,Object? messageDisplayStyle = null,Object? themeMode = freezed,Object? disableAnimation = null,Object? groupedChatList = null,Object? firstLaunchAt = freezed,Object? askedReview = null,Object? dashSearchEngine = freezed,Object? defaultScreen = freezed,Object? showFediverseContent = null,}) {
return _then(_self.copyWith(
dataSavingMode: null == dataSavingMode ? _self.dataSavingMode : dataSavingMode // ignore: cast_nullable_to_non_nullable
as bool,soundEffects: null == soundEffects ? _self.soundEffects : soundEffects // ignore: cast_nullable_to_non_nullable
@@ -362,7 +362,8 @@ as bool,firstLaunchAt: freezed == firstLaunchAt ? _self.firstLaunchAt : firstLau
as String?,askedReview: null == askedReview ? _self.askedReview : askedReview // ignore: cast_nullable_to_non_nullable
as bool,dashSearchEngine: freezed == dashSearchEngine ? _self.dashSearchEngine : dashSearchEngine // ignore: cast_nullable_to_non_nullable
as String?,defaultScreen: freezed == defaultScreen ? _self.defaultScreen : defaultScreen // ignore: cast_nullable_to_non_nullable
as String?,
as String?,showFediverseContent: null == showFediverseContent ? _self.showFediverseContent : showFediverseContent // ignore: cast_nullable_to_non_nullable
as bool,
));
}
/// Create a copy of AppSettings
@@ -456,10 +457,10 @@ return $default(_that);case _:
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( bool dataSavingMode, bool soundEffects, bool festivalFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, bool notifyWithHaptic, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool disableAnimation, bool groupedChatList, String? firstLaunchAt, bool askedReview, String? dashSearchEngine, String? defaultScreen)? $default,{required TResult orElse(),}) {final _that = this;
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( bool dataSavingMode, bool soundEffects, bool festivalFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, bool notifyWithHaptic, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool disableAnimation, bool groupedChatList, String? firstLaunchAt, bool askedReview, String? dashSearchEngine, String? defaultScreen, bool showFediverseContent)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _AppSettings() when $default != null:
return $default(_that.dataSavingMode,_that.soundEffects,_that.festivalFeatures,_that.enterToSend,_that.appBarTransparent,_that.showBackgroundImage,_that.notifyWithHaptic,_that.customFonts,_that.appColorScheme,_that.customColors,_that.windowSize,_that.windowOpacity,_that.cardTransparency,_that.defaultPoolId,_that.messageDisplayStyle,_that.themeMode,_that.disableAnimation,_that.groupedChatList,_that.firstLaunchAt,_that.askedReview,_that.dashSearchEngine,_that.defaultScreen);case _:
return $default(_that.dataSavingMode,_that.soundEffects,_that.festivalFeatures,_that.enterToSend,_that.appBarTransparent,_that.showBackgroundImage,_that.notifyWithHaptic,_that.customFonts,_that.appColorScheme,_that.customColors,_that.windowSize,_that.windowOpacity,_that.cardTransparency,_that.defaultPoolId,_that.messageDisplayStyle,_that.themeMode,_that.disableAnimation,_that.groupedChatList,_that.firstLaunchAt,_that.askedReview,_that.dashSearchEngine,_that.defaultScreen,_that.showFediverseContent);case _:
return orElse();
}
@@ -477,10 +478,10 @@ return $default(_that.dataSavingMode,_that.soundEffects,_that.festivalFeatures,_
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( bool dataSavingMode, bool soundEffects, bool festivalFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, bool notifyWithHaptic, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool disableAnimation, bool groupedChatList, String? firstLaunchAt, bool askedReview, String? dashSearchEngine, String? defaultScreen) $default,) {final _that = this;
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( bool dataSavingMode, bool soundEffects, bool festivalFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, bool notifyWithHaptic, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool disableAnimation, bool groupedChatList, String? firstLaunchAt, bool askedReview, String? dashSearchEngine, String? defaultScreen, bool showFediverseContent) $default,) {final _that = this;
switch (_that) {
case _AppSettings():
return $default(_that.dataSavingMode,_that.soundEffects,_that.festivalFeatures,_that.enterToSend,_that.appBarTransparent,_that.showBackgroundImage,_that.notifyWithHaptic,_that.customFonts,_that.appColorScheme,_that.customColors,_that.windowSize,_that.windowOpacity,_that.cardTransparency,_that.defaultPoolId,_that.messageDisplayStyle,_that.themeMode,_that.disableAnimation,_that.groupedChatList,_that.firstLaunchAt,_that.askedReview,_that.dashSearchEngine,_that.defaultScreen);}
return $default(_that.dataSavingMode,_that.soundEffects,_that.festivalFeatures,_that.enterToSend,_that.appBarTransparent,_that.showBackgroundImage,_that.notifyWithHaptic,_that.customFonts,_that.appColorScheme,_that.customColors,_that.windowSize,_that.windowOpacity,_that.cardTransparency,_that.defaultPoolId,_that.messageDisplayStyle,_that.themeMode,_that.disableAnimation,_that.groupedChatList,_that.firstLaunchAt,_that.askedReview,_that.dashSearchEngine,_that.defaultScreen,_that.showFediverseContent);}
}
/// A variant of `when` that fallback to returning `null`
///
@@ -494,10 +495,10 @@ return $default(_that.dataSavingMode,_that.soundEffects,_that.festivalFeatures,_
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( bool dataSavingMode, bool soundEffects, bool festivalFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, bool notifyWithHaptic, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool disableAnimation, bool groupedChatList, String? firstLaunchAt, bool askedReview, String? dashSearchEngine, String? defaultScreen)? $default,) {final _that = this;
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( bool dataSavingMode, bool soundEffects, bool festivalFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, bool notifyWithHaptic, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool disableAnimation, bool groupedChatList, String? firstLaunchAt, bool askedReview, String? dashSearchEngine, String? defaultScreen, bool showFediverseContent)? $default,) {final _that = this;
switch (_that) {
case _AppSettings() when $default != null:
return $default(_that.dataSavingMode,_that.soundEffects,_that.festivalFeatures,_that.enterToSend,_that.appBarTransparent,_that.showBackgroundImage,_that.notifyWithHaptic,_that.customFonts,_that.appColorScheme,_that.customColors,_that.windowSize,_that.windowOpacity,_that.cardTransparency,_that.defaultPoolId,_that.messageDisplayStyle,_that.themeMode,_that.disableAnimation,_that.groupedChatList,_that.firstLaunchAt,_that.askedReview,_that.dashSearchEngine,_that.defaultScreen);case _:
return $default(_that.dataSavingMode,_that.soundEffects,_that.festivalFeatures,_that.enterToSend,_that.appBarTransparent,_that.showBackgroundImage,_that.notifyWithHaptic,_that.customFonts,_that.appColorScheme,_that.customColors,_that.windowSize,_that.windowOpacity,_that.cardTransparency,_that.defaultPoolId,_that.messageDisplayStyle,_that.themeMode,_that.disableAnimation,_that.groupedChatList,_that.firstLaunchAt,_that.askedReview,_that.dashSearchEngine,_that.defaultScreen,_that.showFediverseContent);case _:
return null;
}
@@ -509,7 +510,7 @@ return $default(_that.dataSavingMode,_that.soundEffects,_that.festivalFeatures,_
class _AppSettings implements AppSettings {
const _AppSettings({required this.dataSavingMode, required this.soundEffects, required this.festivalFeatures, required this.enterToSend, required this.appBarTransparent, required this.showBackgroundImage, required this.notifyWithHaptic, required this.customFonts, required this.appColorScheme, required this.customColors, required this.windowSize, required this.windowOpacity, required this.cardTransparency, required this.defaultPoolId, required this.messageDisplayStyle, required this.themeMode, required this.disableAnimation, required this.groupedChatList, required this.firstLaunchAt, required this.askedReview, required this.dashSearchEngine, required this.defaultScreen});
const _AppSettings({required this.dataSavingMode, required this.soundEffects, required this.festivalFeatures, required this.enterToSend, required this.appBarTransparent, required this.showBackgroundImage, required this.notifyWithHaptic, required this.customFonts, required this.appColorScheme, required this.customColors, required this.windowSize, required this.windowOpacity, required this.cardTransparency, required this.defaultPoolId, required this.messageDisplayStyle, required this.themeMode, required this.disableAnimation, required this.groupedChatList, required this.firstLaunchAt, required this.askedReview, required this.dashSearchEngine, required this.defaultScreen, required this.showFediverseContent});
@override final bool dataSavingMode;
@@ -538,6 +539,7 @@ class _AppSettings implements AppSettings {
@override final bool askedReview;
@override final String? dashSearchEngine;
@override final String? defaultScreen;
@override final bool showFediverseContent;
/// Create a copy of AppSettings
/// with the given fields replaced by the non-null parameter values.
@@ -549,16 +551,16 @@ _$AppSettingsCopyWith<_AppSettings> get copyWith => __$AppSettingsCopyWithImpl<_
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _AppSettings&&(identical(other.dataSavingMode, dataSavingMode) || other.dataSavingMode == dataSavingMode)&&(identical(other.soundEffects, soundEffects) || other.soundEffects == soundEffects)&&(identical(other.festivalFeatures, festivalFeatures) || other.festivalFeatures == festivalFeatures)&&(identical(other.enterToSend, enterToSend) || other.enterToSend == enterToSend)&&(identical(other.appBarTransparent, appBarTransparent) || other.appBarTransparent == appBarTransparent)&&(identical(other.showBackgroundImage, showBackgroundImage) || other.showBackgroundImage == showBackgroundImage)&&(identical(other.notifyWithHaptic, notifyWithHaptic) || other.notifyWithHaptic == notifyWithHaptic)&&(identical(other.customFonts, customFonts) || other.customFonts == customFonts)&&(identical(other.appColorScheme, appColorScheme) || other.appColorScheme == appColorScheme)&&(identical(other.customColors, customColors) || other.customColors == customColors)&&(identical(other.windowSize, windowSize) || other.windowSize == windowSize)&&(identical(other.windowOpacity, windowOpacity) || other.windowOpacity == windowOpacity)&&(identical(other.cardTransparency, cardTransparency) || other.cardTransparency == cardTransparency)&&(identical(other.defaultPoolId, defaultPoolId) || other.defaultPoolId == defaultPoolId)&&(identical(other.messageDisplayStyle, messageDisplayStyle) || other.messageDisplayStyle == messageDisplayStyle)&&(identical(other.themeMode, themeMode) || other.themeMode == themeMode)&&(identical(other.disableAnimation, disableAnimation) || other.disableAnimation == disableAnimation)&&(identical(other.groupedChatList, groupedChatList) || other.groupedChatList == groupedChatList)&&(identical(other.firstLaunchAt, firstLaunchAt) || other.firstLaunchAt == firstLaunchAt)&&(identical(other.askedReview, askedReview) || other.askedReview == askedReview)&&(identical(other.dashSearchEngine, dashSearchEngine) || other.dashSearchEngine == dashSearchEngine)&&(identical(other.defaultScreen, defaultScreen) || other.defaultScreen == defaultScreen));
return identical(this, other) || (other.runtimeType == runtimeType&&other is _AppSettings&&(identical(other.dataSavingMode, dataSavingMode) || other.dataSavingMode == dataSavingMode)&&(identical(other.soundEffects, soundEffects) || other.soundEffects == soundEffects)&&(identical(other.festivalFeatures, festivalFeatures) || other.festivalFeatures == festivalFeatures)&&(identical(other.enterToSend, enterToSend) || other.enterToSend == enterToSend)&&(identical(other.appBarTransparent, appBarTransparent) || other.appBarTransparent == appBarTransparent)&&(identical(other.showBackgroundImage, showBackgroundImage) || other.showBackgroundImage == showBackgroundImage)&&(identical(other.notifyWithHaptic, notifyWithHaptic) || other.notifyWithHaptic == notifyWithHaptic)&&(identical(other.customFonts, customFonts) || other.customFonts == customFonts)&&(identical(other.appColorScheme, appColorScheme) || other.appColorScheme == appColorScheme)&&(identical(other.customColors, customColors) || other.customColors == customColors)&&(identical(other.windowSize, windowSize) || other.windowSize == windowSize)&&(identical(other.windowOpacity, windowOpacity) || other.windowOpacity == windowOpacity)&&(identical(other.cardTransparency, cardTransparency) || other.cardTransparency == cardTransparency)&&(identical(other.defaultPoolId, defaultPoolId) || other.defaultPoolId == defaultPoolId)&&(identical(other.messageDisplayStyle, messageDisplayStyle) || other.messageDisplayStyle == messageDisplayStyle)&&(identical(other.themeMode, themeMode) || other.themeMode == themeMode)&&(identical(other.disableAnimation, disableAnimation) || other.disableAnimation == disableAnimation)&&(identical(other.groupedChatList, groupedChatList) || other.groupedChatList == groupedChatList)&&(identical(other.firstLaunchAt, firstLaunchAt) || other.firstLaunchAt == firstLaunchAt)&&(identical(other.askedReview, askedReview) || other.askedReview == askedReview)&&(identical(other.dashSearchEngine, dashSearchEngine) || other.dashSearchEngine == dashSearchEngine)&&(identical(other.defaultScreen, defaultScreen) || other.defaultScreen == defaultScreen)&&(identical(other.showFediverseContent, showFediverseContent) || other.showFediverseContent == showFediverseContent));
}
@override
int get hashCode => Object.hashAll([runtimeType,dataSavingMode,soundEffects,festivalFeatures,enterToSend,appBarTransparent,showBackgroundImage,notifyWithHaptic,customFonts,appColorScheme,customColors,windowSize,windowOpacity,cardTransparency,defaultPoolId,messageDisplayStyle,themeMode,disableAnimation,groupedChatList,firstLaunchAt,askedReview,dashSearchEngine,defaultScreen]);
int get hashCode => Object.hashAll([runtimeType,dataSavingMode,soundEffects,festivalFeatures,enterToSend,appBarTransparent,showBackgroundImage,notifyWithHaptic,customFonts,appColorScheme,customColors,windowSize,windowOpacity,cardTransparency,defaultPoolId,messageDisplayStyle,themeMode,disableAnimation,groupedChatList,firstLaunchAt,askedReview,dashSearchEngine,defaultScreen,showFediverseContent]);
@override
String toString() {
return 'AppSettings(dataSavingMode: $dataSavingMode, soundEffects: $soundEffects, festivalFeatures: $festivalFeatures, enterToSend: $enterToSend, appBarTransparent: $appBarTransparent, showBackgroundImage: $showBackgroundImage, notifyWithHaptic: $notifyWithHaptic, customFonts: $customFonts, appColorScheme: $appColorScheme, customColors: $customColors, windowSize: $windowSize, windowOpacity: $windowOpacity, cardTransparency: $cardTransparency, defaultPoolId: $defaultPoolId, messageDisplayStyle: $messageDisplayStyle, themeMode: $themeMode, disableAnimation: $disableAnimation, groupedChatList: $groupedChatList, firstLaunchAt: $firstLaunchAt, askedReview: $askedReview, dashSearchEngine: $dashSearchEngine, defaultScreen: $defaultScreen)';
return 'AppSettings(dataSavingMode: $dataSavingMode, soundEffects: $soundEffects, festivalFeatures: $festivalFeatures, enterToSend: $enterToSend, appBarTransparent: $appBarTransparent, showBackgroundImage: $showBackgroundImage, notifyWithHaptic: $notifyWithHaptic, customFonts: $customFonts, appColorScheme: $appColorScheme, customColors: $customColors, windowSize: $windowSize, windowOpacity: $windowOpacity, cardTransparency: $cardTransparency, defaultPoolId: $defaultPoolId, messageDisplayStyle: $messageDisplayStyle, themeMode: $themeMode, disableAnimation: $disableAnimation, groupedChatList: $groupedChatList, firstLaunchAt: $firstLaunchAt, askedReview: $askedReview, dashSearchEngine: $dashSearchEngine, defaultScreen: $defaultScreen, showFediverseContent: $showFediverseContent)';
}
@@ -569,7 +571,7 @@ abstract mixin class _$AppSettingsCopyWith<$Res> implements $AppSettingsCopyWith
factory _$AppSettingsCopyWith(_AppSettings value, $Res Function(_AppSettings) _then) = __$AppSettingsCopyWithImpl;
@override @useResult
$Res call({
bool dataSavingMode, bool soundEffects, bool festivalFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, bool notifyWithHaptic, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool disableAnimation, bool groupedChatList, String? firstLaunchAt, bool askedReview, String? dashSearchEngine, String? defaultScreen
bool dataSavingMode, bool soundEffects, bool festivalFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, bool notifyWithHaptic, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool disableAnimation, bool groupedChatList, String? firstLaunchAt, bool askedReview, String? dashSearchEngine, String? defaultScreen, bool showFediverseContent
});
@@ -586,7 +588,7 @@ class __$AppSettingsCopyWithImpl<$Res>
/// Create a copy of AppSettings
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? dataSavingMode = null,Object? soundEffects = null,Object? festivalFeatures = null,Object? enterToSend = null,Object? appBarTransparent = null,Object? showBackgroundImage = null,Object? notifyWithHaptic = null,Object? customFonts = freezed,Object? appColorScheme = freezed,Object? customColors = freezed,Object? windowSize = freezed,Object? windowOpacity = null,Object? cardTransparency = null,Object? defaultPoolId = freezed,Object? messageDisplayStyle = null,Object? themeMode = freezed,Object? disableAnimation = null,Object? groupedChatList = null,Object? firstLaunchAt = freezed,Object? askedReview = null,Object? dashSearchEngine = freezed,Object? defaultScreen = freezed,}) {
@override @pragma('vm:prefer-inline') $Res call({Object? dataSavingMode = null,Object? soundEffects = null,Object? festivalFeatures = null,Object? enterToSend = null,Object? appBarTransparent = null,Object? showBackgroundImage = null,Object? notifyWithHaptic = null,Object? customFonts = freezed,Object? appColorScheme = freezed,Object? customColors = freezed,Object? windowSize = freezed,Object? windowOpacity = null,Object? cardTransparency = null,Object? defaultPoolId = freezed,Object? messageDisplayStyle = null,Object? themeMode = freezed,Object? disableAnimation = null,Object? groupedChatList = null,Object? firstLaunchAt = freezed,Object? askedReview = null,Object? dashSearchEngine = freezed,Object? defaultScreen = freezed,Object? showFediverseContent = null,}) {
return _then(_AppSettings(
dataSavingMode: null == dataSavingMode ? _self.dataSavingMode : dataSavingMode // ignore: cast_nullable_to_non_nullable
as bool,soundEffects: null == soundEffects ? _self.soundEffects : soundEffects // ignore: cast_nullable_to_non_nullable
@@ -610,7 +612,8 @@ as bool,firstLaunchAt: freezed == firstLaunchAt ? _self.firstLaunchAt : firstLau
as String?,askedReview: null == askedReview ? _self.askedReview : askedReview // ignore: cast_nullable_to_non_nullable
as bool,dashSearchEngine: freezed == dashSearchEngine ? _self.dashSearchEngine : dashSearchEngine // ignore: cast_nullable_to_non_nullable
as String?,defaultScreen: freezed == defaultScreen ? _self.defaultScreen : defaultScreen // ignore: cast_nullable_to_non_nullable
as String?,
as String?,showFediverseContent: null == showFediverseContent ? _self.showFediverseContent : showFediverseContent // ignore: cast_nullable_to_non_nullable
as bool,
));
}

View File

@@ -33,11 +33,11 @@ Map<String, dynamic> _$ThemeColorsToJson(_ThemeColors instance) =>
// ignore_for_file: type=lint, type=warning
@ProviderFor(AppSettingsNotifier)
const appSettingsProvider = AppSettingsNotifierProvider._();
final appSettingsProvider = AppSettingsNotifierProvider._();
final class AppSettingsNotifierProvider
extends $NotifierProvider<AppSettingsNotifier, AppSettings> {
const AppSettingsNotifierProvider._()
AppSettingsNotifierProvider._()
: super(
from: null,
argument: null,
@@ -65,14 +65,13 @@ final class AppSettingsNotifierProvider
}
String _$appSettingsNotifierHash() =>
r'6592261baf8182fe78d3e58e2fd9bb53d3287736';
r'2437c621dcb1625a120ed1f21ab5c29906ba98be';
abstract class _$AppSettingsNotifier extends $Notifier<AppSettings> {
AppSettings build();
@$mustCallSuper
@override
void runBuild() {
final created = build();
final ref = this.ref as $Ref<AppSettings, AppSettings>;
final element =
ref.element
@@ -82,6 +81,6 @@ abstract class _$AppSettingsNotifier extends $Notifier<AppSettings> {
Object?,
Object?
>;
element.handleValue(ref, created);
element.handleCreate(ref, build);
}
}

View File

@@ -18,7 +18,8 @@ final indexedCloudFileListProvider = AsyncNotifierProvider.autoDispose(
IndexedCloudFileListNotifier.new,
);
class IndexedCloudFileListNotifier extends AsyncNotifier<List<FileListItem>>
class IndexedCloudFileListNotifier
extends AsyncNotifier<PaginationState<FileListItem>>
with AsyncPaginationController<FileListItem> {
String _currentPath = '/';
String? _poolId;
@@ -51,6 +52,19 @@ class IndexedCloudFileListNotifier extends AsyncNotifier<List<FileListItem>>
ref.invalidateSelf();
}
@override
FutureOr<PaginationState<FileListItem>> build() async {
final items = await fetch();
return PaginationState(
items: items,
isLoading: false,
isReloading: false,
totalCount: null,
hasMore: false,
cursor: null,
);
}
@override
Future<List<FileListItem>> fetch() async {
final client = ref.read(apiClientProvider);
@@ -96,7 +110,8 @@ final unindexedFileListProvider = AsyncNotifierProvider.autoDispose(
UnindexedFileListNotifier.new,
);
class UnindexedFileListNotifier extends AsyncNotifier<List<FileListItem>>
class UnindexedFileListNotifier
extends AsyncNotifier<PaginationState<FileListItem>>
with AsyncPaginationController<FileListItem> {
String? _poolId;
bool _recycled = false;
@@ -131,6 +146,19 @@ class UnindexedFileListNotifier extends AsyncNotifier<List<FileListItem>>
static const int pageSize = 20;
@override
FutureOr<PaginationState<FileListItem>> build() async {
final items = await fetch();
return PaginationState(
items: items,
isLoading: false,
isReloading: false,
totalCount: totalCount,
hasMore: hasMore,
cursor: cursor,
);
}
@override
Future<List<FileListItem>> fetch() async {
final client = ref.read(apiClientProvider);

View File

@@ -10,7 +10,7 @@ part of 'file_list.dart';
// ignore_for_file: type=lint, type=warning
@ProviderFor(billingUsage)
const billingUsageProvider = BillingUsageProvider._();
final billingUsageProvider = BillingUsageProvider._();
final class BillingUsageProvider
extends
@@ -22,7 +22,7 @@ final class BillingUsageProvider
with
$FutureModifier<Map<String, dynamic>?>,
$FutureProvider<Map<String, dynamic>?> {
const BillingUsageProvider._()
BillingUsageProvider._()
: super(
from: null,
argument: null,
@@ -51,7 +51,7 @@ final class BillingUsageProvider
String _$billingUsageHash() => r'58d8bc774868d60781574c85d6b25869a79c57aa';
@ProviderFor(billingQuota)
const billingQuotaProvider = BillingQuotaProvider._();
final billingQuotaProvider = BillingQuotaProvider._();
final class BillingQuotaProvider
extends
@@ -63,7 +63,7 @@ final class BillingQuotaProvider
with
$FutureModifier<Map<String, dynamic>?>,
$FutureProvider<Map<String, dynamic>?> {
const BillingQuotaProvider._()
BillingQuotaProvider._()
: super(
from: null,
argument: null,

View File

@@ -10,7 +10,7 @@ part of 'file_references.dart';
// ignore_for_file: type=lint, type=warning
@ProviderFor(fileReferences)
const fileReferencesProvider = FileReferencesFamily._();
final fileReferencesProvider = FileReferencesFamily._();
final class FileReferencesProvider
extends
@@ -20,7 +20,7 @@ final class FileReferencesProvider
FutureOr<List<Reference>>
>
with $FutureModifier<List<Reference>>, $FutureProvider<List<Reference>> {
const FileReferencesProvider._({
FileReferencesProvider._({
required FileReferencesFamily super.from,
required String super.argument,
}) : super(
@@ -68,7 +68,7 @@ String _$fileReferencesHash() => r'd66c678c221f61978bdb242b98e6dbe31d0c204b';
final class FileReferencesFamily extends $Family
with $FunctionalFamilyOverride<FutureOr<List<Reference>>, String> {
const FileReferencesFamily._()
FileReferencesFamily._()
: super(
retry: null,
name: r'fileReferencesProvider',

View File

@@ -12,7 +12,7 @@ part of 'event_calendar.dart';
/// This can be used anywhere in the app where calendar data is needed
@ProviderFor(eventCalendar)
const eventCalendarProvider = EventCalendarFamily._();
final eventCalendarProvider = EventCalendarFamily._();
/// Provider for fetching event calendar data
/// This can be used anywhere in the app where calendar data is needed
@@ -29,7 +29,7 @@ final class EventCalendarProvider
$FutureProvider<List<SnEventCalendarEntry>> {
/// Provider for fetching event calendar data
/// This can be used anywhere in the app where calendar data is needed
const EventCalendarProvider._({
EventCalendarProvider._({
required EventCalendarFamily super.from,
required EventCalendarQuery super.argument,
}) : super(
@@ -84,7 +84,7 @@ final class EventCalendarFamily extends $Family
FutureOr<List<SnEventCalendarEntry>>,
EventCalendarQuery
> {
const EventCalendarFamily._()
EventCalendarFamily._()
: super(
retry: null,
name: r'eventCalendarProvider',

View File

@@ -10,11 +10,11 @@ part of 'link_preview.dart';
// ignore_for_file: type=lint, type=warning
@ProviderFor(LinkPreview)
const linkPreviewProvider = LinkPreviewFamily._();
final linkPreviewProvider = LinkPreviewFamily._();
final class LinkPreviewProvider
extends $AsyncNotifierProvider<LinkPreview, SnScrappedLink?> {
const LinkPreviewProvider._({
LinkPreviewProvider._({
required LinkPreviewFamily super.from,
required String super.argument,
}) : super(
@@ -61,7 +61,7 @@ final class LinkPreviewFamily extends $Family
FutureOr<SnScrappedLink?>,
String
> {
const LinkPreviewFamily._()
LinkPreviewFamily._()
: super(
retry: null,
name: r'linkPreviewProvider',
@@ -85,7 +85,6 @@ abstract class _$LinkPreview extends $AsyncNotifier<SnScrappedLink?> {
@$mustCallSuper
@override
void runBuild() {
final created = build(_$args);
final ref = this.ref as $Ref<AsyncValue<SnScrappedLink?>, SnScrappedLink?>;
final element =
ref.element
@@ -95,6 +94,6 @@ abstract class _$LinkPreview extends $AsyncNotifier<SnScrappedLink?> {
Object?,
Object?
>;
element.handleValue(ref, created);
element.handleCreate(ref, () => build(_$args));
}
}

View File

@@ -10,11 +10,11 @@ part of 'network.dart';
// ignore_for_file: type=lint, type=warning
@ProviderFor(NetworkStatusNotifier)
const networkStatusProvider = NetworkStatusNotifierProvider._();
final networkStatusProvider = NetworkStatusNotifierProvider._();
final class NetworkStatusNotifierProvider
extends $NotifierProvider<NetworkStatusNotifier, NetworkStatus> {
const NetworkStatusNotifierProvider._()
NetworkStatusNotifierProvider._()
: super(
from: null,
argument: null,
@@ -49,7 +49,6 @@ abstract class _$NetworkStatusNotifier extends $Notifier<NetworkStatus> {
@$mustCallSuper
@override
void runBuild() {
final created = build();
final ref = this.ref as $Ref<NetworkStatus, NetworkStatus>;
final element =
ref.element
@@ -59,6 +58,6 @@ abstract class _$NetworkStatusNotifier extends $Notifier<NetworkStatus> {
Object?,
Object?
>;
element.handleValue(ref, created);
element.handleCreate(ref, build);
}
}

View File

@@ -2,12 +2,49 @@ import 'dart:async';
import 'package:hooks_riverpod/hooks_riverpod.dart';
class PaginationState<T> {
final List<T> items;
final bool isLoading;
final bool isReloading;
final int? totalCount;
final bool hasMore;
final String? cursor;
const PaginationState({
required this.items,
required this.isLoading,
required this.isReloading,
required this.totalCount,
required this.hasMore,
required this.cursor,
});
PaginationState<T> copyWith({
List<T>? items,
bool? isLoading,
bool? isReloading,
int? totalCount,
bool? hasMore,
String? cursor,
}) {
return PaginationState<T>(
items: items ?? this.items,
isLoading: isLoading ?? this.isLoading,
isReloading: isReloading ?? this.isReloading,
totalCount: totalCount ?? this.totalCount,
hasMore: hasMore ?? this.hasMore,
cursor: cursor ?? this.cursor,
);
}
}
abstract class PaginationController<T> {
int? get totalCount;
int get fetchedCount;
bool get fetchedAll;
bool get isLoading;
bool get isReloading;
bool get hasMore;
set hasMore(bool value);
String? get cursor;
@@ -26,46 +63,86 @@ abstract class PaginationFiltered<F> {
Future<void> applyFilter(F filter);
}
mixin AsyncPaginationController<T> on AsyncNotifier<List<T>>
mixin AsyncPaginationController<T> on AsyncNotifier<PaginationState<T>>
implements PaginationController<T> {
@override
int? totalCount;
@override
int get fetchedCount => state.value?.length ?? 0;
int get fetchedCount =>
state.value?.isReloading == true ? 0 : state.value?.items.length ?? 0;
@override
bool get fetchedAll =>
!hasMore || (totalCount != null && fetchedCount >= totalCount!);
!(state.value?.hasMore ?? true) ||
((state.value?.totalCount != null &&
fetchedCount >= state.value!.totalCount!));
@override
bool isLoading = false;
bool get isLoading => state.value?.isLoading ?? false;
@override
bool hasMore = true;
bool get isReloading => state.value?.isReloading ?? false;
@override
String? cursor;
bool get hasMore => state.value?.hasMore ?? true;
@override
FutureOr<List<T>> build() async {
cursor = null;
return fetch();
String? get cursor => state.value?.cursor;
@override
set hasMore(bool value) {
if (state is AsyncData) {
state = AsyncData((state as AsyncData).value.copyWith(hasMore: value));
}
}
@override
set cursor(String? value) {
if (state is AsyncData) {
state = AsyncData((state as AsyncData).value.copyWith(cursor: value));
}
}
@override
FutureOr<PaginationState<T>> build() async {
final items = await fetch();
return PaginationState(
items: items,
isLoading: false,
isReloading: false,
totalCount: totalCount,
hasMore: hasMore,
cursor: cursor,
);
}
@override
Future<void> refresh() async {
isLoading = true;
totalCount = null;
hasMore = true;
cursor = null;
state = AsyncLoading<List<T>>();
state = AsyncData(
PaginationState(
items: [],
isLoading: true,
isReloading: true,
totalCount: null,
hasMore: true,
cursor: null,
),
);
final newState = await AsyncValue.guard<List<T>>(() async {
return await fetch();
});
state = newState;
isLoading = false;
final newItems = await fetch();
if (!ref.mounted) return;
state = AsyncData(
PaginationState(
items: newItems,
isLoading: false,
isReloading: false,
totalCount: totalCount,
hasMore: hasMore,
cursor: cursor,
),
);
}
@override
@@ -73,16 +150,17 @@ mixin AsyncPaginationController<T> on AsyncNotifier<List<T>>
if (fetchedAll) return;
if (isLoading) return;
isLoading = true;
state = AsyncLoading<List<T>>();
state = AsyncData(state.value!.copyWith(isLoading: true));
final newState = await AsyncValue.guard<List<T>>(() async {
final elements = await fetch();
return [...?state.value, ...elements];
});
final newItems = await fetch();
state = newState;
isLoading = false;
if (!ref.mounted) return;
state = AsyncData(
state.value!.copyWith(
items: [...state.value!.items, ...newItems],
isLoading: false,
),
);
}
}
@@ -91,18 +169,31 @@ mixin AsyncPaginationFilter<F, T> on AsyncPaginationController<T>
@override
Future<void> applyFilter(F filter) async {
if (currentFilter == filter) return;
// Reset the data
isLoading = true;
totalCount = null;
hasMore = true;
cursor = null;
state = AsyncLoading<List<T>>();
state = AsyncData(
PaginationState(
items: [],
isLoading: true,
isReloading: true,
totalCount: null,
hasMore: true,
cursor: null,
),
);
currentFilter = filter;
final newState = await AsyncValue.guard<List<T>>(() async {
return await fetch();
});
state = newState;
isLoading = false;
final newItems = await fetch();
if (!ref.mounted) return;
state = AsyncData(
PaginationState(
items: newItems,
isLoading: false,
isReloading: false,
totalCount: totalCount,
hasMore: hasMore,
cursor: cursor,
),
);
}
}

View File

@@ -1,4 +1,6 @@
// Post Categories Notifier
import 'dart:async';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/models/post_category.dart';
import 'package:island/models/post_tag.dart';
@@ -8,11 +10,25 @@ import 'package:island/pods/paging.dart';
final postCategoriesProvider =
AsyncNotifierProvider.autoDispose<
PostCategoriesNotifier,
List<SnPostCategory>
PaginationState<SnPostCategory>
>(PostCategoriesNotifier.new);
class PostCategoriesNotifier extends AsyncNotifier<List<SnPostCategory>>
class PostCategoriesNotifier
extends AsyncNotifier<PaginationState<SnPostCategory>>
with AsyncPaginationController<SnPostCategory> {
@override
FutureOr<PaginationState<SnPostCategory>> build() async {
final items = await fetch();
return PaginationState(
items: items,
isLoading: false,
isReloading: false,
totalCount: totalCount,
hasMore: hasMore,
cursor: cursor,
);
}
@override
Future<List<SnPostCategory>> fetch() async {
final client = ref.read(apiClientProvider);
@@ -30,12 +46,26 @@ class PostCategoriesNotifier extends AsyncNotifier<List<SnPostCategory>>
// Post Tags Notifier
final postTagsProvider =
AsyncNotifierProvider.autoDispose<PostTagsNotifier, List<SnPostTag>>(
PostTagsNotifier.new,
);
AsyncNotifierProvider.autoDispose<
PostTagsNotifier,
PaginationState<SnPostTag>
>(PostTagsNotifier.new);
class PostTagsNotifier extends AsyncNotifier<List<SnPostTag>>
class PostTagsNotifier extends AsyncNotifier<PaginationState<SnPostTag>>
with AsyncPaginationController<SnPostTag> {
@override
FutureOr<PaginationState<SnPostTag>> build() async {
final items = await fetch();
return PaginationState(
items: items,
isLoading: false,
isReloading: false,
totalCount: totalCount,
hasMore: hasMore,
cursor: cursor,
);
}
@override
Future<List<SnPostTag>> fetch() async {
final client = ref.read(apiClientProvider);

View File

@@ -1,3 +1,5 @@
import 'dart:async';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/models/post.dart';
@@ -39,7 +41,7 @@ final postListProvider = AsyncNotifierProvider.autoDispose.family(
PostListNotifier.new,
);
class PostListNotifier extends AsyncNotifier<List<SnPost>>
class PostListNotifier extends AsyncNotifier<PaginationState<SnPost>>
with
AsyncPaginationController<SnPost>,
AsyncPaginationFilter<PostListQuery, SnPost> {
@@ -53,9 +55,17 @@ class PostListNotifier extends AsyncNotifier<List<SnPost>>
late PostListQuery currentFilter;
@override
Future<List<SnPost>> build() async {
FutureOr<PaginationState<SnPost>> build() async {
currentFilter = config.initialFilter;
return fetch();
final items = await fetch();
return PaginationState(
items: items,
isLoading: false,
isReloading: false,
totalCount: totalCount,
hasMore: hasMore,
cursor: cursor,
);
}
@override

View File

@@ -10,7 +10,7 @@ part of 'site_files.dart';
// ignore_for_file: type=lint, type=warning
@ProviderFor(siteFiles)
const siteFilesProvider = SiteFilesFamily._();
final siteFilesProvider = SiteFilesFamily._();
final class SiteFilesProvider
extends
@@ -22,7 +22,7 @@ final class SiteFilesProvider
with
$FutureModifier<List<SnSiteFileEntry>>,
$FutureProvider<List<SnSiteFileEntry>> {
const SiteFilesProvider._({
SiteFilesProvider._({
required SiteFilesFamily super.from,
required ({String siteId, String? path}) super.argument,
}) : super(
@@ -74,7 +74,7 @@ final class SiteFilesFamily extends $Family
FutureOr<List<SnSiteFileEntry>>,
({String siteId, String? path})
> {
const SiteFilesFamily._()
SiteFilesFamily._()
: super(
retry: null,
name: r'siteFilesProvider',
@@ -91,7 +91,7 @@ final class SiteFilesFamily extends $Family
}
@ProviderFor(siteFileContent)
const siteFileContentProvider = SiteFileContentFamily._();
final siteFileContentProvider = SiteFileContentFamily._();
final class SiteFileContentProvider
extends
@@ -101,7 +101,7 @@ final class SiteFileContentProvider
FutureOr<SnFileContent>
>
with $FutureModifier<SnFileContent>, $FutureProvider<SnFileContent> {
const SiteFileContentProvider._({
SiteFileContentProvider._({
required SiteFileContentFamily super.from,
required ({String siteId, String relativePath}) super.argument,
}) : super(
@@ -157,7 +157,7 @@ final class SiteFileContentFamily extends $Family
FutureOr<SnFileContent>,
({String siteId, String relativePath})
> {
const SiteFileContentFamily._()
SiteFileContentFamily._()
: super(
retry: null,
name: r'siteFileContentProvider',
@@ -179,12 +179,12 @@ final class SiteFileContentFamily extends $Family
}
@ProviderFor(siteFileContentRaw)
const siteFileContentRawProvider = SiteFileContentRawFamily._();
final siteFileContentRawProvider = SiteFileContentRawFamily._();
final class SiteFileContentRawProvider
extends $FunctionalProvider<AsyncValue<String>, String, FutureOr<String>>
with $FutureModifier<String>, $FutureProvider<String> {
const SiteFileContentRawProvider._({
SiteFileContentRawProvider._({
required SiteFileContentRawFamily super.from,
required ({String siteId, String relativePath}) super.argument,
}) : super(
@@ -240,7 +240,7 @@ final class SiteFileContentRawFamily extends $Family
FutureOr<String>,
({String siteId, String relativePath})
> {
const SiteFileContentRawFamily._()
SiteFileContentRawFamily._()
: super(
retry: null,
name: r'siteFileContentRawProvider',

View File

@@ -10,7 +10,7 @@ part of 'site_pages.dart';
// ignore_for_file: type=lint, type=warning
@ProviderFor(sitePages)
const sitePagesProvider = SitePagesFamily._();
final sitePagesProvider = SitePagesFamily._();
final class SitePagesProvider
extends
@@ -22,7 +22,7 @@ final class SitePagesProvider
with
$FutureModifier<List<SnPublicationPage>>,
$FutureProvider<List<SnPublicationPage>> {
const SitePagesProvider._({
SitePagesProvider._({
required SitePagesFamily super.from,
required (String, String) super.argument,
}) : super(
@@ -74,7 +74,7 @@ final class SitePagesFamily extends $Family
FutureOr<List<SnPublicationPage>>,
(String, String)
> {
const SitePagesFamily._()
SitePagesFamily._()
: super(
retry: null,
name: r'sitePagesProvider',
@@ -91,7 +91,7 @@ final class SitePagesFamily extends $Family
}
@ProviderFor(sitePage)
const sitePageProvider = SitePageFamily._();
final sitePageProvider = SitePageFamily._();
final class SitePageProvider
extends
@@ -103,7 +103,7 @@ final class SitePageProvider
with
$FutureModifier<SnPublicationPage>,
$FutureProvider<SnPublicationPage> {
const SitePageProvider._({
SitePageProvider._({
required SitePageFamily super.from,
required String super.argument,
}) : super(
@@ -151,7 +151,7 @@ String _$sitePageHash() => r'542f70c5b103fe34d7cf7eb0821d52f017022efc';
final class SitePageFamily extends $Family
with $FunctionalFamilyOverride<FutureOr<SnPublicationPage>, String> {
const SitePageFamily._()
SitePageFamily._()
: super(
retry: null,
name: r'sitePageProvider',

View File

@@ -10,12 +10,12 @@ part of 'theme.dart';
// ignore_for_file: type=lint, type=warning
@ProviderFor(theme)
const themeProvider = ThemeProvider._();
final themeProvider = ThemeProvider._();
final class ThemeProvider
extends $FunctionalProvider<ThemeSet, ThemeSet, ThemeSet>
with $Provider<ThemeSet> {
const ThemeProvider._()
ThemeProvider._()
: super(
from: null,
argument: null,

View File

@@ -1,5 +1,8 @@
import 'dart:async';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/models/activity.dart';
import 'package:island/pods/config.dart';
import 'package:island/pods/network.dart';
import 'package:island/pods/paging.dart';
@@ -7,23 +10,39 @@ final activityListProvider = AsyncNotifierProvider.autoDispose(
ActivityListNotifier.new,
);
class ActivityListNotifier extends AsyncNotifier<List<SnTimelineEvent>>
class ActivityListNotifier
extends AsyncNotifier<PaginationState<SnTimelineEvent>>
with
AsyncPaginationController<SnTimelineEvent>,
AsyncPaginationFilter<String?, SnTimelineEvent> {
static const int pageSize = 20;
@override
FutureOr<PaginationState<SnTimelineEvent>> build() async {
final items = await fetch();
return PaginationState(
items: items,
isLoading: false,
isReloading: false,
totalCount: totalCount,
hasMore: hasMore,
cursor: cursor,
);
}
@override
String? currentFilter;
@override
Future<List<SnTimelineEvent>> fetch() async {
final client = ref.read(apiClientProvider);
final settings = ref.read(appSettingsProvider);
final queryParameters = {
if (cursor != null) 'cursor': cursor,
'take': pageSize,
if (currentFilter != null) 'filter': currentFilter,
'showFediverse': settings.showFediverseContent,
};
final response = await client.get(
@@ -53,9 +72,9 @@ class ActivityListNotifier extends AsyncNotifier<List<SnTimelineEvent>>
final currentState = state.value;
if (currentState == null) return;
final updatedItems = [...currentState];
final updatedItems = [...currentState.items];
updatedItems[index] = activity;
state = AsyncData(updatedItems);
state = AsyncData(currentState.copyWith(items: updatedItems));
}
}

View File

@@ -10,12 +10,12 @@ part of 'translate.dart';
// ignore_for_file: type=lint, type=warning
@ProviderFor(translateString)
const translateStringProvider = TranslateStringFamily._();
final translateStringProvider = TranslateStringFamily._();
final class TranslateStringProvider
extends $FunctionalProvider<AsyncValue<String>, String, FutureOr<String>>
with $FutureModifier<String>, $FutureProvider<String> {
const TranslateStringProvider._({
TranslateStringProvider._({
required TranslateStringFamily super.from,
required TranslateQuery super.argument,
}) : super(
@@ -62,7 +62,7 @@ String _$translateStringHash() => r'51d638cf07cbf3ffa9469298f5bd9c667bc0ccb7';
final class TranslateStringFamily extends $Family
with $FunctionalFamilyOverride<FutureOr<String>, TranslateQuery> {
const TranslateStringFamily._()
TranslateStringFamily._()
: super(
retry: null,
name: r'translateStringProvider',
@@ -79,12 +79,12 @@ final class TranslateStringFamily extends $Family
}
@ProviderFor(detectStringLanguage)
const detectStringLanguageProvider = DetectStringLanguageFamily._();
final detectStringLanguageProvider = DetectStringLanguageFamily._();
final class DetectStringLanguageProvider
extends $FunctionalProvider<String?, String?, String?>
with $Provider<String?> {
const DetectStringLanguageProvider._({
DetectStringLanguageProvider._({
required DetectStringLanguageFamily super.from,
required String super.argument,
}) : super(
@@ -140,7 +140,7 @@ String _$detectStringLanguageHash() =>
final class DetectStringLanguageFamily extends $Family
with $FunctionalFamilyOverride<String?, String> {
const DetectStringLanguageFamily._()
DetectStringLanguageFamily._()
: super(
retry: null,
name: r'detectStringLanguageProvider',

View File

@@ -8,7 +8,7 @@ import 'package:island/pods/network.dart';
final webFeedListProvider = FutureProvider.autoDispose
.family<List<SnWebFeed>, String>((ref, pubName) async {
final client = ref.watch(apiClientProvider);
final response = await client.get('/sphere/publishers/$pubName/feeds');
final response = await client.get('/insight/publishers/$pubName/feeds');
return (response.data as List)
.map((json) => SnWebFeed.fromJson(json))
.toList();

View File

@@ -18,7 +18,7 @@ import 'package:island/screens/files/file_list.dart';
import 'package:island/screens/files/file_detail.dart';
import 'package:island/screens/posts/post_categories_list.dart';
import 'package:island/screens/posts/post_category_detail.dart';
import 'package:island/screens/posts/post_search.dart';
import 'package:island/screens/search.dart';
import 'package:island/widgets/app_scaffold.dart';
import 'package:island/widgets/app_wrapper.dart';
import 'package:island/screens/tabs.dart';
@@ -169,6 +169,7 @@ final routerProvider = Provider<GoRouter>((ref) {
builder: (context, state) => const AboutScreen(),
),
// File routes
GoRoute(
name: 'fileDetail',
path: '/files/:id',
@@ -185,6 +186,56 @@ final routerProvider = Provider<GoRouter>((ref) {
},
),
// Post routes
GoRoute(
name: 'postShuffle',
path: '/posts/shuffle',
builder: (context, state) => const PostShuffleScreen(),
),
GoRoute(
name: 'postCategories',
path: '/posts/categories',
builder: (context, state) => const PostCategoriesListScreen(),
),
GoRoute(
name: 'postCategoryDetail',
path: '/posts/categories/:slug',
builder: (context, state) {
final slug = state.pathParameters['slug']!;
return PostCategoryDetailScreen(slug: slug, isCategory: true);
},
),
GoRoute(
name: 'postTagDetail',
path: '/posts/tags/:slug',
builder: (context, state) {
final slug = state.pathParameters['slug']!;
return PostCategoryDetailScreen(slug: slug, isCategory: false);
},
),
GoRoute(
name: 'postDetail',
path: '/posts/:id',
builder: (context, state) {
final id = state.pathParameters['id']!;
return PostDetailScreen(id: id);
},
),
GoRoute(
name: 'publisherProfile',
path: '/publishers/:name',
builder: (context, state) {
final name = state.pathParameters['name']!;
return PublisherProfileScreen(name: name);
},
),
GoRoute(
name: 'universalSearch',
path: '/search',
builder: (context, state) => const UniversalSearchScreen(),
),
// Main tabs with TabsScreen shell
ShellRoute(
navigatorKey: _tabsShellKey,
@@ -212,56 +263,7 @@ final routerProvider = Provider<GoRouter>((ref) {
transitionsBuilder: _tabPagesTransitionBuilder,
),
),
GoRoute(
name: 'postSearch',
path: '/posts/search',
builder: (context, state) => const PostSearchScreen(),
),
GoRoute(
name: 'postShuffle',
path: '/posts/shuffle',
builder: (context, state) => const PostShuffleScreen(),
),
GoRoute(
name: 'postCategories',
path: '/posts/categories',
builder: (context, state) => const PostCategoriesListScreen(),
),
GoRoute(
name: 'postCategoryDetail',
path: '/posts/categories/:slug',
builder: (context, state) {
final slug = state.pathParameters['slug']!;
return PostCategoryDetailScreen(slug: slug, isCategory: true);
},
),
GoRoute(
name: 'postTagDetail',
path: '/posts/tags/:slug',
builder: (context, state) {
final slug = state.pathParameters['slug']!;
return PostCategoryDetailScreen(
slug: slug,
isCategory: false,
);
},
),
GoRoute(
name: 'postDetail',
path: '/posts/:id',
builder: (context, state) {
final id = state.pathParameters['id']!;
return PostDetailScreen(id: id);
},
),
GoRoute(
name: 'publisherProfile',
path: '/publishers/:name',
builder: (context, state) {
final name = state.pathParameters['name']!;
return PublisherProfileScreen(name: name);
},
),
GoRoute(
name: 'discoveryRealms',
path: '/discovery/realms',

View File

@@ -74,7 +74,7 @@ class AccountScreen extends HookConsumerWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (user.value?.profile.background?.id != null)
if (user.value?.profile.background != null)
Stack(
clipBehavior: Clip.none,
children: [
@@ -112,7 +112,7 @@ class AccountScreen extends HookConsumerWidget {
Builder(
builder: (context) {
final hasBackground =
user.value?.profile.background?.id != null;
user.value?.profile.background != null;
return Row(
crossAxisAlignment: CrossAxisAlignment.center,
spacing: hasBackground ? 0 : 16,

View File

@@ -1,3 +1,5 @@
import 'dart:async';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
@@ -28,10 +30,23 @@ final socialCreditHistoryNotifierProvider = AsyncNotifierProvider.autoDispose(
);
class SocialCreditHistoryNotifier
extends AsyncNotifier<List<SnSocialCreditRecord>>
extends AsyncNotifier<PaginationState<SnSocialCreditRecord>>
with AsyncPaginationController<SnSocialCreditRecord> {
static const int pageSize = 20;
@override
FutureOr<PaginationState<SnSocialCreditRecord>> build() async {
final items = await fetch();
return PaginationState(
items: items,
isLoading: false,
isReloading: false,
totalCount: totalCount,
hasMore: hasMore,
cursor: cursor,
);
}
@override
Future<List<SnSocialCreditRecord>> fetch() async {
final client = ref.read(apiClientProvider);

View File

@@ -10,12 +10,12 @@ part of 'credits.dart';
// ignore_for_file: type=lint, type=warning
@ProviderFor(socialCredits)
const socialCreditsProvider = SocialCreditsProvider._();
final socialCreditsProvider = SocialCreditsProvider._();
final class SocialCreditsProvider
extends $FunctionalProvider<AsyncValue<double>, double, FutureOr<double>>
with $FutureModifier<double>, $FutureProvider<double> {
const SocialCreditsProvider._()
SocialCreditsProvider._()
: super(
from: null,
argument: null,

View File

@@ -1,3 +1,5 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
@@ -14,14 +16,30 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:island/widgets/paging/pagination_list.dart';
import 'package:styled_widget/styled_widget.dart';
final levelingHistoryNotifierProvider = AsyncNotifierProvider.autoDispose(
LevelingHistoryNotifier.new,
);
final levelingHistoryNotifierProvider =
AsyncNotifierProvider.autoDispose<
LevelingHistoryNotifier,
PaginationState<SnExperienceRecord>
>(LevelingHistoryNotifier.new);
class LevelingHistoryNotifier extends AsyncNotifier<List<SnExperienceRecord>>
class LevelingHistoryNotifier
extends AsyncNotifier<PaginationState<SnExperienceRecord>>
with AsyncPaginationController<SnExperienceRecord> {
static const int pageSize = 20;
@override
FutureOr<PaginationState<SnExperienceRecord>> build() async {
final items = await fetch();
return PaginationState(
items: items,
isLoading: false,
isReloading: false,
totalCount: totalCount,
hasMore: hasMore,
cursor: cursor,
);
}
@override
Future<List<SnExperienceRecord>> fetch() async {
final client = ref.read(apiClientProvider);

View File

@@ -10,7 +10,7 @@ part of 'account_settings.dart';
// ignore_for_file: type=lint, type=warning
@ProviderFor(authFactors)
const authFactorsProvider = AuthFactorsProvider._();
final authFactorsProvider = AuthFactorsProvider._();
final class AuthFactorsProvider
extends
@@ -22,7 +22,7 @@ final class AuthFactorsProvider
with
$FutureModifier<List<SnAuthFactor>>,
$FutureProvider<List<SnAuthFactor>> {
const AuthFactorsProvider._()
AuthFactorsProvider._()
: super(
from: null,
argument: null,
@@ -51,7 +51,7 @@ final class AuthFactorsProvider
String _$authFactorsHash() => r'ed87d7dbd421fef0a5620416727c3dc598c97ef5';
@ProviderFor(contactMethods)
const contactMethodsProvider = ContactMethodsProvider._();
final contactMethodsProvider = ContactMethodsProvider._();
final class ContactMethodsProvider
extends
@@ -63,7 +63,7 @@ final class ContactMethodsProvider
with
$FutureModifier<List<SnContactMethod>>,
$FutureProvider<List<SnContactMethod>> {
const ContactMethodsProvider._()
ContactMethodsProvider._()
: super(
from: null,
argument: null,
@@ -92,7 +92,7 @@ final class ContactMethodsProvider
String _$contactMethodsHash() => r'1d3d03e9ffbf36126236558ead22cb7d88bb9cb2';
@ProviderFor(accountConnections)
const accountConnectionsProvider = AccountConnectionsProvider._();
final accountConnectionsProvider = AccountConnectionsProvider._();
final class AccountConnectionsProvider
extends
@@ -104,7 +104,7 @@ final class AccountConnectionsProvider
with
$FutureModifier<List<SnAccountConnection>>,
$FutureProvider<List<SnAccountConnection>> {
const AccountConnectionsProvider._()
AccountConnectionsProvider._()
: super(
from: null,
argument: null,

View File

@@ -74,14 +74,10 @@ class UpdateProfileScreen extends HookConsumerWidget {
submitting.value = true;
try {
final cloudFile =
await FileUploader.createCloudFile(
ref: ref,
fileData: UniversalFile(
data: result,
type: UniversalFileType.image,
),
).future;
final cloudFile = await FileUploader.createCloudFile(
ref: ref,
fileData: UniversalFile(data: result, type: UniversalFileType.image),
).future;
if (cloudFile == null) {
throw ArgumentError('Failed to upload the file...');
}
@@ -188,8 +184,9 @@ class UpdateProfileScreen extends HookConsumerWidget {
if (usernameColorType.value == 'gradient') ...{
if (usernameColorDirection.text.isNotEmpty)
'direction': usernameColorDirection.text,
'colors':
usernameColorColors.value.where((c) => c.isNotEmpty).toList(),
'colors': usernameColorColors.value
.where((c) => c.isNotEmpty)
.toList(),
},
};
@@ -206,18 +203,16 @@ class UpdateProfileScreen extends HookConsumerWidget {
'time_zone': timeZoneController.text,
'birthday': birthday.value?.toUtc().toIso8601String(),
'username_color': usernameColorData,
'links':
links.value
.where((e) => e.name.isNotEmpty && e.url.isNotEmpty)
.toList(),
'links': links.value
.where((e) => e.name.isNotEmpty && e.url.isNotEmpty)
.toList(),
},
);
final userNotifier = ref.read(userInfoProvider.notifier);
userNotifier.fetchUser();
links.value =
links.value
.where((e) => e.name.isNotEmpty && e.url.isNotEmpty)
.toList();
links.value = links.value
.where((e) => e.name.isNotEmpty && e.url.isNotEmpty)
.toList();
} catch (err) {
showErrorAlert(err);
} finally {
@@ -244,13 +239,12 @@ class UpdateProfileScreen extends HookConsumerWidget {
GestureDetector(
child: Container(
color: Theme.of(context).colorScheme.surfaceContainerHigh,
child:
user.value!.profile.background?.id != null
? CloudImageWidget(
fileId: user.value!.profile.background!.id,
fit: BoxFit.cover,
)
: const SizedBox.shrink(),
child: user.value!.profile.background != null
? CloudImageWidget(
file: user.value!.profile.background,
fit: BoxFit.cover,
)
: const SizedBox.shrink(),
),
onTap: () {
updateProfilePicture('background');
@@ -261,7 +255,7 @@ class UpdateProfileScreen extends HookConsumerWidget {
bottom: -32,
child: GestureDetector(
child: ProfilePictureWidget(
fileId: user.value!.profile.picture?.id,
file: user.value!.profile.picture,
radius: 40,
),
onTap: () {
@@ -291,14 +285,14 @@ class UpdateProfileScreen extends HookConsumerWidget {
),
controller: usernameController,
readOnly: true,
onTapOutside:
(_) => FocusManager.instance.primaryFocus?.unfocus(),
onTapOutside: (_) =>
FocusManager.instance.primaryFocus?.unfocus(),
),
TextFormField(
decoration: InputDecoration(labelText: 'nickname'.tr()),
controller: nicknameController,
onTapOutside:
(_) => FocusManager.instance.primaryFocus?.unfocus(),
onTapOutside: (_) =>
FocusManager.instance.primaryFocus?.unfocus(),
),
DropdownButtonFormField2<String>(
decoration: InputDecoration(
@@ -385,9 +379,8 @@ class UpdateProfileScreen extends HookConsumerWidget {
labelText: 'firstName'.tr(),
),
controller: firstNameController,
onTapOutside:
(_) =>
FocusManager.instance.primaryFocus?.unfocus(),
onTapOutside: (_) =>
FocusManager.instance.primaryFocus?.unfocus(),
),
),
Expanded(
@@ -396,9 +389,8 @@ class UpdateProfileScreen extends HookConsumerWidget {
labelText: 'middleName'.tr(),
),
controller: middleNameController,
onTapOutside:
(_) =>
FocusManager.instance.primaryFocus?.unfocus(),
onTapOutside: (_) =>
FocusManager.instance.primaryFocus?.unfocus(),
),
),
Expanded(
@@ -407,9 +399,8 @@ class UpdateProfileScreen extends HookConsumerWidget {
labelText: 'lastName'.tr(),
),
controller: lastNameController,
onTapOutside:
(_) =>
FocusManager.instance.primaryFocus?.unfocus(),
onTapOutside: (_) =>
FocusManager.instance.primaryFocus?.unfocus(),
),
),
],
@@ -423,8 +414,8 @@ class UpdateProfileScreen extends HookConsumerWidget {
maxLines: null,
minLines: 3,
controller: bioController,
onTapOutside:
(_) => FocusManager.instance.primaryFocus?.unfocus(),
onTapOutside: (_) =>
FocusManager.instance.primaryFocus?.unfocus(),
),
Row(
spacing: 16,
@@ -445,33 +436,34 @@ class UpdateProfileScreen extends HookConsumerWidget {
onSelected: (String selection) {
genderController.text = selection;
},
fieldViewBuilder: (
context,
controller,
focusNode,
onFieldSubmitted,
) {
// Initialize the controller with the current value
if (controller.text.isEmpty &&
genderController.text.isNotEmpty) {
controller.text = genderController.text;
}
fieldViewBuilder:
(
context,
controller,
focusNode,
onFieldSubmitted,
) {
// Initialize the controller with the current value
if (controller.text.isEmpty &&
genderController.text.isNotEmpty) {
controller.text = genderController.text;
}
return TextFormField(
controller: controller,
focusNode: focusNode,
decoration: InputDecoration(
labelText: 'gender'.tr(),
),
onChanged: (value) {
genderController.text = value;
return TextFormField(
controller: controller,
focusNode: focusNode,
decoration: InputDecoration(
labelText: 'gender'.tr(),
),
onChanged: (value) {
genderController.text = value;
},
onTapOutside: (_) => FocusManager
.instance
.primaryFocus
?.unfocus(),
);
},
onTapOutside:
(_) =>
FocusManager.instance.primaryFocus
?.unfocus(),
);
},
),
),
Expanded(
@@ -480,9 +472,8 @@ class UpdateProfileScreen extends HookConsumerWidget {
labelText: 'pronouns'.tr(),
),
controller: pronounsController,
onTapOutside:
(_) =>
FocusManager.instance.primaryFocus?.unfocus(),
onTapOutside: (_) =>
FocusManager.instance.primaryFocus?.unfocus(),
),
),
],
@@ -496,9 +487,8 @@ class UpdateProfileScreen extends HookConsumerWidget {
labelText: 'location'.tr(),
),
controller: locationController,
onTapOutside:
(_) =>
FocusManager.instance.primaryFocus?.unfocus(),
onTapOutside: (_) =>
FocusManager.instance.primaryFocus?.unfocus(),
),
),
Expanded(
@@ -507,8 +497,8 @@ class UpdateProfileScreen extends HookConsumerWidget {
if (textEditingValue.text.isEmpty) {
return const Iterable<String>.empty();
}
final lowercaseQuery =
textEditingValue.text.toLowerCase();
final lowercaseQuery = textEditingValue.text
.toLowerCase();
return getAvailableTz().where((tz) {
return tz.toLowerCase().contains(lowercaseQuery);
});
@@ -516,46 +506,49 @@ class UpdateProfileScreen extends HookConsumerWidget {
onSelected: (String selection) {
timeZoneController.text = selection;
},
fieldViewBuilder: (
context,
controller,
focusNode,
onFieldSubmitted,
) {
// Sync the controller with timeZoneController when the widget is built
if (controller.text != timeZoneController.text) {
controller.text = timeZoneController.text;
}
fieldViewBuilder:
(
context,
controller,
focusNode,
onFieldSubmitted,
) {
// Sync the controller with timeZoneController when the widget is built
if (controller.text !=
timeZoneController.text) {
controller.text = timeZoneController.text;
}
return TextFormField(
controller: controller,
focusNode: focusNode,
decoration: InputDecoration(
labelText: 'timeZone'.tr(),
suffix: InkWell(
child: const Icon(
Symbols.my_location,
size: 18,
return TextFormField(
controller: controller,
focusNode: focusNode,
decoration: InputDecoration(
labelText: 'timeZone'.tr(),
suffix: InkWell(
child: const Icon(
Symbols.my_location,
size: 18,
),
onTap: () async {
try {
showLoadingModal(context);
final machineTz =
await getMachineTz();
controller.text = machineTz;
timeZoneController.text = machineTz;
} finally {
if (context.mounted) {
hideLoadingModal(context);
}
}
},
),
),
onTap: () async {
try {
showLoadingModal(context);
final machineTz = await getMachineTz();
controller.text = machineTz;
timeZoneController.text = machineTz;
} finally {
if (context.mounted) {
hideLoadingModal(context);
}
}
onChanged: (value) {
timeZoneController.text = value;
},
),
),
onChanged: (value) {
timeZoneController.text = value;
);
},
);
},
optionsViewBuilder: (context, onSelected, options) {
return Align(
alignment: Alignment.topLeft,
@@ -569,21 +562,21 @@ class UpdateProfileScreen extends HookConsumerWidget {
child: ListView.builder(
padding: const EdgeInsets.all(8.0),
itemCount: options.length,
itemBuilder: (
BuildContext context,
int index,
) {
final option = options.elementAt(index);
return ListTile(
title: Text(
option,
overflow: TextOverflow.ellipsis,
),
onTap: () {
onSelected(option);
itemBuilder:
(BuildContext context, int index) {
final option = options.elementAt(
index,
);
return ListTile(
title: Text(
option,
overflow: TextOverflow.ellipsis,
),
onTap: () {
onSelected(option);
},
);
},
);
},
),
),
),
@@ -644,10 +637,9 @@ class UpdateProfileScreen extends HookConsumerWidget {
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color:
Theme.of(
context,
).colorScheme.surfaceContainerHighest,
color: Theme.of(
context,
).colorScheme.surfaceContainerHighest,
borderRadius: BorderRadius.circular(8),
),
child: Column(
@@ -664,25 +656,23 @@ class UpdateProfileScreen extends HookConsumerWidget {
type: usernameColorType.value,
value:
usernameColorType.value == 'plain' &&
usernameColorValue
.text
.isNotEmpty
? usernameColorValue.text
: null,
usernameColorValue.text.isNotEmpty
? usernameColorValue.text
: null,
direction:
usernameColorType.value ==
'gradient' &&
usernameColorDirection
.text
.isNotEmpty
? usernameColorDirection.text
: null,
'gradient' &&
usernameColorDirection
.text
.isNotEmpty
? usernameColorDirection.text
: null,
colors:
usernameColorType.value == 'gradient'
? usernameColorColors.value
.where((c) => c.isNotEmpty)
.toList()
: null,
? usernameColorColors.value
.where((c) => c.isNotEmpty)
.toList()
: null,
),
),
);
@@ -724,10 +714,9 @@ class UpdateProfileScreen extends HookConsumerWidget {
? Symbols.check_circle
: Symbols.error,
size: 16,
color:
canUseColor
? Colors.green
: Colors.red,
color: canUseColor
? Colors.green
: Colors.red,
),
const Gap(4),
Text(
@@ -736,10 +725,9 @@ class UpdateProfileScreen extends HookConsumerWidget {
: 'upgradeRequired'.tr(),
style: TextStyle(
fontSize: 12,
color:
canUseColor
? Colors.green
: Colors.red,
color: canUseColor
? Colors.green
: Colors.red,
),
),
],
@@ -792,34 +780,35 @@ class UpdateProfileScreen extends HookConsumerWidget {
onSelected: (String selection) {
usernameColorValue.text = selection;
},
fieldViewBuilder: (
context,
controller,
focusNode,
onFieldSubmitted,
) {
// Initialize the controller with the current value
if (controller.text.isEmpty &&
usernameColorValue.text.isNotEmpty) {
controller.text = usernameColorValue.text;
}
fieldViewBuilder:
(
context,
controller,
focusNode,
onFieldSubmitted,
) {
// Initialize the controller with the current value
if (controller.text.isEmpty &&
usernameColorValue.text.isNotEmpty) {
controller.text = usernameColorValue.text;
}
return TextFormField(
controller: controller,
focusNode: focusNode,
decoration: InputDecoration(
labelText: 'colorValue'.tr(),
hintText: 'e.g. red or #ff6600',
),
onChanged: (value) {
usernameColorValue.text = value;
return TextFormField(
controller: controller,
focusNode: focusNode,
decoration: InputDecoration(
labelText: 'colorValue'.tr(),
hintText: 'e.g. red or #ff6600',
),
onChanged: (value) {
usernameColorValue.text = value;
},
onTapOutside: (_) => FocusManager
.instance
.primaryFocus
?.unfocus(),
);
},
onTapOutside:
(_) =>
FocusManager.instance.primaryFocus
?.unfocus(),
);
},
),
if (usernameColorType.value == 'gradient') ...[
DropdownButtonFormField2<String>(
@@ -862,10 +851,9 @@ class UpdateProfileScreen extends HookConsumerWidget {
child: Text('gradientDirectionToTopLeft'.tr()),
),
],
value:
usernameColorDirection.text.isNotEmpty
? usernameColorDirection.text
: 'to right',
value: usernameColorDirection.text.isNotEmpty
? usernameColorDirection.text
: 'to right',
onChanged: (value) {
usernameColorDirection.text = value ?? 'to right';
},
@@ -911,21 +899,19 @@ class UpdateProfileScreen extends HookConsumerWidget {
onChanged: (value) {
usernameColorColors.value[i] = value;
},
onTapOutside:
(_) =>
FocusManager.instance.primaryFocus
?.unfocus(),
onTapOutside: (_) => FocusManager
.instance
.primaryFocus
?.unfocus(),
),
),
IconButton(
icon: const Icon(Symbols.delete),
onPressed: () {
usernameColorColors.value =
usernameColorColors.value
.whereIndexed(
(idx, _) => idx != i,
)
.toList();
usernameColorColors
.value = usernameColorColors.value
.whereIndexed((idx, _) => idx != i)
.toList();
},
),
],
@@ -968,10 +954,10 @@ class UpdateProfileScreen extends HookConsumerWidget {
name: value,
);
},
onTapOutside:
(_) =>
FocusManager.instance.primaryFocus
?.unfocus(),
onTapOutside: (_) => FocusManager
.instance
.primaryFocus
?.unfocus(),
),
),
const Gap(8),
@@ -987,19 +973,18 @@ class UpdateProfileScreen extends HookConsumerWidget {
url: value,
);
},
onTapOutside:
(_) =>
FocusManager.instance.primaryFocus
?.unfocus(),
onTapOutside: (_) => FocusManager
.instance
.primaryFocus
?.unfocus(),
),
),
IconButton(
icon: const Icon(Symbols.delete),
onPressed: () {
links.value =
links.value
.whereIndexed((idx, _) => idx != i)
.toList();
links.value = links.value
.whereIndexed((idx, _) => idx != i)
.toList();
},
),
],

View File

@@ -57,7 +57,7 @@ class _AccountBasicInfo extends StatelessWidget {
return Card(
child: Builder(
builder: (context) {
final hasBackground = data.profile.background?.id != null;
final hasBackground = data.profile.background != null;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@@ -476,9 +476,9 @@ class _AccountPublisherList extends StatelessWidget {
subtitle: Text(
publisher.bio.isNotEmpty
? publisher.bio
.split('\n')
.where((line) => line.trim().isNotEmpty)
.join('\n')
.split('\n')
.where((line) => line.trim().isNotEmpty)
.join('\n')
: 'descriptionNone'.tr(),
maxLines: 3,
overflow: TextOverflow.ellipsis,
@@ -550,16 +550,14 @@ class _AccountAction extends StatelessWidget {
),
),
onPressed: relationshipAction,
label:
Text(
accountRelationship.value == null
? 'addFriendShort'
: 'added',
).tr(),
icon:
accountRelationship.value == null
? const Icon(Symbols.person_add)
: const Icon(Symbols.person_check),
label: Text(
accountRelationship.value == null
? 'addFriendShort'
: 'added',
).tr(),
icon: accountRelationship.value == null
? const Icon(Symbols.person_add)
: const Icon(Symbols.person_check),
),
),
if (accountRelationship.value == null ||
@@ -579,16 +577,14 @@ class _AccountAction extends StatelessWidget {
),
),
onPressed: blockAction,
label:
Text(
accountRelationship.value == null
? 'blockUser'
: 'unblockUser',
).tr(),
icon:
accountRelationship.value == null
? const Icon(Symbols.block)
: const Icon(Symbols.person_cancel),
label: Text(
accountRelationship.value == null
? 'blockUser'
: 'unblockUser',
).tr(),
icon: accountRelationship.value == null
? const Icon(Symbols.block)
: const Icon(Symbols.person_cancel),
),
),
],
@@ -600,13 +596,12 @@ class _AccountAction extends StatelessWidget {
child: FilledButton.icon(
onPressed: directMessageAction,
icon: const Icon(Symbols.message),
label:
Text(
accountChat.value == null
? 'createDirectMessage'
: 'gotoDirectMessage',
maxLines: 1,
).tr(),
label: Text(
accountChat.value == null
? 'createDirectMessage'
: 'gotoDirectMessage',
maxLines: 1,
).tr(),
),
),
IconButton.filled(
@@ -664,7 +659,7 @@ Future<Color?> accountAppbarForcegroundColor(Ref ref, String uname) async {
if (account.profile.background == null) return null;
final colors = await ColorExtractionService.getColorsFromImage(
CloudImageWidget.provider(
fileId: account.profile.background!.id,
file: account.profile.background!,
serverUrl: ref.watch(serverUrlProvider),
),
);
@@ -683,7 +678,7 @@ Future<SnChatRoom?> accountDirectChat(Ref ref, String uname) async {
final account = await ref.watch(accountProvider(uname).future);
final apiClient = ref.watch(apiClientProvider);
try {
final resp = await apiClient.get("/sphere/chat/direct/${account.id}");
final resp = await apiClient.get("/messager/chat/direct/${account.id}");
return SnChatRoom.fromJson(resp.data);
} catch (err) {
if (err is DioException && err.response?.statusCode == 404) {
@@ -812,7 +807,7 @@ class AccountProfileScreen extends HookConsumerWidget {
try {
final client = ref.watch(apiClientProvider);
final resp = await client.post(
'/sphere/chat/direct',
'/messager/chat/direct',
data: {'related_user_id': account.value!.id},
);
final chat = SnChatRoom.fromJson(resp.data);
@@ -838,262 +833,256 @@ class AccountProfileScreen extends HookConsumerWidget {
final accountPublishers = ref.watch(accountPublishersProvider(data.id));
return AppScaffold(
isNoBackground: false,
appBar:
isWideScreen(context)
? AppBar(
foregroundColor: appbarColor.value,
leading: PageBackButton(
color: appbarColor.value,
appBar: isWideScreen(context)
? AppBar(
foregroundColor: appbarColor.value,
leading: PageBackButton(
color: appbarColor.value,
shadows: [appbarShadow],
),
title: Text(
data.nick,
style: TextStyle(
color:
appbarColor.value ??
Theme.of(context).appBarTheme.foregroundColor,
shadows: [appbarShadow],
),
title: Text(
data.nick,
style: TextStyle(
color:
appbarColor.value ??
Theme.of(context).appBarTheme.foregroundColor,
shadows: [appbarShadow],
),
),
)
: null,
body:
isWideScreen(context)
? Row(
children: [
Flexible(
child: CustomScrollView(
slivers: [
SliverToBoxAdapter(
child: _AccountBasicInfo(
data: data,
uname: name,
accountDeveloper: accountDeveloper,
).padding(horizontal: 4, top: 20),
),
if (data.badges.isNotEmpty)
SliverToBoxAdapter(
child: Card(
child: BadgeList(
badges: data.badges,
).padding(horizontal: 26, vertical: 20),
).padding(left: 2, right: 4),
),
SliverToBoxAdapter(
child: Column(
spacing: 12,
children: [
LevelingProgressCard(
level: data.profile.level,
experience: data.profile.experience,
progress: data.profile.levelingProgress,
).padding(left: 2, right: 4),
if (data.profile.verification != null)
Card(
margin: EdgeInsets.zero,
child: VerificationStatusCard(
mark: data.profile.verification!,
),
),
],
).padding(horizontal: 4, top: 8),
),
SliverToBoxAdapter(
child: _AccountProfileBio(
data: data,
).padding(top: 4),
),
if (data.profile.links.isNotEmpty)
SliverToBoxAdapter(
child: _AccountProfileLinks(data: data),
),
if (data.contacts.any((c) => c.isPublic))
SliverToBoxAdapter(
child: _AccountProfileContacts(data: data),
),
SliverToBoxAdapter(
child: _AccountProfileDetail(data: data),
),
],
),
),
Flexible(
child: CustomScrollView(
slivers: [
SliverGap(18),
SliverToBoxAdapter(
child: ActivityPresenceWidget(
uname: name,
).padding(horizontal: 4, top: 4, bottom: 4),
),
SliverToBoxAdapter(
child: _AccountPublisherList(
publishers: accountPublishers.value ?? [],
),
),
if (user.value != null && !isCurrentUser)
SliverToBoxAdapter(
child: _AccountAction(
data: data,
accountRelationship: accountRelationship,
accountChat: accountChat,
relationshipAction: relationshipAction,
blockAction: blockAction,
directMessageAction: directMessageAction,
),
),
),
)
: null,
body: isWideScreen(context)
? Row(
children: [
Flexible(
child: CustomScrollView(
slivers: [
SliverToBoxAdapter(
child: _AccountBasicInfo(
data: data,
uname: name,
accountDeveloper: accountDeveloper,
).padding(horizontal: 4, top: 20),
),
if (data.badges.isNotEmpty)
SliverToBoxAdapter(
child: Card(
child: FortuneGraphWidget(
events: accountEvents,
eventCalandarUser: data.name,
margin: EdgeInsets.zero,
),
child: BadgeList(
badges: data.badges,
).padding(horizontal: 26, vertical: 20),
).padding(left: 2, right: 4),
),
SliverToBoxAdapter(
child: Column(
spacing: 12,
children: [
LevelingProgressCard(
level: data.profile.level,
experience: data.profile.experience,
progress: data.profile.levelingProgress,
).padding(left: 2, right: 4),
if (data.profile.verification != null)
Card(
margin: EdgeInsets.zero,
child: VerificationStatusCard(
mark: data.profile.verification!,
),
),
],
).padding(horizontal: 4, top: 8),
),
SliverToBoxAdapter(
child: _AccountProfileBio(
data: data,
).padding(top: 4),
),
if (data.profile.links.isNotEmpty)
SliverToBoxAdapter(
child: _AccountProfileLinks(data: data),
),
if (data.contacts.any((c) => c.isPublic))
SliverToBoxAdapter(
child: _AccountProfileContacts(data: data),
),
SliverToBoxAdapter(
child: _AccountProfileDetail(data: data),
),
],
),
),
Flexible(
child: CustomScrollView(
slivers: [
SliverGap(18),
SliverToBoxAdapter(
child: ActivityPresenceWidget(
uname: name,
).padding(horizontal: 4, top: 4, bottom: 4),
),
SliverToBoxAdapter(
child: _AccountPublisherList(
publishers: accountPublishers.value ?? [],
),
),
if (user.value != null && !isCurrentUser)
SliverToBoxAdapter(
child: _AccountAction(
data: data,
accountRelationship: accountRelationship,
accountChat: accountChat,
relationshipAction: relationshipAction,
blockAction: blockAction,
directMessageAction: directMessageAction,
),
),
],
),
),
],
).padding(horizontal: 24)
: CustomScrollView(
slivers: [
SliverAppBar(
foregroundColor: appbarColor.value,
expandedHeight: 180,
pinned: true,
leading: PageBackButton(
color: appbarColor.value,
shadows: [appbarShadow],
),
flexibleSpace: Stack(
children: [
Positioned.fill(
child:
data.profile.background?.id != null
? CloudImageWidget(
file: data.profile.background,
)
: Container(
color:
Theme.of(
context,
).appBarTheme.backgroundColor,
),
),
FlexibleSpaceBar(
title: Text(
data.nick,
style: TextStyle(
color:
appbarColor.value ??
Theme.of(
context,
).appBarTheme.foregroundColor,
shadows: [appbarShadow],
),
SliverToBoxAdapter(
child: Card(
child: FortuneGraphWidget(
events: accountEvents,
eventCalandarUser: data.name,
margin: EdgeInsets.zero,
),
),
],
),
),
],
),
SliverToBoxAdapter(
child: _AccountBasicInfo(
data: data,
uname: name,
accountDeveloper: accountDeveloper,
).padding(horizontal: 4, top: 8),
),
],
).padding(horizontal: 24)
: CustomScrollView(
slivers: [
SliverAppBar(
foregroundColor: appbarColor.value,
expandedHeight: 180,
pinned: true,
leading: PageBackButton(
color: appbarColor.value,
shadows: [appbarShadow],
),
if (data.badges.isNotEmpty)
SliverToBoxAdapter(
child: Card(
child: BadgeList(
badges: data.badges,
).padding(horizontal: 26, vertical: 20),
).padding(horizontal: 4),
),
SliverToBoxAdapter(
child: Column(
children: [
LevelingProgressCard(
level: data.profile.level,
experience: data.profile.experience,
progress: data.profile.levelingProgress,
).padding(top: 8, horizontal: 8, bottom: 4),
if (data.profile.verification != null)
Card(
child: VerificationStatusCard(
mark: data.profile.verification!,
),
).padding(horizontal: 4),
],
),
flexibleSpace: Stack(
children: [
Positioned.fill(
child: data.profile.background != null
? CloudImageWidget(
file: data.profile.background,
)
: Container(
color: Theme.of(
context,
).appBarTheme.backgroundColor,
),
),
FlexibleSpaceBar(
title: Text(
data.nick,
style: TextStyle(
color:
appbarColor.value ??
Theme.of(
context,
).appBarTheme.foregroundColor,
shadows: [appbarShadow],
),
),
),
],
),
SliverToBoxAdapter(
child: _AccountProfileBio(
data: data,
).padding(horizontal: 4),
),
if (data.profile.links.isNotEmpty)
SliverToBoxAdapter(
child: _AccountProfileLinks(
data: data,
).padding(horizontal: 4),
),
if (data.contacts.any((c) => c.isPublic))
SliverToBoxAdapter(
child: _AccountProfileContacts(
data: data,
).padding(horizontal: 4),
),
SliverToBoxAdapter(
child: ActivityPresenceWidget(
uname: name,
).padding(horizontal: 8, top: 4, bottom: 4),
),
SliverToBoxAdapter(
child: _AccountPublisherList(
publishers: accountPublishers.value ?? [],
).padding(horizontal: 4),
),
SliverToBoxAdapter(
child: _AccountProfileDetail(
data: data,
).padding(horizontal: 4),
),
if (user.value != null && !isCurrentUser)
SliverToBoxAdapter(
child: _AccountAction(
data: data,
accountRelationship: accountRelationship,
accountChat: accountChat,
relationshipAction: relationshipAction,
blockAction: blockAction,
directMessageAction: directMessageAction,
).padding(horizontal: 4),
),
),
SliverToBoxAdapter(
child: _AccountBasicInfo(
data: data,
uname: name,
accountDeveloper: accountDeveloper,
).padding(horizontal: 4, top: 8),
),
if (data.badges.isNotEmpty)
SliverToBoxAdapter(
child: Card(
child: FortuneGraphWidget(
events: accountEvents,
eventCalandarUser: data.name,
),
child: BadgeList(
badges: data.badges,
).padding(horizontal: 26, vertical: 20),
).padding(horizontal: 4),
),
],
),
SliverToBoxAdapter(
child: Column(
children: [
LevelingProgressCard(
level: data.profile.level,
experience: data.profile.experience,
progress: data.profile.levelingProgress,
).padding(top: 8, horizontal: 8, bottom: 4),
if (data.profile.verification != null)
Card(
child: VerificationStatusCard(
mark: data.profile.verification!,
),
).padding(horizontal: 4),
],
),
),
SliverToBoxAdapter(
child: _AccountProfileBio(
data: data,
).padding(horizontal: 4),
),
if (data.profile.links.isNotEmpty)
SliverToBoxAdapter(
child: _AccountProfileLinks(
data: data,
).padding(horizontal: 4),
),
if (data.contacts.any((c) => c.isPublic))
SliverToBoxAdapter(
child: _AccountProfileContacts(
data: data,
).padding(horizontal: 4),
),
SliverToBoxAdapter(
child: ActivityPresenceWidget(
uname: name,
).padding(horizontal: 8, top: 4, bottom: 4),
),
SliverToBoxAdapter(
child: _AccountPublisherList(
publishers: accountPublishers.value ?? [],
).padding(horizontal: 4),
),
SliverToBoxAdapter(
child: _AccountProfileDetail(
data: data,
).padding(horizontal: 4),
),
if (user.value != null && !isCurrentUser)
SliverToBoxAdapter(
child: _AccountAction(
data: data,
accountRelationship: accountRelationship,
accountChat: accountChat,
relationshipAction: relationshipAction,
blockAction: blockAction,
directMessageAction: directMessageAction,
).padding(horizontal: 4),
),
SliverToBoxAdapter(
child: Card(
child: FortuneGraphWidget(
events: accountEvents,
eventCalandarUser: data.name,
),
).padding(horizontal: 4),
),
],
),
);
},
error:
(error, stackTrace) => AppScaffold(
appBar: AppBar(leading: const PageBackButton()),
body: Center(child: Text(error.toString())),
),
loading:
() => AppScaffold(
appBar: AppBar(leading: const PageBackButton()),
body: Center(child: CircularProgressIndicator()),
),
error: (error, stackTrace) => AppScaffold(
appBar: AppBar(leading: const PageBackButton()),
body: Center(child: Text(error.toString())),
),
loading: () => AppScaffold(
appBar: AppBar(leading: const PageBackButton()),
body: Center(child: CircularProgressIndicator()),
),
);
}
}

View File

@@ -10,7 +10,7 @@ part of 'profile.dart';
// ignore_for_file: type=lint, type=warning
@ProviderFor(account)
const accountProvider = AccountFamily._();
final accountProvider = AccountFamily._();
final class AccountProvider
extends
@@ -20,7 +20,7 @@ final class AccountProvider
FutureOr<SnAccount>
>
with $FutureModifier<SnAccount>, $FutureProvider<SnAccount> {
const AccountProvider._({
AccountProvider._({
required AccountFamily super.from,
required String super.argument,
}) : super(
@@ -67,7 +67,7 @@ String _$accountHash() => r'5e2b7bd59151b4638a5561f495537c259f767123';
final class AccountFamily extends $Family
with $FunctionalFamilyOverride<FutureOr<SnAccount>, String> {
const AccountFamily._()
AccountFamily._()
: super(
retry: null,
name: r'accountProvider',
@@ -84,7 +84,7 @@ final class AccountFamily extends $Family
}
@ProviderFor(accountBadges)
const accountBadgesProvider = AccountBadgesFamily._();
final accountBadgesProvider = AccountBadgesFamily._();
final class AccountBadgesProvider
extends
@@ -96,7 +96,7 @@ final class AccountBadgesProvider
with
$FutureModifier<List<SnAccountBadge>>,
$FutureProvider<List<SnAccountBadge>> {
const AccountBadgesProvider._({
AccountBadgesProvider._({
required AccountBadgesFamily super.from,
required String super.argument,
}) : super(
@@ -144,7 +144,7 @@ String _$accountBadgesHash() => r'68db63f49827020beecbdbf20529520d0cd14a7d';
final class AccountBadgesFamily extends $Family
with $FunctionalFamilyOverride<FutureOr<List<SnAccountBadge>>, String> {
const AccountBadgesFamily._()
AccountBadgesFamily._()
: super(
retry: null,
name: r'accountBadgesProvider',
@@ -161,13 +161,13 @@ final class AccountBadgesFamily extends $Family
}
@ProviderFor(accountAppbarForcegroundColor)
const accountAppbarForcegroundColorProvider =
final accountAppbarForcegroundColorProvider =
AccountAppbarForcegroundColorFamily._();
final class AccountAppbarForcegroundColorProvider
extends $FunctionalProvider<AsyncValue<Color?>, Color?, FutureOr<Color?>>
with $FutureModifier<Color?>, $FutureProvider<Color?> {
const AccountAppbarForcegroundColorProvider._({
AccountAppbarForcegroundColorProvider._({
required AccountAppbarForcegroundColorFamily super.from,
required String super.argument,
}) : super(
@@ -212,11 +212,11 @@ final class AccountAppbarForcegroundColorProvider
}
String _$accountAppbarForcegroundColorHash() =>
r'127fcc7fd6ec6a41ac4a6975276b5271aa4fa7d0';
r'59e0049a5158ea653f0afd724df9ff2312b90050';
final class AccountAppbarForcegroundColorFamily extends $Family
with $FunctionalFamilyOverride<FutureOr<Color?>, String> {
const AccountAppbarForcegroundColorFamily._()
AccountAppbarForcegroundColorFamily._()
: super(
retry: null,
name: r'accountAppbarForcegroundColorProvider',
@@ -233,7 +233,7 @@ final class AccountAppbarForcegroundColorFamily extends $Family
}
@ProviderFor(accountDirectChat)
const accountDirectChatProvider = AccountDirectChatFamily._();
final accountDirectChatProvider = AccountDirectChatFamily._();
final class AccountDirectChatProvider
extends
@@ -243,7 +243,7 @@ final class AccountDirectChatProvider
FutureOr<SnChatRoom?>
>
with $FutureModifier<SnChatRoom?>, $FutureProvider<SnChatRoom?> {
const AccountDirectChatProvider._({
AccountDirectChatProvider._({
required AccountDirectChatFamily super.from,
required String super.argument,
}) : super(
@@ -287,11 +287,11 @@ final class AccountDirectChatProvider
}
}
String _$accountDirectChatHash() => r'149ea3a3730672cfbbb8c16fe1f2caa0bb9f0e17';
String _$accountDirectChatHash() => r'71bc9eed34a436a3743e8ef87f7aaae861fc5746';
final class AccountDirectChatFamily extends $Family
with $FunctionalFamilyOverride<FutureOr<SnChatRoom?>, String> {
const AccountDirectChatFamily._()
AccountDirectChatFamily._()
: super(
retry: null,
name: r'accountDirectChatProvider',
@@ -308,7 +308,7 @@ final class AccountDirectChatFamily extends $Family
}
@ProviderFor(accountRelationship)
const accountRelationshipProvider = AccountRelationshipFamily._();
final accountRelationshipProvider = AccountRelationshipFamily._();
final class AccountRelationshipProvider
extends
@@ -318,7 +318,7 @@ final class AccountRelationshipProvider
FutureOr<SnRelationship?>
>
with $FutureModifier<SnRelationship?>, $FutureProvider<SnRelationship?> {
const AccountRelationshipProvider._({
AccountRelationshipProvider._({
required AccountRelationshipFamily super.from,
required String super.argument,
}) : super(
@@ -367,7 +367,7 @@ String _$accountRelationshipHash() =>
final class AccountRelationshipFamily extends $Family
with $FunctionalFamilyOverride<FutureOr<SnRelationship?>, String> {
const AccountRelationshipFamily._()
AccountRelationshipFamily._()
: super(
retry: null,
name: r'accountRelationshipProvider',
@@ -384,7 +384,7 @@ final class AccountRelationshipFamily extends $Family
}
@ProviderFor(accountBotDeveloper)
const accountBotDeveloperProvider = AccountBotDeveloperFamily._();
final accountBotDeveloperProvider = AccountBotDeveloperFamily._();
final class AccountBotDeveloperProvider
extends
@@ -394,7 +394,7 @@ final class AccountBotDeveloperProvider
FutureOr<SnDeveloper?>
>
with $FutureModifier<SnDeveloper?>, $FutureProvider<SnDeveloper?> {
const AccountBotDeveloperProvider._({
AccountBotDeveloperProvider._({
required AccountBotDeveloperFamily super.from,
required String super.argument,
}) : super(
@@ -443,7 +443,7 @@ String _$accountBotDeveloperHash() =>
final class AccountBotDeveloperFamily extends $Family
with $FunctionalFamilyOverride<FutureOr<SnDeveloper?>, String> {
const AccountBotDeveloperFamily._()
AccountBotDeveloperFamily._()
: super(
retry: null,
name: r'accountBotDeveloperProvider',
@@ -460,7 +460,7 @@ final class AccountBotDeveloperFamily extends $Family
}
@ProviderFor(accountPublishers)
const accountPublishersProvider = AccountPublishersFamily._();
final accountPublishersProvider = AccountPublishersFamily._();
final class AccountPublishersProvider
extends
@@ -472,7 +472,7 @@ final class AccountPublishersProvider
with
$FutureModifier<List<SnPublisher>>,
$FutureProvider<List<SnPublisher>> {
const AccountPublishersProvider._({
AccountPublishersProvider._({
required AccountPublishersFamily super.from,
required String super.argument,
}) : super(
@@ -520,7 +520,7 @@ String _$accountPublishersHash() => r'25f5695b4a5154163d77f1769876d826bf736609';
final class AccountPublishersFamily extends $Family
with $FunctionalFamilyOverride<FutureOr<List<SnPublisher>>, String> {
const AccountPublishersFamily._()
AccountPublishersFamily._()
: super(
retry: null,
name: r'accountPublishersProvider',

View File

@@ -1,3 +1,5 @@
import 'dart:async';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
@@ -29,12 +31,28 @@ Future<List<SnRelationship>> sentFriendRequest(Ref ref) async {
.toList();
}
final relationshipListNotifierProvider = AsyncNotifierProvider.autoDispose(
RelationshipListNotifier.new,
);
final relationshipListNotifierProvider =
AsyncNotifierProvider.autoDispose<
RelationshipListNotifier,
PaginationState<SnRelationship>
>(RelationshipListNotifier.new);
class RelationshipListNotifier extends AsyncNotifier<List<SnRelationship>>
class RelationshipListNotifier
extends AsyncNotifier<PaginationState<SnRelationship>>
with AsyncPaginationController<SnRelationship> {
@override
FutureOr<PaginationState<SnRelationship>> build() async {
final items = await fetch();
return PaginationState(
items: items,
isLoading: false,
isReloading: false,
totalCount: totalCount,
hasMore: hasMore,
cursor: cursor,
);
}
@override
Future<List<SnRelationship>> fetch() async {
final client = ref.read(apiClientProvider);
@@ -95,7 +113,7 @@ class RelationshipListTile extends StatelessWidget {
contentPadding: const EdgeInsets.only(left: 16, right: 12),
leading: AccountPfcGestureDetector(
uname: account.name,
child: ProfilePictureWidget(fileId: account.profile.picture?.id),
child: ProfilePictureWidget(file: account.profile.picture),
),
title: Row(
spacing: 6,

View File

@@ -10,7 +10,7 @@ part of 'relationship.dart';
// ignore_for_file: type=lint, type=warning
@ProviderFor(sentFriendRequest)
const sentFriendRequestProvider = SentFriendRequestProvider._();
final sentFriendRequestProvider = SentFriendRequestProvider._();
final class SentFriendRequestProvider
extends
@@ -22,7 +22,7 @@ final class SentFriendRequestProvider
with
$FutureModifier<List<SnRelationship>>,
$FutureProvider<List<SnRelationship>> {
const SentFriendRequestProvider._()
SentFriendRequestProvider._()
: super(
from: null,
argument: null,

View File

@@ -0,0 +1,180 @@
import 'dart:async';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:gap/gap.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/models/activitypub.dart';
import 'package:island/services/activitypub_service.dart';
import 'package:island/widgets/activitypub/actor_list_item.dart';
import 'package:island/widgets/alert.dart';
import 'package:island/widgets/app_scaffold.dart';
import 'package:island/widgets/extended_refresh_indicator.dart';
import 'package:material_symbols_icons/symbols.dart';
import 'package:styled_widget/styled_widget.dart';
class ApSearchScreen extends HookConsumerWidget {
const ApSearchScreen({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final searchController = useTextEditingController();
final debounce = useMemoized(() => const Duration(milliseconds: 500));
final debounceTimer = useRef<Timer?>(null);
final searchResults = useState<List<SnActivityPubActor>>([]);
final isSearching = useState(false);
useEffect(() {
return () {
searchController.dispose();
debounceTimer.value?.cancel();
};
}, []);
Future<void> performSearch(String query) async {
if (query.trim().isEmpty) {
searchResults.value = [];
return;
}
isSearching.value = true;
try {
final service = ref.read(activityPubServiceProvider);
final results = await service.searchUsers(query);
searchResults.value = results;
} catch (err) {
showErrorAlert(err);
} finally {
isSearching.value = false;
}
}
void onSearchChanged(String query) {
if (debounceTimer.value?.isActive ?? false) {
debounceTimer.value!.cancel();
}
debounceTimer.value = Timer(debounce, () {
performSearch(query);
});
}
void updateActorIsFollowing(String actorId, bool isFollowing) {
searchResults.value = searchResults.value
.map(
(a) => a.id == actorId ? a.copyWith(isFollowing: isFollowing) : a,
)
.toList();
}
Future<void> handleFollow(SnActivityPubActor actor) async {
try {
updateActorIsFollowing(actor.id, true);
final service = ref.read(activityPubServiceProvider);
await service.followRemoteUser(actor.uri);
showSnackBar(
'followedUser'.tr(
args: [
'${actor.username?.isNotEmpty ?? false ? actor.username : actor.displayName}',
],
),
);
} catch (err) {
showErrorAlert(err);
updateActorIsFollowing(actor.id, false);
}
}
Future<void> handleUnfollow(SnActivityPubActor actor) async {
try {
updateActorIsFollowing(actor.id, false);
final service = ref.read(activityPubServiceProvider);
await service.unfollowRemoteUser(actor.uri);
showSnackBar(
'unfollowedUser'.tr(
args: [
'${actor.username?.isNotEmpty ?? false ? actor.username : actor.displayName}',
],
),
);
} catch (err) {
showErrorAlert(err);
updateActorIsFollowing(actor.id, true);
}
}
return AppScaffold(
isNoBackground: false,
appBar: AppBar(title: Text('searchFediverse'.tr()), elevation: 0),
body: Column(
children: [
Padding(
padding: const EdgeInsets.all(16),
child: SearchBar(
controller: searchController,
hintText: 'searchFediverseHint'.tr(
args: ['@username@instance.com'],
),
leading: const Icon(Symbols.search).padding(horizontal: 24),
onChanged: onSearchChanged,
onSubmitted: (value) {
onSearchChanged(value);
performSearch(value);
},
),
),
Expanded(
child: isSearching.value
? const Center(child: CircularProgressIndicator())
: searchResults.value.isEmpty
? Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Symbols.search,
size: 64,
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
const SizedBox(height: 16),
if (searchController.text.isEmpty)
Text(
'searchFediverseEmpty'.tr(),
style: Theme.of(context).textTheme.titleMedium,
)
else
Text(
'searchFediverseNoResults'.tr(),
style: Theme.of(context).textTheme.titleMedium,
),
],
),
)
: ExtendedRefreshIndicator(
onRefresh: () => performSearch(searchController.text),
child: ListView.separated(
padding: const EdgeInsets.symmetric(vertical: 8),
itemCount: searchResults.value.length,
separatorBuilder: (context, index) => const Gap(8),
itemBuilder: (context, index) {
final actor = searchResults.value[index];
return Center(
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 560),
child: ApActorListItem(
actor: actor,
isFollowing: actor.isFollowing ?? false,
isLoading: false,
onFollow: () => handleFollow(actor),
onUnfollow: () => handleUnfollow(actor),
),
),
);
},
),
),
),
],
),
);
}
}

View File

@@ -10,12 +10,12 @@ part of 'captcha.config.dart';
// ignore_for_file: type=lint, type=warning
@ProviderFor(captchaUrl)
const captchaUrlProvider = CaptchaUrlProvider._();
final captchaUrlProvider = CaptchaUrlProvider._();
final class CaptchaUrlProvider
extends $FunctionalProvider<AsyncValue<String>, String, FutureOr<String>>
with $FutureModifier<String>, $FutureProvider<String> {
const CaptchaUrlProvider._()
CaptchaUrlProvider._()
: super(
from: null,
argument: null,

View File

@@ -505,7 +505,7 @@ class ChatListScreen extends HookConsumerWidget {
final client = ref.read(apiClientProvider);
try {
await client.post(
'/sphere/chat/direct',
'/messager/chat/direct',
data: {'related_user_id': result.id},
);
eventBus.fire(const ChatRoomsRefreshEvent());
@@ -519,7 +519,7 @@ class ChatListScreen extends HookConsumerWidget {
),
);
},
).padding(bottom: isWideScreen(context) ? null : 56)
).padding(bottom: MediaQuery.of(context).padding.bottom)
: null,
appBar: AppBar(
flexibleSpace: Container(
@@ -599,11 +599,13 @@ class ChatListScreen extends HookConsumerWidget {
),
),
),
body: ChatListBodyWidget(
isFloating: false,
tabController: tabController,
selectedTab: selectedTab,
),
body: userInfo.value == null
? const ResponseUnauthorizedWidget()
: ChatListBodyWidget(
isFloating: false,
tabController: tabController,
selectedTab: selectedTab,
),
);
}
}
@@ -618,7 +620,9 @@ class _ChatInvitesSheet extends HookConsumerWidget {
Future<void> acceptInvite(SnChatMember invite) async {
try {
final client = ref.read(apiClientProvider);
await client.post('/sphere/chat/invites/${invite.chatRoom!.id}/accept');
await client.post(
'/messager/chat/invites/${invite.chatRoom!.id}/accept',
);
ref.invalidate(chatroomInvitesProvider);
ref.invalidate(chatRoomJoinedProvider);
} catch (err) {
@@ -630,7 +634,7 @@ class _ChatInvitesSheet extends HookConsumerWidget {
try {
final client = ref.read(apiClientProvider);
await client.post(
'/sphere/chat/invites/${invite.chatRoom!.id}/decline',
'/messager/chat/invites/${invite.chatRoom!.id}/decline',
);
ref.invalidate(chatroomInvitesProvider);
} catch (err) {

View File

@@ -97,14 +97,10 @@ class EditChatScreen extends HookConsumerWidget {
submitting.value = true;
try {
final cloudFile =
await FileUploader.createCloudFile(
ref: ref,
fileData: UniversalFile(
data: result,
type: UniversalFileType.image,
),
).future;
final cloudFile = await FileUploader.createCloudFile(
ref: ref,
fileData: UniversalFile(data: result, type: UniversalFileType.image),
).future;
if (cloudFile == null) {
throw ArgumentError('Failed to upload the file...');
}
@@ -129,7 +125,7 @@ class EditChatScreen extends HookConsumerWidget {
try {
final client = ref.watch(apiClientProvider);
final resp = await client.request(
id == null ? '/sphere/chat' : '/sphere/chat/$id',
id == null ? '/messager/chat' : '/messager/chat/$id',
data: {
'name': nameController.text,
'description': descriptionController.text,
@@ -166,13 +162,12 @@ class EditChatScreen extends HookConsumerWidget {
GestureDetector(
child: Container(
color: Theme.of(context).colorScheme.surfaceContainerHigh,
child:
background.value != null
? CloudFileWidget(
item: background.value!,
fit: BoxFit.cover,
)
: const SizedBox.shrink(),
child: background.value != null
? CloudFileWidget(
item: background.value!,
fit: BoxFit.cover,
)
: const SizedBox.shrink(),
),
onTap: () {
setPicture('background');
@@ -183,7 +178,7 @@ class EditChatScreen extends HookConsumerWidget {
bottom: -32,
child: GestureDetector(
child: ProfilePictureWidget(
fileId: picture.value?.id,
file: picture.value,
radius: 40,
fallbackIcon: Symbols.group,
),
@@ -208,8 +203,8 @@ class EditChatScreen extends HookConsumerWidget {
borderRadius: BorderRadius.circular(12),
),
),
onTapOutside:
(_) => FocusManager.instance.primaryFocus?.unfocus(),
onTapOutside: (_) =>
FocusManager.instance.primaryFocus?.unfocus(),
),
const SizedBox(height: 16),
TextFormField(
@@ -223,8 +218,8 @@ class EditChatScreen extends HookConsumerWidget {
),
minLines: 3,
maxLines: null,
onTapOutside:
(_) => FocusManager.instance.primaryFocus?.unfocus(),
onTapOutside: (_) =>
FocusManager.instance.primaryFocus?.unfocus(),
),
const SizedBox(height: 16),
DropdownButtonFormField<SnRealm>(
@@ -241,22 +236,20 @@ class EditChatScreen extends HookConsumerWidget {
child: Text('none'.tr()),
),
...joinedRealms.maybeWhen(
data:
(realms) => realms.map(
(realm) => DropdownMenuItem(
value: realm,
child: Text(realm.name),
),
),
data: (realms) => realms.map(
(realm) => DropdownMenuItem(
value: realm,
child: Text(realm.name),
),
),
orElse: () => [],
),
],
onChanged:
joinedRealms.isLoading
? null
: (SnRealm? value) {
currentRealm.value = value;
},
onChanged: joinedRealms.isLoading
? null
: (SnRealm? value) {
currentRealm.value = value;
},
),
const SizedBox(height: 16),
Card(

View File

@@ -65,8 +65,9 @@ class PublicRoomPreview extends HookConsumerWidget {
extentEstimation: (_, _) => 40,
itemBuilder: (context, index) {
final message = messageList[index];
final nextMessage =
index < messageList.length - 1 ? messageList[index + 1] : null;
final nextMessage = index < messageList.length - 1
? messageList[index + 1]
: null;
final isLastInGroup =
nextMessage == null ||
nextMessage.senderId != message.senderId ||
@@ -97,25 +98,23 @@ class PublicRoomPreview extends HookConsumerWidget {
SizedBox(
height: 26,
width: 26,
child:
(room.type == 1 && room.picture?.id == null)
? SplitAvatarWidget(
filesId:
room.members!
.map((e) => e.account.profile.picture?.id)
.toList(),
)
: room.picture?.id != null
? ProfilePictureWidget(
fileId: room.picture?.id,
fallbackIcon: Symbols.chat,
)
: CircleAvatar(
child: Text(
room.name![0].toUpperCase(),
style: const TextStyle(fontSize: 12),
),
child: (room.type == 1 && room.picture == null)
? SplitAvatarWidget(
files: room.members!
.map((e) => e.account.profile.picture)
.toList(),
)
: room.picture != null
? ProfilePictureWidget(
file: room.picture,
fallbackIcon: Symbols.chat,
)
: CircleAvatar(
child: Text(
room.name![0].toUpperCase(),
style: const TextStyle(fontSize: 12),
),
),
),
Text(
(room.type == 1 && room.name == null)
@@ -132,25 +131,23 @@ class PublicRoomPreview extends HookConsumerWidget {
SizedBox(
height: 26,
width: 26,
child:
(room.type == 1 && room.picture?.id == null)
? SplitAvatarWidget(
filesId:
room.members!
.map((e) => e.account.profile.picture?.id)
.toList(),
)
: room.picture?.id != null
? ProfilePictureWidget(
fileId: room.picture?.id,
fallbackIcon: Symbols.chat,
)
: CircleAvatar(
child: Text(
room.name![0].toUpperCase(),
style: const TextStyle(fontSize: 12),
),
child: (room.type == 1 && room.picture == null)
? SplitAvatarWidget(
files: room.members!
.map((e) => e.account.profile.picture)
.toList(),
)
: room.picture != null
? ProfilePictureWidget(
file: room.picture,
fallbackIcon: Symbols.chat,
)
: CircleAvatar(
child: Text(
room.name![0].toUpperCase(),
style: const TextStyle(fontSize: 12),
),
),
),
Text(
(room.type == 1 && room.name == null)
@@ -181,17 +178,14 @@ class PublicRoomPreview extends HookConsumerWidget {
children: [
Expanded(
child: messages.when(
data:
(messageList) =>
messageList.isEmpty
? Center(child: Text('No messages yet'.tr()))
: chatMessageListWidget(messageList),
data: (messageList) => messageList.isEmpty
? Center(child: Text('No messages yet'.tr()))
: chatMessageListWidget(messageList),
loading: () => const Center(child: CircularProgressIndicator()),
error:
(error, _) => ResponseErrorWidget(
error: error,
onRetry: () => messagesNotifier.loadInitial(),
),
error: (error, _) => ResponseErrorWidget(
error: error,
onRetry: () => messagesNotifier.loadInitial(),
),
),
),
// Join button at the bottom for public rooms
@@ -202,7 +196,7 @@ class PublicRoomPreview extends HookConsumerWidget {
try {
showLoadingModal(context);
final apiClient = ref.read(apiClientProvider);
await apiClient.post('/sphere/chat/${room.id}/members/me');
await apiClient.post('/messager/chat/${room.id}/members/me');
ref.invalidate(chatRoomIdentityProvider(id));
} catch (err) {
showErrorAlert(err);

View File

@@ -48,6 +48,7 @@ class ChatRoomScreen extends HookConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final mediaQuery = MediaQuery.of(context);
final chatRoom = ref.watch(chatRoomProvider(id));
final chatIdentity = ref.watch(chatRoomIdentityProvider(id));
final isSyncing = ref.watch(chatSyncingProvider);
@@ -71,67 +72,64 @@ class ChatRoomScreen extends HookConsumerWidget {
return AppScaffold(
appBar: AppBar(leading: const PageBackButton()),
body: Center(
child:
ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 280),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
room.isCommunity == true
? Symbols.person_add
: Symbols.person_remove,
size: 36,
fill: 1,
).padding(bottom: 4),
Text('chatNotJoined').tr(),
if (room.isCommunity != true)
Text(
'chatUnableJoin',
textAlign: TextAlign.center,
).tr().bold()
else
FilledButton.tonalIcon(
onPressed: () async {
try {
showLoadingModal(context);
final apiClient = ref.read(apiClientProvider);
await apiClient.post(
'/sphere/chat/${room.id}/members/me',
);
ref.invalidate(chatRoomIdentityProvider(id));
} catch (err) {
showErrorAlert(err);
} finally {
if (context.mounted) {
hideLoadingModal(context);
}
}
},
label: Text('chatJoin').tr(),
icon: const Icon(Icons.add),
).padding(top: 8),
],
),
).center(),
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 280),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
room.isCommunity == true
? Symbols.person_add
: Symbols.person_remove,
size: 36,
fill: 1,
).padding(bottom: 4),
Text('chatNotJoined').tr(),
if (room.isCommunity != true)
Text(
'chatUnableJoin',
textAlign: TextAlign.center,
).tr().bold()
else
FilledButton.tonalIcon(
onPressed: () async {
try {
showLoadingModal(context);
final apiClient = ref.read(apiClientProvider);
await apiClient.post(
'/messager/chat/${room.id}/members/me',
);
ref.invalidate(chatRoomIdentityProvider(id));
} catch (err) {
showErrorAlert(err);
} finally {
if (context.mounted) {
hideLoadingModal(context);
}
}
},
label: Text('chatJoin').tr(),
icon: const Icon(Icons.add),
).padding(top: 8),
],
),
).center(),
),
);
}
},
loading:
() => AppScaffold(
appBar: AppBar(leading: const PageBackButton()),
body: CircularProgressIndicator().center(),
),
error:
(error, _) => AppScaffold(
appBar: AppBar(leading: const PageBackButton()),
body: ResponseErrorWidget(
error: error,
onRetry: () => ref.refresh(chatRoomProvider(id)),
),
),
loading: () => AppScaffold(
appBar: AppBar(leading: const PageBackButton()),
body: CircularProgressIndicator().center(),
),
error: (error, _) => AppScaffold(
appBar: AppBar(leading: const PageBackButton()),
body: ResponseErrorWidget(
error: error,
onRetry: () => ref.refresh(chatRoomProvider(id)),
),
),
);
}
@@ -186,10 +184,9 @@ class ChatRoomScreen extends HookConsumerWidget {
case MessageItemAction.edit:
messageEditingTo.value = message.toRemoteMessage();
messageController.text = messageEditingTo.value?.content ?? '';
attachments.value =
messageEditingTo.value!.attachments
.map((e) => UniversalFile.fromAttachment(e))
.toList();
attachments.value = messageEditingTo.value!.attachments
.map((e) => UniversalFile.fromAttachment(e))
.toList();
case MessageItemAction.forward:
messageForwardingTo.value = message.toRemoteMessage();
case MessageItemAction.reply:
@@ -424,38 +421,37 @@ class ChatRoomScreen extends HookConsumerWidget {
label: Text('${(onlineCount.value ?? 0)}'),
textStyle: GoogleFonts.robotoMono(fontSize: 10),
textColor: Colors.white,
backgroundColor:
(onlineCount.value ?? 0) > 1 ? Colors.green : Colors.grey,
backgroundColor: (onlineCount.value ?? 0) > 1
? Colors.green
: Colors.grey,
offset: Offset(6, 14),
child: SizedBox(
height: 26,
width: 26,
child:
(room!.type == 1 && room.picture?.id == null)
? SplitAvatarWidget(
filesId:
getValidMembers(
room.members!,
).map((e) => e.account.profile.picture?.id).toList(),
)
: room.picture?.id != null
? ProfilePictureWidget(
fileId: room.picture?.id,
fallbackIcon: Symbols.chat,
)
: CircleAvatar(
child: Text(
room.name![0].toUpperCase(),
style: const TextStyle(fontSize: 12),
),
child: (room!.type == 1 && room.picture == null)
? SplitAvatarWidget(
files: getValidMembers(
room.members!,
).map((e) => e.account.profile.picture).toList(),
)
: room.picture != null
? ProfilePictureWidget(
file: room.picture,
fallbackIcon: Symbols.chat,
)
: CircleAvatar(
child: Text(
room.name![0].toUpperCase(),
style: const TextStyle(fontSize: 12),
),
),
),
),
Text(
(room.type == 1 && room.name == null)
? getValidMembers(
room.members!,
).map((e) => e.account.nick).join(', ')
room.members!,
).map((e) => e.account.nick).join(', ')
: room.name!,
).fontSize(15),
],
@@ -470,39 +466,38 @@ class ChatRoomScreen extends HookConsumerWidget {
isLabelVisible: (onlineCount.value ?? 0) > 1,
label: Text('${(onlineCount.value ?? 0)}'),
textStyle: GoogleFonts.robotoMono(fontSize: 10),
backgroundColor:
(onlineCount.value ?? 0) > 1 ? Colors.green : Colors.grey,
backgroundColor: (onlineCount.value ?? 0) > 1
? Colors.green
: Colors.grey,
textColor: Colors.white,
offset: Offset(6, 14),
child: SizedBox(
height: 28,
width: 28,
child:
(room!.type == 1 && room.picture?.id == null)
? SplitAvatarWidget(
filesId:
getValidMembers(
room.members!,
).map((e) => e.account.profile.picture?.id).toList(),
)
: room.picture?.id != null
? ProfilePictureWidget(
fileId: room.picture?.id,
fallbackIcon: Symbols.chat,
)
: CircleAvatar(
child: Text(
room.name![0].toUpperCase(),
style: const TextStyle(fontSize: 12),
),
child: (room!.type == 1 && room.picture == null)
? SplitAvatarWidget(
files: getValidMembers(
room.members!,
).map((e) => e.account.profile.picture).toList(),
)
: room.picture != null
? ProfilePictureWidget(
file: room.picture,
fallbackIcon: Symbols.chat,
)
: CircleAvatar(
child: Text(
room.name![0].toUpperCase(),
style: const TextStyle(fontSize: 12),
),
),
),
),
Text(
(room.type == 1 && room.name == null)
? getValidMembers(
room.members!,
).map((e) => e.account.nick).join(', ')
room.members!,
).map((e) => e.account.nick).join(', ')
: room.name!,
).fontSize(19),
],
@@ -531,11 +526,9 @@ class ChatRoomScreen extends HookConsumerWidget {
index: index,
scrollController: scrollController,
alignment: 0.5,
duration:
(estimatedDistance) => Duration(
milliseconds:
(estimatedDistance * 0.5).clamp(200, 800).toInt(),
),
duration: (estimatedDistance) => Duration(
milliseconds: (estimatedDistance * 0.5).clamp(200, 800).toInt(),
),
curve: (estimatedDistance) => Curves.easeOutCubic,
);
@@ -605,12 +598,11 @@ class ChatRoomScreen extends HookConsumerWidget {
final config = await showModalBottomSheet<AttachmentUploadConfig>(
context: context,
isScrollControlled: true,
builder:
(context) => AttachmentUploaderSheet(
ref: ref,
attachments: attachments.value,
index: index,
),
builder: (context) => AttachmentUploaderSheet(
ref: ref,
attachments: attachments.value,
index: index,
),
);
if (config == null) return;
@@ -621,22 +613,20 @@ class ChatRoomScreen extends HookConsumerWidget {
'chat-upload': {index: 0},
};
final cloudFile =
await FileUploader.createCloudFile(
ref: ref,
fileData: attachment,
poolId: config.poolId,
mode:
attachment.type == UniversalFileType.file
? FileUploadMode.generic
: FileUploadMode.mediaSafe,
onProgress: (progress, _) {
attachmentProgress.value = {
...attachmentProgress.value,
'chat-upload': {index: progress ?? 0.0},
};
},
).future;
final cloudFile = await FileUploader.createCloudFile(
ref: ref,
fileData: attachment,
poolId: config.poolId,
mode: attachment.type == UniversalFileType.file
? FileUploadMode.generic
: FileUploadMode.mediaSafe,
onProgress: (progress, _) {
attachmentProgress.value = {
...attachmentProgress.value,
'chat-upload': {index: progress ?? 0.0},
};
},
).future;
if (cloudFile == null) {
throw ArgumentError('Failed to upload the file...');
@@ -662,12 +652,12 @@ class ChatRoomScreen extends HookConsumerWidget {
curve: Curves.easeOut,
tween: EdgeInsetsTween(
begin: EdgeInsets.only(
top: MediaQuery.of(context).padding.top,
bottom: MediaQuery.of(context).padding.bottom + 8 + height,
top: mediaQuery.padding.top,
bottom: mediaQuery.padding.bottom + 8 + height,
),
end: EdgeInsets.only(
top: MediaQuery.of(context).padding.top,
bottom: MediaQuery.of(context).padding.bottom + 8 + height,
top: mediaQuery.padding.top,
bottom: mediaQuery.padding.bottom + 8 + height,
),
),
builder: (context, padding, child) {
@@ -690,10 +680,9 @@ class ChatRoomScreen extends HookConsumerWidget {
extentEstimation: (_, _) => 40,
itemBuilder: (context, index) {
final message = messageList[index];
final nextMessage =
index < messageList.length - 1
? messageList[index + 1]
: null;
final nextMessage = index < messageList.length - 1
? messageList[index + 1]
: null;
final isLastInGroup =
nextMessage == null ||
nextMessage.senderId != message.senderId ||
@@ -718,15 +707,14 @@ class ChatRoomScreen extends HookConsumerWidget {
toggleSelectionMode: toggleSelectionMode,
toggleMessageSelection: toggleMessageSelection,
onMessageAction: onMessageAction,
onJump:
(messageId) => scrollToMessage(
messageId: messageId,
messageList: messageList,
messagesNotifier: messagesNotifier,
listController: listController,
scrollController: scrollController,
ref: ref,
),
onJump: (messageId) => scrollToMessage(
messageId: messageId,
messageList: messageList,
messagesNotifier: messagesNotifier,
listController: listController,
scrollController: scrollController,
ref: ref,
),
attachmentProgress: attachmentProgress.value,
disableAnimation: settings.disableAnimation,
roomOpenTime: roomOpenTime,
@@ -744,17 +732,14 @@ class ChatRoomScreen extends HookConsumerWidget {
automaticallyImplyLeading: false,
toolbarHeight: compactHeader ? null : 74,
title: chatRoom.when(
data:
(room) =>
compactHeader
? compactHeaderWidget(room)
: comfortHeaderWidget(room),
data: (room) => compactHeader
? compactHeaderWidget(room)
: comfortHeaderWidget(room),
loading: () => const Text('Loading...'),
error:
(err, _) => ResponseErrorWidget(
error: err,
onRetry: () => messagesNotifier.loadInitial(),
),
error: (err, _) => ResponseErrorWidget(
error: err,
onRetry: () => messagesNotifier.loadInitial(),
),
),
actions: [
chatRoom.when(
@@ -787,13 +772,11 @@ class ChatRoomScreen extends HookConsumerWidget {
index: index,
scrollController: scrollController,
alignment: 0.5,
duration:
(estimatedDistance) => Duration(
milliseconds:
(estimatedDistance * 0.5)
.clamp(200, 800)
.toInt(),
),
duration: (estimatedDistance) => Duration(
milliseconds: (estimatedDistance * 0.5)
.clamp(200, 800)
.toInt(),
),
curve: (estimatedDistance) => Curves.easeOutCubic,
);
} catch (e) {
@@ -819,38 +802,35 @@ class ChatRoomScreen extends HookConsumerWidget {
duration: const Duration(milliseconds: 300),
switchInCurve: Curves.easeOutCubic,
switchOutCurve: Curves.easeInCubic,
transitionBuilder: (
Widget child,
Animation<double> animation,
) {
return SlideTransition(
position: Tween<Offset>(
begin: const Offset(0, 0.05),
end: Offset.zero,
).animate(animation),
child: FadeTransition(opacity: animation, child: child),
);
},
transitionBuilder:
(Widget child, Animation<double> animation) {
return SlideTransition(
position: Tween<Offset>(
begin: const Offset(0, 0.05),
end: Offset.zero,
).animate(animation),
child: FadeTransition(
opacity: animation,
child: child,
),
);
},
child: messages.when(
data:
(messageList) =>
messageList.isEmpty
? Center(
key: const ValueKey('empty-messages'),
child: Text('No messages yet'.tr()),
)
: chatMessageListWidget(messageList),
loading:
() => const Center(
key: ValueKey('loading-messages'),
child: CircularProgressIndicator(),
),
error:
(error, _) => ResponseErrorWidget(
key: const ValueKey('error-messages'),
error: error,
onRetry: () => messagesNotifier.loadInitial(),
),
data: (messageList) => messageList.isEmpty
? Center(
key: const ValueKey('empty-messages'),
child: Text('No messages yet'.tr()),
)
: chatMessageListWidget(messageList),
loading: () => const Center(
key: ValueKey('loading-messages'),
child: CircularProgressIndicator(),
),
error: (error, _) => ResponseErrorWidget(
key: const ValueKey('error-messages'),
error: error,
onRetry: () => messagesNotifier.loadInitial(),
),
),
),
),
@@ -862,10 +842,8 @@ class ChatRoomScreen extends HookConsumerWidget {
right: 0,
top: 0,
child: chatRoom.when(
data:
(data) => CallOverlayBar(
room: data!,
).padding(horizontal: 8, top: 12),
data: (data) =>
CallOverlayBar(room: data!).padding(horizontal: 8, top: 12),
error: (_, _) => const SizedBox.shrink(),
loading: () => const SizedBox.shrink(),
),
@@ -875,7 +853,12 @@ class ChatRoomScreen extends HookConsumerWidget {
top: 8,
right: 16,
child: Container(
padding: const EdgeInsets.all(8),
padding: EdgeInsets.fromLTRB(
8,
8,
8,
8 + mediaQuery.padding.bottom,
),
decoration: BoxDecoration(
color: Theme.of(
context,
@@ -903,111 +886,100 @@ class ChatRoomScreen extends HookConsumerWidget {
if (!isSelectionMode.value)
AnimatedBuilder(
animation: bottomGradientNotifier.value,
builder:
(context, child) => Positioned(
left: 0,
right: 0,
bottom: 0,
child: Opacity(
opacity: bottomGradientNotifier.value.value,
child: Container(
height: math.min(
MediaQuery.of(context).size.height * 0.1,
128,
),
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.bottomCenter,
end: Alignment.topCenter,
colors: [
Theme.of(
context,
).colorScheme.surfaceContainer.withOpacity(0.8),
Theme.of(
context,
).colorScheme.surfaceContainer.withOpacity(0.0),
],
),
),
builder: (context, child) => Positioned(
left: 0,
right: 0,
bottom: 0,
child: Opacity(
opacity: bottomGradientNotifier.value.value,
child: Container(
height: math.min(mediaQuery.size.height * 0.1, 128),
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.bottomCenter,
end: Alignment.topCenter,
colors: [
Theme.of(
context,
).colorScheme.surfaceContainer.withOpacity(0.8),
Theme.of(
context,
).colorScheme.surfaceContainer.withOpacity(0.0),
],
),
),
),
),
),
),
// Chat Input positioned above gradient (higher z-index)
if (!isSelectionMode.value)
Positioned(
left: 0,
right: 0,
bottom: 0, // At the very bottom, above gradient
bottom: mediaQuery
.padding
.bottom, // At the very bottom, above gradient
child: chatRoom.when(
data:
(room) => Column(
key: inputKey,
mainAxisSize: MainAxisSize.min,
children: [
ChatInput(
messageController: messageController,
chatRoom: room!,
onSend: sendMessage,
onClear: () {
if (messageEditingTo.value != null) {
attachments.value.clear();
messageController.clear();
}
messageEditingTo.value = null;
messageReplyingTo.value = null;
messageForwardingTo.value = null;
selectedPoll.value = null;
selectedFund.value = null;
},
messageEditingTo: messageEditingTo.value,
messageReplyingTo: messageReplyingTo.value,
messageForwardingTo: messageForwardingTo.value,
selectedPoll: selectedPoll.value,
onPollSelected: (poll) => selectedPoll.value = poll,
selectedFund: selectedFund.value,
onFundSelected: (fund) => selectedFund.value = fund,
onPickFile: (bool isPhoto) {
if (isPhoto) {
pickPhotoMedia();
} else {
pickVideoMedia();
}
},
onPickAudio: pickAudioMedia,
onPickGeneralFile: pickGeneralFile,
onLinkAttachment: linkAttachment,
attachments: attachments.value,
onUploadAttachment: uploadAttachment,
onDeleteAttachment: (index) async {
final attachment = attachments.value[index];
if (attachment.isOnCloud && !attachment.isLink) {
final client = ref.watch(apiClientProvider);
await client.delete(
'/drive/files/${attachment.data.id}',
);
}
final clone = List.of(attachments.value);
clone.removeAt(index);
attachments.value = clone;
},
onMoveAttachment: (idx, delta) {
if (idx + delta < 0 ||
idx + delta >= attachments.value.length) {
return;
}
final clone = List.of(attachments.value);
clone.insert(idx + delta, clone.removeAt(idx));
attachments.value = clone;
},
onAttachmentsChanged: (newAttachments) {
attachments.value = newAttachments;
},
attachmentProgress: attachmentProgress.value,
),
Gap(MediaQuery.of(context).padding.bottom),
],
),
data: (room) => ChatInput(
key: inputKey,
messageController: messageController,
chatRoom: room!,
onSend: sendMessage,
onClear: () {
if (messageEditingTo.value != null) {
attachments.value.clear();
messageController.clear();
}
messageEditingTo.value = null;
messageReplyingTo.value = null;
messageForwardingTo.value = null;
selectedPoll.value = null;
selectedFund.value = null;
},
messageEditingTo: messageEditingTo.value,
messageReplyingTo: messageReplyingTo.value,
messageForwardingTo: messageForwardingTo.value,
selectedPoll: selectedPoll.value,
onPollSelected: (poll) => selectedPoll.value = poll,
selectedFund: selectedFund.value,
onFundSelected: (fund) => selectedFund.value = fund,
onPickFile: (bool isPhoto) {
if (isPhoto) {
pickPhotoMedia();
} else {
pickVideoMedia();
}
},
onPickAudio: pickAudioMedia,
onPickGeneralFile: pickGeneralFile,
onLinkAttachment: linkAttachment,
attachments: attachments.value,
onUploadAttachment: uploadAttachment,
onDeleteAttachment: (index) async {
final attachment = attachments.value[index];
if (attachment.isOnCloud && !attachment.isLink) {
final client = ref.watch(apiClientProvider);
await client.delete('/drive/files/${attachment.data.id}');
}
final clone = List.of(attachments.value);
clone.removeAt(index);
attachments.value = clone;
},
onMoveAttachment: (idx, delta) {
if (idx + delta < 0 ||
idx + delta >= attachments.value.length) {
return;
}
final clone = List.of(attachments.value);
clone.insert(idx + delta, clone.removeAt(idx));
attachments.value = clone;
},
onAttachmentsChanged: (newAttachments) {
attachments.value = newAttachments;
},
attachmentProgress: attachmentProgress.value,
),
error: (_, _) => const SizedBox.shrink(),
loading: () => const SizedBox.shrink(),
),
@@ -1024,7 +996,7 @@ class ChatRoomScreen extends HookConsumerWidget {
left: 16,
right: 16,
top: 8,
bottom: MediaQuery.of(context).padding.bottom + 8,
bottom: mediaQuery.padding.bottom + 8,
),
child: Row(
children: [

View File

@@ -67,7 +67,7 @@ class ChatDetailScreen extends HookConsumerWidget {
try {
final client = ref.watch(apiClientProvider);
await client.patch(
'/sphere/chat/$id/members/me/notify',
'/messager/chat/$id/members/me/notify',
data: {'notify_level': level},
);
ref.invalidate(chatRoomIdentityProvider(id));
@@ -85,7 +85,7 @@ class ChatDetailScreen extends HookConsumerWidget {
try {
final client = ref.watch(apiClientProvider);
await client.patch(
'/sphere/chat/$id/members/me/notify',
'/messager/chat/$id/members/me/notify',
data: {'break_until': until.toUtc().toIso8601String()},
);
ref.invalidate(chatRoomIdentityProvider(id));
@@ -279,9 +279,8 @@ class ChatDetailScreen extends HookConsumerWidget {
leading: PageBackButton(shadows: [iconShadow]),
flexibleSpace: FlexibleSpaceBar(
background:
(currentRoom!.type == 1 &&
currentRoom.background?.id != null)
? CloudImageWidget(fileId: currentRoom.background!.id)
(currentRoom!.type == 1 && currentRoom.background != null)
? CloudImageWidget(file: currentRoom.background!)
: (currentRoom.type == 1 &&
currentRoom.members!.length == 1 &&
currentRoom
@@ -293,17 +292,16 @@ class ChatDetailScreen extends HookConsumerWidget {
?.id !=
null)
? CloudImageWidget(
fileId: currentRoom
file: currentRoom
.members!
.first
.account
.profile
.background!
.id,
.background!,
)
: currentRoom.background?.id != null
: currentRoom.background != null
? CloudImageWidget(
fileId: currentRoom.background!.id,
file: currentRoom.background!,
fit: BoxFit.cover,
)
: Container(
@@ -529,7 +527,7 @@ class _ChatRoomActionMenu extends HookConsumerWidget {
).then((confirm) async {
if (confirm) {
final client = ref.watch(apiClientProvider);
await client.delete('/sphere/chat/$id');
await client.delete('/messager/chat/$id');
ref.invalidate(chatRoomJoinedProvider);
if (context.mounted) {
context.pop();
@@ -560,7 +558,7 @@ class _ChatRoomActionMenu extends HookConsumerWidget {
).then((confirm) async {
if (confirm) {
final client = ref.watch(apiClientProvider);
await client.delete('/sphere/chat/$id/members/me');
await client.delete('/messager/chat/$id/members/me');
ref.invalidate(chatRoomJoinedProvider);
if (context.mounted) {
context.pop();
@@ -588,7 +586,8 @@ final chatMemberListProvider = AsyncNotifierProvider.autoDispose.family(
ChatMemberListNotifier.new,
);
class ChatMemberListNotifier extends AsyncNotifier<List<SnChatMember>>
class ChatMemberListNotifier
extends AsyncNotifier<PaginationState<SnChatMember>>
with AsyncPaginationController<SnChatMember> {
static const pageSize = 20;
@@ -599,7 +598,7 @@ class ChatMemberListNotifier extends AsyncNotifier<List<SnChatMember>>
Future<List<SnChatMember>> fetch() async {
final apiClient = ref.watch(apiClientProvider);
final response = await apiClient.get(
'/sphere/chat/$arg/members',
'/messager/chat/$arg/members',
queryParameters: {
'offset': fetchedCount.toString(),
'take': pageSize,
@@ -623,7 +622,8 @@ class _ChatMemberListSheet extends HookConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final memberNotifier = ref.read(chatMemberListProvider(roomId).notifier);
final memberState = ref.watch(chatMemberListProvider(roomId));
final memberNotifier = ref.watch(chatMemberListProvider(roomId).notifier);
final roomIdentity = ref.watch(chatRoomIdentityProvider(roomId));
final chatRoom = ref.watch(chatRoomProvider(roomId));
@@ -643,7 +643,7 @@ class _ChatMemberListSheet extends HookConsumerWidget {
try {
final apiClient = ref.watch(apiClientProvider);
await apiClient.post(
'/sphere/chat/invites/$roomId',
'/messager/chat/invites/$roomId',
data: {'related_user_id': result.id, 'role': 0},
);
memberNotifier.refresh();
@@ -663,7 +663,7 @@ class _ChatMemberListSheet extends HookConsumerWidget {
child: Row(
children: [
Text(
'members'.plural(memberNotifier.totalCount ?? 0),
'members'.plural(memberState.value?.totalCount ?? 0),
style: Theme.of(context).textTheme.headlineSmall?.copyWith(
fontWeight: FontWeight.w600,
letterSpacing: -0.5,
@@ -700,7 +700,7 @@ class _ChatMemberListSheet extends HookConsumerWidget {
leading: AccountPfcGestureDetector(
uname: member.account.name,
child: ProfilePictureWidget(
fileId: member.account.profile.picture?.id,
file: member.account.profile.picture,
),
),
title: Row(
@@ -733,7 +733,7 @@ class _ChatMemberListSheet extends HookConsumerWidget {
try {
final apiClient = ref.watch(apiClientProvider);
await apiClient.delete(
'/sphere/chat/$roomId/members/${member.accountId}',
'/messager/chat/$roomId/members/${member.accountId}',
);
// Refresh both providers
memberNotifier.refresh();

View File

@@ -10,12 +10,12 @@ part of 'room_detail.dart';
// ignore_for_file: type=lint, type=warning
@ProviderFor(totalMessagesCount)
const totalMessagesCountProvider = TotalMessagesCountFamily._();
final totalMessagesCountProvider = TotalMessagesCountFamily._();
final class TotalMessagesCountProvider
extends $FunctionalProvider<AsyncValue<int>, int, FutureOr<int>>
with $FutureModifier<int>, $FutureProvider<int> {
const TotalMessagesCountProvider._({
TotalMessagesCountProvider._({
required TotalMessagesCountFamily super.from,
required String super.argument,
}) : super(
@@ -63,7 +63,7 @@ String _$totalMessagesCountHash() =>
final class TotalMessagesCountFamily extends $Family
with $FunctionalFamilyOverride<FutureOr<int>, String> {
const TotalMessagesCountFamily._()
TotalMessagesCountFamily._()
: super(
retry: null,
name: r'totalMessagesCountProvider',

View File

@@ -6,6 +6,7 @@ import 'package:go_router/go_router.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:gap/gap.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/models/activitypub.dart';
import 'package:island/models/post.dart';
import 'package:island/models/publisher.dart';
import 'package:island/models/heatmap.dart';
@@ -15,6 +16,7 @@ import 'package:island/screens/creators/publishers_form.dart';
import 'package:island/services/responsive.dart';
import 'package:island/utils/text.dart';
import 'package:island/widgets/account/account_picker.dart';
import 'package:island/widgets/activitypub/actor_profile.dart';
import 'package:island/widgets/alert.dart';
import 'package:island/widgets/app_scaffold.dart';
import 'package:island/widgets/content/cloud_files.dart';
@@ -78,16 +80,43 @@ Future<List<SnPublisherMember>> publisherInvites(Ref ref) async {
.toList();
}
@riverpod
Future<SnActorStatusResponse> publisherActorStatus(
Ref ref,
String? publisherName,
) async {
if (publisherName == null) throw Exception('Publisher name is required');
final apiClient = ref.watch(apiClientProvider);
final response = await apiClient.get(
'/sphere/publishers/$publisherName/fediverse',
);
return SnActorStatusResponse.fromJson(response.data);
}
final publisherMemberListNotifierProvider = AsyncNotifierProvider.family
.autoDispose(PublisherMemberListNotifier.new);
class PublisherMemberListNotifier extends AsyncNotifier<List<SnPublisherMember>>
class PublisherMemberListNotifier
extends AsyncNotifier<PaginationState<SnPublisherMember>>
with AsyncPaginationController<SnPublisherMember> {
static const int pageSize = 20;
final String arg;
PublisherMemberListNotifier(this.arg);
@override
FutureOr<PaginationState<SnPublisherMember>> build() async {
final items = await fetch();
return PaginationState(
items: items,
isLoading: false,
isReloading: false,
totalCount: totalCount,
hasMore: hasMore,
cursor: cursor,
);
}
@override
Future<List<SnPublisherMember>> fetch() async {
final apiClient = ref.read(apiClientProvider);
@@ -126,7 +155,7 @@ class PublisherSelector extends StatelessWidget {
if (isReadOnly || currentPublisher == null) {
return ProfilePictureWidget(
radius: 16,
fileId: currentPublisher?.picture?.id,
file: currentPublisher?.picture,
).center().padding(right: 8);
}
@@ -150,7 +179,7 @@ class PublisherSelector extends StatelessWidget {
.map(
(e) => ProfilePictureWidget(
radius: 16,
fileId: e.value?.picture?.id,
file: e.value?.picture,
).center().padding(right: 8),
)
.toList();
@@ -326,10 +355,7 @@ class CreatorHubScreen extends HookConsumerWidget {
value: item,
child: ListTile(
minTileHeight: 48,
leading: ProfilePictureWidget(
radius: 16,
fileId: item.picture?.id,
),
leading: ProfilePictureWidget(radius: 16, file: item.picture),
title: Text(item.nick),
subtitle: Text('@${item.name}'),
trailing: currentPublisher.value?.id == item.id
@@ -501,6 +527,24 @@ class CreatorHubScreen extends HookConsumerWidget {
leading: const Icon(Symbols.edit),
onTap: updatePublisher,
),
ListTile(
shape: RoundedRectangleBorder(
borderRadius: const BorderRadius.all(Radius.circular(8)),
),
minTileHeight: 48,
title: Text('publisherFediverse').tr(),
trailing: Icon(Symbols.chevron_right),
leading: const Icon(Symbols.public),
onTap: () {
showModalBottomSheet(
isScrollControlled: true,
context: context,
builder: (context) => _PublisherFediverseSheet(
publisherUname: currentPublisher.value!.name,
),
);
},
),
ListTile(
shape: RoundedRectangleBorder(
borderRadius: const BorderRadius.all(Radius.circular(8)),
@@ -842,7 +886,7 @@ class _PublisherMemberListSheet extends HookConsumerWidget {
return ListTile(
contentPadding: EdgeInsets.only(left: 16, right: 12),
leading: ProfilePictureWidget(
fileId: member.account!.profile.picture?.id,
file: member.account!.profile.picture,
),
title: Row(
spacing: 6,
@@ -1090,7 +1134,7 @@ class _PublisherInviteSheet extends HookConsumerWidget {
final invite = items[index];
return ListTile(
leading: ProfilePictureWidget(
fileId: invite.publisher!.picture?.id,
file: invite.publisher!.picture,
fallbackIcon: Symbols.group,
),
title: Text(invite.publisher!.nick),
@@ -1126,3 +1170,152 @@ class _PublisherInviteSheet extends HookConsumerWidget {
);
}
}
class _PublisherFediverseSheet extends HookConsumerWidget {
final String publisherUname;
const _PublisherFediverseSheet({required this.publisherUname});
@override
Widget build(BuildContext context, WidgetRef ref) {
final actorStatus = ref.watch(publisherActorStatusProvider(publisherUname));
final apiClient = ref.read(apiClientProvider);
final isLoading = useState(false);
Future<void> toggleActor() async {
final currentStatus = actorStatus.value;
if (currentStatus == null) return;
final confirm = await showConfirmAlert(
currentStatus.enabled
? 'publisherFediverseDisableConfirm'.tr()
: 'publisherFediverseEnableConfirm'.tr(),
currentStatus.enabled
? 'publisherFediverseDisabled'.tr()
: 'publisherFediverseEnabled'.tr(),
isDanger: !currentStatus.enabled,
);
if (confirm != true) return;
try {
isLoading.value = true;
if (currentStatus.enabled) {
await apiClient.delete(
'/sphere/publishers/$publisherUname/fediverse',
);
} else {
await apiClient.post('/sphere/publishers/$publisherUname/fediverse');
}
ref.invalidate(publisherActorStatusProvider(publisherUname));
if (context.mounted) {
Navigator.pop(context);
}
} catch (err) {
showErrorAlert(err);
} finally {
isLoading.value = false;
}
}
return SheetScaffold(
titleText: 'publisherFediverse'.tr(),
child: actorStatus.when(
data: (status) => SingleChildScrollView(
padding: const EdgeInsets.symmetric(vertical: 16),
child: Column(
spacing: 16,
children: [
Card.outlined(
child: SwitchListTile(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(8)),
),
value: status.enabled,
onChanged: isLoading.value ? null : (_) => toggleActor(),
title: Text(
status.enabled
? 'publisherFediverseEnabled'.tr()
: 'publisherFediverseDisabled'.tr(),
),
subtitle: Text(
status.enabled
? 'publisherFediverseDisableHint'.tr()
: 'publisherFediverseEnableHint'.tr(),
),
secondary: isLoading.value
? const SizedBox(
width: 24,
height: 24,
child: CircularProgressIndicator(strokeWidth: 2),
)
: Icon(
status.enabled
? Icons.check_circle
: Icons.circle_outlined,
color: status.enabled ? Colors.green : Colors.grey,
),
),
).padding(horizontal: 16),
if (status.enabled) ...[
if (status.actor != null) ...[
ListTile(
leading: ActorPictureWidget(
actor: status.actor!,
radius: 24,
),
title: Text(
status.actor!.displayName ??
status.actor!.username ??
'unknown'.tr(),
),
subtitle: Text(
'@${status.actor!.username}@${status.actor!.instance.domain}',
),
isThreeLine: true,
contentPadding: const EdgeInsets.symmetric(horizontal: 28),
),
ListTile(
leading: const Icon(Symbols.link),
title: Text('publisherFediverseActorUri').tr(),
subtitle: Text(status.actorUri ?? 'N/A'),
contentPadding: const EdgeInsets.symmetric(horizontal: 32),
),
],
ListTile(
leading: const Icon(Symbols.group),
title: Text('publisherFediverseFollowerCount').tr(),
subtitle: Text(
status.followerCount > 0
? status.followerCount.toString()
: 'publisherFediverseNoFollowers'.tr(),
),
contentPadding: const EdgeInsets.symmetric(horizontal: 32),
),
],
ExpansionTile(
leading: const Icon(Symbols.info),
title: Text('publisherFediverseWhatIs').tr(),
tilePadding: const EdgeInsets.symmetric(horizontal: 32),
children: [
Padding(
padding: const EdgeInsets.symmetric(
vertical: 16,
horizontal: 32,
),
child: Text('publisherFediverseAbout').tr(),
),
],
),
],
),
),
loading: () => const Center(child: CircularProgressIndicator()),
error: (error, _) => ResponseErrorWidget(
error: error,
onRetry: () =>
ref.invalidate(publisherActorStatusProvider(publisherUname)),
),
),
);
}
}

View File

@@ -10,7 +10,7 @@ part of 'hub.dart';
// ignore_for_file: type=lint, type=warning
@ProviderFor(publisherStats)
const publisherStatsProvider = PublisherStatsFamily._();
final publisherStatsProvider = PublisherStatsFamily._();
final class PublisherStatsProvider
extends
@@ -22,7 +22,7 @@ final class PublisherStatsProvider
with
$FutureModifier<SnPublisherStats?>,
$FutureProvider<SnPublisherStats?> {
const PublisherStatsProvider._({
PublisherStatsProvider._({
required PublisherStatsFamily super.from,
required String? super.argument,
}) : super(
@@ -70,7 +70,7 @@ String _$publisherStatsHash() => r'eea4ed98bf165cc785874f83b912bb7e23d1f7bc';
final class PublisherStatsFamily extends $Family
with $FunctionalFamilyOverride<FutureOr<SnPublisherStats?>, String?> {
const PublisherStatsFamily._()
PublisherStatsFamily._()
: super(
retry: null,
name: r'publisherStatsProvider',
@@ -87,7 +87,7 @@ final class PublisherStatsFamily extends $Family
}
@ProviderFor(publisherHeatmap)
const publisherHeatmapProvider = PublisherHeatmapFamily._();
final publisherHeatmapProvider = PublisherHeatmapFamily._();
final class PublisherHeatmapProvider
extends
@@ -97,7 +97,7 @@ final class PublisherHeatmapProvider
FutureOr<SnHeatmap?>
>
with $FutureModifier<SnHeatmap?>, $FutureProvider<SnHeatmap?> {
const PublisherHeatmapProvider._({
PublisherHeatmapProvider._({
required PublisherHeatmapFamily super.from,
required String? super.argument,
}) : super(
@@ -144,7 +144,7 @@ String _$publisherHeatmapHash() => r'5f70c55e14629ec8628445a317888e02fccd9af2';
final class PublisherHeatmapFamily extends $Family
with $FunctionalFamilyOverride<FutureOr<SnHeatmap?>, String?> {
const PublisherHeatmapFamily._()
PublisherHeatmapFamily._()
: super(
retry: null,
name: r'publisherHeatmapProvider',
@@ -161,7 +161,7 @@ final class PublisherHeatmapFamily extends $Family
}
@ProviderFor(publisherIdentity)
const publisherIdentityProvider = PublisherIdentityFamily._();
final publisherIdentityProvider = PublisherIdentityFamily._();
final class PublisherIdentityProvider
extends
@@ -173,7 +173,7 @@ final class PublisherIdentityProvider
with
$FutureModifier<SnPublisherMember?>,
$FutureProvider<SnPublisherMember?> {
const PublisherIdentityProvider._({
PublisherIdentityProvider._({
required PublisherIdentityFamily super.from,
required String super.argument,
}) : super(
@@ -221,7 +221,7 @@ String _$publisherIdentityHash() => r'299372f25fa4b2bf8e11a8ba2d645100fc38e76f';
final class PublisherIdentityFamily extends $Family
with $FunctionalFamilyOverride<FutureOr<SnPublisherMember?>, String> {
const PublisherIdentityFamily._()
PublisherIdentityFamily._()
: super(
retry: null,
name: r'publisherIdentityProvider',
@@ -238,7 +238,7 @@ final class PublisherIdentityFamily extends $Family
}
@ProviderFor(publisherFeatures)
const publisherFeaturesProvider = PublisherFeaturesFamily._();
final publisherFeaturesProvider = PublisherFeaturesFamily._();
final class PublisherFeaturesProvider
extends
@@ -250,7 +250,7 @@ final class PublisherFeaturesProvider
with
$FutureModifier<Map<String, bool>>,
$FutureProvider<Map<String, bool>> {
const PublisherFeaturesProvider._({
PublisherFeaturesProvider._({
required PublisherFeaturesFamily super.from,
required String? super.argument,
}) : super(
@@ -298,7 +298,7 @@ String _$publisherFeaturesHash() => r'08bace2d9a3da227ecec0cbf8709e55ee0646ca2';
final class PublisherFeaturesFamily extends $Family
with $FunctionalFamilyOverride<FutureOr<Map<String, bool>>, String?> {
const PublisherFeaturesFamily._()
PublisherFeaturesFamily._()
: super(
retry: null,
name: r'publisherFeaturesProvider',
@@ -315,7 +315,7 @@ final class PublisherFeaturesFamily extends $Family
}
@ProviderFor(publisherInvites)
const publisherInvitesProvider = PublisherInvitesProvider._();
final publisherInvitesProvider = PublisherInvitesProvider._();
final class PublisherInvitesProvider
extends
@@ -327,7 +327,7 @@ final class PublisherInvitesProvider
with
$FutureModifier<List<SnPublisherMember>>,
$FutureProvider<List<SnPublisherMember>> {
const PublisherInvitesProvider._()
PublisherInvitesProvider._()
: super(
from: null,
argument: null,
@@ -354,3 +354,81 @@ final class PublisherInvitesProvider
}
String _$publisherInvitesHash() => r'93aafc2f02af0a7a055ec1770b3999363dfaabdc';
@ProviderFor(publisherActorStatus)
final publisherActorStatusProvider = PublisherActorStatusFamily._();
final class PublisherActorStatusProvider
extends
$FunctionalProvider<
AsyncValue<SnActorStatusResponse>,
SnActorStatusResponse,
FutureOr<SnActorStatusResponse>
>
with
$FutureModifier<SnActorStatusResponse>,
$FutureProvider<SnActorStatusResponse> {
PublisherActorStatusProvider._({
required PublisherActorStatusFamily super.from,
required String? super.argument,
}) : super(
retry: null,
name: r'publisherActorStatusProvider',
isAutoDispose: true,
dependencies: null,
$allTransitiveDependencies: null,
);
@override
String debugGetCreateSourceHash() => _$publisherActorStatusHash();
@override
String toString() {
return r'publisherActorStatusProvider'
''
'($argument)';
}
@$internal
@override
$FutureProviderElement<SnActorStatusResponse> $createElement(
$ProviderPointer pointer,
) => $FutureProviderElement(pointer);
@override
FutureOr<SnActorStatusResponse> create(Ref ref) {
final argument = this.argument as String?;
return publisherActorStatus(ref, argument);
}
@override
bool operator ==(Object other) {
return other is PublisherActorStatusProvider && other.argument == argument;
}
@override
int get hashCode {
return argument.hashCode;
}
}
String _$publisherActorStatusHash() =>
r'406117cb99b2aef236945ef0ef59e857d8835029';
final class PublisherActorStatusFamily extends $Family
with $FunctionalFamilyOverride<FutureOr<SnActorStatusResponse>, String?> {
PublisherActorStatusFamily._()
: super(
retry: null,
name: r'publisherActorStatusProvider',
dependencies: null,
$allTransitiveDependencies: null,
isAutoDispose: true,
);
PublisherActorStatusProvider call(String? publisherName) =>
PublisherActorStatusProvider._(argument: publisherName, from: this);
@override
String toString() => r'publisherActorStatusProvider';
}

View File

@@ -21,7 +21,7 @@ final pollListNotifierProvider = AsyncNotifierProvider.family.autoDispose(
PollListNotifier.new,
);
class PollListNotifier extends AsyncNotifier<List<SnPollWithStats>>
class PollListNotifier extends AsyncNotifier<PaginationState<SnPollWithStats>>
with AsyncPaginationController<SnPollWithStats> {
static const int pageSize = 20;

View File

@@ -10,7 +10,7 @@ part of 'poll_list.dart';
// ignore_for_file: type=lint, type=warning
@ProviderFor(pollWithStats)
const pollWithStatsProvider = PollWithStatsFamily._();
final pollWithStatsProvider = PollWithStatsFamily._();
final class PollWithStatsProvider
extends
@@ -20,7 +20,7 @@ final class PollWithStatsProvider
FutureOr<SnPollWithStats>
>
with $FutureModifier<SnPollWithStats>, $FutureProvider<SnPollWithStats> {
const PollWithStatsProvider._({
PollWithStatsProvider._({
required PollWithStatsFamily super.from,
required String super.argument,
}) : super(
@@ -68,7 +68,7 @@ String _$pollWithStatsHash() => r'6bb910046ce1e09368f9922dbec52fdc2cc86740';
final class PollWithStatsFamily extends $Family
with $FunctionalFamilyOverride<FutureOr<SnPollWithStats>, String> {
const PollWithStatsFamily._()
PollWithStatsFamily._()
: super(
retry: null,
name: r'pollWithStatsProvider',

View File

@@ -10,7 +10,7 @@ part of 'publishers_form.dart';
// ignore_for_file: type=lint, type=warning
@ProviderFor(publishersManaged)
const publishersManagedProvider = PublishersManagedProvider._();
final publishersManagedProvider = PublishersManagedProvider._();
final class PublishersManagedProvider
extends
@@ -22,7 +22,7 @@ final class PublishersManagedProvider
with
$FutureModifier<List<SnPublisher>>,
$FutureProvider<List<SnPublisher>> {
const PublishersManagedProvider._()
PublishersManagedProvider._()
: super(
from: null,
argument: null,
@@ -51,7 +51,7 @@ final class PublishersManagedProvider
String _$publishersManagedHash() => r'ea83759fed9bd5119738b4d09f12b4476959e0a3';
@ProviderFor(publisherNullable)
const publisherNullableProvider = PublisherNullableFamily._();
final publisherNullableProvider = PublisherNullableFamily._();
final class PublisherNullableProvider
extends
@@ -61,7 +61,7 @@ final class PublisherNullableProvider
FutureOr<SnPublisher?>
>
with $FutureModifier<SnPublisher?>, $FutureProvider<SnPublisher?> {
const PublisherNullableProvider._({
PublisherNullableProvider._({
required PublisherNullableFamily super.from,
required String? super.argument,
}) : super(
@@ -109,7 +109,7 @@ String _$publisherNullableHash() => r'49b28083a2f351c5e5cde0b1a97f6c7503969041';
final class PublisherNullableFamily extends $Family
with $FunctionalFamilyOverride<FutureOr<SnPublisher?>, String?> {
const PublisherNullableFamily._()
PublisherNullableFamily._()
: super(
retry: null,
name: r'publisherNullableProvider',

View File

@@ -10,7 +10,7 @@ part of 'site_detail.dart';
// ignore_for_file: type=lint, type=warning
@ProviderFor(publicationSiteDetail)
const publicationSiteDetailProvider = PublicationSiteDetailFamily._();
final publicationSiteDetailProvider = PublicationSiteDetailFamily._();
final class PublicationSiteDetailProvider
extends
@@ -22,7 +22,7 @@ final class PublicationSiteDetailProvider
with
$FutureModifier<SnPublicationSite>,
$FutureProvider<SnPublicationSite> {
const PublicationSiteDetailProvider._({
PublicationSiteDetailProvider._({
required PublicationSiteDetailFamily super.from,
required (String, String) super.argument,
}) : super(
@@ -75,7 +75,7 @@ final class PublicationSiteDetailFamily extends $Family
FutureOr<SnPublicationSite>,
(String, String)
> {
const PublicationSiteDetailFamily._()
PublicationSiteDetailFamily._()
: super(
retry: null,
name: r'publicationSiteDetailProvider',

View File

@@ -18,7 +18,7 @@ final siteListNotifierProvider = AsyncNotifierProvider.family.autoDispose(
SiteListNotifier.new,
);
class SiteListNotifier extends AsyncNotifier<List<SnPublicationSite>>
class SiteListNotifier extends AsyncNotifier<PaginationState<SnPublicationSite>>
with AsyncPaginationController<SnPublicationSite> {
static const int pageSize = 20;

View File

@@ -69,157 +69,141 @@ class StickerPackDetailContent extends HookConsumerWidget {
}
return pack.when(
data:
(pack) => Column(
crossAxisAlignment: CrossAxisAlignment.start,
data: (pack) => Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
Text(pack!.description),
Row(
spacing: 4,
children: [
Text(pack!.description),
Row(
spacing: 4,
children: [
const Icon(Symbols.folder, size: 16),
Text(
'${packContent.value?.length ?? 0}/24',
style: GoogleFonts.robotoMono(),
),
],
).opacity(0.85),
Row(
spacing: 4,
children: [
const Icon(Symbols.sell, size: 16),
Text(pack.prefix, style: GoogleFonts.robotoMono()),
],
).opacity(0.85),
Row(
spacing: 4,
children: [
const Icon(Symbols.tag, size: 16),
Flexible(
child: SelectableText(
pack.id,
maxLines: 1,
style: GoogleFonts.robotoMono(),
),
),
],
).opacity(0.85),
const Icon(Symbols.folder, size: 16),
Text(
'${packContent.value?.length ?? 0}/24',
style: GoogleFonts.robotoMono(),
),
],
).padding(horizontal: 24, vertical: 24),
const Divider(height: 1),
Expanded(
child: packContent.when(
data:
(stickers) => RefreshIndicator(
onRefresh:
() => ref.refresh(
stickerPackContentProvider(id).future,
),
child: GridView.builder(
padding: const EdgeInsets.symmetric(
horizontal: 24,
vertical: 20,
),
gridDelegate:
const SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 80,
mainAxisSpacing: 8,
crossAxisSpacing: 8,
),
itemCount: stickers.length,
itemBuilder: (context, index) {
final sticker = stickers[index];
return ContextMenuWidget(
menuProvider: (_) {
return Menu(
children: [
MenuAction(
title: 'stickerCopyPlaceholder'.tr(),
image: MenuImage.icon(Symbols.copy_all),
callback: () {
Clipboard.setData(
ClipboardData(
text:
':${pack.prefix}+${sticker.slug}:',
),
);
},
),
MenuSeparator(),
MenuAction(
title: 'edit'.tr(),
image: MenuImage.icon(Symbols.edit),
callback: () {
showModalBottomSheet(
context: context,
isScrollControlled: true,
builder:
(context) => SheetScaffold(
titleText: 'editSticker'.tr(),
child: StickerForm(
packId: id,
id: sticker.id,
),
),
).then((value) {
if (value != null) {
ref.invalidate(
stickerPackContentProvider(id),
);
}
});
},
),
MenuAction(
title: 'delete'.tr(),
image: MenuImage.icon(Symbols.delete),
callback: () {
deleteSticker(sticker);
},
),
],
).opacity(0.85),
Row(
spacing: 4,
children: [
const Icon(Symbols.sell, size: 16),
Text(pack.prefix, style: GoogleFonts.robotoMono()),
],
).opacity(0.85),
Row(
spacing: 4,
children: [
const Icon(Symbols.tag, size: 16),
Flexible(
child: SelectableText(
pack.id,
maxLines: 1,
style: GoogleFonts.robotoMono(),
),
),
],
).opacity(0.85),
],
).padding(horizontal: 24, vertical: 24),
const Divider(height: 1),
Expanded(
child: packContent.when(
data: (stickers) => RefreshIndicator(
onRefresh: () =>
ref.refresh(stickerPackContentProvider(id).future),
child: GridView.builder(
padding: const EdgeInsets.symmetric(
horizontal: 24,
vertical: 20,
),
gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 80,
mainAxisSpacing: 8,
crossAxisSpacing: 8,
),
itemCount: stickers.length,
itemBuilder: (context, index) {
final sticker = stickers[index];
return ContextMenuWidget(
menuProvider: (_) {
return Menu(
children: [
MenuAction(
title: 'stickerCopyPlaceholder'.tr(),
image: MenuImage.icon(Symbols.copy_all),
callback: () {
Clipboard.setData(
ClipboardData(
text: ':${pack.prefix}+${sticker.slug}:',
),
);
},
child: ClipRRect(
borderRadius: BorderRadius.all(
Radius.circular(8),
),
child: Container(
decoration: BoxDecoration(
color:
Theme.of(
context,
).colorScheme.surfaceContainer,
borderRadius: BorderRadius.all(
Radius.circular(8),
),
MenuSeparator(),
MenuAction(
title: 'edit'.tr(),
image: MenuImage.icon(Symbols.edit),
callback: () {
showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (context) => SheetScaffold(
titleText: 'editSticker'.tr(),
child: StickerForm(
packId: id,
id: sticker.id,
),
),
child: CloudImageWidget(
fileId: sticker.image.id,
fit: BoxFit.contain,
),
),
),
);
},
).then((value) {
if (value != null) {
ref.invalidate(
stickerPackContentProvider(id),
);
}
});
},
),
MenuAction(
title: 'delete'.tr(),
image: MenuImage.icon(Symbols.delete),
callback: () {
deleteSticker(sticker);
},
),
],
);
},
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(8)),
child: Container(
decoration: BoxDecoration(
color: Theme.of(
context,
).colorScheme.surfaceContainer,
borderRadius: BorderRadius.all(Radius.circular(8)),
),
child: CloudImageWidget(
file: sticker.image,
fit: BoxFit.contain,
),
),
),
error:
(err, _) =>
Text(
'Error: $err',
).textAlignment(TextAlign.center).center(),
loading: () => const CircularProgressIndicator().center(),
);
},
),
),
],
error: (err, _) =>
Text('Error: $err').textAlignment(TextAlign.center).center(),
loading: () => const CircularProgressIndicator().center(),
),
),
error:
(err, _) =>
Text('Error: $err').textAlignment(TextAlign.center).center(),
],
),
error: (err, _) =>
Text('Error: $err').textAlignment(TextAlign.center).center(),
loading: () => const CircularProgressIndicator().center(),
);
}
@@ -241,65 +225,60 @@ class StickerPackActionMenu extends HookConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) {
return PopupMenuButton(
icon: Icon(Icons.more_vert, shadows: [iconShadow]),
itemBuilder:
(context) => [
PopupMenuItem(
onTap: () {
showModalBottomSheet(
context: context,
isScrollControlled: true,
builder:
(context) => SheetScaffold(
titleText: 'editStickerPack'.tr(),
child: StickerPackForm(
pubName: pubName,
packId: packId,
),
),
).then((value) {
if (value != null) {
ref.invalidate(stickerPackProvider(packId));
}
});
},
child: Row(
children: [
Icon(
Icons.edit,
color: Theme.of(context).colorScheme.onSecondaryContainer,
),
const Gap(12),
const Text('editStickerPack').tr(),
],
itemBuilder: (context) => [
PopupMenuItem(
onTap: () {
showModalBottomSheet(
context: context,
isScrollControlled: true,
builder: (context) => SheetScaffold(
titleText: 'editStickerPack'.tr(),
child: StickerPackForm(pubName: pubName, packId: packId),
),
),
PopupMenuItem(
child: Row(
children: [
const Icon(Icons.delete, color: Colors.red),
const Gap(12),
const Text(
'deleteStickerPack',
style: TextStyle(color: Colors.red),
).tr(),
],
).then((value) {
if (value != null) {
ref.invalidate(stickerPackProvider(packId));
}
});
},
child: Row(
children: [
Icon(
Icons.edit,
color: Theme.of(context).colorScheme.onSecondaryContainer,
),
onTap: () {
showConfirmAlert(
'deleteStickerPackHint'.tr(),
'deleteStickerPack'.tr(),
isDanger: true,
).then((confirm) {
if (confirm) {
final client = ref.watch(apiClientProvider);
client.delete('/sphere/stickers/$packId');
ref.invalidate(stickerPacksProvider);
if (context.mounted) context.pop(true);
}
});
},
),
],
const Gap(12),
const Text('editStickerPack').tr(),
],
),
),
PopupMenuItem(
child: Row(
children: [
const Icon(Icons.delete, color: Colors.red),
const Gap(12),
const Text(
'deleteStickerPack',
style: TextStyle(color: Colors.red),
).tr(),
],
),
onTap: () {
showConfirmAlert(
'deleteStickerPackHint'.tr(),
'deleteStickerPack'.tr(),
isDanger: true,
).then((confirm) {
if (confirm) {
final client = ref.watch(apiClientProvider);
client.delete('/sphere/stickers/$packId');
ref.invalidate(stickerPacksProvider);
if (context.mounted) context.pop(true);
}
});
},
),
],
);
}
}
@@ -372,10 +351,9 @@ class StickerForm extends HookConsumerWidget {
color: Theme.of(context).colorScheme.surfaceContainer,
borderRadius: BorderRadius.all(Radius.circular(8)),
),
child:
(image.value?.isEmpty ?? true)
? const SizedBox.shrink()
: CloudImageWidget(fileId: image.value!),
child: (image.value?.isEmpty ?? true)
? const SizedBox.shrink()
: CloudImageWidget(fileId: image.value!),
),
),
),
@@ -383,10 +361,8 @@ class StickerForm extends HookConsumerWidget {
onPressed: () {
showModalBottomSheet(
context: context,
builder:
(context) => CloudFilePicker(
allowedTypes: {UniversalFileType.image},
),
builder: (context) =>
CloudFilePicker(allowedTypes: {UniversalFileType.image}),
).then((value) {
if (value == null) return;
image.value = value[0].id;
@@ -412,8 +388,8 @@ class StickerForm extends HookConsumerWidget {
borderRadius: BorderRadius.all(Radius.circular(12)),
),
),
onTapOutside:
(_) => FocusManager.instance.primaryFocus?.unfocus(),
onTapOutside: (_) =>
FocusManager.instance.primaryFocus?.unfocus(),
),
],
),

View File

@@ -10,7 +10,7 @@ part of 'pack_detail.dart';
// ignore_for_file: type=lint, type=warning
@ProviderFor(stickerPackContent)
const stickerPackContentProvider = StickerPackContentFamily._();
final stickerPackContentProvider = StickerPackContentFamily._();
final class StickerPackContentProvider
extends
@@ -20,7 +20,7 @@ final class StickerPackContentProvider
FutureOr<List<SnSticker>>
>
with $FutureModifier<List<SnSticker>>, $FutureProvider<List<SnSticker>> {
const StickerPackContentProvider._({
StickerPackContentProvider._({
required StickerPackContentFamily super.from,
required String super.argument,
}) : super(
@@ -69,7 +69,7 @@ String _$stickerPackContentHash() =>
final class StickerPackContentFamily extends $Family
with $FunctionalFamilyOverride<FutureOr<List<SnSticker>>, String> {
const StickerPackContentFamily._()
StickerPackContentFamily._()
: super(
retry: null,
name: r'stickerPackContentProvider',
@@ -86,7 +86,7 @@ final class StickerPackContentFamily extends $Family
}
@ProviderFor(stickerPackSticker)
const stickerPackStickerProvider = StickerPackStickerFamily._();
final stickerPackStickerProvider = StickerPackStickerFamily._();
final class StickerPackStickerProvider
extends
@@ -96,7 +96,7 @@ final class StickerPackStickerProvider
FutureOr<SnSticker?>
>
with $FutureModifier<SnSticker?>, $FutureProvider<SnSticker?> {
const StickerPackStickerProvider._({
StickerPackStickerProvider._({
required StickerPackStickerFamily super.from,
required StickerWithPackQuery? super.argument,
}) : super(
@@ -145,7 +145,7 @@ String _$stickerPackStickerHash() =>
final class StickerPackStickerFamily extends $Family
with
$FunctionalFamilyOverride<FutureOr<SnSticker?>, StickerWithPackQuery?> {
const StickerPackStickerFamily._()
StickerPackStickerFamily._()
: super(
retry: null,
name: r'stickerPackStickerProvider',

View File

@@ -140,7 +140,7 @@ final stickerPacksProvider = AsyncNotifierProvider.family.autoDispose(
StickerPacksNotifier.new,
);
class StickerPacksNotifier extends AsyncNotifier<List<SnStickerPack>>
class StickerPacksNotifier extends AsyncNotifier<PaginationState<SnStickerPack>>
with AsyncPaginationController<SnStickerPack> {
static const int pageSize = 20;

View File

@@ -10,7 +10,7 @@ part of 'stickers.dart';
// ignore_for_file: type=lint, type=warning
@ProviderFor(stickerPack)
const stickerPackProvider = StickerPackFamily._();
final stickerPackProvider = StickerPackFamily._();
final class StickerPackProvider
extends
@@ -20,7 +20,7 @@ final class StickerPackProvider
FutureOr<SnStickerPack?>
>
with $FutureModifier<SnStickerPack?>, $FutureProvider<SnStickerPack?> {
const StickerPackProvider._({
StickerPackProvider._({
required StickerPackFamily super.from,
required String? super.argument,
}) : super(
@@ -68,7 +68,7 @@ String _$stickerPackHash() => r'71ef84471237c8191918095094bdfc87d3920e77';
final class StickerPackFamily extends $Family
with $FunctionalFamilyOverride<FutureOr<SnStickerPack?>, String?> {
const StickerPackFamily._()
StickerPackFamily._()
: super(
retry: null,
name: r'stickerPackProvider',

View File

@@ -21,6 +21,7 @@ import 'package:island/widgets/app_scaffold.dart';
import 'package:island/widgets/notification_tile.dart';
import 'package:island/widgets/post/post_featured.dart';
import 'package:island/widgets/check_in.dart';
import 'package:island/screens/auth/login_modal.dart';
import 'package:island/models/activity.dart';
import 'package:island/screens/notification.dart';
import 'package:material_symbols_icons/material_symbols_icons.dart';
@@ -116,7 +117,11 @@ class DashboardGrid extends HookConsumerWidget {
topRight: isWide ? 0 : 12,
)
.padding(horizontal: isWide ? 0 : 16),
),
)
else
Center(
child: _UnauthorizedCard(isWide: isWide),
).padding(horizontal: isWide ? 24 : 16),
],
),
);
@@ -303,7 +308,9 @@ class ClockCard extends HookConsumerWidget {
spacing: 5,
children: [
notableDay.when(
data: (day) => _buildNotableDayText(context, day!),
data: (day) => day == null
? Text('unauthorized').tr()
: _buildNotableDayText(context, day),
error: (err, _) =>
Text(err.toString()).fontSize(12),
loading: () =>
@@ -412,11 +419,11 @@ class NotificationsCard extends HookConsumerWidget {
loading: () => const SkeletonNotificationTile(),
error: (error, stack) => Center(child: Text('Error: $error')),
data: (notificationList) {
if (notificationList.isEmpty) {
if (notificationList.items.isEmpty) {
return Center(child: Text('noNotificationsYet').tr());
}
// Get the most recent notification (first in the list)
final recentNotification = notificationList.first;
final recentNotification = notificationList.items.first;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
@@ -555,3 +562,64 @@ class FortuneCard extends HookConsumerWidget {
).height(48);
}
}
class _UnauthorizedCard extends HookConsumerWidget {
final bool isWide;
const _UnauthorizedCard({required this.isWide});
@override
Widget build(BuildContext context, WidgetRef ref) {
return Card(
margin: EdgeInsets.zero,
child: Padding(
padding: EdgeInsets.symmetric(
horizontal: isWide ? 48 : 32,
vertical: 32,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
const Gap(16),
Icon(
Symbols.dashboard_rounded,
size: 64,
color: Theme.of(context).colorScheme.primary,
fill: 1,
),
const Gap(16),
Text(
'Welcome to\nthe Solar Network',
style: Theme.of(
context,
).textTheme.headlineSmall?.copyWith(fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
),
const Gap(8),
Text(
'Login to access your personalized dashboard with friends, notifications, chats, and more!',
style: Theme.of(context).textTheme.bodyLarge?.copyWith(
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
textAlign: TextAlign.center,
),
const Gap(12),
FilledButton.icon(
onPressed: () {
showModalBottomSheet(
context: context,
useRootNavigator: true,
isScrollControlled: true,
builder: (context) => const LoginModal(),
);
},
icon: const Icon(Symbols.login),
label: Text('login').tr(),
),
],
),
),
);
}
}

View File

@@ -146,7 +146,7 @@ class _AppOverview extends StatelessWidget {
left: 20,
bottom: -32,
child: ProfilePictureWidget(
fileId: app.picture?.id,
file: app.picture,
radius: 40,
fallbackIcon: Symbols.apps,
),

View File

@@ -10,7 +10,7 @@ part of 'app_secrets.dart';
// ignore_for_file: type=lint, type=warning
@ProviderFor(customAppSecrets)
const customAppSecretsProvider = CustomAppSecretsFamily._();
final customAppSecretsProvider = CustomAppSecretsFamily._();
final class CustomAppSecretsProvider
extends
@@ -22,7 +22,7 @@ final class CustomAppSecretsProvider
with
$FutureModifier<List<CustomAppSecret>>,
$FutureProvider<List<CustomAppSecret>> {
const CustomAppSecretsProvider._({
CustomAppSecretsProvider._({
required CustomAppSecretsFamily super.from,
required (String, String, String) super.argument,
}) : super(
@@ -74,7 +74,7 @@ final class CustomAppSecretsFamily extends $Family
FutureOr<List<CustomAppSecret>>,
(String, String, String)
> {
const CustomAppSecretsFamily._()
CustomAppSecretsFamily._()
: super(
retry: null,
name: r'customAppSecretsProvider',

View File

@@ -153,7 +153,7 @@ class CustomAppsScreen extends HookConsumerWidget {
ListTile(
title: Text(app.name),
leading: ProfilePictureWidget(
fileId: app.picture?.id,
file: app.picture,
fallbackIcon: Symbols.apps,
),
subtitle: Text(

View File

@@ -10,7 +10,7 @@ part of 'apps.dart';
// ignore_for_file: type=lint, type=warning
@ProviderFor(customApp)
const customAppProvider = CustomAppFamily._();
final customAppProvider = CustomAppFamily._();
final class CustomAppProvider
extends
@@ -20,7 +20,7 @@ final class CustomAppProvider
FutureOr<CustomApp>
>
with $FutureModifier<CustomApp>, $FutureProvider<CustomApp> {
const CustomAppProvider._({
CustomAppProvider._({
required CustomAppFamily super.from,
required (String, String, String) super.argument,
}) : super(
@@ -71,7 +71,7 @@ final class CustomAppFamily extends $Family
FutureOr<CustomApp>,
(String, String, String)
> {
const CustomAppFamily._()
CustomAppFamily._()
: super(
retry: null,
name: r'customAppProvider',
@@ -94,7 +94,7 @@ final class CustomAppFamily extends $Family
}
@ProviderFor(customApps)
const customAppsProvider = CustomAppsFamily._();
final customAppsProvider = CustomAppsFamily._();
final class CustomAppsProvider
extends
@@ -104,7 +104,7 @@ final class CustomAppsProvider
FutureOr<List<CustomApp>>
>
with $FutureModifier<List<CustomApp>>, $FutureProvider<List<CustomApp>> {
const CustomAppsProvider._({
CustomAppsProvider._({
required CustomAppsFamily super.from,
required (String, String) super.argument,
}) : super(
@@ -153,7 +153,7 @@ String _$customAppsHash() => r'450bedaf4220b8963cb44afeb14d4c0e80f01b11';
final class CustomAppsFamily extends $Family
with
$FunctionalFamilyOverride<FutureOr<List<CustomApp>>, (String, String)> {
const CustomAppsFamily._()
CustomAppsFamily._()
: super(
retry: null,
name: r'customAppsProvider',

View File

@@ -143,7 +143,7 @@ class _BotOverview extends StatelessWidget {
left: 20,
bottom: -32,
child: ProfilePictureWidget(
fileId: bot.account.profile.picture?.id,
file: bot.account.profile.picture,
radius: 40,
fallbackIcon: Symbols.smart_toy,
),

View File

@@ -10,7 +10,7 @@ part of 'bot_keys.dart';
// ignore_for_file: type=lint, type=warning
@ProviderFor(botKeys)
const botKeysProvider = BotKeysFamily._();
final botKeysProvider = BotKeysFamily._();
final class BotKeysProvider
extends
@@ -22,7 +22,7 @@ final class BotKeysProvider
with
$FutureModifier<List<SnAccountApiKey>>,
$FutureProvider<List<SnAccountApiKey>> {
const BotKeysProvider._({
BotKeysProvider._({
required BotKeysFamily super.from,
required (String, String, String) super.argument,
}) : super(
@@ -74,7 +74,7 @@ final class BotKeysFamily extends $Family
FutureOr<List<SnAccountApiKey>>,
(String, String, String)
> {
const BotKeysFamily._()
BotKeysFamily._()
: super(
retry: null,
name: r'botKeysProvider',

View File

@@ -10,7 +10,7 @@ part of 'bots.dart';
// ignore_for_file: type=lint, type=warning
@ProviderFor(bots)
const botsProvider = BotsFamily._();
final botsProvider = BotsFamily._();
final class BotsProvider
extends
@@ -20,7 +20,7 @@ final class BotsProvider
FutureOr<List<Bot>>
>
with $FutureModifier<List<Bot>>, $FutureProvider<List<Bot>> {
const BotsProvider._({
BotsProvider._({
required BotsFamily super.from,
required (String, String) super.argument,
}) : super(
@@ -67,7 +67,7 @@ String _$botsHash() => r'15cefd5781350eb68208a342e85fcb0b9e0e3269';
final class BotsFamily extends $Family
with $FunctionalFamilyOverride<FutureOr<List<Bot>>, (String, String)> {
const BotsFamily._()
BotsFamily._()
: super(
retry: null,
name: r'botsProvider',

View File

@@ -51,10 +51,9 @@ class EditAppScreen extends HookConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final isNew = id == null;
final app =
isNew
? null
: ref.watch(customAppProvider(publisherName, projectId, id!));
final app = isNew
? null
: ref.watch(customAppProvider(publisherName, projectId, id!));
final formKey = useMemoized(() => GlobalKey<FormState>());
@@ -139,14 +138,10 @@ class EditAppScreen extends HookConsumerWidget {
submitting.value = true;
try {
final cloudFile =
await FileUploader.createCloudFile(
ref: ref,
fileData: UniversalFile(
data: result,
type: UniversalFileType.image,
),
).future;
final cloudFile = await FileUploader.createCloudFile(
ref: ref,
fileData: UniversalFile(data: result, type: UniversalFileType.image),
).future;
if (cloudFile == null) {
throw ArgumentError('Failed to upload the file...');
}
@@ -169,41 +164,40 @@ class EditAppScreen extends HookConsumerWidget {
showModalBottomSheet(
context: context,
isScrollControlled: true,
builder:
(context) => SheetScaffold(
titleText: 'addScope'.tr(),
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
TextFormField(
controller: scopeController,
decoration: InputDecoration(
labelText: 'scopeName'.tr(),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(12)),
),
),
builder: (context) => SheetScaffold(
titleText: 'addScope'.tr(),
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
TextFormField(
controller: scopeController,
decoration: InputDecoration(
labelText: 'scopeName'.tr(),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(12)),
),
const SizedBox(height: 20),
FilledButton.tonalIcon(
onPressed: () {
if (scopeController.text.isNotEmpty) {
allowedScopes.value = [
...allowedScopes.value,
scopeController.text,
];
Navigator.pop(context);
}
},
icon: const Icon(Symbols.add),
label: Text('add').tr(),
),
],
),
),
),
const SizedBox(height: 20),
FilledButton.tonalIcon(
onPressed: () {
if (scopeController.text.isNotEmpty) {
allowedScopes.value = [
...allowedScopes.value,
scopeController.text,
];
Navigator.pop(context);
}
},
icon: const Icon(Symbols.add),
label: Text('add').tr(),
),
],
),
),
),
);
}
@@ -212,57 +206,56 @@ class EditAppScreen extends HookConsumerWidget {
showModalBottomSheet(
context: context,
isScrollControlled: true,
builder:
(context) => SheetScaffold(
titleText: 'addRedirectUri'.tr(),
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
TextFormField(
controller: uriController,
decoration: InputDecoration(
labelText: 'redirectUri'.tr(),
hintText: 'https://example.com/auth/callback',
helperText: 'redirectUriHint'.tr(),
helperMaxLines: 3,
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(12)),
),
),
keyboardType: TextInputType.url,
validator: (value) {
if (value == null || value.isEmpty) {
return 'uriRequired'.tr();
}
final uri = Uri.tryParse(value);
if (uri == null || !uri.hasAbsolutePath) {
return 'invalidUri'.tr();
}
return null;
},
onTapOutside:
(_) => FocusManager.instance.primaryFocus?.unfocus(),
builder: (context) => SheetScaffold(
titleText: 'addRedirectUri'.tr(),
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
TextFormField(
controller: uriController,
decoration: InputDecoration(
labelText: 'redirectUri'.tr(),
hintText: 'https://example.com/auth/callback',
helperText: 'redirectUriHint'.tr(),
helperMaxLines: 3,
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(12)),
),
const SizedBox(height: 20),
FilledButton.tonalIcon(
onPressed: () {
if (uriController.text.isNotEmpty) {
redirectUris.value = [
...redirectUris.value,
uriController.text,
];
Navigator.pop(context);
}
},
icon: const Icon(Symbols.add),
label: Text('add').tr(),
),
],
),
keyboardType: TextInputType.url,
validator: (value) {
if (value == null || value.isEmpty) {
return 'uriRequired'.tr();
}
final uri = Uri.tryParse(value);
if (uri == null || !uri.hasAbsolutePath) {
return 'invalidUri'.tr();
}
return null;
},
onTapOutside: (_) =>
FocusManager.instance.primaryFocus?.unfocus(),
),
),
const SizedBox(height: 20),
FilledButton.tonalIcon(
onPressed: () {
if (uriController.text.isNotEmpty) {
redirectUris.value = [
...redirectUris.value,
uriController.text,
];
Navigator.pop(context);
}
},
icon: const Icon(Symbols.add),
label: Text('add').tr(),
),
],
),
),
),
);
}
@@ -275,31 +268,28 @@ class EditAppScreen extends HookConsumerWidget {
'picture_id': picture.value?.id,
'background_id': background.value?.id,
'links': {
'home_page':
homePageController.text.isNotEmpty
? homePageController.text
: null,
'privacy_policy':
privacyPolicyController.text.isNotEmpty
? privacyPolicyController.text
: null,
'terms_of_service':
termsController.text.isNotEmpty ? termsController.text : null,
'home_page': homePageController.text.isNotEmpty
? homePageController.text
: null,
'privacy_policy': privacyPolicyController.text.isNotEmpty
? privacyPolicyController.text
: null,
'terms_of_service': termsController.text.isNotEmpty
? termsController.text
: null,
},
'oauth_config':
oauthEnabled.value
? {
'redirect_uris': redirectUris.value,
'post_logout_redirect_uris':
postLogoutUris.value.isNotEmpty
? postLogoutUris.value
: null,
'allowed_scopes': allowedScopes.value,
'allowed_grant_types': allowedGrantTypes.value,
'require_pkce': requirePkce.value,
'allow_offline_access': allowOfflineAccess.value,
}
: null,
'oauth_config': oauthEnabled.value
? {
'redirect_uris': redirectUris.value,
'post_logout_redirect_uris': postLogoutUris.value.isNotEmpty
? postLogoutUris.value
: null,
'allowed_scopes': allowedScopes.value,
'allowed_grant_types': allowedGrantTypes.value,
'require_pkce': requirePkce.value,
'allow_offline_access': allowOfflineAccess.value,
}
: null,
};
try {
showLoadingModal(context);
@@ -326,287 +316,269 @@ class EditAppScreen extends HookConsumerWidget {
}
}
final bodyContent =
app == null && !isNew
? const Center(child: CircularProgressIndicator())
: app?.hasError == true && !isNew
? ResponseErrorWidget(
error: app!.error,
onRetry:
() => ref.invalidate(
customAppProvider(publisherName, projectId, id!),
),
)
: SingleChildScrollView(
child: Column(
children: [
AspectRatio(
aspectRatio: 16 / 7,
child: Stack(
clipBehavior: Clip.none,
fit: StackFit.expand,
children: [
GestureDetector(
child: Container(
color:
Theme.of(
context,
).colorScheme.surfaceContainerHigh,
child:
background.value != null
? CloudFileWidget(
item: background.value!,
fit: BoxFit.cover,
)
: const SizedBox.shrink(),
final bodyContent = app == null && !isNew
? const Center(child: CircularProgressIndicator())
: app?.hasError == true && !isNew
? ResponseErrorWidget(
error: app!.error,
onRetry: () => ref.invalidate(
customAppProvider(publisherName, projectId, id!),
),
)
: SingleChildScrollView(
child: Column(
children: [
AspectRatio(
aspectRatio: 16 / 7,
child: Stack(
clipBehavior: Clip.none,
fit: StackFit.expand,
children: [
GestureDetector(
child: Container(
color: Theme.of(
context,
).colorScheme.surfaceContainerHigh,
child: background.value != null
? CloudFileWidget(
item: background.value!,
fit: BoxFit.cover,
)
: const SizedBox.shrink(),
),
onTap: () {
setPicture('background');
},
),
Positioned(
left: 20,
bottom: -32,
child: GestureDetector(
child: ProfilePictureWidget(
file: picture.value,
radius: 40,
fallbackIcon: Symbols.apps,
),
onTap: () {
setPicture('background');
setPicture('picture');
},
),
Positioned(
left: 20,
bottom: -32,
child: GestureDetector(
child: ProfilePictureWidget(
fileId: picture.value?.id,
radius: 40,
fallbackIcon: Symbols.apps,
),
onTap: () {
setPicture('picture');
},
),
),
],
),
).padding(bottom: 32),
Form(
key: formKey,
child: Column(
children: [
TextFormField(
controller: nameController,
decoration: InputDecoration(
labelText: 'name'.tr(),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(12),
),
),
),
onTapOutside:
(_) =>
FocusManager.instance.primaryFocus?.unfocus(),
),
const SizedBox(height: 16),
TextFormField(
controller: slugController,
decoration: InputDecoration(
labelText: 'slug'.tr(),
helperText: 'slugHint'.tr(),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(12),
),
),
),
onTapOutside:
(_) =>
FocusManager.instance.primaryFocus?.unfocus(),
),
const SizedBox(height: 16),
TextFormField(
controller: descriptionController,
decoration: InputDecoration(
labelText: 'description'.tr(),
alignLabelWithHint: true,
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(12),
),
),
),
maxLines: 3,
onTapOutside:
(_) =>
FocusManager.instance.primaryFocus?.unfocus(),
),
const SizedBox(height: 16),
ExpansionPanelList(
expansionCallback: (index, isExpanded) {
switch (index) {
case 0:
enableLinks.value = isExpanded;
break;
case 1:
oauthEnabled.value = isExpanded;
break;
}
},
children: [
ExpansionPanel(
headerBuilder:
(context, isExpanded) =>
ListTile(title: Text('appLinks').tr()),
body: Column(
spacing: 16,
children: [
TextFormField(
controller: homePageController,
decoration: InputDecoration(
labelText: 'homePageUrl'.tr(),
hintText: 'https://example.com',
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(12),
),
),
),
keyboardType: TextInputType.url,
),
TextFormField(
controller: privacyPolicyController,
decoration: InputDecoration(
labelText: 'privacyPolicyUrl'.tr(),
hintText: 'https://example.com/privacy',
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(12),
),
),
),
keyboardType: TextInputType.url,
),
TextFormField(
controller: termsController,
decoration: InputDecoration(
labelText: 'termsOfServiceUrl'.tr(),
hintText: 'https://example.com/terms',
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(12),
),
),
),
keyboardType: TextInputType.url,
),
],
).padding(horizontal: 16, bottom: 24),
isExpanded: enableLinks.value,
),
ExpansionPanel(
headerBuilder:
(context, isExpanded) =>
ListTile(title: Text('oauthConfig').tr()),
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('redirectUris'.tr()),
Card(
margin: const EdgeInsets.symmetric(
vertical: 8,
),
child: Column(
children: [
...redirectUris.value.map(
(uri) => ListTile(
title: Text(uri),
trailing: IconButton(
icon: const Icon(Symbols.delete),
onPressed: () {
redirectUris.value =
redirectUris.value
.where((u) => u != uri)
.toList();
},
),
),
),
if (redirectUris.value.isNotEmpty)
const Divider(height: 1),
ListTile(
leading: const Icon(Symbols.add),
title: Text('addRedirectUri'.tr()),
onTap: showAddRedirectUriDialog,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
8,
),
),
),
],
),
),
const SizedBox(height: 16),
Text('allowedScopes'.tr()),
Card(
margin: const EdgeInsets.symmetric(
vertical: 8,
),
child: Column(
children: [
...allowedScopes.value.map(
(scope) => ListTile(
title: Text(scope),
trailing: IconButton(
icon: const Icon(Symbols.delete),
onPressed: () {
allowedScopes.value =
allowedScopes.value
.where(
(s) => s != scope,
)
.toList();
},
),
),
),
if (allowedScopes.value.isNotEmpty)
const Divider(height: 1),
ListTile(
leading: const Icon(Symbols.add),
title: Text('add').tr(),
onTap: showAddScopeDialog,
),
],
),
),
const SizedBox(height: 16),
SwitchListTile(
title: Text('requirePkce'.tr()),
value: requirePkce.value,
onChanged:
(value) => requirePkce.value = value,
),
SwitchListTile(
title: Text('allowOfflineAccess'.tr()),
value: allowOfflineAccess.value,
onChanged:
(value) =>
allowOfflineAccess.value = value,
),
],
).padding(horizontal: 16, bottom: 24),
isExpanded: oauthEnabled.value,
),
],
),
const SizedBox(height: 16),
Align(
alignment: Alignment.centerRight,
child: TextButton.icon(
onPressed: submitting.value ? null : performAction,
label: Text('saveChanges'.tr()),
icon: const Icon(Symbols.save),
),
),
],
).padding(all: 24),
),
],
),
],
),
);
).padding(bottom: 32),
Form(
key: formKey,
child: Column(
children: [
TextFormField(
controller: nameController,
decoration: InputDecoration(
labelText: 'name'.tr(),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(12)),
),
),
onTapOutside: (_) =>
FocusManager.instance.primaryFocus?.unfocus(),
),
const SizedBox(height: 16),
TextFormField(
controller: slugController,
decoration: InputDecoration(
labelText: 'slug'.tr(),
helperText: 'slugHint'.tr(),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(12)),
),
),
onTapOutside: (_) =>
FocusManager.instance.primaryFocus?.unfocus(),
),
const SizedBox(height: 16),
TextFormField(
controller: descriptionController,
decoration: InputDecoration(
labelText: 'description'.tr(),
alignLabelWithHint: true,
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(12)),
),
),
maxLines: 3,
onTapOutside: (_) =>
FocusManager.instance.primaryFocus?.unfocus(),
),
const SizedBox(height: 16),
ExpansionPanelList(
expansionCallback: (index, isExpanded) {
switch (index) {
case 0:
enableLinks.value = isExpanded;
break;
case 1:
oauthEnabled.value = isExpanded;
break;
}
},
children: [
ExpansionPanel(
headerBuilder: (context, isExpanded) =>
ListTile(title: Text('appLinks').tr()),
body: Column(
spacing: 16,
children: [
TextFormField(
controller: homePageController,
decoration: InputDecoration(
labelText: 'homePageUrl'.tr(),
hintText: 'https://example.com',
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(12),
),
),
),
keyboardType: TextInputType.url,
),
TextFormField(
controller: privacyPolicyController,
decoration: InputDecoration(
labelText: 'privacyPolicyUrl'.tr(),
hintText: 'https://example.com/privacy',
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(12),
),
),
),
keyboardType: TextInputType.url,
),
TextFormField(
controller: termsController,
decoration: InputDecoration(
labelText: 'termsOfServiceUrl'.tr(),
hintText: 'https://example.com/terms',
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(12),
),
),
),
keyboardType: TextInputType.url,
),
],
).padding(horizontal: 16, bottom: 24),
isExpanded: enableLinks.value,
),
ExpansionPanel(
headerBuilder: (context, isExpanded) =>
ListTile(title: Text('oauthConfig').tr()),
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('redirectUris'.tr()),
Card(
margin: const EdgeInsets.symmetric(
vertical: 8,
),
child: Column(
children: [
...redirectUris.value.map(
(uri) => ListTile(
title: Text(uri),
trailing: IconButton(
icon: const Icon(Symbols.delete),
onPressed: () {
redirectUris.value = redirectUris
.value
.where((u) => u != uri)
.toList();
},
),
),
),
if (redirectUris.value.isNotEmpty)
const Divider(height: 1),
ListTile(
leading: const Icon(Symbols.add),
title: Text('addRedirectUri'.tr()),
onTap: showAddRedirectUriDialog,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
8,
),
),
),
],
),
),
const SizedBox(height: 16),
Text('allowedScopes'.tr()),
Card(
margin: const EdgeInsets.symmetric(
vertical: 8,
),
child: Column(
children: [
...allowedScopes.value.map(
(scope) => ListTile(
title: Text(scope),
trailing: IconButton(
icon: const Icon(Symbols.delete),
onPressed: () {
allowedScopes.value =
allowedScopes.value
.where((s) => s != scope)
.toList();
},
),
),
),
if (allowedScopes.value.isNotEmpty)
const Divider(height: 1),
ListTile(
leading: const Icon(Symbols.add),
title: Text('add').tr(),
onTap: showAddScopeDialog,
),
],
),
),
const SizedBox(height: 16),
SwitchListTile(
title: Text('requirePkce'.tr()),
value: requirePkce.value,
onChanged: (value) =>
requirePkce.value = value,
),
SwitchListTile(
title: Text('allowOfflineAccess'.tr()),
value: allowOfflineAccess.value,
onChanged: (value) =>
allowOfflineAccess.value = value,
),
],
).padding(horizontal: 16, bottom: 24),
isExpanded: oauthEnabled.value,
),
],
),
const SizedBox(height: 16),
Align(
alignment: Alignment.centerRight,
child: TextButton.icon(
onPressed: submitting.value ? null : performAction,
label: Text('saveChanges'.tr()),
icon: const Icon(Symbols.save),
),
),
],
).padding(all: 24),
),
],
),
);
if (isModal) {
return bodyContent;

View File

@@ -10,7 +10,7 @@ part of 'edit_app.dart';
// ignore_for_file: type=lint, type=warning
@ProviderFor(customApp)
const customAppProvider = CustomAppFamily._();
final customAppProvider = CustomAppFamily._();
final class CustomAppProvider
extends
@@ -20,7 +20,7 @@ final class CustomAppProvider
FutureOr<CustomApp?>
>
with $FutureModifier<CustomApp?>, $FutureProvider<CustomApp?> {
const CustomAppProvider._({
CustomAppProvider._({
required CustomAppFamily super.from,
required (String, String, String) super.argument,
}) : super(
@@ -71,7 +71,7 @@ final class CustomAppFamily extends $Family
FutureOr<CustomApp?>,
(String, String, String)
> {
const CustomAppFamily._()
CustomAppFamily._()
: super(
retry: null,
name: r'customAppProvider',

View File

@@ -50,8 +50,9 @@ class EditBotScreen extends HookConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final isNew = id == null;
final botData =
isNew ? null : ref.watch(botProvider(publisherName, projectId, id!));
final botData = isNew
? null
: ref.watch(botProvider(publisherName, projectId, id!));
final formKey = useMemoized(() => GlobalKey<FormState>());
final submitting = useState(false);
@@ -125,14 +126,10 @@ class EditBotScreen extends HookConsumerWidget {
submitting.value = true;
try {
final cloudFile =
await FileUploader.createCloudFile(
ref: ref,
fileData: UniversalFile(
data: result,
type: UniversalFileType.image,
),
).future;
final cloudFile = await FileUploader.createCloudFile(
ref: ref,
fileData: UniversalFile(data: result, type: UniversalFileType.image),
).future;
if (cloudFile == null) {
throw ArgumentError('Failed to upload the file...');
}
@@ -193,284 +190,267 @@ class EditBotScreen extends HookConsumerWidget {
}
}
final bodyContent =
botData == null && !isNew
? const Center(child: CircularProgressIndicator())
: botData?.hasError == true && !isNew
? ResponseErrorWidget(
error: botData!.error,
onRetry:
() => ref.invalidate(
botProvider(publisherName, projectId, id!),
),
)
: SingleChildScrollView(
child: Column(
children: [
AspectRatio(
aspectRatio: 16 / 7,
child: Stack(
clipBehavior: Clip.none,
fit: StackFit.expand,
children: [
GestureDetector(
child: Container(
color:
Theme.of(
context,
).colorScheme.surfaceContainerHigh,
child:
background.value != null
? CloudFileWidget(
item: background.value!,
fit: BoxFit.cover,
)
: const SizedBox.shrink(),
final bodyContent = botData == null && !isNew
? const Center(child: CircularProgressIndicator())
: botData?.hasError == true && !isNew
? ResponseErrorWidget(
error: botData!.error,
onRetry: () =>
ref.invalidate(botProvider(publisherName, projectId, id!)),
)
: SingleChildScrollView(
child: Column(
children: [
AspectRatio(
aspectRatio: 16 / 7,
child: Stack(
clipBehavior: Clip.none,
fit: StackFit.expand,
children: [
GestureDetector(
child: Container(
color: Theme.of(
context,
).colorScheme.surfaceContainerHigh,
child: background.value != null
? CloudFileWidget(
item: background.value!,
fit: BoxFit.cover,
)
: const SizedBox.shrink(),
),
onTap: () {
setPicture('background');
},
),
Positioned(
left: 20,
bottom: -32,
child: GestureDetector(
child: ProfilePictureWidget(
file: picture.value,
radius: 40,
fallbackIcon: Symbols.smart_toy,
),
onTap: () {
setPicture('background');
setPicture('picture');
},
),
Positioned(
left: 20,
bottom: -32,
child: GestureDetector(
child: ProfilePictureWidget(
fileId: picture.value?.id,
radius: 40,
fallbackIcon: Symbols.smart_toy,
),
onTap: () {
setPicture('picture');
},
),
),
],
),
).padding(bottom: 32),
Form(
key: formKey,
child: Column(
children: [
TextFormField(
controller: nameController,
decoration: InputDecoration(
labelText: 'name'.tr(),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(12),
),
),
),
),
const SizedBox(height: 16),
TextFormField(
controller: nickController,
decoration: InputDecoration(
labelText: 'nickname'.tr(),
alignLabelWithHint: true,
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(12),
),
),
),
),
const SizedBox(height: 16),
TextFormField(
controller: slugController,
decoration: InputDecoration(
labelText: 'slug'.tr(),
helperText: 'slugHint'.tr(),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(12),
),
),
),
),
const SizedBox(height: 16),
TextFormField(
controller: bioController,
decoration: InputDecoration(
labelText: 'bio'.tr(),
alignLabelWithHint: true,
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(12),
),
),
),
maxLines: 3,
),
const SizedBox(height: 16),
Row(
spacing: 16,
children: [
Expanded(
child: TextFormField(
controller: firstNameController,
decoration: InputDecoration(
labelText: 'firstName'.tr(),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(12),
),
),
),
),
),
Expanded(
child: TextFormField(
controller: middleNameController,
decoration: InputDecoration(
labelText: 'middleName'.tr(),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(12),
),
),
),
),
),
Expanded(
child: TextFormField(
controller: lastNameController,
decoration: InputDecoration(
labelText: 'lastName'.tr(),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(12),
),
),
),
),
),
],
),
const SizedBox(height: 16),
Row(
spacing: 16,
children: [
Expanded(
child: TextFormField(
controller: genderController,
decoration: InputDecoration(
labelText: 'gender'.tr(),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(12),
),
),
),
),
),
Expanded(
child: TextFormField(
controller: pronounsController,
decoration: InputDecoration(
labelText: 'pronouns'.tr(),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(12),
),
),
),
),
),
],
),
const SizedBox(height: 16),
Row(
spacing: 16,
children: [
Expanded(
child: TextFormField(
controller: locationController,
decoration: InputDecoration(
labelText: 'location'.tr(),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(12),
),
),
),
),
),
Expanded(
child: TextFormField(
controller: timeZoneController,
decoration: InputDecoration(
labelText: 'timeZone'.tr(),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(12),
),
),
),
),
),
],
),
const SizedBox(height: 16),
GestureDetector(
onTap: () async {
final date = await showDatePicker(
context: context,
initialDate: birthday.value ?? DateTime.now(),
firstDate: DateTime(1900),
lastDate: DateTime.now(),
);
if (date != null) {
birthday.value = date;
}
},
child: Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
border: Border.all(
color: Theme.of(context).dividerColor,
width: 1,
),
borderRadius: BorderRadius.all(
Radius.circular(12),
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
'birthday'.tr(),
style: TextStyle(
color: Theme.of(context).hintColor,
),
),
Text(
birthday.value != null
? DateFormat.yMMMd().format(
birthday.value!,
)
: 'Select a date'.tr(),
),
],
),
),
),
const SizedBox(height: 16),
Align(
alignment: Alignment.centerRight,
child: TextButton.icon(
onPressed: submitting.value ? null : performAction,
label: Text('saveChanges').tr(),
icon: const Icon(Symbols.save),
),
),
],
).padding(all: 24),
),
],
),
],
),
);
).padding(bottom: 32),
Form(
key: formKey,
child: Column(
children: [
TextFormField(
controller: nameController,
decoration: InputDecoration(
labelText: 'name'.tr(),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(12)),
),
),
),
const SizedBox(height: 16),
TextFormField(
controller: nickController,
decoration: InputDecoration(
labelText: 'nickname'.tr(),
alignLabelWithHint: true,
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(12)),
),
),
),
const SizedBox(height: 16),
TextFormField(
controller: slugController,
decoration: InputDecoration(
labelText: 'slug'.tr(),
helperText: 'slugHint'.tr(),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(12)),
),
),
),
const SizedBox(height: 16),
TextFormField(
controller: bioController,
decoration: InputDecoration(
labelText: 'bio'.tr(),
alignLabelWithHint: true,
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(12)),
),
),
maxLines: 3,
),
const SizedBox(height: 16),
Row(
spacing: 16,
children: [
Expanded(
child: TextFormField(
controller: firstNameController,
decoration: InputDecoration(
labelText: 'firstName'.tr(),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(12),
),
),
),
),
),
Expanded(
child: TextFormField(
controller: middleNameController,
decoration: InputDecoration(
labelText: 'middleName'.tr(),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(12),
),
),
),
),
),
Expanded(
child: TextFormField(
controller: lastNameController,
decoration: InputDecoration(
labelText: 'lastName'.tr(),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(12),
),
),
),
),
),
],
),
const SizedBox(height: 16),
Row(
spacing: 16,
children: [
Expanded(
child: TextFormField(
controller: genderController,
decoration: InputDecoration(
labelText: 'gender'.tr(),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(12),
),
),
),
),
),
Expanded(
child: TextFormField(
controller: pronounsController,
decoration: InputDecoration(
labelText: 'pronouns'.tr(),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(12),
),
),
),
),
),
],
),
const SizedBox(height: 16),
Row(
spacing: 16,
children: [
Expanded(
child: TextFormField(
controller: locationController,
decoration: InputDecoration(
labelText: 'location'.tr(),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(12),
),
),
),
),
),
Expanded(
child: TextFormField(
controller: timeZoneController,
decoration: InputDecoration(
labelText: 'timeZone'.tr(),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(12),
),
),
),
),
),
],
),
const SizedBox(height: 16),
GestureDetector(
onTap: () async {
final date = await showDatePicker(
context: context,
initialDate: birthday.value ?? DateTime.now(),
firstDate: DateTime(1900),
lastDate: DateTime.now(),
);
if (date != null) {
birthday.value = date;
}
},
child: Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
border: Border.all(
color: Theme.of(context).dividerColor,
width: 1,
),
borderRadius: BorderRadius.all(Radius.circular(12)),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
'birthday'.tr(),
style: TextStyle(
color: Theme.of(context).hintColor,
),
),
Text(
birthday.value != null
? DateFormat.yMMMd().format(birthday.value!)
: 'Select a date'.tr(),
),
],
),
),
),
const SizedBox(height: 16),
Align(
alignment: Alignment.centerRight,
child: TextButton.icon(
onPressed: submitting.value ? null : performAction,
label: Text('saveChanges').tr(),
icon: const Icon(Symbols.save),
),
),
],
).padding(all: 24),
),
],
),
);
if (isModal) {
return bodyContent;

View File

@@ -10,12 +10,12 @@ part of 'edit_bot.dart';
// ignore_for_file: type=lint, type=warning
@ProviderFor(bot)
const botProvider = BotFamily._();
final botProvider = BotFamily._();
final class BotProvider
extends $FunctionalProvider<AsyncValue<Bot?>, Bot?, FutureOr<Bot?>>
with $FutureModifier<Bot?>, $FutureProvider<Bot?> {
const BotProvider._({
BotProvider._({
required BotFamily super.from,
required (String, String, String) super.argument,
}) : super(
@@ -62,7 +62,7 @@ String _$botHash() => r'7bec47bb2a4061a5babc6d6d19c3d4c320c91188';
final class BotFamily extends $Family
with $FunctionalFamilyOverride<FutureOr<Bot?>, (String, String, String)> {
const BotFamily._()
BotFamily._()
: super(
retry: null,
name: r'botProvider',

View File

@@ -10,7 +10,7 @@ part of 'edit_project.dart';
// ignore_for_file: type=lint, type=warning
@ProviderFor(devProject)
const devProjectProvider = DevProjectFamily._();
final devProjectProvider = DevProjectFamily._();
final class DevProjectProvider
extends
@@ -20,7 +20,7 @@ final class DevProjectProvider
FutureOr<DevProject?>
>
with $FutureModifier<DevProject?>, $FutureProvider<DevProject?> {
const DevProjectProvider._({
DevProjectProvider._({
required DevProjectFamily super.from,
required (String, String) super.argument,
}) : super(
@@ -68,7 +68,7 @@ String _$devProjectHash() => r'd92be3f5cdc510c2a377615ed5c70622a6842bf2';
final class DevProjectFamily extends $Family
with $FunctionalFamilyOverride<FutureOr<DevProject?>, (String, String)> {
const DevProjectFamily._()
DevProjectFamily._()
: super(
retry: null,
name: r'devProjectProvider',

View File

@@ -329,7 +329,7 @@ class DeveloperSelector extends HookConsumerWidget {
minTileHeight: 48,
leading: ProfilePictureWidget(
radius: 16,
fileId: item.publisher?.picture?.id,
file: item.publisher?.picture,
),
title: Text(item.publisher!.nick),
subtitle: Text('@${item.publisher!.name}'),
@@ -348,7 +348,7 @@ class DeveloperSelector extends HookConsumerWidget {
if (isReadOnly || currentDeveloper == null) {
return ProfilePictureWidget(
radius: 16,
fileId: currentDeveloper?.publisher?.picture?.id,
file: currentDeveloper?.publisher?.picture,
).center().padding(right: 8);
}
@@ -373,7 +373,7 @@ class DeveloperSelector extends HookConsumerWidget {
...developersMenu.map(
(e) => ProfilePictureWidget(
radius: 16,
fileId: e.value?.publisher?.picture?.id,
file: e.value?.publisher?.picture,
).center().padding(right: 8),
),
];
@@ -928,7 +928,7 @@ class _DeveloperEnrollmentSheet extends HookConsumerWidget {
final publisher = items[index];
return ListTile(
leading: ProfilePictureWidget(
fileId: publisher.picture?.id,
file: publisher.picture,
fallbackIcon: Symbols.group,
),
title: Text(publisher.nick),

View File

@@ -10,7 +10,7 @@ part of 'hub.dart';
// ignore_for_file: type=lint, type=warning
@ProviderFor(developerStats)
const developerStatsProvider = DeveloperStatsFamily._();
final developerStatsProvider = DeveloperStatsFamily._();
final class DeveloperStatsProvider
extends
@@ -20,7 +20,7 @@ final class DeveloperStatsProvider
FutureOr<DeveloperStats?>
>
with $FutureModifier<DeveloperStats?>, $FutureProvider<DeveloperStats?> {
const DeveloperStatsProvider._({
DeveloperStatsProvider._({
required DeveloperStatsFamily super.from,
required String? super.argument,
}) : super(
@@ -68,7 +68,7 @@ String _$developerStatsHash() => r'45546f29ec7cd1a9c3a4e0f4e39275e78bf34755';
final class DeveloperStatsFamily extends $Family
with $FunctionalFamilyOverride<FutureOr<DeveloperStats?>, String?> {
const DeveloperStatsFamily._()
DeveloperStatsFamily._()
: super(
retry: null,
name: r'developerStatsProvider',
@@ -85,7 +85,7 @@ final class DeveloperStatsFamily extends $Family
}
@ProviderFor(developers)
const developersProvider = DevelopersProvider._();
final developersProvider = DevelopersProvider._();
final class DevelopersProvider
extends
@@ -97,7 +97,7 @@ final class DevelopersProvider
with
$FutureModifier<List<SnDeveloper>>,
$FutureProvider<List<SnDeveloper>> {
const DevelopersProvider._()
DevelopersProvider._()
: super(
from: null,
argument: null,
@@ -126,7 +126,7 @@ final class DevelopersProvider
String _$developersHash() => r'252341098617ac398ce133994453f318dd3edbd2';
@ProviderFor(devProjects)
const devProjectsProvider = DevProjectsFamily._();
final devProjectsProvider = DevProjectsFamily._();
final class DevProjectsProvider
extends
@@ -136,7 +136,7 @@ final class DevProjectsProvider
FutureOr<List<DevProject>>
>
with $FutureModifier<List<DevProject>>, $FutureProvider<List<DevProject>> {
const DevProjectsProvider._({
DevProjectsProvider._({
required DevProjectsFamily super.from,
required String super.argument,
}) : super(
@@ -184,7 +184,7 @@ String _$devProjectsHash() => r'715b395bebda785d38691ffee3b88e50b498c91a';
final class DevProjectsFamily extends $Family
with $FunctionalFamilyOverride<FutureOr<List<DevProject>>, String> {
const DevProjectsFamily._()
DevProjectsFamily._()
: super(
retry: null,
name: r'devProjectsProvider',

View File

@@ -22,7 +22,7 @@ final articlesListNotifierProvider = AsyncNotifierProvider.family.autoDispose(
ArticlesListNotifier.new,
);
class ArticlesListNotifier extends AsyncNotifier<List<SnWebArticle>>
class ArticlesListNotifier extends AsyncNotifier<PaginationState<SnWebArticle>>
with AsyncPaginationController<SnWebArticle> {
static const int pageSize = 20;
@@ -42,7 +42,7 @@ class ArticlesListNotifier extends AsyncNotifier<List<SnWebArticle>>
try {
final response = await client.get(
'/sphere/feeds/articles',
'/insight/feeds/articles',
queryParameters: queryParams,
);
@@ -98,7 +98,7 @@ class SliverArticlesList extends ConsumerWidget {
@riverpod
Future<List<SnWebFeed>> subscribedFeeds(Ref ref) async {
final client = ref.watch(apiClientProvider);
final response = await client.get('/sphere/feeds/subscribed');
final response = await client.get('/insight/feeds/subscribed');
final data = response.data as List<dynamic>;
return data.map((json) => SnWebFeed.fromJson(json)).toList();
}

View File

@@ -10,7 +10,7 @@ part of 'articles.dart';
// ignore_for_file: type=lint, type=warning
@ProviderFor(subscribedFeeds)
const subscribedFeedsProvider = SubscribedFeedsProvider._();
final subscribedFeedsProvider = SubscribedFeedsProvider._();
final class SubscribedFeedsProvider
extends
@@ -20,7 +20,7 @@ final class SubscribedFeedsProvider
FutureOr<List<SnWebFeed>>
>
with $FutureModifier<List<SnWebFeed>>, $FutureProvider<List<SnWebFeed>> {
const SubscribedFeedsProvider._()
SubscribedFeedsProvider._()
: super(
from: null,
argument: null,

View File

@@ -18,7 +18,7 @@ part 'feed_detail.g.dart';
@riverpod
Future<SnWebFeed> marketplaceWebFeed(Ref ref, String feedId) async {
final apiClient = ref.watch(apiClientProvider);
final resp = await apiClient.get('/sphere/feeds/$feedId');
final resp = await apiClient.get('/insight/feeds/$feedId');
return SnWebFeed.fromJson(resp.data);
}
@@ -26,7 +26,7 @@ final marketplaceWebFeedContentNotifierProvider = AsyncNotifierProvider.family
.autoDispose(MarketplaceWebFeedContentNotifier.new);
class MarketplaceWebFeedContentNotifier
extends AsyncNotifier<List<SnWebArticle>>
extends AsyncNotifier<PaginationState<SnWebArticle>>
with AsyncPaginationController<SnWebArticle> {
static const int pageSize = 20;
@@ -40,7 +40,7 @@ class MarketplaceWebFeedContentNotifier
final queryParams = {'offset': fetchedCount.toString(), 'take': pageSize};
final response = await client.get(
'/sphere/feeds/$arg/articles',
'/insight/feeds/$arg/articles',
queryParameters: queryParams,
);
totalCount = int.parse(response.headers.value('X-Total') ?? '0');
@@ -61,7 +61,7 @@ Future<bool> marketplaceWebFeedSubscription(
}) async {
final api = ref.watch(apiClientProvider);
try {
await api.get('/sphere/feeds/$feedId/subscription');
await api.get('/insight/feeds/$feedId/subscription');
// If not 404, consider subscribed
return true;
} on Object catch (e) {
@@ -86,7 +86,7 @@ class MarketplaceWebFeedDetailScreen extends HookConsumerWidget {
// Subscribe to web feed
Future<void> subscribeToFeed() async {
final apiClient = ref.watch(apiClientProvider);
await apiClient.post('/sphere/feeds/$id/subscribe');
await apiClient.post('/insight/feeds/$id/subscribe');
HapticFeedback.selectionClick();
ref.invalidate(marketplaceWebFeedSubscriptionProvider(feedId: id));
if (!context.mounted) return;
@@ -96,7 +96,7 @@ class MarketplaceWebFeedDetailScreen extends HookConsumerWidget {
// Unsubscribe from web feed
Future<void> unsubscribeFromFeed() async {
final apiClient = ref.watch(apiClientProvider);
await apiClient.delete('/sphere/feeds/$id/subscribe');
await apiClient.delete('/insight/feeds/$id/subscribe');
HapticFeedback.selectionClick();
ref.invalidate(marketplaceWebFeedSubscriptionProvider(feedId: id));
if (!context.mounted) return;

View File

@@ -10,7 +10,7 @@ part of 'feed_detail.dart';
// ignore_for_file: type=lint, type=warning
@ProviderFor(marketplaceWebFeed)
const marketplaceWebFeedProvider = MarketplaceWebFeedFamily._();
final marketplaceWebFeedProvider = MarketplaceWebFeedFamily._();
final class MarketplaceWebFeedProvider
extends
@@ -20,7 +20,7 @@ final class MarketplaceWebFeedProvider
FutureOr<SnWebFeed>
>
with $FutureModifier<SnWebFeed>, $FutureProvider<SnWebFeed> {
const MarketplaceWebFeedProvider._({
MarketplaceWebFeedProvider._({
required MarketplaceWebFeedFamily super.from,
required String super.argument,
}) : super(
@@ -68,7 +68,7 @@ String _$marketplaceWebFeedHash() =>
final class MarketplaceWebFeedFamily extends $Family
with $FunctionalFamilyOverride<FutureOr<SnWebFeed>, String> {
const MarketplaceWebFeedFamily._()
MarketplaceWebFeedFamily._()
: super(
retry: null,
name: r'marketplaceWebFeedProvider',
@@ -87,7 +87,7 @@ final class MarketplaceWebFeedFamily extends $Family
/// Provider for web feed subscription status
@ProviderFor(marketplaceWebFeedSubscription)
const marketplaceWebFeedSubscriptionProvider =
final marketplaceWebFeedSubscriptionProvider =
MarketplaceWebFeedSubscriptionFamily._();
/// Provider for web feed subscription status
@@ -96,7 +96,7 @@ final class MarketplaceWebFeedSubscriptionProvider
extends $FunctionalProvider<AsyncValue<bool>, bool, FutureOr<bool>>
with $FutureModifier<bool>, $FutureProvider<bool> {
/// Provider for web feed subscription status
const MarketplaceWebFeedSubscriptionProvider._({
MarketplaceWebFeedSubscriptionProvider._({
required MarketplaceWebFeedSubscriptionFamily super.from,
required String super.argument,
}) : super(
@@ -147,7 +147,7 @@ String _$marketplaceWebFeedSubscriptionHash() =>
final class MarketplaceWebFeedSubscriptionFamily extends $Family
with $FunctionalFamilyOverride<FutureOr<bool>, String> {
const MarketplaceWebFeedSubscriptionFamily._()
MarketplaceWebFeedSubscriptionFamily._()
: super(
retry: null,
name: r'marketplaceWebFeedSubscriptionProvider',

View File

@@ -16,7 +16,8 @@ final marketplaceWebFeedsNotifierProvider = AsyncNotifierProvider.autoDispose(
MarketplaceWebFeedsNotifier.new,
);
class MarketplaceWebFeedsNotifier extends AsyncNotifier<List<SnWebFeed>>
class MarketplaceWebFeedsNotifier
extends AsyncNotifier<PaginationState<SnWebFeed>>
with
AsyncPaginationController<SnWebFeed>,
AsyncPaginationFilter<String?, SnWebFeed> {
@@ -28,7 +29,7 @@ class MarketplaceWebFeedsNotifier extends AsyncNotifier<List<SnWebFeed>>
final client = ref.read(apiClientProvider);
final response = await client.get(
'/sphere/feeds/explore',
'/insight/feeds/explore',
queryParameters: {
'offset': fetchedCount.toString(),
'take': 20,

View File

@@ -138,6 +138,18 @@ class ExploreScreen extends HookConsumerWidget {
),
PopupMenuButton(
itemBuilder: (context) => [
PopupMenuItem(
child: Row(
children: [
const Icon(Symbols.search),
const Gap(12),
Text('search').tr(),
],
),
onTap: () {
context.pushNamed('universalSearch');
},
),
PopupMenuItem(
child: Row(
children: [
@@ -162,18 +174,6 @@ class ExploreScreen extends HookConsumerWidget {
context.pushNamed('postShuffle');
},
),
PopupMenuItem(
child: Row(
children: [
const Icon(Symbols.search),
const Gap(12),
Text('search').tr(),
],
),
onTap: () {
context.pushNamed('postSearch');
},
),
],
icon: Icon(Symbols.action_key),
tooltip: 'search'.tr(),
@@ -255,7 +255,7 @@ class ExploreScreen extends HookConsumerWidget {
),
);
},
).padding(bottom: isWideScreen(context) ? null : 56)
).padding(bottom: MediaQuery.of(context).padding.bottom)
: null,
body: isWide
? _buildWideBody(
@@ -375,6 +375,8 @@ class ExploreScreen extends HookConsumerWidget {
? null // Post list handles its own refreshing
: ref.watch(activityListProvider.notifier);
final activityState = ref.watch(activityListProvider);
return Row(
spacing: 12,
children: [
@@ -387,6 +389,10 @@ class ExploreScreen extends HookConsumerWidget {
child: CustomScrollView(
slivers: [
const SliverGap(12),
if (activityState.value?.isLoading ?? false)
SliverToBoxAdapter(
child: LinearProgressIndicator().padding(bottom: 8),
),
SliverToBoxAdapter(child: filterBar),
const SliverGap(8),
bodyView,
@@ -532,6 +538,18 @@ class ExploreScreen extends HookConsumerWidget {
),
PopupMenuButton(
itemBuilder: (context) => [
PopupMenuItem(
child: Row(
children: [
const Icon(Symbols.search),
const Gap(12),
Text('search').tr(),
],
),
onTap: () {
context.pushNamed('universalSearch');
},
),
PopupMenuItem(
child: Row(
children: [
@@ -556,18 +574,6 @@ class ExploreScreen extends HookConsumerWidget {
context.pushNamed('postShuffle');
},
),
PopupMenuItem(
child: Row(
children: [
const Icon(Symbols.search),
const Gap(12),
Text('search').tr(),
],
),
onTap: () {
context.pushNamed('postSearch');
},
),
],
icon: Icon(Symbols.action_key, color: foregroundColor),
tooltip: 'search'.tr(),

View File

@@ -1,28 +1,19 @@
import 'dart:io';
import 'package:file_saver/file_saver.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:gal/gal.dart';
import 'package:gap/gap.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/models/file.dart';
import 'package:island/pods/config.dart';
import 'package:island/pods/drive/file_references.dart';
import 'package:island/pods/network.dart';
import 'package:island/pods/drive/upload_tasks.dart';
import 'package:island/models/drive_task.dart';
import 'package:island/services/file_download.dart';
import 'package:island/services/responsive.dart';
import 'package:island/services/time.dart';
import 'package:island/widgets/alert.dart';
import 'package:island/widgets/app_scaffold.dart';
import 'package:island/widgets/content/file_info_sheet.dart';
import 'package:island/widgets/content/file_viewer_contents.dart';
import 'package:island/widgets/content/sheet.dart';
import 'package:path/path.dart' show extension;
import 'package:path_provider/path_provider.dart';
import 'package:styled_widget/styled_widget.dart';
class FileDetailScreen extends HookConsumerWidget {
@@ -155,7 +146,7 @@ class FileDetailScreen extends HookConsumerWidget {
actions.add(
IconButton(
icon: Icon(Icons.save_alt),
onPressed: () async => _saveToGallery(ref),
onPressed: () => FileDownloadService(ref).saveToGallery(item),
),
);
}
@@ -166,7 +157,8 @@ class FileDetailScreen extends HookConsumerWidget {
actions.add(
IconButton(
icon: Icon(Icons.save_alt),
onPressed: () async => _downloadFile(ref),
onPressed: () =>
FileDownloadService(ref).downloadWithProgress(item),
),
);
}
@@ -199,80 +191,6 @@ class FileDetailScreen extends HookConsumerWidget {
return actions;
}
Future<void> _saveToGallery(WidgetRef ref) async {
try {
showSnackBar('Saving image...');
final client = ref.read(apiClientProvider);
final tempDir = await getTemporaryDirectory();
var extName = extension(item.name).trim();
if (extName.isEmpty) {
extName = item.mimeType?.split('/').lastOrNull ?? 'jpeg';
}
final filePath = '${tempDir.path}/${item.id}.$extName';
await client.download(
'/drive/files/${item.id}',
filePath,
queryParameters: {'original': true},
);
if (!kIsWeb && (Platform.isAndroid || Platform.isIOS)) {
await Gal.putImage(filePath, album: 'Solar Network');
showSnackBar('Image saved to gallery');
} else {
await FileSaver.instance.saveFile(
name: item.name.isEmpty ? '${item.id}.$extName' : item.name,
file: File(filePath),
);
showSnackBar('Image saved to $filePath');
}
} catch (e) {
showErrorAlert(e);
}
}
Future<void> _downloadFile(WidgetRef ref) async {
final taskNotifier = ref.read(uploadTasksProvider.notifier);
final taskId = taskNotifier.addLocalDownloadTask(item);
try {
showSnackBar('Downloading file...');
final client = ref.read(apiClientProvider);
final tempDir = await getTemporaryDirectory();
var extName = extension(item.name).trim();
if (extName.isEmpty) {
extName = item.mimeType?.split('/').lastOrNull ?? 'bin';
}
final filePath = '${tempDir.path}/${item.id}.$extName';
await client.download(
'/drive/files/${item.id}',
filePath,
queryParameters: {'original': true},
onReceiveProgress: (count, total) {
if (total > 0) {
taskNotifier.updateDownloadProgress(taskId, count, total);
taskNotifier.updateTransmissionProgress(taskId, count / total);
}
},
);
await FileSaver.instance.saveFile(
name: item.name.isEmpty ? '${item.id}.$extName' : item.name,
file: File(filePath),
);
taskNotifier.updateTaskStatus(taskId, DriveTaskStatus.completed);
showSnackBar('File saved to downloads');
} catch (e) {
taskNotifier.updateTaskStatus(
taskId,
DriveTaskStatus.failed,
errorMessage: e.toString(),
);
showErrorAlert(e);
}
}
Widget _buildContent(BuildContext context, WidgetRef ref, String serverUrl) {
final uri = '$serverUrl/drive/files/${item.id}';

View File

@@ -10,7 +10,7 @@ part of 'lottery.dart';
// ignore_for_file: type=lint, type=warning
@ProviderFor(lotteryTickets)
const lotteryTicketsProvider = LotteryTicketsFamily._();
final lotteryTicketsProvider = LotteryTicketsFamily._();
final class LotteryTicketsProvider
extends
@@ -22,7 +22,7 @@ final class LotteryTicketsProvider
with
$FutureModifier<List<SnLotteryTicket>>,
$FutureProvider<List<SnLotteryTicket>> {
const LotteryTicketsProvider._({
LotteryTicketsProvider._({
required LotteryTicketsFamily super.from,
required ({int offset, int take}) super.argument,
}) : super(
@@ -74,7 +74,7 @@ final class LotteryTicketsFamily extends $Family
FutureOr<List<SnLotteryTicket>>,
({int offset, int take})
> {
const LotteryTicketsFamily._()
LotteryTicketsFamily._()
: super(
retry: null,
name: r'lotteryTicketsProvider',
@@ -94,7 +94,7 @@ final class LotteryTicketsFamily extends $Family
}
@ProviderFor(lotteryRecords)
const lotteryRecordsProvider = LotteryRecordsFamily._();
final lotteryRecordsProvider = LotteryRecordsFamily._();
final class LotteryRecordsProvider
extends
@@ -106,7 +106,7 @@ final class LotteryRecordsProvider
with
$FutureModifier<List<SnLotteryRecord>>,
$FutureProvider<List<SnLotteryRecord>> {
const LotteryRecordsProvider._({
LotteryRecordsProvider._({
required LotteryRecordsFamily super.from,
required ({int offset, int take}) super.argument,
}) : super(
@@ -158,7 +158,7 @@ final class LotteryRecordsFamily extends $Family
FutureOr<List<SnLotteryRecord>>,
({int offset, int take})
> {
const LotteryRecordsFamily._()
LotteryRecordsFamily._()
: super(
retry: null,
name: r'lotteryRecordsProvider',

View File

@@ -37,7 +37,7 @@ class SkeletonNotificationTile extends StatelessWidget {
isThreeLine: true,
contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
leading: fakePfp != null
? ProfilePictureWidget(fileId: fakePfp, radius: 20)
? ProfilePictureWidget(file: null, radius: 20)
: CircleAvatar(
backgroundColor: Theme.of(context).colorScheme.primaryContainer,
child: Icon(
@@ -164,10 +164,24 @@ final notificationListProvider = AsyncNotifierProvider.autoDispose(
NotificationListNotifier.new,
);
class NotificationListNotifier extends AsyncNotifier<List<SnNotification>>
class NotificationListNotifier
extends AsyncNotifier<PaginationState<SnNotification>>
with AsyncPaginationController<SnNotification> {
static const int pageSize = 5;
@override
FutureOr<PaginationState<SnNotification>> build() async {
final items = await fetch();
return PaginationState(
items: items,
isLoading: false,
isReloading: false,
totalCount: totalCount,
hasMore: hasMore,
cursor: cursor,
);
}
@override
Future<List<SnNotification>> fetch() async {
final client = ref.read(apiClientProvider);

Some files were not shown because too many files have changed in this diff Show More