Compare commits
27 Commits
d7dcde898c
...
v3
Author | SHA1 | Date | |
---|---|---|---|
|
c9b71701c8 | ||
|
28e98488f1 | ||
|
b4d476613e | ||
|
b48a1aac44 | ||
|
596d212593 | ||
|
54f290327e | ||
|
16f248ceab | ||
|
856d811187 | ||
|
d07b194c04 | ||
|
2554b58be6 | ||
|
a627b5838e | ||
|
c479a9f381 | ||
|
02057e663b | ||
|
6501594100 | ||
|
c6599edc3d | ||
|
709a0620b6 | ||
|
f9b2a96c7c | ||
|
4dca6189cb | ||
|
c7f5b63fe5 | ||
|
96c2f45c85 | ||
|
06f04eb3a5 | ||
|
8af97e43b4 | ||
|
d1e8234b93 | ||
|
a03d6015a6 | ||
|
246ac52d0a | ||
|
abf395ff9a | ||
|
4fdc8eb1d0 |
@@ -386,6 +386,7 @@
|
|||||||
"postSettings": "Settings",
|
"postSettings": "Settings",
|
||||||
"postPublisherUnselected": "Publisher Unspecified",
|
"postPublisherUnselected": "Publisher Unspecified",
|
||||||
"postType": "Post Type",
|
"postType": "Post Type",
|
||||||
|
"postTypePost": "Post",
|
||||||
"articleAttachmentHint": "Attachments must be uploaded and inserted into the article body to be visible.",
|
"articleAttachmentHint": "Attachments must be uploaded and inserted into the article body to be visible.",
|
||||||
"postVisibility": "Post Visibility",
|
"postVisibility": "Post Visibility",
|
||||||
"postVisibilityPublic": "Public",
|
"postVisibilityPublic": "Public",
|
||||||
@@ -867,7 +868,7 @@
|
|||||||
"failedToLoadUserInfoNetwork": "It seems be network issue, you can tap the button below to try again.",
|
"failedToLoadUserInfoNetwork": "It seems be network issue, you can tap the button below to try again.",
|
||||||
"failedToLoadUserInfoUnauthorized": "It seems your session has been logged out or not available anymore, you can still try agian to fetch the user info if you want.",
|
"failedToLoadUserInfoUnauthorized": "It seems your session has been logged out or not available anymore, you can still try agian to fetch the user info if you want.",
|
||||||
"okay": "Okay",
|
"okay": "Okay",
|
||||||
"postDetails": "Post Details",
|
"postDetail": "Post Detail",
|
||||||
"postCount": {
|
"postCount": {
|
||||||
"zero": "No posts",
|
"zero": "No posts",
|
||||||
"one": "{} post",
|
"one": "{} post",
|
||||||
@@ -883,6 +884,7 @@
|
|||||||
"stellarProgram": "Stellar Program",
|
"stellarProgram": "Stellar Program",
|
||||||
"socialCredits": "Social Credits",
|
"socialCredits": "Social Credits",
|
||||||
"credits": "Credits",
|
"credits": "Credits",
|
||||||
|
"creditsStatus": "Credits Status",
|
||||||
"socialCreditsDescription": "Social Credit is a way for Solar Network to evaluate users. It is calculated based on their behavior and interactions. With a base score of 100, higher scores indicate a user's credibility within the community. Scores change over time to reflect a user's recent behavior. Users with higher credit ratings enjoy more benefits, while users with lower credit ratings may have some functionality restricted.",
|
"socialCreditsDescription": "Social Credit is a way for Solar Network to evaluate users. It is calculated based on their behavior and interactions. With a base score of 100, higher scores indicate a user's credibility within the community. Scores change over time to reflect a user's recent behavior. Users with higher credit ratings enjoy more benefits, while users with lower credit ratings may have some functionality restricted.",
|
||||||
"socialCreditsLevelPoor": "Poor",
|
"socialCreditsLevelPoor": "Poor",
|
||||||
"socialCreditsLevelNormal": "Normal",
|
"socialCreditsLevelNormal": "Normal",
|
||||||
@@ -907,5 +909,56 @@
|
|||||||
"copyKeyHint": "Please copy this key and store it somewhere safe. You will not be able to see it again.",
|
"copyKeyHint": "Please copy this key and store it somewhere safe. You will not be able to see it again.",
|
||||||
"rotateKey": "Rotate Key",
|
"rotateKey": "Rotate Key",
|
||||||
"rotateBotKey": "Rotate Bot Key",
|
"rotateBotKey": "Rotate Bot Key",
|
||||||
"rotateBotKeyHint": "Are you sure you want to rotate this key? The old key will become invalid immediately. This action cannot be undone."
|
"rotateBotKeyHint": "Are you sure you want to rotate this key? The old key will become invalid immediately. This action cannot be undone.",
|
||||||
|
"webFeedArticleCount": {
|
||||||
|
"zero": "No articles",
|
||||||
|
"one": "{} article",
|
||||||
|
"other": "{} articles"
|
||||||
|
},
|
||||||
|
"webFeedSubscribed": "The feed has been subscribed",
|
||||||
|
"webFeedUnsubscribed": "The feed has been unsubscribed",
|
||||||
|
"appDetails": "App Details",
|
||||||
|
"secrets": "Secrets",
|
||||||
|
"appNotFound": "App not found.",
|
||||||
|
"secretCopied": "Secret copied to clipboard.",
|
||||||
|
"deleteSecret": "Delete Secret",
|
||||||
|
"deleteSecretHint": "Are you sure you want to delete this secret? This action cannot be undone.",
|
||||||
|
"generateSecret": "Generate New Secret",
|
||||||
|
"createdAt": "Created at {}",
|
||||||
|
"newSecretGenerated": "New Secret Generated",
|
||||||
|
"copySecretHint": "Please copy this secret and store it somewhere safe. You will not be able to see it again.",
|
||||||
|
"expiresIn": "Expires In (seconds)",
|
||||||
|
"isOidc": "OIDC Compliant",
|
||||||
|
"pinPost": "Pin Post",
|
||||||
|
"unpinPost": "Unpin Post",
|
||||||
|
"pinnedPost": "Pinned",
|
||||||
|
"publisherPage": "Publisher Page",
|
||||||
|
"realmPage": "Realm Page",
|
||||||
|
"replyPage": "Reply Page",
|
||||||
|
"pinPostPublisherHint": "Pin this post to your publisher page",
|
||||||
|
"pinPostRealmHint": "Pin this post to the realm page",
|
||||||
|
"pinPostRealmDisabledHint": "This post doesn't belong to any realm",
|
||||||
|
"pinPostReplyHint": "Pin this post to the reply page",
|
||||||
|
"pinPostReplyDisabledHint": "This post is not a reply",
|
||||||
|
"pin": "Pin",
|
||||||
|
"unpinPostHint": "Are you sure you want to unpin this post?",
|
||||||
|
"all": "All",
|
||||||
|
"statusPresent": "Present",
|
||||||
|
"accountAutomated": "Automated",
|
||||||
|
"chatBreakClearButton": "Clear",
|
||||||
|
"chatBreak5m": "5m",
|
||||||
|
"chatBreak10m": "10m",
|
||||||
|
"chatBreak15m": "15m",
|
||||||
|
"chatBreak30m": "30m",
|
||||||
|
"chatBreakCustomMinutes": "Custom (minutes)",
|
||||||
|
"chatBreakEnterMinutes": "Enter minutes",
|
||||||
|
"errorGeneric": "Error: {}",
|
||||||
|
"searchMessages": "Search Messages",
|
||||||
|
"messagesCount": "{} messages",
|
||||||
|
"dotSeparator": "·",
|
||||||
|
"roleValidationHint": "Role must be between 0 and 100",
|
||||||
|
"searchMessagesHint": "Search messages...",
|
||||||
|
"searchLinks": "Links",
|
||||||
|
"searchAttachments": "Attachments",
|
||||||
|
"noMessagesFound": "No messages found"
|
||||||
}
|
}
|
@@ -829,7 +829,7 @@
|
|||||||
"failedToLoadUserInfoNetwork": "这看起来是个网络问题,你可以按下面的按钮来重试",
|
"failedToLoadUserInfoNetwork": "这看起来是个网络问题,你可以按下面的按钮来重试",
|
||||||
"failedToLoadUserInfoUnauthorized": "看来您的会话已被注销或不再可用,如果您愿意,您仍然可以再次尝试获取用户信息。",
|
"failedToLoadUserInfoUnauthorized": "看来您的会话已被注销或不再可用,如果您愿意,您仍然可以再次尝试获取用户信息。",
|
||||||
"okay": "了解",
|
"okay": "了解",
|
||||||
"postDetails": "帖子详情",
|
"postDetail": "帖子详情",
|
||||||
"mimeType": "类型",
|
"mimeType": "类型",
|
||||||
"fileSize": "大小",
|
"fileSize": "大小",
|
||||||
"fileHash": "哈希",
|
"fileHash": "哈希",
|
||||||
@@ -843,5 +843,19 @@
|
|||||||
"socialCreditsLevelPoor": "糟糕",
|
"socialCreditsLevelPoor": "糟糕",
|
||||||
"socialCreditsLevelNormal": "正常",
|
"socialCreditsLevelNormal": "正常",
|
||||||
"socialCreditsLevelGood": "良好",
|
"socialCreditsLevelGood": "良好",
|
||||||
"socialCreditsLevelExcellent": "优秀"
|
"socialCreditsLevelExcellent": "优秀",
|
||||||
|
"appDetails": "应用详情",
|
||||||
|
"secrets": "密钥",
|
||||||
|
"appNotFound": "应用未找到。",
|
||||||
|
"secretCopied": "密钥已复制到剪贴板。",
|
||||||
|
"deleteSecret": "删除密钥",
|
||||||
|
"deleteSecretHint": "您确定要删除此密钥吗?此操作无法撤销。",
|
||||||
|
"generateSecret": "生成新密钥",
|
||||||
|
"createdAt": "创建于 {}",
|
||||||
|
"newSecretGenerated": "已生成新密钥",
|
||||||
|
"copySecretHint": "请复制此密钥并将其存放在安全的地方。您将无法再次看到它。",
|
||||||
|
"expiresIn": "过期时间(秒)",
|
||||||
|
"isOidc": "OIDC 兼容",
|
||||||
|
"statusPresent": "至今",
|
||||||
|
"accountAutomated": "机器人"
|
||||||
}
|
}
|
||||||
|
@@ -811,5 +811,17 @@
|
|||||||
"filesListAdditional": {
|
"filesListAdditional": {
|
||||||
"one": "+{} 個文件被摺疊",
|
"one": "+{} 個文件被摺疊",
|
||||||
"other": "+{} 個文件被摺疊"
|
"other": "+{} 個文件被摺疊"
|
||||||
}
|
},
|
||||||
|
"appDetails": "應用程式詳情",
|
||||||
|
"secrets": "密鑰",
|
||||||
|
"appNotFound": "找不到應用程式。",
|
||||||
|
"secretCopied": "密鑰已複製到剪貼簿。",
|
||||||
|
"deleteSecret": "刪除密鑰",
|
||||||
|
"deleteSecretHint": "您確定要刪除此密鑰嗎?此操作無法復原。",
|
||||||
|
"generateSecret": "產生新密鑰",
|
||||||
|
"createdAt": "建立於 {}",
|
||||||
|
"newSecretGenerated": "已產生新密鑰",
|
||||||
|
"copySecretHint": "請複製此密鑰並將其存放在安全的地方。您將無法再次看到它。",
|
||||||
|
"expiresIn": "過期時間(秒)",
|
||||||
|
"isOidc": "OIDC 相容"
|
||||||
}
|
}
|
@@ -40,6 +40,8 @@ PODS:
|
|||||||
- file_picker (0.0.1):
|
- file_picker (0.0.1):
|
||||||
- DKImagePickerController/PhotoGallery
|
- DKImagePickerController/PhotoGallery
|
||||||
- Flutter
|
- Flutter
|
||||||
|
- file_saver (0.0.1):
|
||||||
|
- Flutter
|
||||||
- Firebase/CoreOnly (12.0.0):
|
- Firebase/CoreOnly (12.0.0):
|
||||||
- FirebaseCore (~> 12.0.0)
|
- FirebaseCore (~> 12.0.0)
|
||||||
- Firebase/Crashlytics (12.0.0):
|
- Firebase/Crashlytics (12.0.0):
|
||||||
@@ -303,6 +305,7 @@ DEPENDENCIES:
|
|||||||
- croppy (from `.symlinks/plugins/croppy/ios`)
|
- croppy (from `.symlinks/plugins/croppy/ios`)
|
||||||
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
|
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
|
||||||
- file_picker (from `.symlinks/plugins/file_picker/ios`)
|
- file_picker (from `.symlinks/plugins/file_picker/ios`)
|
||||||
|
- file_saver (from `.symlinks/plugins/file_saver/ios`)
|
||||||
- firebase_analytics (from `.symlinks/plugins/firebase_analytics/ios`)
|
- firebase_analytics (from `.symlinks/plugins/firebase_analytics/ios`)
|
||||||
- firebase_core (from `.symlinks/plugins/firebase_core/ios`)
|
- firebase_core (from `.symlinks/plugins/firebase_core/ios`)
|
||||||
- firebase_crashlytics (from `.symlinks/plugins/firebase_crashlytics/ios`)
|
- firebase_crashlytics (from `.symlinks/plugins/firebase_crashlytics/ios`)
|
||||||
@@ -381,6 +384,8 @@ EXTERNAL SOURCES:
|
|||||||
:path: ".symlinks/plugins/device_info_plus/ios"
|
:path: ".symlinks/plugins/device_info_plus/ios"
|
||||||
file_picker:
|
file_picker:
|
||||||
:path: ".symlinks/plugins/file_picker/ios"
|
:path: ".symlinks/plugins/file_picker/ios"
|
||||||
|
file_saver:
|
||||||
|
:path: ".symlinks/plugins/file_saver/ios"
|
||||||
firebase_analytics:
|
firebase_analytics:
|
||||||
:path: ".symlinks/plugins/firebase_analytics/ios"
|
:path: ".symlinks/plugins/firebase_analytics/ios"
|
||||||
firebase_core:
|
firebase_core:
|
||||||
@@ -464,6 +469,7 @@ SPEC CHECKSUMS:
|
|||||||
DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c
|
DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c
|
||||||
DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60
|
DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60
|
||||||
file_picker: a0560bc09d61de87f12d246fc47d2119e6ef37be
|
file_picker: a0560bc09d61de87f12d246fc47d2119e6ef37be
|
||||||
|
file_saver: 6cdbcddd690cb02b0c1a0c225b37cd805c2bf8b6
|
||||||
Firebase: 800d487043c0557d9faed71477a38d9aafb08a41
|
Firebase: 800d487043c0557d9faed71477a38d9aafb08a41
|
||||||
firebase_analytics: cd56fc56f75c1df30a6ff5290cd56e230996a76d
|
firebase_analytics: cd56fc56f75c1df30a6ff5290cd56e230996a76d
|
||||||
firebase_core: 633e1851ffe1b9ab875f6467a4f574c79cef02e4
|
firebase_core: 633e1851ffe1b9ab875f6467a4f574c79cef02e4
|
||||||
|
@@ -68,6 +68,34 @@ class AppDatabase extends _$AppDatabase {
|
|||||||
return (delete(chatMessages)..where((m) => m.id.equals(id))).go();
|
return (delete(chatMessages)..where((m) => m.id.equals(id))).go();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<int> getTotalMessagesForRoom(String roomId) {
|
||||||
|
return (select(chatMessages)..where((m) => m.roomId.equals(roomId))).get().then((list) => list.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<LocalChatMessage>> searchMessages(
|
||||||
|
String roomId,
|
||||||
|
String query,
|
||||||
|
) async {
|
||||||
|
var selectStatement = select(chatMessages)
|
||||||
|
..where((m) => m.roomId.equals(roomId));
|
||||||
|
|
||||||
|
if (query.isNotEmpty) {
|
||||||
|
selectStatement =
|
||||||
|
selectStatement
|
||||||
|
..where((m) => m.content.like('%${query.toLowerCase()}%'));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
final messages =
|
||||||
|
await (selectStatement
|
||||||
|
..orderBy([(m) => OrderingTerm.desc(m.createdAt)]))
|
||||||
|
.get();
|
||||||
|
return messages.map((msg) => companionToMessage(msg)).toList();
|
||||||
|
}
|
||||||
|
|
||||||
// Convert between Drift and model objects
|
// Convert between Drift and model objects
|
||||||
ChatMessagesCompanion messageToCompanion(LocalChatMessage message) {
|
ChatMessagesCompanion messageToCompanion(LocalChatMessage message) {
|
||||||
return ChatMessagesCompanion(
|
return ChatMessagesCompanion(
|
||||||
|
@@ -8,7 +8,7 @@ import 'package:firebase_crashlytics/firebase_crashlytics.dart';
|
|||||||
import 'package:firebase_messaging/firebase_messaging.dart';
|
import 'package:firebase_messaging/firebase_messaging.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
@@ -169,12 +169,12 @@ class IslandApp extends HookConsumerWidget {
|
|||||||
final theme = ref.watch(themeProvider);
|
final theme = ref.watch(themeProvider);
|
||||||
|
|
||||||
void handleMessage(RemoteMessage notification) {
|
void handleMessage(RemoteMessage notification) {
|
||||||
if (notification.data['action_uri'] != null) {
|
if (notification.data['meta']?['action_uri'] != null) {
|
||||||
var uri = notification.data['action_uri'] as String;
|
var uri = notification.data['meta']['action_uri'] as String;
|
||||||
if (uri.startsWith('/')) {
|
if (uri.startsWith('/')) {
|
||||||
// In-app routes
|
// In-app routes
|
||||||
final router = ref.read(routerProvider);
|
final router = ref.read(routerProvider);
|
||||||
router.go(notification.data['action_uri']);
|
router.push(notification.data['meta']['action_uri']);
|
||||||
} else {
|
} else {
|
||||||
// External links
|
// External links
|
||||||
launchUrlString(uri);
|
launchUrlString(uri);
|
||||||
@@ -186,27 +186,6 @@ class IslandApp extends HookConsumerWidget {
|
|||||||
if (!kIsWeb && Platform.isLinux) {
|
if (!kIsWeb && Platform.isLinux) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const channel = MethodChannel('dev.solsynth.solian/notifications');
|
|
||||||
|
|
||||||
Future<void> handleInitialLink() async {
|
|
||||||
final String? link = await channel.invokeMethod('initialLink');
|
|
||||||
if (link != null) {
|
|
||||||
final router = ref.read(routerProvider);
|
|
||||||
router.go(link);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!kIsWeb && Platform.isAndroid) {
|
|
||||||
handleInitialLink();
|
|
||||||
}
|
|
||||||
|
|
||||||
channel.setMethodCallHandler((call) async {
|
|
||||||
if (call.method == 'newLink') {
|
|
||||||
final String link = call.arguments;
|
|
||||||
final router = ref.read(routerProvider);
|
|
||||||
router.go(link);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// When the app is opened from a terminated state.
|
// When the app is opened from a terminated state.
|
||||||
FirebaseMessaging.instance.getInitialMessage().then((message) {
|
FirebaseMessaging.instance.getInitialMessage().then((message) {
|
||||||
|
@@ -71,6 +71,8 @@ sealed class SnAccountProfile with _$SnAccountProfile {
|
|||||||
SnAccountBadge? activeBadge,
|
SnAccountBadge? activeBadge,
|
||||||
required int experience,
|
required int experience,
|
||||||
required int level,
|
required int level,
|
||||||
|
@Default(100) double socialCredits,
|
||||||
|
@Default(0) int socialCreditsLevel,
|
||||||
required double levelingProgress,
|
required double levelingProgress,
|
||||||
required SnCloudFile? picture,
|
required SnCloudFile? picture,
|
||||||
required SnCloudFile? background,
|
required SnCloudFile? background,
|
||||||
|
@@ -613,7 +613,7 @@ as String,
|
|||||||
/// @nodoc
|
/// @nodoc
|
||||||
mixin _$SnAccountProfile {
|
mixin _$SnAccountProfile {
|
||||||
|
|
||||||
String get id; String get firstName; String get middleName; String get lastName; String get bio; String get gender; String get pronouns; String get location; String get timeZone; DateTime? get birthday;@ProfileLinkConverter() List<ProfileLink> get links; DateTime? get lastSeenAt; SnAccountBadge? get activeBadge; int get experience; int get level; double get levelingProgress; SnCloudFile? get picture; SnCloudFile? get background; SnVerificationMark? get verification; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt;
|
String get id; String get firstName; String get middleName; String get lastName; String get bio; String get gender; String get pronouns; String get location; String get timeZone; DateTime? get birthday;@ProfileLinkConverter() List<ProfileLink> get links; DateTime? get lastSeenAt; SnAccountBadge? get activeBadge; int get experience; int get level; double get socialCredits; int get socialCreditsLevel; double get levelingProgress; SnCloudFile? get picture; SnCloudFile? get background; SnVerificationMark? get verification; DateTime get createdAt; DateTime get updatedAt; DateTime? get deletedAt;
|
||||||
/// Create a copy of SnAccountProfile
|
/// Create a copy of SnAccountProfile
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@@ -626,16 +626,16 @@ $SnAccountProfileCopyWith<SnAccountProfile> get copyWith => _$SnAccountProfileCo
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnAccountProfile&&(identical(other.id, id) || other.id == id)&&(identical(other.firstName, firstName) || other.firstName == firstName)&&(identical(other.middleName, middleName) || other.middleName == middleName)&&(identical(other.lastName, lastName) || other.lastName == lastName)&&(identical(other.bio, bio) || other.bio == bio)&&(identical(other.gender, gender) || other.gender == gender)&&(identical(other.pronouns, pronouns) || other.pronouns == pronouns)&&(identical(other.location, location) || other.location == location)&&(identical(other.timeZone, timeZone) || other.timeZone == timeZone)&&(identical(other.birthday, birthday) || other.birthday == birthday)&&const DeepCollectionEquality().equals(other.links, links)&&(identical(other.lastSeenAt, lastSeenAt) || other.lastSeenAt == lastSeenAt)&&(identical(other.activeBadge, activeBadge) || other.activeBadge == activeBadge)&&(identical(other.experience, experience) || other.experience == experience)&&(identical(other.level, level) || other.level == level)&&(identical(other.levelingProgress, levelingProgress) || other.levelingProgress == levelingProgress)&&(identical(other.picture, picture) || other.picture == picture)&&(identical(other.background, background) || other.background == background)&&(identical(other.verification, verification) || other.verification == verification)&&(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 SnAccountProfile&&(identical(other.id, id) || other.id == id)&&(identical(other.firstName, firstName) || other.firstName == firstName)&&(identical(other.middleName, middleName) || other.middleName == middleName)&&(identical(other.lastName, lastName) || other.lastName == lastName)&&(identical(other.bio, bio) || other.bio == bio)&&(identical(other.gender, gender) || other.gender == gender)&&(identical(other.pronouns, pronouns) || other.pronouns == pronouns)&&(identical(other.location, location) || other.location == location)&&(identical(other.timeZone, timeZone) || other.timeZone == timeZone)&&(identical(other.birthday, birthday) || other.birthday == birthday)&&const DeepCollectionEquality().equals(other.links, links)&&(identical(other.lastSeenAt, lastSeenAt) || other.lastSeenAt == lastSeenAt)&&(identical(other.activeBadge, activeBadge) || other.activeBadge == activeBadge)&&(identical(other.experience, experience) || other.experience == experience)&&(identical(other.level, level) || other.level == level)&&(identical(other.socialCredits, socialCredits) || other.socialCredits == socialCredits)&&(identical(other.socialCreditsLevel, socialCreditsLevel) || other.socialCreditsLevel == socialCreditsLevel)&&(identical(other.levelingProgress, levelingProgress) || other.levelingProgress == levelingProgress)&&(identical(other.picture, picture) || other.picture == picture)&&(identical(other.background, background) || other.background == background)&&(identical(other.verification, verification) || other.verification == verification)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt));
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hashAll([runtimeType,id,firstName,middleName,lastName,bio,gender,pronouns,location,timeZone,birthday,const DeepCollectionEquality().hash(links),lastSeenAt,activeBadge,experience,level,levelingProgress,picture,background,verification,createdAt,updatedAt,deletedAt]);
|
int get hashCode => Object.hashAll([runtimeType,id,firstName,middleName,lastName,bio,gender,pronouns,location,timeZone,birthday,const DeepCollectionEquality().hash(links),lastSeenAt,activeBadge,experience,level,socialCredits,socialCreditsLevel,levelingProgress,picture,background,verification,createdAt,updatedAt,deletedAt]);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'SnAccountProfile(id: $id, firstName: $firstName, middleName: $middleName, lastName: $lastName, bio: $bio, gender: $gender, pronouns: $pronouns, location: $location, timeZone: $timeZone, birthday: $birthday, links: $links, lastSeenAt: $lastSeenAt, activeBadge: $activeBadge, experience: $experience, level: $level, levelingProgress: $levelingProgress, picture: $picture, background: $background, verification: $verification, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)';
|
return 'SnAccountProfile(id: $id, firstName: $firstName, middleName: $middleName, lastName: $lastName, bio: $bio, gender: $gender, pronouns: $pronouns, location: $location, timeZone: $timeZone, birthday: $birthday, links: $links, lastSeenAt: $lastSeenAt, activeBadge: $activeBadge, experience: $experience, level: $level, socialCredits: $socialCredits, socialCreditsLevel: $socialCreditsLevel, levelingProgress: $levelingProgress, picture: $picture, background: $background, verification: $verification, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -646,7 +646,7 @@ abstract mixin class $SnAccountProfileCopyWith<$Res> {
|
|||||||
factory $SnAccountProfileCopyWith(SnAccountProfile value, $Res Function(SnAccountProfile) _then) = _$SnAccountProfileCopyWithImpl;
|
factory $SnAccountProfileCopyWith(SnAccountProfile value, $Res Function(SnAccountProfile) _then) = _$SnAccountProfileCopyWithImpl;
|
||||||
@useResult
|
@useResult
|
||||||
$Res call({
|
$Res call({
|
||||||
String id, String firstName, String middleName, String lastName, String bio, String gender, String pronouns, String location, String timeZone, DateTime? birthday,@ProfileLinkConverter() List<ProfileLink> links, DateTime? lastSeenAt, SnAccountBadge? activeBadge, int experience, int level, double levelingProgress, SnCloudFile? picture, SnCloudFile? background, SnVerificationMark? verification, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt
|
String id, String firstName, String middleName, String lastName, String bio, String gender, String pronouns, String location, String timeZone, DateTime? birthday,@ProfileLinkConverter() List<ProfileLink> links, DateTime? lastSeenAt, SnAccountBadge? activeBadge, int experience, int level, double socialCredits, int socialCreditsLevel, double levelingProgress, SnCloudFile? picture, SnCloudFile? background, SnVerificationMark? verification, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -663,7 +663,7 @@ class _$SnAccountProfileCopyWithImpl<$Res>
|
|||||||
|
|
||||||
/// Create a copy of SnAccountProfile
|
/// Create a copy of SnAccountProfile
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? firstName = null,Object? middleName = null,Object? lastName = null,Object? bio = null,Object? gender = null,Object? pronouns = null,Object? location = null,Object? timeZone = null,Object? birthday = freezed,Object? links = null,Object? lastSeenAt = freezed,Object? activeBadge = freezed,Object? experience = null,Object? level = null,Object? levelingProgress = null,Object? picture = freezed,Object? background = freezed,Object? verification = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) {
|
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? firstName = null,Object? middleName = null,Object? lastName = null,Object? bio = null,Object? gender = null,Object? pronouns = null,Object? location = null,Object? timeZone = null,Object? birthday = freezed,Object? links = null,Object? lastSeenAt = freezed,Object? activeBadge = freezed,Object? experience = null,Object? level = null,Object? socialCredits = null,Object? socialCreditsLevel = null,Object? levelingProgress = null,Object? picture = freezed,Object? background = freezed,Object? verification = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) {
|
||||||
return _then(_self.copyWith(
|
return _then(_self.copyWith(
|
||||||
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
||||||
as String,firstName: null == firstName ? _self.firstName : firstName // ignore: cast_nullable_to_non_nullable
|
as String,firstName: null == firstName ? _self.firstName : firstName // ignore: cast_nullable_to_non_nullable
|
||||||
@@ -680,6 +680,8 @@ as List<ProfileLink>,lastSeenAt: freezed == lastSeenAt ? _self.lastSeenAt : last
|
|||||||
as DateTime?,activeBadge: freezed == activeBadge ? _self.activeBadge : activeBadge // ignore: cast_nullable_to_non_nullable
|
as DateTime?,activeBadge: freezed == activeBadge ? _self.activeBadge : activeBadge // ignore: cast_nullable_to_non_nullable
|
||||||
as SnAccountBadge?,experience: null == experience ? _self.experience : experience // ignore: cast_nullable_to_non_nullable
|
as SnAccountBadge?,experience: null == experience ? _self.experience : experience // ignore: cast_nullable_to_non_nullable
|
||||||
as int,level: null == level ? _self.level : level // ignore: cast_nullable_to_non_nullable
|
as int,level: null == level ? _self.level : level // ignore: cast_nullable_to_non_nullable
|
||||||
|
as int,socialCredits: null == socialCredits ? _self.socialCredits : socialCredits // ignore: cast_nullable_to_non_nullable
|
||||||
|
as double,socialCreditsLevel: null == socialCreditsLevel ? _self.socialCreditsLevel : socialCreditsLevel // ignore: cast_nullable_to_non_nullable
|
||||||
as int,levelingProgress: null == levelingProgress ? _self.levelingProgress : levelingProgress // ignore: cast_nullable_to_non_nullable
|
as int,levelingProgress: null == levelingProgress ? _self.levelingProgress : levelingProgress // ignore: cast_nullable_to_non_nullable
|
||||||
as double,picture: freezed == picture ? _self.picture : picture // ignore: cast_nullable_to_non_nullable
|
as double,picture: freezed == picture ? _self.picture : picture // ignore: cast_nullable_to_non_nullable
|
||||||
as SnCloudFile?,background: freezed == background ? _self.background : background // ignore: cast_nullable_to_non_nullable
|
as SnCloudFile?,background: freezed == background ? _self.background : background // ignore: cast_nullable_to_non_nullable
|
||||||
@@ -817,10 +819,10 @@ return $default(_that);case _:
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String firstName, String middleName, String lastName, String bio, String gender, String pronouns, String location, String timeZone, DateTime? birthday, @ProfileLinkConverter() List<ProfileLink> links, DateTime? lastSeenAt, SnAccountBadge? activeBadge, int experience, int level, double levelingProgress, SnCloudFile? picture, SnCloudFile? background, SnVerificationMark? verification, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,{required TResult orElse(),}) {final _that = this;
|
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String firstName, String middleName, String lastName, String bio, String gender, String pronouns, String location, String timeZone, DateTime? birthday, @ProfileLinkConverter() List<ProfileLink> links, DateTime? lastSeenAt, SnAccountBadge? activeBadge, int experience, int level, double socialCredits, int socialCreditsLevel, double levelingProgress, SnCloudFile? picture, SnCloudFile? background, SnVerificationMark? verification, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,{required TResult orElse(),}) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _SnAccountProfile() when $default != null:
|
case _SnAccountProfile() when $default != null:
|
||||||
return $default(_that.id,_that.firstName,_that.middleName,_that.lastName,_that.bio,_that.gender,_that.pronouns,_that.location,_that.timeZone,_that.birthday,_that.links,_that.lastSeenAt,_that.activeBadge,_that.experience,_that.level,_that.levelingProgress,_that.picture,_that.background,_that.verification,_that.createdAt,_that.updatedAt,_that.deletedAt);case _:
|
return $default(_that.id,_that.firstName,_that.middleName,_that.lastName,_that.bio,_that.gender,_that.pronouns,_that.location,_that.timeZone,_that.birthday,_that.links,_that.lastSeenAt,_that.activeBadge,_that.experience,_that.level,_that.socialCredits,_that.socialCreditsLevel,_that.levelingProgress,_that.picture,_that.background,_that.verification,_that.createdAt,_that.updatedAt,_that.deletedAt);case _:
|
||||||
return orElse();
|
return orElse();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -838,10 +840,10 @@ return $default(_that.id,_that.firstName,_that.middleName,_that.lastName,_that.b
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String firstName, String middleName, String lastName, String bio, String gender, String pronouns, String location, String timeZone, DateTime? birthday, @ProfileLinkConverter() List<ProfileLink> links, DateTime? lastSeenAt, SnAccountBadge? activeBadge, int experience, int level, double levelingProgress, SnCloudFile? picture, SnCloudFile? background, SnVerificationMark? verification, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt) $default,) {final _that = this;
|
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String firstName, String middleName, String lastName, String bio, String gender, String pronouns, String location, String timeZone, DateTime? birthday, @ProfileLinkConverter() List<ProfileLink> links, DateTime? lastSeenAt, SnAccountBadge? activeBadge, int experience, int level, double socialCredits, int socialCreditsLevel, double levelingProgress, SnCloudFile? picture, SnCloudFile? background, SnVerificationMark? verification, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt) $default,) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _SnAccountProfile():
|
case _SnAccountProfile():
|
||||||
return $default(_that.id,_that.firstName,_that.middleName,_that.lastName,_that.bio,_that.gender,_that.pronouns,_that.location,_that.timeZone,_that.birthday,_that.links,_that.lastSeenAt,_that.activeBadge,_that.experience,_that.level,_that.levelingProgress,_that.picture,_that.background,_that.verification,_that.createdAt,_that.updatedAt,_that.deletedAt);}
|
return $default(_that.id,_that.firstName,_that.middleName,_that.lastName,_that.bio,_that.gender,_that.pronouns,_that.location,_that.timeZone,_that.birthday,_that.links,_that.lastSeenAt,_that.activeBadge,_that.experience,_that.level,_that.socialCredits,_that.socialCreditsLevel,_that.levelingProgress,_that.picture,_that.background,_that.verification,_that.createdAt,_that.updatedAt,_that.deletedAt);}
|
||||||
}
|
}
|
||||||
/// A variant of `when` that fallback to returning `null`
|
/// A variant of `when` that fallback to returning `null`
|
||||||
///
|
///
|
||||||
@@ -855,10 +857,10 @@ return $default(_that.id,_that.firstName,_that.middleName,_that.lastName,_that.b
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String firstName, String middleName, String lastName, String bio, String gender, String pronouns, String location, String timeZone, DateTime? birthday, @ProfileLinkConverter() List<ProfileLink> links, DateTime? lastSeenAt, SnAccountBadge? activeBadge, int experience, int level, double levelingProgress, SnCloudFile? picture, SnCloudFile? background, SnVerificationMark? verification, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,) {final _that = this;
|
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String firstName, String middleName, String lastName, String bio, String gender, String pronouns, String location, String timeZone, DateTime? birthday, @ProfileLinkConverter() List<ProfileLink> links, DateTime? lastSeenAt, SnAccountBadge? activeBadge, int experience, int level, double socialCredits, int socialCreditsLevel, double levelingProgress, SnCloudFile? picture, SnCloudFile? background, SnVerificationMark? verification, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt)? $default,) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _SnAccountProfile() when $default != null:
|
case _SnAccountProfile() when $default != null:
|
||||||
return $default(_that.id,_that.firstName,_that.middleName,_that.lastName,_that.bio,_that.gender,_that.pronouns,_that.location,_that.timeZone,_that.birthday,_that.links,_that.lastSeenAt,_that.activeBadge,_that.experience,_that.level,_that.levelingProgress,_that.picture,_that.background,_that.verification,_that.createdAt,_that.updatedAt,_that.deletedAt);case _:
|
return $default(_that.id,_that.firstName,_that.middleName,_that.lastName,_that.bio,_that.gender,_that.pronouns,_that.location,_that.timeZone,_that.birthday,_that.links,_that.lastSeenAt,_that.activeBadge,_that.experience,_that.level,_that.socialCredits,_that.socialCreditsLevel,_that.levelingProgress,_that.picture,_that.background,_that.verification,_that.createdAt,_that.updatedAt,_that.deletedAt);case _:
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -870,7 +872,7 @@ return $default(_that.id,_that.firstName,_that.middleName,_that.lastName,_that.b
|
|||||||
@JsonSerializable()
|
@JsonSerializable()
|
||||||
|
|
||||||
class _SnAccountProfile implements SnAccountProfile {
|
class _SnAccountProfile implements SnAccountProfile {
|
||||||
const _SnAccountProfile({required this.id, this.firstName = '', this.middleName = '', this.lastName = '', this.bio = '', this.gender = '', this.pronouns = '', this.location = '', this.timeZone = '', this.birthday, @ProfileLinkConverter() final List<ProfileLink> links = const [], this.lastSeenAt, this.activeBadge, required this.experience, required this.level, required this.levelingProgress, required this.picture, required this.background, required this.verification, required this.createdAt, required this.updatedAt, required this.deletedAt}): _links = links;
|
const _SnAccountProfile({required this.id, this.firstName = '', this.middleName = '', this.lastName = '', this.bio = '', this.gender = '', this.pronouns = '', this.location = '', this.timeZone = '', this.birthday, @ProfileLinkConverter() final List<ProfileLink> links = const [], this.lastSeenAt, this.activeBadge, required this.experience, required this.level, this.socialCredits = 100, this.socialCreditsLevel = 0, required this.levelingProgress, required this.picture, required this.background, required this.verification, required this.createdAt, required this.updatedAt, required this.deletedAt}): _links = links;
|
||||||
factory _SnAccountProfile.fromJson(Map<String, dynamic> json) => _$SnAccountProfileFromJson(json);
|
factory _SnAccountProfile.fromJson(Map<String, dynamic> json) => _$SnAccountProfileFromJson(json);
|
||||||
|
|
||||||
@override final String id;
|
@override final String id;
|
||||||
@@ -894,6 +896,8 @@ class _SnAccountProfile implements SnAccountProfile {
|
|||||||
@override final SnAccountBadge? activeBadge;
|
@override final SnAccountBadge? activeBadge;
|
||||||
@override final int experience;
|
@override final int experience;
|
||||||
@override final int level;
|
@override final int level;
|
||||||
|
@override@JsonKey() final double socialCredits;
|
||||||
|
@override@JsonKey() final int socialCreditsLevel;
|
||||||
@override final double levelingProgress;
|
@override final double levelingProgress;
|
||||||
@override final SnCloudFile? picture;
|
@override final SnCloudFile? picture;
|
||||||
@override final SnCloudFile? background;
|
@override final SnCloudFile? background;
|
||||||
@@ -915,16 +919,16 @@ Map<String, dynamic> toJson() {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnAccountProfile&&(identical(other.id, id) || other.id == id)&&(identical(other.firstName, firstName) || other.firstName == firstName)&&(identical(other.middleName, middleName) || other.middleName == middleName)&&(identical(other.lastName, lastName) || other.lastName == lastName)&&(identical(other.bio, bio) || other.bio == bio)&&(identical(other.gender, gender) || other.gender == gender)&&(identical(other.pronouns, pronouns) || other.pronouns == pronouns)&&(identical(other.location, location) || other.location == location)&&(identical(other.timeZone, timeZone) || other.timeZone == timeZone)&&(identical(other.birthday, birthday) || other.birthday == birthday)&&const DeepCollectionEquality().equals(other._links, _links)&&(identical(other.lastSeenAt, lastSeenAt) || other.lastSeenAt == lastSeenAt)&&(identical(other.activeBadge, activeBadge) || other.activeBadge == activeBadge)&&(identical(other.experience, experience) || other.experience == experience)&&(identical(other.level, level) || other.level == level)&&(identical(other.levelingProgress, levelingProgress) || other.levelingProgress == levelingProgress)&&(identical(other.picture, picture) || other.picture == picture)&&(identical(other.background, background) || other.background == background)&&(identical(other.verification, verification) || other.verification == verification)&&(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 _SnAccountProfile&&(identical(other.id, id) || other.id == id)&&(identical(other.firstName, firstName) || other.firstName == firstName)&&(identical(other.middleName, middleName) || other.middleName == middleName)&&(identical(other.lastName, lastName) || other.lastName == lastName)&&(identical(other.bio, bio) || other.bio == bio)&&(identical(other.gender, gender) || other.gender == gender)&&(identical(other.pronouns, pronouns) || other.pronouns == pronouns)&&(identical(other.location, location) || other.location == location)&&(identical(other.timeZone, timeZone) || other.timeZone == timeZone)&&(identical(other.birthday, birthday) || other.birthday == birthday)&&const DeepCollectionEquality().equals(other._links, _links)&&(identical(other.lastSeenAt, lastSeenAt) || other.lastSeenAt == lastSeenAt)&&(identical(other.activeBadge, activeBadge) || other.activeBadge == activeBadge)&&(identical(other.experience, experience) || other.experience == experience)&&(identical(other.level, level) || other.level == level)&&(identical(other.socialCredits, socialCredits) || other.socialCredits == socialCredits)&&(identical(other.socialCreditsLevel, socialCreditsLevel) || other.socialCreditsLevel == socialCreditsLevel)&&(identical(other.levelingProgress, levelingProgress) || other.levelingProgress == levelingProgress)&&(identical(other.picture, picture) || other.picture == picture)&&(identical(other.background, background) || other.background == background)&&(identical(other.verification, verification) || other.verification == verification)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt));
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hashAll([runtimeType,id,firstName,middleName,lastName,bio,gender,pronouns,location,timeZone,birthday,const DeepCollectionEquality().hash(_links),lastSeenAt,activeBadge,experience,level,levelingProgress,picture,background,verification,createdAt,updatedAt,deletedAt]);
|
int get hashCode => Object.hashAll([runtimeType,id,firstName,middleName,lastName,bio,gender,pronouns,location,timeZone,birthday,const DeepCollectionEquality().hash(_links),lastSeenAt,activeBadge,experience,level,socialCredits,socialCreditsLevel,levelingProgress,picture,background,verification,createdAt,updatedAt,deletedAt]);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'SnAccountProfile(id: $id, firstName: $firstName, middleName: $middleName, lastName: $lastName, bio: $bio, gender: $gender, pronouns: $pronouns, location: $location, timeZone: $timeZone, birthday: $birthday, links: $links, lastSeenAt: $lastSeenAt, activeBadge: $activeBadge, experience: $experience, level: $level, levelingProgress: $levelingProgress, picture: $picture, background: $background, verification: $verification, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)';
|
return 'SnAccountProfile(id: $id, firstName: $firstName, middleName: $middleName, lastName: $lastName, bio: $bio, gender: $gender, pronouns: $pronouns, location: $location, timeZone: $timeZone, birthday: $birthday, links: $links, lastSeenAt: $lastSeenAt, activeBadge: $activeBadge, experience: $experience, level: $level, socialCredits: $socialCredits, socialCreditsLevel: $socialCreditsLevel, levelingProgress: $levelingProgress, picture: $picture, background: $background, verification: $verification, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -935,7 +939,7 @@ abstract mixin class _$SnAccountProfileCopyWith<$Res> implements $SnAccountProfi
|
|||||||
factory _$SnAccountProfileCopyWith(_SnAccountProfile value, $Res Function(_SnAccountProfile) _then) = __$SnAccountProfileCopyWithImpl;
|
factory _$SnAccountProfileCopyWith(_SnAccountProfile value, $Res Function(_SnAccountProfile) _then) = __$SnAccountProfileCopyWithImpl;
|
||||||
@override @useResult
|
@override @useResult
|
||||||
$Res call({
|
$Res call({
|
||||||
String id, String firstName, String middleName, String lastName, String bio, String gender, String pronouns, String location, String timeZone, DateTime? birthday,@ProfileLinkConverter() List<ProfileLink> links, DateTime? lastSeenAt, SnAccountBadge? activeBadge, int experience, int level, double levelingProgress, SnCloudFile? picture, SnCloudFile? background, SnVerificationMark? verification, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt
|
String id, String firstName, String middleName, String lastName, String bio, String gender, String pronouns, String location, String timeZone, DateTime? birthday,@ProfileLinkConverter() List<ProfileLink> links, DateTime? lastSeenAt, SnAccountBadge? activeBadge, int experience, int level, double socialCredits, int socialCreditsLevel, double levelingProgress, SnCloudFile? picture, SnCloudFile? background, SnVerificationMark? verification, DateTime createdAt, DateTime updatedAt, DateTime? deletedAt
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -952,7 +956,7 @@ class __$SnAccountProfileCopyWithImpl<$Res>
|
|||||||
|
|
||||||
/// Create a copy of SnAccountProfile
|
/// Create a copy of SnAccountProfile
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? firstName = null,Object? middleName = null,Object? lastName = null,Object? bio = null,Object? gender = null,Object? pronouns = null,Object? location = null,Object? timeZone = null,Object? birthday = freezed,Object? links = null,Object? lastSeenAt = freezed,Object? activeBadge = freezed,Object? experience = null,Object? level = null,Object? levelingProgress = null,Object? picture = freezed,Object? background = freezed,Object? verification = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) {
|
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? firstName = null,Object? middleName = null,Object? lastName = null,Object? bio = null,Object? gender = null,Object? pronouns = null,Object? location = null,Object? timeZone = null,Object? birthday = freezed,Object? links = null,Object? lastSeenAt = freezed,Object? activeBadge = freezed,Object? experience = null,Object? level = null,Object? socialCredits = null,Object? socialCreditsLevel = null,Object? levelingProgress = null,Object? picture = freezed,Object? background = freezed,Object? verification = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) {
|
||||||
return _then(_SnAccountProfile(
|
return _then(_SnAccountProfile(
|
||||||
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
||||||
as String,firstName: null == firstName ? _self.firstName : firstName // ignore: cast_nullable_to_non_nullable
|
as String,firstName: null == firstName ? _self.firstName : firstName // ignore: cast_nullable_to_non_nullable
|
||||||
@@ -969,6 +973,8 @@ as List<ProfileLink>,lastSeenAt: freezed == lastSeenAt ? _self.lastSeenAt : last
|
|||||||
as DateTime?,activeBadge: freezed == activeBadge ? _self.activeBadge : activeBadge // ignore: cast_nullable_to_non_nullable
|
as DateTime?,activeBadge: freezed == activeBadge ? _self.activeBadge : activeBadge // ignore: cast_nullable_to_non_nullable
|
||||||
as SnAccountBadge?,experience: null == experience ? _self.experience : experience // ignore: cast_nullable_to_non_nullable
|
as SnAccountBadge?,experience: null == experience ? _self.experience : experience // ignore: cast_nullable_to_non_nullable
|
||||||
as int,level: null == level ? _self.level : level // ignore: cast_nullable_to_non_nullable
|
as int,level: null == level ? _self.level : level // ignore: cast_nullable_to_non_nullable
|
||||||
|
as int,socialCredits: null == socialCredits ? _self.socialCredits : socialCredits // ignore: cast_nullable_to_non_nullable
|
||||||
|
as double,socialCreditsLevel: null == socialCreditsLevel ? _self.socialCreditsLevel : socialCreditsLevel // ignore: cast_nullable_to_non_nullable
|
||||||
as int,levelingProgress: null == levelingProgress ? _self.levelingProgress : levelingProgress // ignore: cast_nullable_to_non_nullable
|
as int,levelingProgress: null == levelingProgress ? _self.levelingProgress : levelingProgress // ignore: cast_nullable_to_non_nullable
|
||||||
as double,picture: freezed == picture ? _self.picture : picture // ignore: cast_nullable_to_non_nullable
|
as double,picture: freezed == picture ? _self.picture : picture // ignore: cast_nullable_to_non_nullable
|
||||||
as SnCloudFile?,background: freezed == background ? _self.background : background // ignore: cast_nullable_to_non_nullable
|
as SnCloudFile?,background: freezed == background ? _self.background : background // ignore: cast_nullable_to_non_nullable
|
||||||
|
@@ -86,6 +86,8 @@ _SnAccountProfile _$SnAccountProfileFromJson(Map<String, dynamic> json) =>
|
|||||||
),
|
),
|
||||||
experience: (json['experience'] as num).toInt(),
|
experience: (json['experience'] as num).toInt(),
|
||||||
level: (json['level'] as num).toInt(),
|
level: (json['level'] as num).toInt(),
|
||||||
|
socialCredits: (json['social_credits'] as num?)?.toDouble() ?? 100,
|
||||||
|
socialCreditsLevel: (json['social_credits_level'] as num?)?.toInt() ?? 0,
|
||||||
levelingProgress: (json['leveling_progress'] as num).toDouble(),
|
levelingProgress: (json['leveling_progress'] as num).toDouble(),
|
||||||
picture:
|
picture:
|
||||||
json['picture'] == null
|
json['picture'] == null
|
||||||
@@ -128,6 +130,8 @@ Map<String, dynamic> _$SnAccountProfileToJson(_SnAccountProfile instance) =>
|
|||||||
'active_badge': instance.activeBadge?.toJson(),
|
'active_badge': instance.activeBadge?.toJson(),
|
||||||
'experience': instance.experience,
|
'experience': instance.experience,
|
||||||
'level': instance.level,
|
'level': instance.level,
|
||||||
|
'social_credits': instance.socialCredits,
|
||||||
|
'social_credits_level': instance.socialCreditsLevel,
|
||||||
'leveling_progress': instance.levelingProgress,
|
'leveling_progress': instance.levelingProgress,
|
||||||
'picture': instance.picture?.toJson(),
|
'picture': instance.picture?.toJson(),
|
||||||
'background': instance.background?.toJson(),
|
'background': instance.background?.toJson(),
|
||||||
|
@@ -54,7 +54,7 @@ sealed class SnEventCalendarEntry with _$SnEventCalendarEntry {
|
|||||||
const factory SnEventCalendarEntry({
|
const factory SnEventCalendarEntry({
|
||||||
required DateTime date,
|
required DateTime date,
|
||||||
required SnCheckInResult? checkInResult,
|
required SnCheckInResult? checkInResult,
|
||||||
required List<dynamic> statuses,
|
required List<SnAccountStatus> statuses,
|
||||||
}) = _SnEventCalendarEntry;
|
}) = _SnEventCalendarEntry;
|
||||||
|
|
||||||
factory SnEventCalendarEntry.fromJson(Map<String, dynamic> json) =>
|
factory SnEventCalendarEntry.fromJson(Map<String, dynamic> json) =>
|
||||||
|
@@ -861,7 +861,7 @@ as String,
|
|||||||
/// @nodoc
|
/// @nodoc
|
||||||
mixin _$SnEventCalendarEntry {
|
mixin _$SnEventCalendarEntry {
|
||||||
|
|
||||||
DateTime get date; SnCheckInResult? get checkInResult; List<dynamic> get statuses;
|
DateTime get date; SnCheckInResult? get checkInResult; List<SnAccountStatus> get statuses;
|
||||||
/// Create a copy of SnEventCalendarEntry
|
/// Create a copy of SnEventCalendarEntry
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@@ -894,7 +894,7 @@ abstract mixin class $SnEventCalendarEntryCopyWith<$Res> {
|
|||||||
factory $SnEventCalendarEntryCopyWith(SnEventCalendarEntry value, $Res Function(SnEventCalendarEntry) _then) = _$SnEventCalendarEntryCopyWithImpl;
|
factory $SnEventCalendarEntryCopyWith(SnEventCalendarEntry value, $Res Function(SnEventCalendarEntry) _then) = _$SnEventCalendarEntryCopyWithImpl;
|
||||||
@useResult
|
@useResult
|
||||||
$Res call({
|
$Res call({
|
||||||
DateTime date, SnCheckInResult? checkInResult, List<dynamic> statuses
|
DateTime date, SnCheckInResult? checkInResult, List<SnAccountStatus> statuses
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -916,7 +916,7 @@ class _$SnEventCalendarEntryCopyWithImpl<$Res>
|
|||||||
date: null == date ? _self.date : date // ignore: cast_nullable_to_non_nullable
|
date: null == date ? _self.date : date // ignore: cast_nullable_to_non_nullable
|
||||||
as DateTime,checkInResult: freezed == checkInResult ? _self.checkInResult : checkInResult // ignore: cast_nullable_to_non_nullable
|
as DateTime,checkInResult: freezed == checkInResult ? _self.checkInResult : checkInResult // ignore: cast_nullable_to_non_nullable
|
||||||
as SnCheckInResult?,statuses: null == statuses ? _self.statuses : statuses // ignore: cast_nullable_to_non_nullable
|
as SnCheckInResult?,statuses: null == statuses ? _self.statuses : statuses // ignore: cast_nullable_to_non_nullable
|
||||||
as List<dynamic>,
|
as List<SnAccountStatus>,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
/// Create a copy of SnEventCalendarEntry
|
/// Create a copy of SnEventCalendarEntry
|
||||||
@@ -1010,7 +1010,7 @@ return $default(_that);case _:
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( DateTime date, SnCheckInResult? checkInResult, List<dynamic> statuses)? $default,{required TResult orElse(),}) {final _that = this;
|
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( DateTime date, SnCheckInResult? checkInResult, List<SnAccountStatus> statuses)? $default,{required TResult orElse(),}) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _SnEventCalendarEntry() when $default != null:
|
case _SnEventCalendarEntry() when $default != null:
|
||||||
return $default(_that.date,_that.checkInResult,_that.statuses);case _:
|
return $default(_that.date,_that.checkInResult,_that.statuses);case _:
|
||||||
@@ -1031,7 +1031,7 @@ return $default(_that.date,_that.checkInResult,_that.statuses);case _:
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( DateTime date, SnCheckInResult? checkInResult, List<dynamic> statuses) $default,) {final _that = this;
|
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( DateTime date, SnCheckInResult? checkInResult, List<SnAccountStatus> statuses) $default,) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _SnEventCalendarEntry():
|
case _SnEventCalendarEntry():
|
||||||
return $default(_that.date,_that.checkInResult,_that.statuses);}
|
return $default(_that.date,_that.checkInResult,_that.statuses);}
|
||||||
@@ -1048,7 +1048,7 @@ return $default(_that.date,_that.checkInResult,_that.statuses);}
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( DateTime date, SnCheckInResult? checkInResult, List<dynamic> statuses)? $default,) {final _that = this;
|
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( DateTime date, SnCheckInResult? checkInResult, List<SnAccountStatus> statuses)? $default,) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _SnEventCalendarEntry() when $default != null:
|
case _SnEventCalendarEntry() when $default != null:
|
||||||
return $default(_that.date,_that.checkInResult,_that.statuses);case _:
|
return $default(_that.date,_that.checkInResult,_that.statuses);case _:
|
||||||
@@ -1063,13 +1063,13 @@ return $default(_that.date,_that.checkInResult,_that.statuses);case _:
|
|||||||
@JsonSerializable()
|
@JsonSerializable()
|
||||||
|
|
||||||
class _SnEventCalendarEntry implements SnEventCalendarEntry {
|
class _SnEventCalendarEntry implements SnEventCalendarEntry {
|
||||||
const _SnEventCalendarEntry({required this.date, required this.checkInResult, required final List<dynamic> statuses}): _statuses = statuses;
|
const _SnEventCalendarEntry({required this.date, required this.checkInResult, required final List<SnAccountStatus> statuses}): _statuses = statuses;
|
||||||
factory _SnEventCalendarEntry.fromJson(Map<String, dynamic> json) => _$SnEventCalendarEntryFromJson(json);
|
factory _SnEventCalendarEntry.fromJson(Map<String, dynamic> json) => _$SnEventCalendarEntryFromJson(json);
|
||||||
|
|
||||||
@override final DateTime date;
|
@override final DateTime date;
|
||||||
@override final SnCheckInResult? checkInResult;
|
@override final SnCheckInResult? checkInResult;
|
||||||
final List<dynamic> _statuses;
|
final List<SnAccountStatus> _statuses;
|
||||||
@override List<dynamic> get statuses {
|
@override List<SnAccountStatus> get statuses {
|
||||||
if (_statuses is EqualUnmodifiableListView) return _statuses;
|
if (_statuses is EqualUnmodifiableListView) return _statuses;
|
||||||
// ignore: implicit_dynamic_type
|
// ignore: implicit_dynamic_type
|
||||||
return EqualUnmodifiableListView(_statuses);
|
return EqualUnmodifiableListView(_statuses);
|
||||||
@@ -1109,7 +1109,7 @@ abstract mixin class _$SnEventCalendarEntryCopyWith<$Res> implements $SnEventCal
|
|||||||
factory _$SnEventCalendarEntryCopyWith(_SnEventCalendarEntry value, $Res Function(_SnEventCalendarEntry) _then) = __$SnEventCalendarEntryCopyWithImpl;
|
factory _$SnEventCalendarEntryCopyWith(_SnEventCalendarEntry value, $Res Function(_SnEventCalendarEntry) _then) = __$SnEventCalendarEntryCopyWithImpl;
|
||||||
@override @useResult
|
@override @useResult
|
||||||
$Res call({
|
$Res call({
|
||||||
DateTime date, SnCheckInResult? checkInResult, List<dynamic> statuses
|
DateTime date, SnCheckInResult? checkInResult, List<SnAccountStatus> statuses
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -1131,7 +1131,7 @@ class __$SnEventCalendarEntryCopyWithImpl<$Res>
|
|||||||
date: null == date ? _self.date : date // ignore: cast_nullable_to_non_nullable
|
date: null == date ? _self.date : date // ignore: cast_nullable_to_non_nullable
|
||||||
as DateTime,checkInResult: freezed == checkInResult ? _self.checkInResult : checkInResult // ignore: cast_nullable_to_non_nullable
|
as DateTime,checkInResult: freezed == checkInResult ? _self.checkInResult : checkInResult // ignore: cast_nullable_to_non_nullable
|
||||||
as SnCheckInResult?,statuses: null == statuses ? _self._statuses : statuses // ignore: cast_nullable_to_non_nullable
|
as SnCheckInResult?,statuses: null == statuses ? _self._statuses : statuses // ignore: cast_nullable_to_non_nullable
|
||||||
as List<dynamic>,
|
as List<SnAccountStatus>,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -87,7 +87,10 @@ _SnEventCalendarEntry _$SnEventCalendarEntryFromJson(
|
|||||||
: SnCheckInResult.fromJson(
|
: SnCheckInResult.fromJson(
|
||||||
json['check_in_result'] as Map<String, dynamic>,
|
json['check_in_result'] as Map<String, dynamic>,
|
||||||
),
|
),
|
||||||
statuses: json['statuses'] as List<dynamic>,
|
statuses:
|
||||||
|
(json['statuses'] as List<dynamic>)
|
||||||
|
.map((e) => SnAccountStatus.fromJson(e as Map<String, dynamic>))
|
||||||
|
.toList(),
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> _$SnEventCalendarEntryToJson(
|
Map<String, dynamic> _$SnEventCalendarEntryToJson(
|
||||||
@@ -95,5 +98,5 @@ Map<String, dynamic> _$SnEventCalendarEntryToJson(
|
|||||||
) => <String, dynamic>{
|
) => <String, dynamic>{
|
||||||
'date': instance.date.toIso8601String(),
|
'date': instance.date.toIso8601String(),
|
||||||
'check_in_result': instance.checkInResult?.toJson(),
|
'check_in_result': instance.checkInResult?.toJson(),
|
||||||
'statuses': instance.statuses,
|
'statuses': instance.statuses.map((e) => e.toJson()).toList(),
|
||||||
};
|
};
|
||||||
|
19
lib/models/custom_app_secret.dart
Normal file
19
lib/models/custom_app_secret.dart
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
|
||||||
|
part 'custom_app_secret.freezed.dart';
|
||||||
|
part 'custom_app_secret.g.dart';
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
sealed class CustomAppSecret with _$CustomAppSecret {
|
||||||
|
const factory CustomAppSecret({
|
||||||
|
required String id,
|
||||||
|
required String? secret,
|
||||||
|
required DateTime createdAt,
|
||||||
|
String? description,
|
||||||
|
int? expiresIn,
|
||||||
|
bool? isOidc,
|
||||||
|
}) = _CustomAppSecret;
|
||||||
|
|
||||||
|
factory CustomAppSecret.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$CustomAppSecretFromJson(json);
|
||||||
|
}
|
286
lib/models/custom_app_secret.freezed.dart
Normal file
286
lib/models/custom_app_secret.freezed.dart
Normal file
@@ -0,0 +1,286 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
// coverage:ignore-file
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||||
|
|
||||||
|
part of 'custom_app_secret.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// FreezedGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
// dart format off
|
||||||
|
T _$identity<T>(T value) => value;
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
mixin _$CustomAppSecret {
|
||||||
|
|
||||||
|
String get id; String? get secret; DateTime get createdAt; String? get description; int? get expiresIn; bool? get isOidc;
|
||||||
|
/// Create a copy of CustomAppSecret
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$CustomAppSecretCopyWith<CustomAppSecret> get copyWith => _$CustomAppSecretCopyWithImpl<CustomAppSecret>(this as CustomAppSecret, _$identity);
|
||||||
|
|
||||||
|
/// Serializes this CustomAppSecret to a JSON map.
|
||||||
|
Map<String, dynamic> toJson();
|
||||||
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is CustomAppSecret&&(identical(other.id, id) || other.id == id)&&(identical(other.secret, secret) || other.secret == secret)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.description, description) || other.description == description)&&(identical(other.expiresIn, expiresIn) || other.expiresIn == expiresIn)&&(identical(other.isOidc, isOidc) || other.isOidc == isOidc));
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(runtimeType,id,secret,createdAt,description,expiresIn,isOidc);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'CustomAppSecret(id: $id, secret: $secret, createdAt: $createdAt, description: $description, expiresIn: $expiresIn, isOidc: $isOidc)';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract mixin class $CustomAppSecretCopyWith<$Res> {
|
||||||
|
factory $CustomAppSecretCopyWith(CustomAppSecret value, $Res Function(CustomAppSecret) _then) = _$CustomAppSecretCopyWithImpl;
|
||||||
|
@useResult
|
||||||
|
$Res call({
|
||||||
|
String id, String? secret, DateTime createdAt, String? description, int? expiresIn, bool? isOidc
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
/// @nodoc
|
||||||
|
class _$CustomAppSecretCopyWithImpl<$Res>
|
||||||
|
implements $CustomAppSecretCopyWith<$Res> {
|
||||||
|
_$CustomAppSecretCopyWithImpl(this._self, this._then);
|
||||||
|
|
||||||
|
final CustomAppSecret _self;
|
||||||
|
final $Res Function(CustomAppSecret) _then;
|
||||||
|
|
||||||
|
/// Create a copy of CustomAppSecret
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? secret = freezed,Object? createdAt = null,Object? description = freezed,Object? expiresIn = freezed,Object? isOidc = freezed,}) {
|
||||||
|
return _then(_self.copyWith(
|
||||||
|
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,secret: freezed == secret ? _self.secret : secret // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
|
||||||
|
as DateTime,description: freezed == description ? _self.description : description // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,expiresIn: freezed == expiresIn ? _self.expiresIn : expiresIn // ignore: cast_nullable_to_non_nullable
|
||||||
|
as int?,isOidc: freezed == isOidc ? _self.isOidc : isOidc // ignore: cast_nullable_to_non_nullable
|
||||||
|
as bool?,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Adds pattern-matching-related methods to [CustomAppSecret].
|
||||||
|
extension CustomAppSecretPatterns on CustomAppSecret {
|
||||||
|
/// A variant of `map` that fallback to returning `orElse`.
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case final Subclass value:
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return orElse();
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _CustomAppSecret value)? $default,{required TResult orElse(),}){
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _CustomAppSecret() when $default != null:
|
||||||
|
return $default(_that);case _:
|
||||||
|
return orElse();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// A `switch`-like method, using callbacks.
|
||||||
|
///
|
||||||
|
/// Callbacks receives the raw object, upcasted.
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case final Subclass value:
|
||||||
|
/// return ...;
|
||||||
|
/// case final Subclass2 value:
|
||||||
|
/// return ...;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _CustomAppSecret value) $default,){
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _CustomAppSecret():
|
||||||
|
return $default(_that);}
|
||||||
|
}
|
||||||
|
/// A variant of `map` that fallback to returning `null`.
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case final Subclass value:
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return null;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _CustomAppSecret value)? $default,){
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _CustomAppSecret() when $default != null:
|
||||||
|
return $default(_that);case _:
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// A variant of `when` that fallback to an `orElse` callback.
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case Subclass(:final field):
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return orElse();
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String? secret, DateTime createdAt, String? description, int? expiresIn, bool? isOidc)? $default,{required TResult orElse(),}) {final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _CustomAppSecret() when $default != null:
|
||||||
|
return $default(_that.id,_that.secret,_that.createdAt,_that.description,_that.expiresIn,_that.isOidc);case _:
|
||||||
|
return orElse();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// A `switch`-like method, using callbacks.
|
||||||
|
///
|
||||||
|
/// As opposed to `map`, this offers destructuring.
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case Subclass(:final field):
|
||||||
|
/// return ...;
|
||||||
|
/// case Subclass2(:final field2):
|
||||||
|
/// return ...;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String? secret, DateTime createdAt, String? description, int? expiresIn, bool? isOidc) $default,) {final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _CustomAppSecret():
|
||||||
|
return $default(_that.id,_that.secret,_that.createdAt,_that.description,_that.expiresIn,_that.isOidc);}
|
||||||
|
}
|
||||||
|
/// A variant of `when` that fallback to returning `null`
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case Subclass(:final field):
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return null;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String? secret, DateTime createdAt, String? description, int? expiresIn, bool? isOidc)? $default,) {final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _CustomAppSecret() when $default != null:
|
||||||
|
return $default(_that.id,_that.secret,_that.createdAt,_that.description,_that.expiresIn,_that.isOidc);case _:
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
@JsonSerializable()
|
||||||
|
|
||||||
|
class _CustomAppSecret implements CustomAppSecret {
|
||||||
|
const _CustomAppSecret({required this.id, required this.secret, required this.createdAt, this.description, this.expiresIn, this.isOidc});
|
||||||
|
factory _CustomAppSecret.fromJson(Map<String, dynamic> json) => _$CustomAppSecretFromJson(json);
|
||||||
|
|
||||||
|
@override final String id;
|
||||||
|
@override final String? secret;
|
||||||
|
@override final DateTime createdAt;
|
||||||
|
@override final String? description;
|
||||||
|
@override final int? expiresIn;
|
||||||
|
@override final bool? isOidc;
|
||||||
|
|
||||||
|
/// Create a copy of CustomAppSecret
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
_$CustomAppSecretCopyWith<_CustomAppSecret> get copyWith => __$CustomAppSecretCopyWithImpl<_CustomAppSecret>(this, _$identity);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return _$CustomAppSecretToJson(this, );
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is _CustomAppSecret&&(identical(other.id, id) || other.id == id)&&(identical(other.secret, secret) || other.secret == secret)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.description, description) || other.description == description)&&(identical(other.expiresIn, expiresIn) || other.expiresIn == expiresIn)&&(identical(other.isOidc, isOidc) || other.isOidc == isOidc));
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(runtimeType,id,secret,createdAt,description,expiresIn,isOidc);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'CustomAppSecret(id: $id, secret: $secret, createdAt: $createdAt, description: $description, expiresIn: $expiresIn, isOidc: $isOidc)';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract mixin class _$CustomAppSecretCopyWith<$Res> implements $CustomAppSecretCopyWith<$Res> {
|
||||||
|
factory _$CustomAppSecretCopyWith(_CustomAppSecret value, $Res Function(_CustomAppSecret) _then) = __$CustomAppSecretCopyWithImpl;
|
||||||
|
@override @useResult
|
||||||
|
$Res call({
|
||||||
|
String id, String? secret, DateTime createdAt, String? description, int? expiresIn, bool? isOidc
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
/// @nodoc
|
||||||
|
class __$CustomAppSecretCopyWithImpl<$Res>
|
||||||
|
implements _$CustomAppSecretCopyWith<$Res> {
|
||||||
|
__$CustomAppSecretCopyWithImpl(this._self, this._then);
|
||||||
|
|
||||||
|
final _CustomAppSecret _self;
|
||||||
|
final $Res Function(_CustomAppSecret) _then;
|
||||||
|
|
||||||
|
/// Create a copy of CustomAppSecret
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? secret = freezed,Object? createdAt = null,Object? description = freezed,Object? expiresIn = freezed,Object? isOidc = freezed,}) {
|
||||||
|
return _then(_CustomAppSecret(
|
||||||
|
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,secret: freezed == secret ? _self.secret : secret // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
|
||||||
|
as DateTime,description: freezed == description ? _self.description : description // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,expiresIn: freezed == expiresIn ? _self.expiresIn : expiresIn // ignore: cast_nullable_to_non_nullable
|
||||||
|
as int?,isOidc: freezed == isOidc ? _self.isOidc : isOidc // ignore: cast_nullable_to_non_nullable
|
||||||
|
as bool?,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// dart format on
|
27
lib/models/custom_app_secret.g.dart
Normal file
27
lib/models/custom_app_secret.g.dart
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'custom_app_secret.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// JsonSerializableGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
_CustomAppSecret _$CustomAppSecretFromJson(Map<String, dynamic> json) =>
|
||||||
|
_CustomAppSecret(
|
||||||
|
id: json['id'] as String,
|
||||||
|
secret: json['secret'] as String?,
|
||||||
|
createdAt: DateTime.parse(json['created_at'] as String),
|
||||||
|
description: json['description'] as String?,
|
||||||
|
expiresIn: (json['expires_in'] as num?)?.toInt(),
|
||||||
|
isOidc: json['is_oidc'] as bool?,
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$CustomAppSecretToJson(_CustomAppSecret instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'id': instance.id,
|
||||||
|
'secret': instance.secret,
|
||||||
|
'created_at': instance.createdAt.toIso8601String(),
|
||||||
|
'description': instance.description,
|
||||||
|
'expires_in': instance.expiresIn,
|
||||||
|
'is_oidc': instance.isOidc,
|
||||||
|
};
|
@@ -27,6 +27,7 @@ sealed class SnPost with _$SnPost {
|
|||||||
@Default(0) int upvotes,
|
@Default(0) int upvotes,
|
||||||
@Default(0) int downvotes,
|
@Default(0) int downvotes,
|
||||||
@Default(0) int repliesCount,
|
@Default(0) int repliesCount,
|
||||||
|
int? pinMode,
|
||||||
String? threadedPostId,
|
String? threadedPostId,
|
||||||
SnPost? threadedPost,
|
SnPost? threadedPost,
|
||||||
String? repliedPostId,
|
String? repliedPostId,
|
||||||
|
@@ -15,7 +15,7 @@ T _$identity<T>(T value) => value;
|
|||||||
/// @nodoc
|
/// @nodoc
|
||||||
mixin _$SnPost {
|
mixin _$SnPost {
|
||||||
|
|
||||||
String get id; String? get title; String? get description; String? get language; DateTime? get editedAt; DateTime? get publishedAt; int get visibility; String? get content; String? get slug; int get type; Map<String, dynamic>? get meta; int get viewsUnique; int get viewsTotal; int get upvotes; int get downvotes; int get repliesCount; String? get threadedPostId; SnPost? get threadedPost; String? get repliedPostId; SnPost? get repliedPost; String? get forwardedPostId; SnPost? get forwardedPost; String? get realmId; SnRealm? get realm; List<SnCloudFile> get attachments; SnPublisher get publisher; Map<String, int> get reactionsCount; Map<String, bool> get reactionsMade; List<dynamic> get reactions; List<SnPostTag> get tags; List<SnPostCategory> get categories; List<dynamic> get collections; DateTime? get createdAt; DateTime? get updatedAt; DateTime? get deletedAt; bool get isTruncated;
|
String get id; String? get title; String? get description; String? get language; DateTime? get editedAt; DateTime? get publishedAt; int get visibility; String? get content; String? get slug; int get type; Map<String, dynamic>? get meta; int get viewsUnique; int get viewsTotal; int get upvotes; int get downvotes; int get repliesCount; 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; DateTime? get createdAt; DateTime? get updatedAt; DateTime? get deletedAt; bool get isTruncated;
|
||||||
/// Create a copy of SnPost
|
/// Create a copy of SnPost
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@@ -28,16 +28,16 @@ $SnPostCopyWith<SnPost> get copyWith => _$SnPostCopyWithImpl<SnPost>(this as SnP
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnPost&&(identical(other.id, id) || other.id == id)&&(identical(other.title, title) || other.title == title)&&(identical(other.description, description) || other.description == description)&&(identical(other.language, language) || other.language == language)&&(identical(other.editedAt, editedAt) || other.editedAt == editedAt)&&(identical(other.publishedAt, publishedAt) || other.publishedAt == publishedAt)&&(identical(other.visibility, visibility) || other.visibility == visibility)&&(identical(other.content, content) || other.content == content)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.type, type) || other.type == type)&&const DeepCollectionEquality().equals(other.meta, meta)&&(identical(other.viewsUnique, viewsUnique) || other.viewsUnique == viewsUnique)&&(identical(other.viewsTotal, viewsTotal) || other.viewsTotal == viewsTotal)&&(identical(other.upvotes, upvotes) || other.upvotes == upvotes)&&(identical(other.downvotes, downvotes) || other.downvotes == downvotes)&&(identical(other.repliesCount, repliesCount) || other.repliesCount == repliesCount)&&(identical(other.threadedPostId, threadedPostId) || other.threadedPostId == threadedPostId)&&(identical(other.threadedPost, threadedPost) || other.threadedPost == threadedPost)&&(identical(other.repliedPostId, repliedPostId) || other.repliedPostId == repliedPostId)&&(identical(other.repliedPost, repliedPost) || other.repliedPost == repliedPost)&&(identical(other.forwardedPostId, forwardedPostId) || other.forwardedPostId == forwardedPostId)&&(identical(other.forwardedPost, forwardedPost) || other.forwardedPost == forwardedPost)&&(identical(other.realmId, realmId) || other.realmId == realmId)&&(identical(other.realm, realm) || other.realm == realm)&&const DeepCollectionEquality().equals(other.attachments, attachments)&&(identical(other.publisher, publisher) || other.publisher == publisher)&&const DeepCollectionEquality().equals(other.reactionsCount, reactionsCount)&&const DeepCollectionEquality().equals(other.reactionsMade, reactionsMade)&&const DeepCollectionEquality().equals(other.reactions, reactions)&&const DeepCollectionEquality().equals(other.tags, tags)&&const DeepCollectionEquality().equals(other.categories, categories)&&const DeepCollectionEquality().equals(other.collections, collections)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.isTruncated, isTruncated) || other.isTruncated == isTruncated));
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnPost&&(identical(other.id, id) || other.id == id)&&(identical(other.title, title) || other.title == title)&&(identical(other.description, description) || other.description == description)&&(identical(other.language, language) || other.language == language)&&(identical(other.editedAt, editedAt) || other.editedAt == editedAt)&&(identical(other.publishedAt, publishedAt) || other.publishedAt == publishedAt)&&(identical(other.visibility, visibility) || other.visibility == visibility)&&(identical(other.content, content) || other.content == content)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.type, type) || other.type == type)&&const DeepCollectionEquality().equals(other.meta, meta)&&(identical(other.viewsUnique, viewsUnique) || other.viewsUnique == viewsUnique)&&(identical(other.viewsTotal, viewsTotal) || other.viewsTotal == viewsTotal)&&(identical(other.upvotes, upvotes) || other.upvotes == upvotes)&&(identical(other.downvotes, downvotes) || other.downvotes == downvotes)&&(identical(other.repliesCount, repliesCount) || other.repliesCount == repliesCount)&&(identical(other.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)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.isTruncated, isTruncated) || other.isTruncated == isTruncated));
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hashAll([runtimeType,id,title,description,language,editedAt,publishedAt,visibility,content,slug,type,const DeepCollectionEquality().hash(meta),viewsUnique,viewsTotal,upvotes,downvotes,repliesCount,threadedPostId,threadedPost,repliedPostId,repliedPost,forwardedPostId,forwardedPost,realmId,realm,const DeepCollectionEquality().hash(attachments),publisher,const DeepCollectionEquality().hash(reactionsCount),const DeepCollectionEquality().hash(reactionsMade),const DeepCollectionEquality().hash(reactions),const DeepCollectionEquality().hash(tags),const DeepCollectionEquality().hash(categories),const DeepCollectionEquality().hash(collections),createdAt,updatedAt,deletedAt,isTruncated]);
|
int get hashCode => Object.hashAll([runtimeType,id,title,description,language,editedAt,publishedAt,visibility,content,slug,type,const DeepCollectionEquality().hash(meta),viewsUnique,viewsTotal,upvotes,downvotes,repliesCount,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),createdAt,updatedAt,deletedAt,isTruncated]);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'SnPost(id: $id, title: $title, description: $description, language: $language, editedAt: $editedAt, publishedAt: $publishedAt, visibility: $visibility, content: $content, slug: $slug, type: $type, meta: $meta, viewsUnique: $viewsUnique, viewsTotal: $viewsTotal, upvotes: $upvotes, downvotes: $downvotes, repliesCount: $repliesCount, threadedPostId: $threadedPostId, threadedPost: $threadedPost, repliedPostId: $repliedPostId, repliedPost: $repliedPost, forwardedPostId: $forwardedPostId, forwardedPost: $forwardedPost, realmId: $realmId, realm: $realm, attachments: $attachments, publisher: $publisher, reactionsCount: $reactionsCount, reactionsMade: $reactionsMade, reactions: $reactions, tags: $tags, categories: $categories, collections: $collections, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, isTruncated: $isTruncated)';
|
return 'SnPost(id: $id, title: $title, description: $description, language: $language, editedAt: $editedAt, publishedAt: $publishedAt, visibility: $visibility, content: $content, slug: $slug, type: $type, meta: $meta, viewsUnique: $viewsUnique, viewsTotal: $viewsTotal, upvotes: $upvotes, downvotes: $downvotes, repliesCount: $repliesCount, 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, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, isTruncated: $isTruncated)';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -48,7 +48,7 @@ abstract mixin class $SnPostCopyWith<$Res> {
|
|||||||
factory $SnPostCopyWith(SnPost value, $Res Function(SnPost) _then) = _$SnPostCopyWithImpl;
|
factory $SnPostCopyWith(SnPost value, $Res Function(SnPost) _then) = _$SnPostCopyWithImpl;
|
||||||
@useResult
|
@useResult
|
||||||
$Res call({
|
$Res call({
|
||||||
String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map<String, dynamic>? meta, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, String? realmId, SnRealm? realm, List<SnCloudFile> attachments, SnPublisher publisher, Map<String, int> reactionsCount, Map<String, bool> reactionsMade, List<dynamic> reactions, List<SnPostTag> tags, List<SnPostCategory> categories, List<dynamic> collections, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool isTruncated
|
String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map<String, dynamic>? meta, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, 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, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool isTruncated
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -65,7 +65,7 @@ class _$SnPostCopyWithImpl<$Res>
|
|||||||
|
|
||||||
/// Create a copy of SnPost
|
/// Create a copy of SnPost
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? title = freezed,Object? description = freezed,Object? language = freezed,Object? editedAt = freezed,Object? publishedAt = freezed,Object? visibility = null,Object? content = freezed,Object? slug = freezed,Object? type = null,Object? meta = freezed,Object? viewsUnique = null,Object? viewsTotal = null,Object? upvotes = null,Object? downvotes = null,Object? repliesCount = null,Object? threadedPostId = freezed,Object? threadedPost = freezed,Object? repliedPostId = freezed,Object? repliedPost = freezed,Object? forwardedPostId = freezed,Object? forwardedPost = freezed,Object? realmId = freezed,Object? realm = freezed,Object? attachments = null,Object? publisher = null,Object? reactionsCount = null,Object? reactionsMade = null,Object? reactions = null,Object? tags = null,Object? categories = null,Object? collections = null,Object? createdAt = freezed,Object? updatedAt = freezed,Object? deletedAt = freezed,Object? isTruncated = null,}) {
|
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? title = freezed,Object? description = freezed,Object? language = freezed,Object? editedAt = freezed,Object? publishedAt = freezed,Object? visibility = null,Object? content = freezed,Object? slug = freezed,Object? type = null,Object? meta = freezed,Object? viewsUnique = null,Object? viewsTotal = null,Object? upvotes = null,Object? downvotes = null,Object? repliesCount = null,Object? 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? createdAt = freezed,Object? updatedAt = freezed,Object? deletedAt = freezed,Object? isTruncated = null,}) {
|
||||||
return _then(_self.copyWith(
|
return _then(_self.copyWith(
|
||||||
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
||||||
as String,title: freezed == title ? _self.title : title // ignore: cast_nullable_to_non_nullable
|
as String,title: freezed == title ? _self.title : title // ignore: cast_nullable_to_non_nullable
|
||||||
@@ -83,7 +83,8 @@ as int,viewsTotal: null == viewsTotal ? _self.viewsTotal : viewsTotal // ignore:
|
|||||||
as int,upvotes: null == upvotes ? _self.upvotes : upvotes // ignore: cast_nullable_to_non_nullable
|
as int,upvotes: null == upvotes ? _self.upvotes : upvotes // ignore: cast_nullable_to_non_nullable
|
||||||
as int,downvotes: null == downvotes ? _self.downvotes : downvotes // ignore: cast_nullable_to_non_nullable
|
as int,downvotes: null == downvotes ? _self.downvotes : downvotes // ignore: cast_nullable_to_non_nullable
|
||||||
as int,repliesCount: null == repliesCount ? _self.repliesCount : repliesCount // ignore: cast_nullable_to_non_nullable
|
as int,repliesCount: null == repliesCount ? _self.repliesCount : repliesCount // ignore: cast_nullable_to_non_nullable
|
||||||
as int,threadedPostId: freezed == threadedPostId ? _self.threadedPostId : threadedPostId // ignore: cast_nullable_to_non_nullable
|
as int,pinMode: freezed == pinMode ? _self.pinMode : pinMode // ignore: cast_nullable_to_non_nullable
|
||||||
|
as int?,threadedPostId: freezed == threadedPostId ? _self.threadedPostId : threadedPostId // ignore: cast_nullable_to_non_nullable
|
||||||
as String?,threadedPost: freezed == threadedPost ? _self.threadedPost : threadedPost // ignore: cast_nullable_to_non_nullable
|
as String?,threadedPost: freezed == threadedPost ? _self.threadedPost : threadedPost // ignore: cast_nullable_to_non_nullable
|
||||||
as SnPost?,repliedPostId: freezed == repliedPostId ? _self.repliedPostId : repliedPostId // ignore: cast_nullable_to_non_nullable
|
as SnPost?,repliedPostId: freezed == repliedPostId ? _self.repliedPostId : repliedPostId // ignore: cast_nullable_to_non_nullable
|
||||||
as String?,repliedPost: freezed == repliedPost ? _self.repliedPost : repliedPost // ignore: cast_nullable_to_non_nullable
|
as String?,repliedPost: freezed == repliedPost ? _self.repliedPost : repliedPost // ignore: cast_nullable_to_non_nullable
|
||||||
@@ -242,10 +243,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, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, String? realmId, SnRealm? realm, List<SnCloudFile> attachments, SnPublisher publisher, Map<String, int> reactionsCount, Map<String, bool> reactionsMade, List<dynamic> reactions, List<SnPostTag> tags, List<SnPostCategory> categories, List<dynamic> collections, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool isTruncated)? $default,{required TResult orElse(),}) {final _that = this;
|
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map<String, dynamic>? meta, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, 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, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool isTruncated)? $default,{required TResult orElse(),}) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _SnPost() when $default != null:
|
case _SnPost() when $default != null:
|
||||||
return $default(_that.id,_that.title,_that.description,_that.language,_that.editedAt,_that.publishedAt,_that.visibility,_that.content,_that.slug,_that.type,_that.meta,_that.viewsUnique,_that.viewsTotal,_that.upvotes,_that.downvotes,_that.repliesCount,_that.threadedPostId,_that.threadedPost,_that.repliedPostId,_that.repliedPost,_that.forwardedPostId,_that.forwardedPost,_that.realmId,_that.realm,_that.attachments,_that.publisher,_that.reactionsCount,_that.reactionsMade,_that.reactions,_that.tags,_that.categories,_that.collections,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.isTruncated);case _:
|
return $default(_that.id,_that.title,_that.description,_that.language,_that.editedAt,_that.publishedAt,_that.visibility,_that.content,_that.slug,_that.type,_that.meta,_that.viewsUnique,_that.viewsTotal,_that.upvotes,_that.downvotes,_that.repliesCount,_that.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.createdAt,_that.updatedAt,_that.deletedAt,_that.isTruncated);case _:
|
||||||
return orElse();
|
return orElse();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -263,10 +264,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, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, String? realmId, SnRealm? realm, List<SnCloudFile> attachments, SnPublisher publisher, Map<String, int> reactionsCount, Map<String, bool> reactionsMade, List<dynamic> reactions, List<SnPostTag> tags, List<SnPostCategory> categories, List<dynamic> collections, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool isTruncated) $default,) {final _that = this;
|
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map<String, dynamic>? meta, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, 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, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool isTruncated) $default,) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _SnPost():
|
case _SnPost():
|
||||||
return $default(_that.id,_that.title,_that.description,_that.language,_that.editedAt,_that.publishedAt,_that.visibility,_that.content,_that.slug,_that.type,_that.meta,_that.viewsUnique,_that.viewsTotal,_that.upvotes,_that.downvotes,_that.repliesCount,_that.threadedPostId,_that.threadedPost,_that.repliedPostId,_that.repliedPost,_that.forwardedPostId,_that.forwardedPost,_that.realmId,_that.realm,_that.attachments,_that.publisher,_that.reactionsCount,_that.reactionsMade,_that.reactions,_that.tags,_that.categories,_that.collections,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.isTruncated);}
|
return $default(_that.id,_that.title,_that.description,_that.language,_that.editedAt,_that.publishedAt,_that.visibility,_that.content,_that.slug,_that.type,_that.meta,_that.viewsUnique,_that.viewsTotal,_that.upvotes,_that.downvotes,_that.repliesCount,_that.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.createdAt,_that.updatedAt,_that.deletedAt,_that.isTruncated);}
|
||||||
}
|
}
|
||||||
/// A variant of `when` that fallback to returning `null`
|
/// A variant of `when` that fallback to returning `null`
|
||||||
///
|
///
|
||||||
@@ -280,10 +281,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, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, String? realmId, SnRealm? realm, List<SnCloudFile> attachments, SnPublisher publisher, Map<String, int> reactionsCount, Map<String, bool> reactionsMade, List<dynamic> reactions, List<SnPostTag> tags, List<SnPostCategory> categories, List<dynamic> collections, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool isTruncated)? $default,) {final _that = this;
|
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map<String, dynamic>? meta, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, 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, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool isTruncated)? $default,) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _SnPost() when $default != null:
|
case _SnPost() when $default != null:
|
||||||
return $default(_that.id,_that.title,_that.description,_that.language,_that.editedAt,_that.publishedAt,_that.visibility,_that.content,_that.slug,_that.type,_that.meta,_that.viewsUnique,_that.viewsTotal,_that.upvotes,_that.downvotes,_that.repliesCount,_that.threadedPostId,_that.threadedPost,_that.repliedPostId,_that.repliedPost,_that.forwardedPostId,_that.forwardedPost,_that.realmId,_that.realm,_that.attachments,_that.publisher,_that.reactionsCount,_that.reactionsMade,_that.reactions,_that.tags,_that.categories,_that.collections,_that.createdAt,_that.updatedAt,_that.deletedAt,_that.isTruncated);case _:
|
return $default(_that.id,_that.title,_that.description,_that.language,_that.editedAt,_that.publishedAt,_that.visibility,_that.content,_that.slug,_that.type,_that.meta,_that.viewsUnique,_that.viewsTotal,_that.upvotes,_that.downvotes,_that.repliesCount,_that.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.createdAt,_that.updatedAt,_that.deletedAt,_that.isTruncated);case _:
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -295,7 +296,7 @@ return $default(_that.id,_that.title,_that.description,_that.language,_that.edit
|
|||||||
@JsonSerializable()
|
@JsonSerializable()
|
||||||
|
|
||||||
class _SnPost implements SnPost {
|
class _SnPost implements SnPost {
|
||||||
const _SnPost({required this.id, this.title, this.description, this.language, this.editedAt, this.publishedAt = null, this.visibility = 0, this.content, this.slug, this.type = 0, final Map<String, dynamic>? meta, this.viewsUnique = 0, this.viewsTotal = 0, this.upvotes = 0, this.downvotes = 0, this.repliesCount = 0, this.threadedPostId, this.threadedPost, this.repliedPostId, this.repliedPost, this.forwardedPostId, this.forwardedPost, this.realmId, this.realm, final List<SnCloudFile> attachments = const [], required this.publisher, final Map<String, int> reactionsCount = const {}, final Map<String, bool> reactionsMade = const {}, final List<dynamic> reactions = const [], final List<SnPostTag> tags = const [], final List<SnPostCategory> categories = const [], final List<dynamic> collections = const [], this.createdAt = null, this.updatedAt = null, this.deletedAt, this.isTruncated = false}): _meta = meta,_attachments = attachments,_reactionsCount = reactionsCount,_reactionsMade = reactionsMade,_reactions = reactions,_tags = tags,_categories = categories,_collections = collections;
|
const _SnPost({required this.id, this.title, this.description, this.language, this.editedAt, this.publishedAt = null, this.visibility = 0, this.content, this.slug, this.type = 0, final Map<String, dynamic>? meta, this.viewsUnique = 0, this.viewsTotal = 0, this.upvotes = 0, this.downvotes = 0, this.repliesCount = 0, this.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 [], this.createdAt = null, this.updatedAt = null, this.deletedAt, this.isTruncated = false}): _meta = meta,_attachments = attachments,_reactionsCount = reactionsCount,_reactionsMade = reactionsMade,_reactions = reactions,_tags = tags,_categories = categories,_collections = collections;
|
||||||
factory _SnPost.fromJson(Map<String, dynamic> json) => _$SnPostFromJson(json);
|
factory _SnPost.fromJson(Map<String, dynamic> json) => _$SnPostFromJson(json);
|
||||||
|
|
||||||
@override final String id;
|
@override final String id;
|
||||||
@@ -322,6 +323,7 @@ class _SnPost implements SnPost {
|
|||||||
@override@JsonKey() final int upvotes;
|
@override@JsonKey() final int upvotes;
|
||||||
@override@JsonKey() final int downvotes;
|
@override@JsonKey() final int downvotes;
|
||||||
@override@JsonKey() final int repliesCount;
|
@override@JsonKey() final int repliesCount;
|
||||||
|
@override final int? pinMode;
|
||||||
@override final String? threadedPostId;
|
@override final String? threadedPostId;
|
||||||
@override final SnPost? threadedPost;
|
@override final SnPost? threadedPost;
|
||||||
@override final String? repliedPostId;
|
@override final String? repliedPostId;
|
||||||
@@ -398,16 +400,16 @@ Map<String, dynamic> toJson() {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnPost&&(identical(other.id, id) || other.id == id)&&(identical(other.title, title) || other.title == title)&&(identical(other.description, description) || other.description == description)&&(identical(other.language, language) || other.language == language)&&(identical(other.editedAt, editedAt) || other.editedAt == editedAt)&&(identical(other.publishedAt, publishedAt) || other.publishedAt == publishedAt)&&(identical(other.visibility, visibility) || other.visibility == visibility)&&(identical(other.content, content) || other.content == content)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.type, type) || other.type == type)&&const DeepCollectionEquality().equals(other._meta, _meta)&&(identical(other.viewsUnique, viewsUnique) || other.viewsUnique == viewsUnique)&&(identical(other.viewsTotal, viewsTotal) || other.viewsTotal == viewsTotal)&&(identical(other.upvotes, upvotes) || other.upvotes == upvotes)&&(identical(other.downvotes, downvotes) || other.downvotes == downvotes)&&(identical(other.repliesCount, repliesCount) || other.repliesCount == repliesCount)&&(identical(other.threadedPostId, threadedPostId) || other.threadedPostId == threadedPostId)&&(identical(other.threadedPost, threadedPost) || other.threadedPost == threadedPost)&&(identical(other.repliedPostId, repliedPostId) || other.repliedPostId == repliedPostId)&&(identical(other.repliedPost, repliedPost) || other.repliedPost == repliedPost)&&(identical(other.forwardedPostId, forwardedPostId) || other.forwardedPostId == forwardedPostId)&&(identical(other.forwardedPost, forwardedPost) || other.forwardedPost == forwardedPost)&&(identical(other.realmId, realmId) || other.realmId == realmId)&&(identical(other.realm, realm) || other.realm == realm)&&const DeepCollectionEquality().equals(other._attachments, _attachments)&&(identical(other.publisher, publisher) || other.publisher == publisher)&&const DeepCollectionEquality().equals(other._reactionsCount, _reactionsCount)&&const DeepCollectionEquality().equals(other._reactionsMade, _reactionsMade)&&const DeepCollectionEquality().equals(other._reactions, _reactions)&&const DeepCollectionEquality().equals(other._tags, _tags)&&const DeepCollectionEquality().equals(other._categories, _categories)&&const DeepCollectionEquality().equals(other._collections, _collections)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.isTruncated, isTruncated) || other.isTruncated == isTruncated));
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnPost&&(identical(other.id, id) || other.id == id)&&(identical(other.title, title) || other.title == title)&&(identical(other.description, description) || other.description == description)&&(identical(other.language, language) || other.language == language)&&(identical(other.editedAt, editedAt) || other.editedAt == editedAt)&&(identical(other.publishedAt, publishedAt) || other.publishedAt == publishedAt)&&(identical(other.visibility, visibility) || other.visibility == visibility)&&(identical(other.content, content) || other.content == content)&&(identical(other.slug, slug) || other.slug == slug)&&(identical(other.type, type) || other.type == type)&&const DeepCollectionEquality().equals(other._meta, _meta)&&(identical(other.viewsUnique, viewsUnique) || other.viewsUnique == viewsUnique)&&(identical(other.viewsTotal, viewsTotal) || other.viewsTotal == viewsTotal)&&(identical(other.upvotes, upvotes) || other.upvotes == upvotes)&&(identical(other.downvotes, downvotes) || other.downvotes == downvotes)&&(identical(other.repliesCount, repliesCount) || other.repliesCount == repliesCount)&&(identical(other.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)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt)&&(identical(other.isTruncated, isTruncated) || other.isTruncated == isTruncated));
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hashAll([runtimeType,id,title,description,language,editedAt,publishedAt,visibility,content,slug,type,const DeepCollectionEquality().hash(_meta),viewsUnique,viewsTotal,upvotes,downvotes,repliesCount,threadedPostId,threadedPost,repliedPostId,repliedPost,forwardedPostId,forwardedPost,realmId,realm,const DeepCollectionEquality().hash(_attachments),publisher,const DeepCollectionEquality().hash(_reactionsCount),const DeepCollectionEquality().hash(_reactionsMade),const DeepCollectionEquality().hash(_reactions),const DeepCollectionEquality().hash(_tags),const DeepCollectionEquality().hash(_categories),const DeepCollectionEquality().hash(_collections),createdAt,updatedAt,deletedAt,isTruncated]);
|
int get hashCode => Object.hashAll([runtimeType,id,title,description,language,editedAt,publishedAt,visibility,content,slug,type,const DeepCollectionEquality().hash(_meta),viewsUnique,viewsTotal,upvotes,downvotes,repliesCount,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),createdAt,updatedAt,deletedAt,isTruncated]);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'SnPost(id: $id, title: $title, description: $description, language: $language, editedAt: $editedAt, publishedAt: $publishedAt, visibility: $visibility, content: $content, slug: $slug, type: $type, meta: $meta, viewsUnique: $viewsUnique, viewsTotal: $viewsTotal, upvotes: $upvotes, downvotes: $downvotes, repliesCount: $repliesCount, threadedPostId: $threadedPostId, threadedPost: $threadedPost, repliedPostId: $repliedPostId, repliedPost: $repliedPost, forwardedPostId: $forwardedPostId, forwardedPost: $forwardedPost, realmId: $realmId, realm: $realm, attachments: $attachments, publisher: $publisher, reactionsCount: $reactionsCount, reactionsMade: $reactionsMade, reactions: $reactions, tags: $tags, categories: $categories, collections: $collections, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, isTruncated: $isTruncated)';
|
return 'SnPost(id: $id, title: $title, description: $description, language: $language, editedAt: $editedAt, publishedAt: $publishedAt, visibility: $visibility, content: $content, slug: $slug, type: $type, meta: $meta, viewsUnique: $viewsUnique, viewsTotal: $viewsTotal, upvotes: $upvotes, downvotes: $downvotes, repliesCount: $repliesCount, 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, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, isTruncated: $isTruncated)';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -418,7 +420,7 @@ abstract mixin class _$SnPostCopyWith<$Res> implements $SnPostCopyWith<$Res> {
|
|||||||
factory _$SnPostCopyWith(_SnPost value, $Res Function(_SnPost) _then) = __$SnPostCopyWithImpl;
|
factory _$SnPostCopyWith(_SnPost value, $Res Function(_SnPost) _then) = __$SnPostCopyWithImpl;
|
||||||
@override @useResult
|
@override @useResult
|
||||||
$Res call({
|
$Res call({
|
||||||
String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map<String, dynamic>? meta, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, String? threadedPostId, SnPost? threadedPost, String? repliedPostId, SnPost? repliedPost, String? forwardedPostId, SnPost? forwardedPost, String? realmId, SnRealm? realm, List<SnCloudFile> attachments, SnPublisher publisher, Map<String, int> reactionsCount, Map<String, bool> reactionsMade, List<dynamic> reactions, List<SnPostTag> tags, List<SnPostCategory> categories, List<dynamic> collections, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool isTruncated
|
String id, String? title, String? description, String? language, DateTime? editedAt, DateTime? publishedAt, int visibility, String? content, String? slug, int type, Map<String, dynamic>? meta, int viewsUnique, int viewsTotal, int upvotes, int downvotes, int repliesCount, 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, DateTime? createdAt, DateTime? updatedAt, DateTime? deletedAt, bool isTruncated
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -435,7 +437,7 @@ class __$SnPostCopyWithImpl<$Res>
|
|||||||
|
|
||||||
/// Create a copy of SnPost
|
/// Create a copy of SnPost
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? title = freezed,Object? description = freezed,Object? language = freezed,Object? editedAt = freezed,Object? publishedAt = freezed,Object? visibility = null,Object? content = freezed,Object? slug = freezed,Object? type = null,Object? meta = freezed,Object? viewsUnique = null,Object? viewsTotal = null,Object? upvotes = null,Object? downvotes = null,Object? repliesCount = null,Object? threadedPostId = freezed,Object? threadedPost = freezed,Object? repliedPostId = freezed,Object? repliedPost = freezed,Object? forwardedPostId = freezed,Object? forwardedPost = freezed,Object? realmId = freezed,Object? realm = freezed,Object? attachments = null,Object? publisher = null,Object? reactionsCount = null,Object? reactionsMade = null,Object? reactions = null,Object? tags = null,Object? categories = null,Object? collections = null,Object? createdAt = freezed,Object? updatedAt = freezed,Object? deletedAt = freezed,Object? isTruncated = null,}) {
|
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? title = freezed,Object? description = freezed,Object? language = freezed,Object? editedAt = freezed,Object? publishedAt = freezed,Object? visibility = null,Object? content = freezed,Object? slug = freezed,Object? type = null,Object? meta = freezed,Object? viewsUnique = null,Object? viewsTotal = null,Object? upvotes = null,Object? downvotes = null,Object? repliesCount = null,Object? 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? createdAt = freezed,Object? updatedAt = freezed,Object? deletedAt = freezed,Object? isTruncated = null,}) {
|
||||||
return _then(_SnPost(
|
return _then(_SnPost(
|
||||||
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
|
||||||
as String,title: freezed == title ? _self.title : title // ignore: cast_nullable_to_non_nullable
|
as String,title: freezed == title ? _self.title : title // ignore: cast_nullable_to_non_nullable
|
||||||
@@ -453,7 +455,8 @@ as int,viewsTotal: null == viewsTotal ? _self.viewsTotal : viewsTotal // ignore:
|
|||||||
as int,upvotes: null == upvotes ? _self.upvotes : upvotes // ignore: cast_nullable_to_non_nullable
|
as int,upvotes: null == upvotes ? _self.upvotes : upvotes // ignore: cast_nullable_to_non_nullable
|
||||||
as int,downvotes: null == downvotes ? _self.downvotes : downvotes // ignore: cast_nullable_to_non_nullable
|
as int,downvotes: null == downvotes ? _self.downvotes : downvotes // ignore: cast_nullable_to_non_nullable
|
||||||
as int,repliesCount: null == repliesCount ? _self.repliesCount : repliesCount // ignore: cast_nullable_to_non_nullable
|
as int,repliesCount: null == repliesCount ? _self.repliesCount : repliesCount // ignore: cast_nullable_to_non_nullable
|
||||||
as int,threadedPostId: freezed == threadedPostId ? _self.threadedPostId : threadedPostId // ignore: cast_nullable_to_non_nullable
|
as int,pinMode: freezed == pinMode ? _self.pinMode : pinMode // ignore: cast_nullable_to_non_nullable
|
||||||
|
as int?,threadedPostId: freezed == threadedPostId ? _self.threadedPostId : threadedPostId // ignore: cast_nullable_to_non_nullable
|
||||||
as String?,threadedPost: freezed == threadedPost ? _self.threadedPost : threadedPost // ignore: cast_nullable_to_non_nullable
|
as String?,threadedPost: freezed == threadedPost ? _self.threadedPost : threadedPost // ignore: cast_nullable_to_non_nullable
|
||||||
as SnPost?,repliedPostId: freezed == repliedPostId ? _self.repliedPostId : repliedPostId // ignore: cast_nullable_to_non_nullable
|
as SnPost?,repliedPostId: freezed == repliedPostId ? _self.repliedPostId : repliedPostId // ignore: cast_nullable_to_non_nullable
|
||||||
as String?,repliedPost: freezed == repliedPost ? _self.repliedPost : repliedPost // ignore: cast_nullable_to_non_nullable
|
as String?,repliedPost: freezed == repliedPost ? _self.repliedPost : repliedPost // ignore: cast_nullable_to_non_nullable
|
||||||
|
@@ -29,6 +29,7 @@ _SnPost _$SnPostFromJson(Map<String, dynamic> json) => _SnPost(
|
|||||||
upvotes: (json['upvotes'] as num?)?.toInt() ?? 0,
|
upvotes: (json['upvotes'] as num?)?.toInt() ?? 0,
|
||||||
downvotes: (json['downvotes'] as num?)?.toInt() ?? 0,
|
downvotes: (json['downvotes'] as num?)?.toInt() ?? 0,
|
||||||
repliesCount: (json['replies_count'] as num?)?.toInt() ?? 0,
|
repliesCount: (json['replies_count'] as num?)?.toInt() ?? 0,
|
||||||
|
pinMode: (json['pin_mode'] as num?)?.toInt(),
|
||||||
threadedPostId: json['threaded_post_id'] as String?,
|
threadedPostId: json['threaded_post_id'] as String?,
|
||||||
threadedPost:
|
threadedPost:
|
||||||
json['threaded_post'] == null
|
json['threaded_post'] == null
|
||||||
@@ -109,6 +110,7 @@ Map<String, dynamic> _$SnPostToJson(_SnPost instance) => <String, dynamic>{
|
|||||||
'upvotes': instance.upvotes,
|
'upvotes': instance.upvotes,
|
||||||
'downvotes': instance.downvotes,
|
'downvotes': instance.downvotes,
|
||||||
'replies_count': instance.repliesCount,
|
'replies_count': instance.repliesCount,
|
||||||
|
'pin_mode': instance.pinMode,
|
||||||
'threaded_post_id': instance.threadedPostId,
|
'threaded_post_id': instance.threadedPostId,
|
||||||
'threaded_post': instance.threadedPost?.toJson(),
|
'threaded_post': instance.threadedPost?.toJson(),
|
||||||
'replied_post_id': instance.repliedPostId,
|
'replied_post_id': instance.repliedPostId,
|
||||||
|
@@ -7,6 +7,7 @@ import 'package:go_router/go_router.dart';
|
|||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:island/screens/about.dart';
|
import 'package:island/screens/about.dart';
|
||||||
import 'package:island/screens/account/credits.dart';
|
import 'package:island/screens/account/credits.dart';
|
||||||
|
import 'package:island/screens/developers/app_detail.dart';
|
||||||
import 'package:island/screens/developers/bot_detail.dart';
|
import 'package:island/screens/developers/bot_detail.dart';
|
||||||
import 'package:island/screens/developers/edit_app.dart';
|
import 'package:island/screens/developers/edit_app.dart';
|
||||||
import 'package:island/screens/developers/edit_bot.dart';
|
import 'package:island/screens/developers/edit_bot.dart';
|
||||||
@@ -37,6 +38,7 @@ import 'package:island/screens/chat/chat.dart';
|
|||||||
import 'package:island/screens/chat/room.dart';
|
import 'package:island/screens/chat/room.dart';
|
||||||
import 'package:island/screens/chat/room_detail.dart';
|
import 'package:island/screens/chat/room_detail.dart';
|
||||||
import 'package:island/screens/chat/call.dart';
|
import 'package:island/screens/chat/call.dart';
|
||||||
|
import 'package:island/screens/chat/search_messages_screen.dart';
|
||||||
import 'package:island/screens/creators/hub.dart';
|
import 'package:island/screens/creators/hub.dart';
|
||||||
import 'package:island/screens/creators/posts/post_manage_list.dart';
|
import 'package:island/screens/creators/posts/post_manage_list.dart';
|
||||||
import 'package:island/screens/creators/stickers/stickers.dart';
|
import 'package:island/screens/creators/stickers/stickers.dart';
|
||||||
@@ -349,6 +351,16 @@ final routerProvider = Provider<GoRouter>((ref) {
|
|||||||
id: state.pathParameters['id']!,
|
id: state.pathParameters['id']!,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
GoRoute(
|
||||||
|
name: 'developerAppDetail',
|
||||||
|
path: 'apps/:appId',
|
||||||
|
builder:
|
||||||
|
(context, state) => AppDetailScreen(
|
||||||
|
publisherName: state.pathParameters['name']!,
|
||||||
|
projectId: state.pathParameters['projectId']!,
|
||||||
|
appId: state.pathParameters['appId']!,
|
||||||
|
),
|
||||||
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
name: 'developerBotDetail',
|
name: 'developerBotDetail',
|
||||||
path: 'bots/:botId',
|
path: 'bots/:botId',
|
||||||
@@ -544,6 +556,14 @@ final routerProvider = Provider<GoRouter>((ref) {
|
|||||||
return ChatDetailScreen(id: id);
|
return ChatDetailScreen(id: id);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
GoRoute(
|
||||||
|
name: 'searchMessages',
|
||||||
|
path: '/chat/:id/search',
|
||||||
|
builder: (context, state) {
|
||||||
|
final id = state.pathParameters['id']!;
|
||||||
|
return SearchMessagesScreen(roomId: id);
|
||||||
|
},
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
||||||
|
@@ -95,8 +95,24 @@ class LevelingScreen extends HookConsumerWidget {
|
|||||||
title: Text('levelingProgress'.tr()),
|
title: Text('levelingProgress'.tr()),
|
||||||
bottom: TabBar(
|
bottom: TabBar(
|
||||||
tabs: [
|
tabs: [
|
||||||
Tab(text: 'leveling'.tr()),
|
Tab(
|
||||||
Tab(text: 'stellarProgram'.tr()),
|
child: Text(
|
||||||
|
'leveling'.tr(),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).appBarTheme.foregroundColor!,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Tab(
|
||||||
|
child: Text(
|
||||||
|
'stellarProgram'.tr(),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).appBarTheme.foregroundColor!,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@@ -279,6 +279,24 @@ class AccountProfileScreen extends HookConsumerWidget {
|
|||||||
if (data.profile.lastName.isNotEmpty) Text(data.profile.lastName),
|
if (data.profile.lastName.isNotEmpty) Text(data.profile.lastName),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
Tooltip(
|
||||||
|
message: 'creditsStatus'.tr(),
|
||||||
|
child: Row(
|
||||||
|
spacing: 6,
|
||||||
|
children: [
|
||||||
|
Icon(Symbols.star, size: 17, fill: 1).padding(right: 2),
|
||||||
|
Text('${data.profile.socialCredits.toStringAsFixed(2)} pts'),
|
||||||
|
Text('·').bold(),
|
||||||
|
switch (data.profile.socialCreditsLevel) {
|
||||||
|
-1 => Text('socialCreditsLevelPoor').tr(),
|
||||||
|
0 => Text('socialCreditsLevelNormal').tr(),
|
||||||
|
1 => Text('socialCreditsLevelGood').tr(),
|
||||||
|
2 => Text('socialCreditsLevelExcellent').tr(),
|
||||||
|
_ => Text('unknown').tr(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -72,6 +72,207 @@ class _AppLifecycleObserver extends WidgetsBindingObserver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _PublicRoomPreview extends HookConsumerWidget {
|
||||||
|
final String id;
|
||||||
|
final SnChatRoom room;
|
||||||
|
|
||||||
|
const _PublicRoomPreview({required this.id, required this.room});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final messages = ref.watch(messagesNotifierProvider(id));
|
||||||
|
final messagesNotifier = ref.read(messagesNotifierProvider(id).notifier);
|
||||||
|
final scrollController = useScrollController();
|
||||||
|
|
||||||
|
final listController = useMemoized(() => ListController(), []);
|
||||||
|
|
||||||
|
var isLoading = false;
|
||||||
|
|
||||||
|
// Add scroll listener for pagination
|
||||||
|
useEffect(() {
|
||||||
|
void onScroll() {
|
||||||
|
if (scrollController.position.pixels >=
|
||||||
|
scrollController.position.maxScrollExtent - 200) {
|
||||||
|
if (isLoading) return;
|
||||||
|
isLoading = true;
|
||||||
|
messagesNotifier.loadMore().then((_) => isLoading = false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
scrollController.addListener(onScroll);
|
||||||
|
return () => scrollController.removeListener(onScroll);
|
||||||
|
}, [scrollController]);
|
||||||
|
|
||||||
|
Widget chatMessageListWidget(List<LocalChatMessage> messageList) =>
|
||||||
|
SuperListView.builder(
|
||||||
|
listController: listController,
|
||||||
|
padding: EdgeInsets.symmetric(vertical: 16),
|
||||||
|
controller: scrollController,
|
||||||
|
reverse: true, // Show newest messages at the bottom
|
||||||
|
itemCount: messageList.length,
|
||||||
|
findChildIndexCallback: (key) {
|
||||||
|
final valueKey = key as ValueKey;
|
||||||
|
final messageId = valueKey.value as String;
|
||||||
|
return messageList.indexWhere((m) => m.id == messageId);
|
||||||
|
},
|
||||||
|
extentEstimation: (_, _) => 40,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final message = messageList[index];
|
||||||
|
final nextMessage =
|
||||||
|
index < messageList.length - 1 ? messageList[index + 1] : null;
|
||||||
|
final isLastInGroup =
|
||||||
|
nextMessage == null ||
|
||||||
|
nextMessage.senderId != message.senderId ||
|
||||||
|
nextMessage.createdAt
|
||||||
|
.difference(message.createdAt)
|
||||||
|
.inMinutes
|
||||||
|
.abs() >
|
||||||
|
3;
|
||||||
|
|
||||||
|
return MessageItem(
|
||||||
|
message: message,
|
||||||
|
isCurrentUser: false, // User is not a member, so not current user
|
||||||
|
onAction: null, // No actions allowed in preview mode
|
||||||
|
onJump: (_) {}, // No jump functionality in preview
|
||||||
|
progress: null,
|
||||||
|
showAvatar: isLastInGroup,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
final compactHeader = isWideScreen(context);
|
||||||
|
|
||||||
|
Widget comfortHeaderWidget() => Column(
|
||||||
|
spacing: 4,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
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),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
(room.type == 1 && room.name == null)
|
||||||
|
? room.members!.map((e) => e.account.nick).join(', ')
|
||||||
|
: room.name!,
|
||||||
|
).fontSize(15),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget compactHeaderWidget() => Row(
|
||||||
|
spacing: 8,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
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),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
(room.type == 1 && room.name == null)
|
||||||
|
? room.members!.map((e) => e.account.nick).join(', ')
|
||||||
|
: room.name!,
|
||||||
|
).fontSize(19),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
return AppScaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
leading: !compactHeader ? const Center(child: PageBackButton()) : null,
|
||||||
|
automaticallyImplyLeading: false,
|
||||||
|
toolbarHeight: compactHeader ? null : 64,
|
||||||
|
title: compactHeader ? compactHeaderWidget() : comfortHeaderWidget(),
|
||||||
|
actions: [
|
||||||
|
IconButton(
|
||||||
|
icon: const Icon(Icons.more_vert),
|
||||||
|
onPressed: () {
|
||||||
|
context.pushNamed('chatDetail', pathParameters: {'id': id});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
const Gap(8),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
body: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: messages.when(
|
||||||
|
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(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// Join button at the bottom for public rooms
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
child: 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),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@riverpod
|
@riverpod
|
||||||
class MessagesNotifier extends _$MessagesNotifier {
|
class MessagesNotifier extends _$MessagesNotifier {
|
||||||
late final Dio _apiClient;
|
late final Dio _apiClient;
|
||||||
@@ -82,6 +283,9 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
final Map<String, LocalChatMessage> _pendingMessages = {};
|
final Map<String, LocalChatMessage> _pendingMessages = {};
|
||||||
final Map<String, Map<int, double>> _fileUploadProgress = {};
|
final Map<String, Map<int, double>> _fileUploadProgress = {};
|
||||||
int? _totalCount;
|
int? _totalCount;
|
||||||
|
String? _searchQuery;
|
||||||
|
bool? _withLinks;
|
||||||
|
bool? _withAttachments;
|
||||||
|
|
||||||
late final String _roomId;
|
late final String _roomId;
|
||||||
int _currentPage = 0;
|
int _currentPage = 0;
|
||||||
@@ -96,28 +300,42 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
_database = ref.watch(databaseProvider);
|
_database = ref.watch(databaseProvider);
|
||||||
final room = await ref.watch(chatroomProvider(roomId).future);
|
final room = await ref.watch(chatroomProvider(roomId).future);
|
||||||
final identity = await ref.watch(chatroomIdentityProvider(roomId).future);
|
final identity = await ref.watch(chatroomIdentityProvider(roomId).future);
|
||||||
if (room == null || identity == null) {
|
|
||||||
throw Exception('Room or identity not found');
|
if (room == null) {
|
||||||
|
throw Exception('Room not found');
|
||||||
}
|
}
|
||||||
_room = room;
|
_room = room;
|
||||||
_identity = identity;
|
|
||||||
|
// Allow building even if identity is null for public rooms
|
||||||
|
if (identity != null) {
|
||||||
|
_identity = identity;
|
||||||
|
}
|
||||||
|
|
||||||
developer.log(
|
developer.log(
|
||||||
'MessagesNotifier built for room $roomId',
|
'MessagesNotifier built for room $roomId',
|
||||||
name: 'MessagesNotifier',
|
name: 'MessagesNotifier',
|
||||||
);
|
);
|
||||||
|
|
||||||
ref.listen(appLifecycleStateProvider, (_, next) {
|
// Only setup sync and lifecycle listeners if user is a member
|
||||||
if (next.hasValue && next.value == AppLifecycleState.resumed) {
|
if (identity != null) {
|
||||||
developer.log(
|
ref.listen(appLifecycleStateProvider, (_, next) {
|
||||||
'App resumed, syncing messages',
|
if (next.hasValue && next.value == AppLifecycleState.resumed) {
|
||||||
name: 'MessagesNotifier',
|
developer.log(
|
||||||
);
|
'App resumed, syncing messages',
|
||||||
syncMessages();
|
name: 'MessagesNotifier',
|
||||||
}
|
);
|
||||||
});
|
syncMessages();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return await loadInitial();
|
loadInitial();
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
List<LocalChatMessage> _sortMessages(List<LocalChatMessage> messages) {
|
||||||
|
messages.sort((a, b) => b.createdAt.compareTo(a.createdAt));
|
||||||
|
return messages;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<LocalChatMessage>> _getCachedMessages({
|
Future<List<LocalChatMessage>> _getCachedMessages({
|
||||||
@@ -128,13 +346,32 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
'Getting cached messages from offset $offset, take $take',
|
'Getting cached messages from offset $offset, take $take',
|
||||||
name: 'MessagesNotifier',
|
name: 'MessagesNotifier',
|
||||||
);
|
);
|
||||||
final dbMessages = await _database.getMessagesForRoom(
|
final List<LocalChatMessage> dbMessages;
|
||||||
_roomId,
|
if (_searchQuery != null && _searchQuery!.isNotEmpty) {
|
||||||
offset: offset,
|
dbMessages = await _database.searchMessages(_roomId, _searchQuery ?? '');
|
||||||
limit: take,
|
} else {
|
||||||
);
|
final chatMessagesFromDb = await _database.getMessagesForRoom(
|
||||||
final dbLocalMessages =
|
_roomId,
|
||||||
dbMessages.map(_database.companionToMessage).toList();
|
offset: offset,
|
||||||
|
limit: take,
|
||||||
|
);
|
||||||
|
dbMessages =
|
||||||
|
chatMessagesFromDb.map(_database.companionToMessage).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<LocalChatMessage> filteredMessages = dbMessages;
|
||||||
|
|
||||||
|
if (_withLinks == true) {
|
||||||
|
filteredMessages =
|
||||||
|
filteredMessages.where((msg) => _hasLink(msg)).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_withAttachments == true) {
|
||||||
|
filteredMessages =
|
||||||
|
filteredMessages.where((msg) => _hasAttachment(msg)).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
final dbLocalMessages = filteredMessages;
|
||||||
|
|
||||||
if (offset == 0) {
|
if (offset == 0) {
|
||||||
final pendingForRoom =
|
final pendingForRoom =
|
||||||
@@ -143,7 +380,7 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
final allMessages = [...pendingForRoom, ...dbLocalMessages];
|
final allMessages = [...pendingForRoom, ...dbLocalMessages];
|
||||||
allMessages.sort((a, b) => b.createdAt.compareTo(a.createdAt));
|
_sortMessages(allMessages); // Use the helper function
|
||||||
|
|
||||||
final uniqueMessages = <LocalChatMessage>[];
|
final uniqueMessages = <LocalChatMessage>[];
|
||||||
final seenIds = <String>{};
|
final seenIds = <String>{};
|
||||||
@@ -218,7 +455,7 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
_isSyncing = true;
|
_isSyncing = true;
|
||||||
|
|
||||||
developer.log('Starting message sync', name: 'MessagesNotifier');
|
developer.log('Starting message sync', name: 'MessagesNotifier');
|
||||||
ref.read(isSyncingProvider.notifier).state = true;
|
Future.microtask(() => ref.read(isSyncingProvider.notifier).state = true);
|
||||||
try {
|
try {
|
||||||
final dbMessages = await _database.getMessagesForRoom(
|
final dbMessages = await _database.getMessagesForRoom(
|
||||||
_room.id,
|
_room.id,
|
||||||
@@ -279,7 +516,9 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
showErrorAlert(err);
|
showErrorAlert(err);
|
||||||
} finally {
|
} finally {
|
||||||
developer.log('Finished message sync', name: 'MessagesNotifier');
|
developer.log('Finished message sync', name: 'MessagesNotifier');
|
||||||
ref.read(isSyncingProvider.notifier).state = false;
|
Future.microtask(
|
||||||
|
() => ref.read(isSyncingProvider.notifier).state = false,
|
||||||
|
);
|
||||||
_isSyncing = false;
|
_isSyncing = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -290,7 +529,9 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
bool synced = false,
|
bool synced = false,
|
||||||
}) async {
|
}) async {
|
||||||
try {
|
try {
|
||||||
if (offset == 0 && !synced) {
|
if (offset == 0 &&
|
||||||
|
!synced &&
|
||||||
|
(_searchQuery == null || _searchQuery!.isEmpty)) {
|
||||||
_fetchAndCacheMessages(offset: 0, take: take).catchError((_) {
|
_fetchAndCacheMessages(offset: 0, take: take).catchError((_) {
|
||||||
return <LocalChatMessage>[];
|
return <LocalChatMessage>[];
|
||||||
});
|
});
|
||||||
@@ -305,7 +546,11 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
return localMessages;
|
return localMessages;
|
||||||
}
|
}
|
||||||
|
|
||||||
return await _fetchAndCacheMessages(offset: offset, take: take);
|
if (_searchQuery == null || _searchQuery!.isEmpty) {
|
||||||
|
return await _fetchAndCacheMessages(offset: offset, take: take);
|
||||||
|
} else {
|
||||||
|
return []; // If searching, and no local messages, don't fetch from network
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
final localMessages = await _getCachedMessages(
|
final localMessages = await _getCachedMessages(
|
||||||
offset: offset,
|
offset: offset,
|
||||||
@@ -319,13 +564,15 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<LocalChatMessage>> loadInitial() async {
|
Future<void> loadInitial() async {
|
||||||
developer.log('Loading initial messages', name: 'MessagesNotifier');
|
developer.log('Loading initial messages', name: 'MessagesNotifier');
|
||||||
syncMessages();
|
if (_searchQuery == null || _searchQuery!.isEmpty) {
|
||||||
|
syncMessages();
|
||||||
|
}
|
||||||
final messages = await _getCachedMessages(offset: 0, take: 100);
|
final messages = await _getCachedMessages(offset: 0, take: 100);
|
||||||
_currentPage = 0;
|
_currentPage = 0;
|
||||||
_hasMore = messages.length == _pageSize;
|
_hasMore = messages.length == _pageSize;
|
||||||
return messages;
|
state = AsyncValue.data(messages);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> loadMore() async {
|
Future<void> loadMore() async {
|
||||||
@@ -344,7 +591,9 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
_hasMore = false;
|
_hasMore = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
state = AsyncValue.data([...currentMessages, ...newMessages]);
|
state = AsyncValue.data(
|
||||||
|
_sortMessages([...currentMessages, ...newMessages]),
|
||||||
|
);
|
||||||
} catch (err, stackTrace) {
|
} catch (err, stackTrace) {
|
||||||
developer.log(
|
developer.log(
|
||||||
'Error loading more messages',
|
'Error loading more messages',
|
||||||
@@ -455,10 +704,13 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
|
|
||||||
final currentMessages = state.value ?? [];
|
final currentMessages = state.value ?? [];
|
||||||
if (editingTo != null) {
|
if (editingTo != null) {
|
||||||
final newMessages = currentMessages
|
final newMessages =
|
||||||
.where((m) => m.id != localMessage.id) // remove pending message
|
currentMessages
|
||||||
.map((m) => m.id == editingTo.id ? updatedMessage : m) // update original message
|
.where((m) => m.id != localMessage.id) // remove pending message
|
||||||
.toList();
|
.map(
|
||||||
|
(m) => m.id == editingTo.id ? updatedMessage : m,
|
||||||
|
) // update original message
|
||||||
|
.toList();
|
||||||
state = AsyncValue.data(newMessages);
|
state = AsyncValue.data(newMessages);
|
||||||
} else {
|
} else {
|
||||||
final newMessages =
|
final newMessages =
|
||||||
@@ -566,7 +818,7 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
}
|
}
|
||||||
return m;
|
return m;
|
||||||
}).toList();
|
}).toList();
|
||||||
state = AsyncValue.data(newMessages);
|
state = AsyncValue.data(_sortMessages(newMessages));
|
||||||
showErrorAlert(e);
|
showErrorAlert(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -626,7 +878,7 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
final newList = [...currentMessages];
|
final newList = [...currentMessages];
|
||||||
newList[index] = updatedMessage;
|
newList[index] = updatedMessage;
|
||||||
state = AsyncValue.data(newList);
|
state = AsyncValue.data(_sortMessages(newList));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -686,6 +938,20 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void searchMessages(String query, {bool? withLinks, bool? withAttachments}) {
|
||||||
|
_searchQuery = query.trim();
|
||||||
|
_withLinks = withLinks;
|
||||||
|
_withAttachments = withAttachments;
|
||||||
|
loadInitial();
|
||||||
|
}
|
||||||
|
|
||||||
|
void clearSearch() {
|
||||||
|
_searchQuery = null;
|
||||||
|
_withLinks = null;
|
||||||
|
_withAttachments = null;
|
||||||
|
loadInitial();
|
||||||
|
}
|
||||||
|
|
||||||
Future<LocalChatMessage?> fetchMessageById(String messageId) async {
|
Future<LocalChatMessage?> fetchMessageById(String messageId) async {
|
||||||
developer.log(
|
developer.log(
|
||||||
'Fetching message by id $messageId',
|
'Fetching message by id $messageId',
|
||||||
@@ -715,6 +981,18 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool _hasLink(LocalChatMessage message) {
|
||||||
|
final content = message.toRemoteMessage().content;
|
||||||
|
if (content == null) return false;
|
||||||
|
final urlRegex = RegExp(r'https?://[^\s/$.?#].[^\s]*');
|
||||||
|
return urlRegex.hasMatch(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _hasAttachment(LocalChatMessage message) {
|
||||||
|
final remoteMessage = message.toRemoteMessage();
|
||||||
|
return remoteMessage.attachments.isNotEmpty;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ChatRoomScreen extends HookConsumerWidget {
|
class ChatRoomScreen extends HookConsumerWidget {
|
||||||
@@ -734,57 +1012,77 @@ class ChatRoomScreen extends HookConsumerWidget {
|
|||||||
);
|
);
|
||||||
} else if (chatIdentity.value == null) {
|
} else if (chatIdentity.value == null) {
|
||||||
// Identity was not found, user was not joined
|
// Identity was not found, user was not joined
|
||||||
return AppScaffold(
|
return chatRoom.when(
|
||||||
appBar: AppBar(leading: const PageBackButton()),
|
data: (room) {
|
||||||
body: Center(
|
if (room!.isPublic) {
|
||||||
child:
|
// Show public room preview with messages but no input
|
||||||
ConstrainedBox(
|
return _PublicRoomPreview(id: id, room: room);
|
||||||
constraints: const BoxConstraints(maxWidth: 280),
|
} else {
|
||||||
child: Column(
|
// Show regular "not joined" screen for private rooms
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
return AppScaffold(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
appBar: AppBar(leading: const PageBackButton()),
|
||||||
children: [
|
body: Center(
|
||||||
Icon(
|
child:
|
||||||
chatRoom.value?.isCommunity == true
|
ConstrainedBox(
|
||||||
? Symbols.person_add
|
constraints: const BoxConstraints(maxWidth: 280),
|
||||||
: Symbols.person_remove,
|
child: Column(
|
||||||
size: 36,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
fill: 1,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
).padding(bottom: 4),
|
children: [
|
||||||
Text('chatNotJoined').tr(),
|
Icon(
|
||||||
if (chatRoom.value?.isCommunity != true)
|
room.isCommunity == true
|
||||||
Text(
|
? Symbols.person_add
|
||||||
'chatUnableJoin',
|
: Symbols.person_remove,
|
||||||
textAlign: TextAlign.center,
|
size: 36,
|
||||||
).tr().bold()
|
fill: 1,
|
||||||
else
|
).padding(bottom: 4),
|
||||||
FilledButton.tonalIcon(
|
Text('chatNotJoined').tr(),
|
||||||
onPressed: () async {
|
if (room.isCommunity != true)
|
||||||
try {
|
Text(
|
||||||
showLoadingModal(context);
|
'chatUnableJoin',
|
||||||
final apiClient = ref.read(apiClientProvider);
|
textAlign: TextAlign.center,
|
||||||
if (chatRoom.value == null) {
|
).tr().bold()
|
||||||
hideLoadingModal(context);
|
else
|
||||||
return;
|
FilledButton.tonalIcon(
|
||||||
}
|
onPressed: () async {
|
||||||
|
try {
|
||||||
await apiClient.post(
|
showLoadingModal(context);
|
||||||
'/sphere/chat/${chatRoom.value!.id}/members/me',
|
final apiClient = ref.read(apiClientProvider);
|
||||||
);
|
await apiClient.post(
|
||||||
ref.invalidate(chatroomIdentityProvider(id));
|
'/sphere/chat/${room.id}/members/me',
|
||||||
} catch (err) {
|
);
|
||||||
showErrorAlert(err);
|
ref.invalidate(chatroomIdentityProvider(id));
|
||||||
} finally {
|
} catch (err) {
|
||||||
if (context.mounted) hideLoadingModal(context);
|
showErrorAlert(err);
|
||||||
}
|
} finally {
|
||||||
},
|
if (context.mounted) {
|
||||||
label: Text('chatJoin').tr(),
|
hideLoadingModal(context);
|
||||||
icon: const Icon(Icons.add),
|
}
|
||||||
).padding(top: 8),
|
}
|
||||||
],
|
},
|
||||||
),
|
label: Text('chatJoin').tr(),
|
||||||
).center(),
|
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)),
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1549,7 +1847,7 @@ class _ChatInput extends HookConsumerWidget {
|
|||||||
children: [
|
children: [
|
||||||
IconButton(
|
IconButton(
|
||||||
tooltip: 'stickers'.tr(),
|
tooltip: 'stickers'.tr(),
|
||||||
icon: const Icon(Symbols.emoji_symbols),
|
icon: const Icon(Symbols.add_reaction),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
final size = MediaQuery.of(context).size;
|
final size = MediaQuery.of(context).size;
|
||||||
showStickerPickerPopover(
|
showStickerPickerPopover(
|
||||||
@@ -1659,8 +1957,13 @@ class _ChatInput extends HookConsumerWidget {
|
|||||||
horizontal: 12,
|
horizontal: 12,
|
||||||
vertical: 4,
|
vertical: 4,
|
||||||
),
|
),
|
||||||
|
counterText:
|
||||||
|
messageController.text.length > 1024
|
||||||
|
? '${messageController.text.length}/4096'
|
||||||
|
: null,
|
||||||
),
|
),
|
||||||
maxLines: null,
|
maxLines: 3,
|
||||||
|
minLines: 1,
|
||||||
onTapOutside:
|
onTapOutside:
|
||||||
(_) => FocusManager.instance.primaryFocus?.unfocus(),
|
(_) => FocusManager.instance.primaryFocus?.unfocus(),
|
||||||
),
|
),
|
||||||
|
@@ -6,7 +6,7 @@ part of 'room.dart';
|
|||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$messagesNotifierHash() => r'32afe6ea24086d869cc47bd3389c8fd734409ca0';
|
String _$messagesNotifierHash() => r'fc3b66dfb8dd3fc55d142dae5c5e7bdc67eca5d4';
|
||||||
|
|
||||||
/// Copied from Dart SDK
|
/// Copied from Dart SDK
|
||||||
class _SystemHash {
|
class _SystemHash {
|
||||||
|
@@ -9,6 +9,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|||||||
import 'package:island/models/chat.dart';
|
import 'package:island/models/chat.dart';
|
||||||
import 'package:island/pods/network.dart';
|
import 'package:island/pods/network.dart';
|
||||||
import 'package:island/screens/chat/chat.dart';
|
import 'package:island/screens/chat/chat.dart';
|
||||||
|
import 'package:island/widgets/account/account_pfc.dart';
|
||||||
import 'package:island/widgets/account/account_picker.dart';
|
import 'package:island/widgets/account/account_picker.dart';
|
||||||
import 'package:island/widgets/account/status.dart';
|
import 'package:island/widgets/account/status.dart';
|
||||||
import 'package:island/widgets/alert.dart';
|
import 'package:island/widgets/alert.dart';
|
||||||
@@ -19,10 +20,17 @@ import 'package:material_symbols_icons/symbols.dart';
|
|||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
import 'package:riverpod_paging_utils/riverpod_paging_utils.dart';
|
import 'package:riverpod_paging_utils/riverpod_paging_utils.dart';
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
|
import 'package:island/pods/database.dart';
|
||||||
|
|
||||||
part 'room_detail.freezed.dart';
|
part 'room_detail.freezed.dart';
|
||||||
part 'room_detail.g.dart';
|
part 'room_detail.g.dart';
|
||||||
|
|
||||||
|
@riverpod
|
||||||
|
Future<int> totalMessagesCount(Ref ref, String roomId) async {
|
||||||
|
final database = ref.watch(databaseProvider);
|
||||||
|
return database.getTotalMessagesForRoom(roomId);
|
||||||
|
}
|
||||||
|
|
||||||
class ChatDetailScreen extends HookConsumerWidget {
|
class ChatDetailScreen extends HookConsumerWidget {
|
||||||
final String id;
|
final String id;
|
||||||
const ChatDetailScreen({super.key, required this.id});
|
const ChatDetailScreen({super.key, required this.id});
|
||||||
@@ -31,6 +39,7 @@ class ChatDetailScreen extends HookConsumerWidget {
|
|||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final roomState = ref.watch(chatroomProvider(id));
|
final roomState = ref.watch(chatroomProvider(id));
|
||||||
final roomIdentity = ref.watch(chatroomIdentityProvider(id));
|
final roomIdentity = ref.watch(chatroomIdentityProvider(id));
|
||||||
|
final totalMessages = ref.watch(totalMessagesCountProvider(id));
|
||||||
|
|
||||||
const kNotifyLevelText = [
|
const kNotifyLevelText = [
|
||||||
'chatNotifyLevelAll',
|
'chatNotifyLevelAll',
|
||||||
@@ -131,7 +140,7 @@ class ChatDetailScreen extends HookConsumerWidget {
|
|||||||
const Text('chatBreakDescription').tr(),
|
const Text('chatBreakDescription').tr(),
|
||||||
const Gap(16),
|
const Gap(16),
|
||||||
ListTile(
|
ListTile(
|
||||||
title: const Text('Clear').tr(),
|
title: const Text('chatBreakClearButton').tr(),
|
||||||
subtitle: const Text('chatBreakClear').tr(),
|
subtitle: const Text('chatBreakClear').tr(),
|
||||||
leading: const Icon(Icons.notifications_active),
|
leading: const Icon(Icons.notifications_active),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
@@ -143,8 +152,8 @@ class ChatDetailScreen extends HookConsumerWidget {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
title: const Text('5m'),
|
title: const Text('chatBreak5m').tr(),
|
||||||
subtitle: const Text('chatBreakHour').tr(args: ['5m']),
|
subtitle: const Text('chatBreakHour').tr(args: ['chatBreak5m'.tr()]),
|
||||||
leading: const Icon(Symbols.circle),
|
leading: const Icon(Symbols.circle),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
setChatBreak(now.add(const Duration(minutes: 5)));
|
setChatBreak(now.add(const Duration(minutes: 5)));
|
||||||
@@ -155,8 +164,8 @@ class ChatDetailScreen extends HookConsumerWidget {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
title: const Text('10m'),
|
title: const Text('chatBreak10m').tr(),
|
||||||
subtitle: const Text('chatBreakHour').tr(args: ['10m']),
|
subtitle: const Text('chatBreakHour').tr(args: ['chatBreak10m'.tr()]),
|
||||||
leading: const Icon(Symbols.circle),
|
leading: const Icon(Symbols.circle),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
setChatBreak(now.add(const Duration(minutes: 10)));
|
setChatBreak(now.add(const Duration(minutes: 10)));
|
||||||
@@ -167,8 +176,8 @@ class ChatDetailScreen extends HookConsumerWidget {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
title: const Text('15m'),
|
title: const Text('chatBreak15m').tr(),
|
||||||
subtitle: const Text('chatBreakHour').tr(args: ['15m']),
|
subtitle: const Text('chatBreakHour').tr(args: ['chatBreak15m'.tr()]),
|
||||||
leading: const Icon(Symbols.timer_3),
|
leading: const Icon(Symbols.timer_3),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
setChatBreak(now.add(const Duration(minutes: 15)));
|
setChatBreak(now.add(const Duration(minutes: 15)));
|
||||||
@@ -179,8 +188,8 @@ class ChatDetailScreen extends HookConsumerWidget {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
title: const Text('30m'),
|
title: const Text('chatBreak30m').tr(),
|
||||||
subtitle: const Text('chatBreakHour').tr(args: ['30m']),
|
subtitle: const Text('chatBreakHour').tr(args: ['chatBreak30m'.tr()]),
|
||||||
leading: const Icon(Symbols.timer),
|
leading: const Icon(Symbols.timer),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
setChatBreak(now.add(const Duration(minutes: 30)));
|
setChatBreak(now.add(const Duration(minutes: 30)));
|
||||||
@@ -194,8 +203,8 @@ class ChatDetailScreen extends HookConsumerWidget {
|
|||||||
TextField(
|
TextField(
|
||||||
controller: durationController,
|
controller: durationController,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
labelText: 'Custom (minutes)'.tr(),
|
labelText: 'chatBreakCustomMinutes'.tr(),
|
||||||
hintText: 'Enter minutes'.tr(),
|
hintText: 'chatBreakEnterMinutes'.tr(),
|
||||||
border: const OutlineInputBorder(),
|
border: const OutlineInputBorder(),
|
||||||
suffixIcon: IconButton(
|
suffixIcon: IconButton(
|
||||||
icon: const Icon(Icons.check),
|
icon: const Icon(Icons.check),
|
||||||
@@ -238,7 +247,7 @@ class ChatDetailScreen extends HookConsumerWidget {
|
|||||||
return AppScaffold(
|
return AppScaffold(
|
||||||
body: roomState.when(
|
body: roomState.when(
|
||||||
loading: () => const Center(child: CircularProgressIndicator()),
|
loading: () => const Center(child: CircularProgressIndicator()),
|
||||||
error: (error, _) => Center(child: Text('Error: $error')),
|
error: (error, _) => Center(child: Text('errorGeneric'.tr(args: [error.toString()]))),
|
||||||
data:
|
data:
|
||||||
(currentRoom) => CustomScrollView(
|
(currentRoom) => CustomScrollView(
|
||||||
slivers: [
|
slivers: [
|
||||||
@@ -358,6 +367,22 @@ class ChatDetailScreen extends HookConsumerWidget {
|
|||||||
: const Text('chatBreakNone').tr(),
|
: const Text('chatBreakNone').tr(),
|
||||||
onTap: () => showChatBreakDialog(),
|
onTap: () => showChatBreakDialog(),
|
||||||
),
|
),
|
||||||
|
ListTile(
|
||||||
|
contentPadding: EdgeInsets.symmetric(
|
||||||
|
horizontal: 24,
|
||||||
|
),
|
||||||
|
leading: const Icon(Icons.search),
|
||||||
|
trailing: const Icon(Symbols.chevron_right),
|
||||||
|
title: const Text('searchMessages').tr(),
|
||||||
|
subtitle: totalMessages.when(
|
||||||
|
data: (count) => Text('messagesCount'.tr(args: [count.toString()])),
|
||||||
|
loading: () => const CircularProgressIndicator(),
|
||||||
|
error: (err, stack) => Text('errorGeneric'.tr(args: [err.toString()])),
|
||||||
|
),
|
||||||
|
onTap: () {
|
||||||
|
context.pushNamed('searchMessages', pathParameters: {'id': id});
|
||||||
|
},
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
error: (_, _) => const SizedBox.shrink(),
|
error: (_, _) => const SizedBox.shrink(),
|
||||||
@@ -666,8 +691,11 @@ class _ChatMemberListSheet extends HookConsumerWidget {
|
|||||||
final member = data.items[index];
|
final member = data.items[index];
|
||||||
return ListTile(
|
return ListTile(
|
||||||
contentPadding: EdgeInsets.only(left: 16, right: 12),
|
contentPadding: EdgeInsets.only(left: 16, right: 12),
|
||||||
leading: ProfilePictureWidget(
|
leading: AccountPfcGestureDetector(
|
||||||
fileId: member.account.profile.picture?.id,
|
uname: member.account.name,
|
||||||
|
child: ProfilePictureWidget(
|
||||||
|
fileId: member.account.profile.picture?.id,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
title: Row(
|
title: Row(
|
||||||
spacing: 6,
|
spacing: 6,
|
||||||
@@ -688,7 +716,7 @@ class _ChatMemberListSheet extends HookConsumerWidget {
|
|||||||
? 'permissionModerator'
|
? 'permissionModerator'
|
||||||
: 'permissionMember',
|
: 'permissionMember',
|
||||||
).tr(),
|
).tr(),
|
||||||
Text('·').bold().padding(horizontal: 6),
|
Text('dotSeparator').bold().padding(horizontal: 6),
|
||||||
Expanded(child: Text("@${member.account.name}")),
|
Expanded(child: Text("@${member.account.name}")),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -848,7 +876,7 @@ class _ChatMemberRoleSheet extends HookConsumerWidget {
|
|||||||
try {
|
try {
|
||||||
final newRole = int.parse(roleController.text);
|
final newRole = int.parse(roleController.text);
|
||||||
if (newRole < 0 || newRole > 100) {
|
if (newRole < 0 || newRole > 100) {
|
||||||
throw 'Role must be between 0 and 100';
|
throw 'roleValidationHint'.tr();
|
||||||
}
|
}
|
||||||
|
|
||||||
final apiClient = ref.read(apiClientProvider);
|
final apiClient = ref.read(apiClientProvider);
|
||||||
|
@@ -6,8 +6,8 @@ part of 'room_detail.dart';
|
|||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$chatMemberListNotifierHash() =>
|
String _$totalMessagesCountHash() =>
|
||||||
r'3ea30150278523e9f6b23f9200ea9a9fbae9c973';
|
r'a15c03461f25c2d4d39c0926509bf626ae2550a6';
|
||||||
|
|
||||||
/// Copied from Dart SDK
|
/// Copied from Dart SDK
|
||||||
class _SystemHash {
|
class _SystemHash {
|
||||||
@@ -30,6 +30,128 @@ class _SystemHash {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// See also [totalMessagesCount].
|
||||||
|
@ProviderFor(totalMessagesCount)
|
||||||
|
const totalMessagesCountProvider = TotalMessagesCountFamily();
|
||||||
|
|
||||||
|
/// See also [totalMessagesCount].
|
||||||
|
class TotalMessagesCountFamily extends Family<AsyncValue<int>> {
|
||||||
|
/// See also [totalMessagesCount].
|
||||||
|
const TotalMessagesCountFamily();
|
||||||
|
|
||||||
|
/// See also [totalMessagesCount].
|
||||||
|
TotalMessagesCountProvider call(String roomId) {
|
||||||
|
return TotalMessagesCountProvider(roomId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
TotalMessagesCountProvider getProviderOverride(
|
||||||
|
covariant TotalMessagesCountProvider provider,
|
||||||
|
) {
|
||||||
|
return call(provider.roomId);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
|
||||||
|
|
||||||
|
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
|
||||||
|
_allTransitiveDependencies;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String? get name => r'totalMessagesCountProvider';
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See also [totalMessagesCount].
|
||||||
|
class TotalMessagesCountProvider extends AutoDisposeFutureProvider<int> {
|
||||||
|
/// See also [totalMessagesCount].
|
||||||
|
TotalMessagesCountProvider(String roomId)
|
||||||
|
: this._internal(
|
||||||
|
(ref) => totalMessagesCount(ref as TotalMessagesCountRef, roomId),
|
||||||
|
from: totalMessagesCountProvider,
|
||||||
|
name: r'totalMessagesCountProvider',
|
||||||
|
debugGetCreateSourceHash:
|
||||||
|
const bool.fromEnvironment('dart.vm.product')
|
||||||
|
? null
|
||||||
|
: _$totalMessagesCountHash,
|
||||||
|
dependencies: TotalMessagesCountFamily._dependencies,
|
||||||
|
allTransitiveDependencies:
|
||||||
|
TotalMessagesCountFamily._allTransitiveDependencies,
|
||||||
|
roomId: roomId,
|
||||||
|
);
|
||||||
|
|
||||||
|
TotalMessagesCountProvider._internal(
|
||||||
|
super._createNotifier, {
|
||||||
|
required super.name,
|
||||||
|
required super.dependencies,
|
||||||
|
required super.allTransitiveDependencies,
|
||||||
|
required super.debugGetCreateSourceHash,
|
||||||
|
required super.from,
|
||||||
|
required this.roomId,
|
||||||
|
}) : super.internal();
|
||||||
|
|
||||||
|
final String roomId;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Override overrideWith(
|
||||||
|
FutureOr<int> Function(TotalMessagesCountRef provider) create,
|
||||||
|
) {
|
||||||
|
return ProviderOverride(
|
||||||
|
origin: this,
|
||||||
|
override: TotalMessagesCountProvider._internal(
|
||||||
|
(ref) => create(ref as TotalMessagesCountRef),
|
||||||
|
from: from,
|
||||||
|
name: null,
|
||||||
|
dependencies: null,
|
||||||
|
allTransitiveDependencies: null,
|
||||||
|
debugGetCreateSourceHash: null,
|
||||||
|
roomId: roomId,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
AutoDisposeFutureProviderElement<int> createElement() {
|
||||||
|
return _TotalMessagesCountProviderElement(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return other is TotalMessagesCountProvider && other.roomId == roomId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode {
|
||||||
|
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||||
|
hash = _SystemHash.combine(hash, roomId.hashCode);
|
||||||
|
|
||||||
|
return _SystemHash.finish(hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
|
mixin TotalMessagesCountRef on AutoDisposeFutureProviderRef<int> {
|
||||||
|
/// The parameter `roomId` of this provider.
|
||||||
|
String get roomId;
|
||||||
|
}
|
||||||
|
|
||||||
|
class _TotalMessagesCountProviderElement
|
||||||
|
extends AutoDisposeFutureProviderElement<int>
|
||||||
|
with TotalMessagesCountRef {
|
||||||
|
_TotalMessagesCountProviderElement(super.provider);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get roomId => (origin as TotalMessagesCountProvider).roomId;
|
||||||
|
}
|
||||||
|
|
||||||
|
String _$chatMemberListNotifierHash() =>
|
||||||
|
r'3ea30150278523e9f6b23f9200ea9a9fbae9c973';
|
||||||
|
|
||||||
abstract class _$ChatMemberListNotifier
|
abstract class _$ChatMemberListNotifier
|
||||||
extends BuildlessAutoDisposeAsyncNotifier<CursorPagingData<SnChatMember>> {
|
extends BuildlessAutoDisposeAsyncNotifier<CursorPagingData<SnChatMember>> {
|
||||||
late final String roomId;
|
late final String roomId;
|
||||||
|
139
lib/screens/chat/search_messages_screen.dart
Normal file
139
lib/screens/chat/search_messages_screen.dart
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:island/screens/chat/room.dart';
|
||||||
|
import 'package:island/widgets/app_scaffold.dart';
|
||||||
|
import 'package:island/widgets/chat/message_item.dart';
|
||||||
|
import 'package:material_symbols_icons/material_symbols_icons.dart';
|
||||||
|
import 'package:super_sliver_list/super_sliver_list.dart';
|
||||||
|
|
||||||
|
class SearchMessagesScreen extends HookConsumerWidget {
|
||||||
|
final String roomId;
|
||||||
|
|
||||||
|
const SearchMessagesScreen({super.key, required this.roomId});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final searchController = useTextEditingController();
|
||||||
|
final withLinks = useState(false);
|
||||||
|
final withAttachments = useState(false);
|
||||||
|
|
||||||
|
final messagesNotifier = ref.read(
|
||||||
|
messagesNotifierProvider(roomId).notifier,
|
||||||
|
);
|
||||||
|
final messages = ref.watch(messagesNotifierProvider(roomId));
|
||||||
|
|
||||||
|
useEffect(() {
|
||||||
|
// Clear search when screen is disposed
|
||||||
|
return () {
|
||||||
|
messagesNotifier.clearSearch();
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return AppScaffold(
|
||||||
|
appBar: AppBar(title: const Text('searchMessages').tr()),
|
||||||
|
body: Column(
|
||||||
|
children: [
|
||||||
|
Column(
|
||||||
|
children: [
|
||||||
|
TextField(
|
||||||
|
controller: searchController,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintText: 'searchMessagesHint'.tr(),
|
||||||
|
border: InputBorder.none,
|
||||||
|
isDense: true,
|
||||||
|
contentPadding: EdgeInsets.only(
|
||||||
|
left: 16,
|
||||||
|
right: 16,
|
||||||
|
top: 12,
|
||||||
|
bottom: 16,
|
||||||
|
),
|
||||||
|
suffix: IconButton(
|
||||||
|
iconSize: 18,
|
||||||
|
visualDensity: VisualDensity.compact,
|
||||||
|
icon: const Icon(Icons.clear),
|
||||||
|
onPressed: () {
|
||||||
|
searchController.clear();
|
||||||
|
messagesNotifier.clearSearch();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onChanged: (query) {
|
||||||
|
messagesNotifier.searchMessages(
|
||||||
|
query,
|
||||||
|
withLinks: withLinks.value,
|
||||||
|
withAttachments: withAttachments.value,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: CheckboxListTile(
|
||||||
|
secondary: const Icon(Symbols.link),
|
||||||
|
title: const Text('searchLinks').tr(),
|
||||||
|
value: withLinks.value,
|
||||||
|
onChanged: (bool? value) {
|
||||||
|
withLinks.value = value!;
|
||||||
|
messagesNotifier.searchMessages(
|
||||||
|
searchController.text,
|
||||||
|
withLinks: withLinks.value,
|
||||||
|
withAttachments: withAttachments.value,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: CheckboxListTile(
|
||||||
|
secondary: const Icon(Symbols.file_copy),
|
||||||
|
title: const Text('searchAttachments').tr(),
|
||||||
|
value: withAttachments.value,
|
||||||
|
onChanged: (bool? value) {
|
||||||
|
withAttachments.value = value!;
|
||||||
|
messagesNotifier.searchMessages(
|
||||||
|
searchController.text,
|
||||||
|
withLinks: withLinks.value,
|
||||||
|
withAttachments: withAttachments.value,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const Divider(height: 1),
|
||||||
|
Expanded(
|
||||||
|
child: messages.when(
|
||||||
|
data:
|
||||||
|
(messageList) =>
|
||||||
|
messageList.isEmpty
|
||||||
|
? Center(child: Text('noMessagesFound'.tr()))
|
||||||
|
: SuperListView.builder(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||||
|
reverse: true, // Show newest messages at the bottom
|
||||||
|
itemCount: messageList.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final message = messageList[index];
|
||||||
|
// Simplified MessageItem for search results, no grouping logic
|
||||||
|
return MessageItem(
|
||||||
|
message: message,
|
||||||
|
isCurrentUser:
|
||||||
|
false, // Or determine based on actual user
|
||||||
|
onAction: null,
|
||||||
|
onJump: (_) {},
|
||||||
|
progress: null,
|
||||||
|
showAvatar: true,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
loading: () => const Center(child: CircularProgressIndicator()),
|
||||||
|
error: (error, _) => Center(child: Text('errorGeneric'.tr(args: [error.toString()]))),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
156
lib/screens/developers/app_detail.dart
Normal file
156
lib/screens/developers/app_detail.dart
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
|
import 'package:go_router/go_router.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:island/models/custom_app.dart';
|
||||||
|
import 'package:island/screens/developers/app_secrets.dart';
|
||||||
|
import 'package:island/screens/developers/apps.dart';
|
||||||
|
import 'package:island/widgets/app_scaffold.dart';
|
||||||
|
import 'package:island/widgets/content/cloud_files.dart';
|
||||||
|
import 'package:island/widgets/response.dart';
|
||||||
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
|
|
||||||
|
class AppDetailScreen extends HookConsumerWidget {
|
||||||
|
final String publisherName;
|
||||||
|
final String projectId;
|
||||||
|
final String appId;
|
||||||
|
|
||||||
|
const AppDetailScreen({
|
||||||
|
super.key,
|
||||||
|
required this.publisherName,
|
||||||
|
required this.projectId,
|
||||||
|
required this.appId,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final tabController = useTabController(initialLength: 2);
|
||||||
|
final appData = ref.watch(
|
||||||
|
customAppProvider(publisherName, projectId, appId),
|
||||||
|
);
|
||||||
|
|
||||||
|
return AppScaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text(appData.value?.name ?? 'appDetails'.tr()),
|
||||||
|
actions: [
|
||||||
|
IconButton(
|
||||||
|
icon: const Icon(Symbols.edit),
|
||||||
|
onPressed:
|
||||||
|
appData.value == null
|
||||||
|
? null
|
||||||
|
: () {
|
||||||
|
context.pushNamed(
|
||||||
|
'developerAppEdit',
|
||||||
|
pathParameters: {
|
||||||
|
'name': publisherName,
|
||||||
|
'projectId': projectId,
|
||||||
|
'id': appId,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
bottom: TabBar(
|
||||||
|
controller: tabController,
|
||||||
|
tabs: [
|
||||||
|
Tab(
|
||||||
|
child: Text(
|
||||||
|
'overview'.tr(),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).appBarTheme.foregroundColor!,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Tab(
|
||||||
|
child: Text(
|
||||||
|
'secrets'.tr(),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).appBarTheme.foregroundColor!,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
body: appData.when(
|
||||||
|
data: (app) {
|
||||||
|
return TabBarView(
|
||||||
|
controller: tabController,
|
||||||
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
|
children: [
|
||||||
|
_AppOverview(app: app),
|
||||||
|
AppSecretsScreen(
|
||||||
|
publisherName: publisherName,
|
||||||
|
projectId: projectId,
|
||||||
|
appId: appId,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
loading: () => const Center(child: CircularProgressIndicator()),
|
||||||
|
error:
|
||||||
|
(err, stack) => ResponseErrorWidget(
|
||||||
|
error: err,
|
||||||
|
onRetry:
|
||||||
|
() => ref.invalidate(
|
||||||
|
customAppProvider(publisherName, projectId, appId),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _AppOverview extends StatelessWidget {
|
||||||
|
final CustomApp app;
|
||||||
|
const _AppOverview({required this.app});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
AspectRatio(
|
||||||
|
aspectRatio: 16 / 7,
|
||||||
|
child: Stack(
|
||||||
|
clipBehavior: Clip.none,
|
||||||
|
fit: StackFit.expand,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
color: Theme.of(context).colorScheme.surfaceContainer,
|
||||||
|
child:
|
||||||
|
app.background != null
|
||||||
|
? CloudFileWidget(
|
||||||
|
item: app.background!,
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
)
|
||||||
|
: const SizedBox.shrink(),
|
||||||
|
),
|
||||||
|
Positioned(
|
||||||
|
left: 20,
|
||||||
|
bottom: -32,
|
||||||
|
child: ProfilePictureWidget(
|
||||||
|
fileId: app.picture?.id,
|
||||||
|
radius: 40,
|
||||||
|
fallbackIcon: Symbols.apps,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
).padding(bottom: 32),
|
||||||
|
ListTile(title: Text('name'.tr()), subtitle: Text(app.name)),
|
||||||
|
ListTile(title: Text('slug'.tr()), subtitle: Text(app.slug)),
|
||||||
|
if (app.description?.isNotEmpty ?? false)
|
||||||
|
ListTile(
|
||||||
|
title: Text('description'.tr()),
|
||||||
|
subtitle: Text(app.description!),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
).padding(bottom: 24),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
252
lib/screens/developers/app_secrets.dart
Normal file
252
lib/screens/developers/app_secrets.dart
Normal file
@@ -0,0 +1,252 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:island/models/custom_app_secret.dart';
|
||||||
|
import 'package:island/pods/network.dart';
|
||||||
|
import 'package:island/services/time.dart';
|
||||||
|
import 'package:island/widgets/alert.dart';
|
||||||
|
import 'package:island/widgets/content/sheet.dart';
|
||||||
|
import 'package:island/widgets/response.dart';
|
||||||
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
|
||||||
|
part 'app_secrets.g.dart';
|
||||||
|
|
||||||
|
@riverpod
|
||||||
|
Future<List<CustomAppSecret>> customAppSecrets(
|
||||||
|
Ref ref,
|
||||||
|
String publisherName,
|
||||||
|
String projectId,
|
||||||
|
String appId,
|
||||||
|
) async {
|
||||||
|
final client = ref.watch(apiClientProvider);
|
||||||
|
final resp = await client.get(
|
||||||
|
'/develop/developers/$publisherName/projects/$projectId/apps/$appId/secrets',
|
||||||
|
);
|
||||||
|
return (resp.data as List)
|
||||||
|
.map((e) => CustomAppSecret.fromJson(e))
|
||||||
|
.cast<CustomAppSecret>()
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
class AppSecretsScreen extends HookConsumerWidget {
|
||||||
|
final String publisherName;
|
||||||
|
final String projectId;
|
||||||
|
final String appId;
|
||||||
|
|
||||||
|
const AppSecretsScreen({
|
||||||
|
super.key,
|
||||||
|
required this.publisherName,
|
||||||
|
required this.projectId,
|
||||||
|
required this.appId,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final secrets = ref.watch(
|
||||||
|
customAppSecretsProvider(publisherName, projectId, appId),
|
||||||
|
);
|
||||||
|
|
||||||
|
void showNewSecretSheet(String newSecret) {
|
||||||
|
showModalBottomSheet(
|
||||||
|
context: context,
|
||||||
|
isScrollControlled: true,
|
||||||
|
builder:
|
||||||
|
(context) => SheetScaffold(
|
||||||
|
titleText: 'newSecretGenerated'.tr(),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(20.0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Text('copySecretHint'.tr()),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.all(12),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Theme.of(context).colorScheme.surfaceContainer,
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
child: SelectableText(newSecret),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
FilledButton.icon(
|
||||||
|
onPressed: () {
|
||||||
|
Clipboard.setData(ClipboardData(text: newSecret));
|
||||||
|
},
|
||||||
|
icon: const Icon(Symbols.copy_all),
|
||||||
|
label: Text('copy'.tr()),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
).whenComplete(() {
|
||||||
|
ref.invalidate(
|
||||||
|
customAppSecretsProvider(publisherName, projectId, appId),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void createSecret() {
|
||||||
|
showModalBottomSheet(
|
||||||
|
context: context,
|
||||||
|
isScrollControlled: true,
|
||||||
|
builder: (context) {
|
||||||
|
return HookBuilder(
|
||||||
|
builder: (context) {
|
||||||
|
final descriptionController = useTextEditingController();
|
||||||
|
final expiresInController = useTextEditingController();
|
||||||
|
final isOidc = useState(false);
|
||||||
|
|
||||||
|
return SheetScaffold(
|
||||||
|
titleText: 'generateSecret'.tr(),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(20.0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
TextFormField(
|
||||||
|
controller: descriptionController,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: 'description'.tr(),
|
||||||
|
),
|
||||||
|
autofocus: true,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
TextFormField(
|
||||||
|
controller: expiresInController,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: 'expiresIn'.tr(),
|
||||||
|
),
|
||||||
|
keyboardType: TextInputType.number,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
SwitchListTile(
|
||||||
|
title: Text('isOidc'.tr()),
|
||||||
|
value: isOidc.value,
|
||||||
|
onChanged: (value) => isOidc.value = value,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
FilledButton.icon(
|
||||||
|
onPressed: () async {
|
||||||
|
final description = descriptionController.text;
|
||||||
|
final expiresIn = int.tryParse(
|
||||||
|
expiresInController.text,
|
||||||
|
);
|
||||||
|
Navigator.pop(context); // Close the sheet
|
||||||
|
try {
|
||||||
|
final client = ref.read(apiClientProvider);
|
||||||
|
final resp = await client.post(
|
||||||
|
'/develop/developers/$publisherName/projects/$projectId/apps/$appId/secrets',
|
||||||
|
data: {
|
||||||
|
'description': description,
|
||||||
|
'expires_in': expiresIn,
|
||||||
|
'is_oidc': isOidc.value,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
final newSecret = CustomAppSecret.fromJson(
|
||||||
|
resp.data,
|
||||||
|
);
|
||||||
|
if (newSecret.secret != null) {
|
||||||
|
showNewSecretSheet(newSecret.secret!);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
showErrorAlert(e.toString());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
icon: const Icon(Symbols.add),
|
||||||
|
label: Text('create'.tr()),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return secrets.when(
|
||||||
|
data: (data) {
|
||||||
|
return RefreshIndicator(
|
||||||
|
onRefresh:
|
||||||
|
() => ref.refresh(
|
||||||
|
customAppSecretsProvider(
|
||||||
|
publisherName,
|
||||||
|
projectId,
|
||||||
|
appId,
|
||||||
|
).future,
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
ListTile(
|
||||||
|
leading: const Icon(Symbols.add),
|
||||||
|
title: Text('generateSecret'.tr()),
|
||||||
|
onTap: createSecret,
|
||||||
|
),
|
||||||
|
const Divider(height: 1),
|
||||||
|
Expanded(
|
||||||
|
child: ListView.builder(
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
itemCount: data.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final secret = data[index];
|
||||||
|
return ListTile(
|
||||||
|
title: Text(secret.description ?? secret.id),
|
||||||
|
subtitle: Text(
|
||||||
|
'createdAt'.tr(args: [secret.createdAt.formatSystem()]),
|
||||||
|
),
|
||||||
|
trailing: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
IconButton(
|
||||||
|
icon: const Icon(Symbols.delete, color: Colors.red),
|
||||||
|
onPressed: () {
|
||||||
|
showConfirmAlert(
|
||||||
|
'deleteSecretHint'.tr(),
|
||||||
|
'deleteSecret'.tr(),
|
||||||
|
).then((confirm) {
|
||||||
|
if (confirm) {
|
||||||
|
final client = ref.read(apiClientProvider);
|
||||||
|
client.delete(
|
||||||
|
'/develop/developers/$publisherName/projects/$projectId/apps/$appId/secrets/${secret.id}',
|
||||||
|
);
|
||||||
|
ref.invalidate(
|
||||||
|
customAppSecretsProvider(
|
||||||
|
publisherName,
|
||||||
|
projectId,
|
||||||
|
appId,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
loading: () => const Center(child: CircularProgressIndicator()),
|
||||||
|
error:
|
||||||
|
(err, stack) => ResponseErrorWidget(
|
||||||
|
error: err,
|
||||||
|
onRetry:
|
||||||
|
() => ref.invalidate(
|
||||||
|
customAppSecretsProvider(publisherName, projectId, appId),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
188
lib/screens/developers/app_secrets.g.dart
Normal file
188
lib/screens/developers/app_secrets.g.dart
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'app_secrets.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// RiverpodGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
String _$customAppSecretsHash() => r'1bc62ad812487883ce739793b22a76168d656752';
|
||||||
|
|
||||||
|
/// Copied from Dart SDK
|
||||||
|
class _SystemHash {
|
||||||
|
_SystemHash._();
|
||||||
|
|
||||||
|
static int combine(int hash, int value) {
|
||||||
|
// ignore: parameter_assignments
|
||||||
|
hash = 0x1fffffff & (hash + value);
|
||||||
|
// ignore: parameter_assignments
|
||||||
|
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
|
||||||
|
return hash ^ (hash >> 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int finish(int hash) {
|
||||||
|
// ignore: parameter_assignments
|
||||||
|
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
|
||||||
|
// ignore: parameter_assignments
|
||||||
|
hash = hash ^ (hash >> 11);
|
||||||
|
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See also [customAppSecrets].
|
||||||
|
@ProviderFor(customAppSecrets)
|
||||||
|
const customAppSecretsProvider = CustomAppSecretsFamily();
|
||||||
|
|
||||||
|
/// See also [customAppSecrets].
|
||||||
|
class CustomAppSecretsFamily extends Family<AsyncValue<List<CustomAppSecret>>> {
|
||||||
|
/// See also [customAppSecrets].
|
||||||
|
const CustomAppSecretsFamily();
|
||||||
|
|
||||||
|
/// See also [customAppSecrets].
|
||||||
|
CustomAppSecretsProvider call(
|
||||||
|
String publisherName,
|
||||||
|
String projectId,
|
||||||
|
String appId,
|
||||||
|
) {
|
||||||
|
return CustomAppSecretsProvider(publisherName, projectId, appId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
CustomAppSecretsProvider getProviderOverride(
|
||||||
|
covariant CustomAppSecretsProvider provider,
|
||||||
|
) {
|
||||||
|
return call(provider.publisherName, provider.projectId, provider.appId);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
|
||||||
|
|
||||||
|
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
|
||||||
|
_allTransitiveDependencies;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String? get name => r'customAppSecretsProvider';
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See also [customAppSecrets].
|
||||||
|
class CustomAppSecretsProvider
|
||||||
|
extends AutoDisposeFutureProvider<List<CustomAppSecret>> {
|
||||||
|
/// See also [customAppSecrets].
|
||||||
|
CustomAppSecretsProvider(String publisherName, String projectId, String appId)
|
||||||
|
: this._internal(
|
||||||
|
(ref) => customAppSecrets(
|
||||||
|
ref as CustomAppSecretsRef,
|
||||||
|
publisherName,
|
||||||
|
projectId,
|
||||||
|
appId,
|
||||||
|
),
|
||||||
|
from: customAppSecretsProvider,
|
||||||
|
name: r'customAppSecretsProvider',
|
||||||
|
debugGetCreateSourceHash:
|
||||||
|
const bool.fromEnvironment('dart.vm.product')
|
||||||
|
? null
|
||||||
|
: _$customAppSecretsHash,
|
||||||
|
dependencies: CustomAppSecretsFamily._dependencies,
|
||||||
|
allTransitiveDependencies:
|
||||||
|
CustomAppSecretsFamily._allTransitiveDependencies,
|
||||||
|
publisherName: publisherName,
|
||||||
|
projectId: projectId,
|
||||||
|
appId: appId,
|
||||||
|
);
|
||||||
|
|
||||||
|
CustomAppSecretsProvider._internal(
|
||||||
|
super._createNotifier, {
|
||||||
|
required super.name,
|
||||||
|
required super.dependencies,
|
||||||
|
required super.allTransitiveDependencies,
|
||||||
|
required super.debugGetCreateSourceHash,
|
||||||
|
required super.from,
|
||||||
|
required this.publisherName,
|
||||||
|
required this.projectId,
|
||||||
|
required this.appId,
|
||||||
|
}) : super.internal();
|
||||||
|
|
||||||
|
final String publisherName;
|
||||||
|
final String projectId;
|
||||||
|
final String appId;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Override overrideWith(
|
||||||
|
FutureOr<List<CustomAppSecret>> Function(CustomAppSecretsRef provider)
|
||||||
|
create,
|
||||||
|
) {
|
||||||
|
return ProviderOverride(
|
||||||
|
origin: this,
|
||||||
|
override: CustomAppSecretsProvider._internal(
|
||||||
|
(ref) => create(ref as CustomAppSecretsRef),
|
||||||
|
from: from,
|
||||||
|
name: null,
|
||||||
|
dependencies: null,
|
||||||
|
allTransitiveDependencies: null,
|
||||||
|
debugGetCreateSourceHash: null,
|
||||||
|
publisherName: publisherName,
|
||||||
|
projectId: projectId,
|
||||||
|
appId: appId,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
AutoDisposeFutureProviderElement<List<CustomAppSecret>> createElement() {
|
||||||
|
return _CustomAppSecretsProviderElement(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return other is CustomAppSecretsProvider &&
|
||||||
|
other.publisherName == publisherName &&
|
||||||
|
other.projectId == projectId &&
|
||||||
|
other.appId == appId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode {
|
||||||
|
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||||
|
hash = _SystemHash.combine(hash, publisherName.hashCode);
|
||||||
|
hash = _SystemHash.combine(hash, projectId.hashCode);
|
||||||
|
hash = _SystemHash.combine(hash, appId.hashCode);
|
||||||
|
|
||||||
|
return _SystemHash.finish(hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
|
mixin CustomAppSecretsRef
|
||||||
|
on AutoDisposeFutureProviderRef<List<CustomAppSecret>> {
|
||||||
|
/// The parameter `publisherName` of this provider.
|
||||||
|
String get publisherName;
|
||||||
|
|
||||||
|
/// The parameter `projectId` of this provider.
|
||||||
|
String get projectId;
|
||||||
|
|
||||||
|
/// The parameter `appId` of this provider.
|
||||||
|
String get appId;
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CustomAppSecretsProviderElement
|
||||||
|
extends AutoDisposeFutureProviderElement<List<CustomAppSecret>>
|
||||||
|
with CustomAppSecretsRef {
|
||||||
|
_CustomAppSecretsProviderElement(super.provider);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get publisherName =>
|
||||||
|
(origin as CustomAppSecretsProvider).publisherName;
|
||||||
|
@override
|
||||||
|
String get projectId => (origin as CustomAppSecretsProvider).projectId;
|
||||||
|
@override
|
||||||
|
String get appId => (origin as CustomAppSecretsProvider).appId;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
@@ -14,6 +14,20 @@ import 'package:styled_widget/styled_widget.dart';
|
|||||||
|
|
||||||
part 'apps.g.dart';
|
part 'apps.g.dart';
|
||||||
|
|
||||||
|
@riverpod
|
||||||
|
Future<CustomApp> customApp(
|
||||||
|
Ref ref,
|
||||||
|
String publisherName,
|
||||||
|
String projectId,
|
||||||
|
String appId,
|
||||||
|
) async {
|
||||||
|
final client = ref.watch(apiClientProvider);
|
||||||
|
final resp = await client.get(
|
||||||
|
'/develop/developers/$publisherName/projects/$projectId/apps/$appId',
|
||||||
|
);
|
||||||
|
return CustomApp.fromJson(resp.data);
|
||||||
|
}
|
||||||
|
|
||||||
@riverpod
|
@riverpod
|
||||||
Future<List<CustomApp>> customApps(
|
Future<List<CustomApp>> customApps(
|
||||||
Ref ref,
|
Ref ref,
|
||||||
@@ -81,98 +95,114 @@ class CustomAppsScreen extends HookConsumerWidget {
|
|||||||
final app = data[index];
|
final app = data[index];
|
||||||
return Card(
|
return Card(
|
||||||
margin: const EdgeInsets.all(8.0),
|
margin: const EdgeInsets.all(8.0),
|
||||||
child: Column(
|
clipBehavior: Clip.antiAlias,
|
||||||
children: [
|
child: InkWell(
|
||||||
SizedBox(
|
onTap: () {
|
||||||
height: 150,
|
context.pushNamed(
|
||||||
child: Stack(
|
'developerAppDetail',
|
||||||
fit: StackFit.expand,
|
pathParameters: {
|
||||||
children: [
|
'name': publisherName,
|
||||||
if (app.background != null)
|
'projectId': projectId,
|
||||||
CloudFileWidget(
|
'appId': app.id,
|
||||||
item: app.background!,
|
},
|
||||||
fit: BoxFit.cover,
|
);
|
||||||
).clipRRect(topLeft: 8, topRight: 8),
|
},
|
||||||
if (app.picture != null)
|
child: Column(
|
||||||
Positioned(
|
children: [
|
||||||
left: 16,
|
SizedBox(
|
||||||
bottom: 16,
|
height: 150,
|
||||||
child: ProfilePictureWidget(
|
child: Stack(
|
||||||
fileId: app.picture!.id,
|
fit: StackFit.expand,
|
||||||
radius: 40,
|
children: [
|
||||||
fallbackIcon: Symbols.apps,
|
if (app.background != null)
|
||||||
),
|
CloudFileWidget(
|
||||||
),
|
item: app.background!,
|
||||||
],
|
fit: BoxFit.cover,
|
||||||
),
|
).clipRRect(topLeft: 8, topRight: 8),
|
||||||
),
|
if (app.picture != null)
|
||||||
ListTile(
|
Positioned(
|
||||||
title: Text(app.name),
|
left: 16,
|
||||||
subtitle: Text(
|
bottom: 16,
|
||||||
app.slug,
|
child: ProfilePictureWidget(
|
||||||
style: GoogleFonts.robotoMono(fontSize: 12),
|
fileId: app.picture!.id,
|
||||||
),
|
radius: 40,
|
||||||
contentPadding: EdgeInsets.only(left: 20, right: 12),
|
fallbackIcon: Symbols.apps,
|
||||||
trailing: PopupMenuButton(
|
|
||||||
itemBuilder:
|
|
||||||
(context) => [
|
|
||||||
PopupMenuItem(
|
|
||||||
value: 'edit',
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
const Icon(Symbols.edit),
|
|
||||||
const SizedBox(width: 12),
|
|
||||||
Text('edit').tr(),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
PopupMenuItem(
|
],
|
||||||
value: 'delete',
|
),
|
||||||
child: Row(
|
),
|
||||||
children: [
|
ListTile(
|
||||||
const Icon(
|
title: Text(app.name),
|
||||||
Symbols.delete,
|
subtitle: Text(
|
||||||
color: Colors.red,
|
app.slug,
|
||||||
|
style: GoogleFonts.robotoMono(fontSize: 12),
|
||||||
|
),
|
||||||
|
contentPadding: EdgeInsets.only(left: 20, right: 12),
|
||||||
|
trailing: PopupMenuButton(
|
||||||
|
itemBuilder:
|
||||||
|
(context) => [
|
||||||
|
PopupMenuItem(
|
||||||
|
value: 'edit',
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
const Icon(Symbols.edit),
|
||||||
|
const SizedBox(width: 12),
|
||||||
|
Text('edit').tr(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
PopupMenuItem(
|
||||||
|
value: 'delete',
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
const Icon(
|
||||||
|
Symbols.delete,
|
||||||
|
color: Colors.red,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 12),
|
||||||
|
Text(
|
||||||
|
'delete',
|
||||||
|
style: TextStyle(color: Colors.red),
|
||||||
|
).tr(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
onSelected: (value) {
|
||||||
|
if (value == 'edit') {
|
||||||
|
context.pushNamed(
|
||||||
|
'developerAppEdit',
|
||||||
|
pathParameters: {
|
||||||
|
'name': publisherName,
|
||||||
|
'projectId': projectId,
|
||||||
|
'id': app.id,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} else if (value == 'delete') {
|
||||||
|
showConfirmAlert(
|
||||||
|
'deleteCustomAppHint'.tr(),
|
||||||
|
'deleteCustomApp'.tr(),
|
||||||
|
).then((confirm) {
|
||||||
|
if (confirm) {
|
||||||
|
final client = ref.read(apiClientProvider);
|
||||||
|
client.delete(
|
||||||
|
'/develop/developers/$publisherName/projects/$projectId/apps/${app.id}',
|
||||||
|
);
|
||||||
|
ref.invalidate(
|
||||||
|
customAppsProvider(
|
||||||
|
publisherName,
|
||||||
|
projectId,
|
||||||
),
|
),
|
||||||
const SizedBox(width: 12),
|
);
|
||||||
Text(
|
}
|
||||||
'delete',
|
});
|
||||||
style: TextStyle(color: Colors.red),
|
}
|
||||||
).tr(),
|
},
|
||||||
],
|
),
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
onSelected: (value) {
|
|
||||||
if (value == 'edit') {
|
|
||||||
context.pushNamed(
|
|
||||||
'developerAppEdit',
|
|
||||||
pathParameters: {
|
|
||||||
'name': publisherName,
|
|
||||||
'projectId': projectId,
|
|
||||||
'id': app.id,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
} else if (value == 'delete') {
|
|
||||||
showConfirmAlert(
|
|
||||||
'deleteCustomAppHint'.tr(),
|
|
||||||
'deleteCustomApp'.tr(),
|
|
||||||
).then((confirm) {
|
|
||||||
if (confirm) {
|
|
||||||
final client = ref.read(apiClientProvider);
|
|
||||||
client.delete(
|
|
||||||
'/develop/developers/$publisherName/projects/$projectId/apps/${app.id}',
|
|
||||||
);
|
|
||||||
ref.invalidate(
|
|
||||||
customAppsProvider(publisherName, projectId),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
],
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@@ -6,7 +6,7 @@ part of 'apps.dart';
|
|||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$customAppsHash() => r'450bedaf4220b8963cb44afeb14d4c0e80f01b11';
|
String _$customAppHash() => r'be05431ba8bf06fd20ee988a61c3663a68e15fc9';
|
||||||
|
|
||||||
/// Copied from Dart SDK
|
/// Copied from Dart SDK
|
||||||
class _SystemHash {
|
class _SystemHash {
|
||||||
@@ -29,6 +29,148 @@ class _SystemHash {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// See also [customApp].
|
||||||
|
@ProviderFor(customApp)
|
||||||
|
const customAppProvider = CustomAppFamily();
|
||||||
|
|
||||||
|
/// See also [customApp].
|
||||||
|
class CustomAppFamily extends Family<AsyncValue<CustomApp>> {
|
||||||
|
/// See also [customApp].
|
||||||
|
const CustomAppFamily();
|
||||||
|
|
||||||
|
/// See also [customApp].
|
||||||
|
CustomAppProvider call(String publisherName, String projectId, String appId) {
|
||||||
|
return CustomAppProvider(publisherName, projectId, appId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
CustomAppProvider getProviderOverride(covariant CustomAppProvider provider) {
|
||||||
|
return call(provider.publisherName, provider.projectId, provider.appId);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
|
||||||
|
|
||||||
|
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
|
||||||
|
_allTransitiveDependencies;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String? get name => r'customAppProvider';
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See also [customApp].
|
||||||
|
class CustomAppProvider extends AutoDisposeFutureProvider<CustomApp> {
|
||||||
|
/// See also [customApp].
|
||||||
|
CustomAppProvider(String publisherName, String projectId, String appId)
|
||||||
|
: this._internal(
|
||||||
|
(ref) =>
|
||||||
|
customApp(ref as CustomAppRef, publisherName, projectId, appId),
|
||||||
|
from: customAppProvider,
|
||||||
|
name: r'customAppProvider',
|
||||||
|
debugGetCreateSourceHash:
|
||||||
|
const bool.fromEnvironment('dart.vm.product')
|
||||||
|
? null
|
||||||
|
: _$customAppHash,
|
||||||
|
dependencies: CustomAppFamily._dependencies,
|
||||||
|
allTransitiveDependencies: CustomAppFamily._allTransitiveDependencies,
|
||||||
|
publisherName: publisherName,
|
||||||
|
projectId: projectId,
|
||||||
|
appId: appId,
|
||||||
|
);
|
||||||
|
|
||||||
|
CustomAppProvider._internal(
|
||||||
|
super._createNotifier, {
|
||||||
|
required super.name,
|
||||||
|
required super.dependencies,
|
||||||
|
required super.allTransitiveDependencies,
|
||||||
|
required super.debugGetCreateSourceHash,
|
||||||
|
required super.from,
|
||||||
|
required this.publisherName,
|
||||||
|
required this.projectId,
|
||||||
|
required this.appId,
|
||||||
|
}) : super.internal();
|
||||||
|
|
||||||
|
final String publisherName;
|
||||||
|
final String projectId;
|
||||||
|
final String appId;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Override overrideWith(
|
||||||
|
FutureOr<CustomApp> Function(CustomAppRef provider) create,
|
||||||
|
) {
|
||||||
|
return ProviderOverride(
|
||||||
|
origin: this,
|
||||||
|
override: CustomAppProvider._internal(
|
||||||
|
(ref) => create(ref as CustomAppRef),
|
||||||
|
from: from,
|
||||||
|
name: null,
|
||||||
|
dependencies: null,
|
||||||
|
allTransitiveDependencies: null,
|
||||||
|
debugGetCreateSourceHash: null,
|
||||||
|
publisherName: publisherName,
|
||||||
|
projectId: projectId,
|
||||||
|
appId: appId,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
AutoDisposeFutureProviderElement<CustomApp> createElement() {
|
||||||
|
return _CustomAppProviderElement(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return other is CustomAppProvider &&
|
||||||
|
other.publisherName == publisherName &&
|
||||||
|
other.projectId == projectId &&
|
||||||
|
other.appId == appId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode {
|
||||||
|
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||||
|
hash = _SystemHash.combine(hash, publisherName.hashCode);
|
||||||
|
hash = _SystemHash.combine(hash, projectId.hashCode);
|
||||||
|
hash = _SystemHash.combine(hash, appId.hashCode);
|
||||||
|
|
||||||
|
return _SystemHash.finish(hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
|
mixin CustomAppRef on AutoDisposeFutureProviderRef<CustomApp> {
|
||||||
|
/// The parameter `publisherName` of this provider.
|
||||||
|
String get publisherName;
|
||||||
|
|
||||||
|
/// The parameter `projectId` of this provider.
|
||||||
|
String get projectId;
|
||||||
|
|
||||||
|
/// The parameter `appId` of this provider.
|
||||||
|
String get appId;
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CustomAppProviderElement
|
||||||
|
extends AutoDisposeFutureProviderElement<CustomApp>
|
||||||
|
with CustomAppRef {
|
||||||
|
_CustomAppProviderElement(super.provider);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get publisherName => (origin as CustomAppProvider).publisherName;
|
||||||
|
@override
|
||||||
|
String get projectId => (origin as CustomAppProvider).projectId;
|
||||||
|
@override
|
||||||
|
String get appId => (origin as CustomAppProvider).appId;
|
||||||
|
}
|
||||||
|
|
||||||
|
String _$customAppsHash() => r'450bedaf4220b8963cb44afeb14d4c0e80f01b11';
|
||||||
|
|
||||||
/// See also [customApps].
|
/// See also [customApps].
|
||||||
@ProviderFor(customApps)
|
@ProviderFor(customApps)
|
||||||
const customAppsProvider = CustomAppsFamily();
|
const customAppsProvider = CustomAppsFamily();
|
||||||
|
@@ -52,7 +52,26 @@ class BotDetailScreen extends HookConsumerWidget {
|
|||||||
],
|
],
|
||||||
bottom: TabBar(
|
bottom: TabBar(
|
||||||
controller: tabController,
|
controller: tabController,
|
||||||
tabs: [Tab(text: 'overview'.tr()), Tab(text: 'keys'.tr())],
|
tabs: [
|
||||||
|
Tab(
|
||||||
|
child: Text(
|
||||||
|
'overview'.tr(),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).appBarTheme.foregroundColor!,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Tab(
|
||||||
|
child: Text(
|
||||||
|
'keys'.tr(),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).appBarTheme.foregroundColor!,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
body: botData.when(
|
body: botData.when(
|
||||||
|
@@ -297,16 +297,24 @@ class EditAppScreen extends HookConsumerWidget {
|
|||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
};
|
};
|
||||||
if (isNew) {
|
try {
|
||||||
await client.post(
|
showLoadingModal(context);
|
||||||
'/develop/developers/$publisherName/projects/$projectId/apps',
|
if (isNew) {
|
||||||
data: data,
|
await client.post(
|
||||||
);
|
'/develop/developers/$publisherName/projects/$projectId/apps',
|
||||||
} else {
|
data: data,
|
||||||
await client.patch(
|
);
|
||||||
'/develop/developers/$publisherName/projects/$projectId/apps/$id',
|
} else {
|
||||||
data: data,
|
await client.patch(
|
||||||
);
|
'/develop/developers/$publisherName/projects/$projectId/apps/$id',
|
||||||
|
data: data,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
showErrorAlert(err);
|
||||||
|
return;
|
||||||
|
} finally {
|
||||||
|
if (context.mounted) hideLoadingModal(context);
|
||||||
}
|
}
|
||||||
ref.invalidate(customAppsProvider(publisherName, projectId));
|
ref.invalidate(customAppsProvider(publisherName, projectId));
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
|
@@ -58,7 +58,26 @@ class ProjectDetailScreen extends HookConsumerWidget {
|
|||||||
],
|
],
|
||||||
bottom: TabBar(
|
bottom: TabBar(
|
||||||
controller: tabController,
|
controller: tabController,
|
||||||
tabs: [Tab(text: 'customApps'.tr()), Tab(text: 'bots'.tr())],
|
tabs: [
|
||||||
|
Tab(
|
||||||
|
child: Text(
|
||||||
|
'customApps'.tr(),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).appBarTheme.foregroundColor!,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Tab(
|
||||||
|
child: Text(
|
||||||
|
'bots'.tr(),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).appBarTheme.foregroundColor!,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
body: TabBarView(
|
body: TabBarView(
|
||||||
|
@@ -101,7 +101,7 @@ class SliverArticlesList extends ConsumerWidget {
|
|||||||
publisherId: publisherId,
|
publisherId: publisherId,
|
||||||
).notifier,
|
).notifier,
|
||||||
contentBuilder:
|
contentBuilder:
|
||||||
(data, widgetCount, endItemView) => SliverList.builder(
|
(data, widgetCount, endItemView) => SliverList.separated(
|
||||||
itemCount: widgetCount,
|
itemCount: widgetCount,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
if (index == widgetCount - 1) {
|
if (index == widgetCount - 1) {
|
||||||
@@ -111,38 +111,116 @@ class SliverArticlesList extends ConsumerWidget {
|
|||||||
final article = data.items[index];
|
final article = data.items[index];
|
||||||
return WebArticleCard(article: article, showDetails: true);
|
return WebArticleCard(article: article, showDetails: true);
|
||||||
},
|
},
|
||||||
|
separatorBuilder: (context, index) => const SizedBox(height: 12),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@riverpod
|
||||||
|
Future<List<SnWebFeed>> subscribedFeeds(Ref ref) async {
|
||||||
|
final client = ref.watch(apiClientProvider);
|
||||||
|
final response = await client.get('/sphere/feeds/subscribed');
|
||||||
|
final data = response.data as List<dynamic>;
|
||||||
|
return data.map((json) => SnWebFeed.fromJson(json)).toList();
|
||||||
|
}
|
||||||
|
|
||||||
class ArticlesScreen extends ConsumerWidget {
|
class ArticlesScreen extends ConsumerWidget {
|
||||||
final String? feedId;
|
const ArticlesScreen({super.key});
|
||||||
final String? publisherId;
|
|
||||||
final String? title;
|
|
||||||
|
|
||||||
const ArticlesScreen({super.key, this.feedId, this.publisherId, this.title});
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
return AppScaffold(
|
final subscribedFeedsAsync = ref.watch(subscribedFeedsProvider);
|
||||||
appBar: AppBar(title: Text(title ?? 'Articles')),
|
|
||||||
body: Center(
|
return subscribedFeedsAsync.when(
|
||||||
child: ConstrainedBox(
|
data: (feeds) {
|
||||||
constraints: const BoxConstraints(maxWidth: 560),
|
return DefaultTabController(
|
||||||
child: CustomScrollView(
|
length: feeds.length + 1,
|
||||||
slivers: [
|
child: AppScaffold(
|
||||||
SliverPadding(
|
isNoBackground: false,
|
||||||
padding: const EdgeInsets.only(top: 8, left: 8, right: 8),
|
appBar: AppBar(
|
||||||
sliver: SliverArticlesList(
|
title: const Text('Articles'),
|
||||||
feedId: feedId,
|
bottom: TabBar(
|
||||||
publisherId: publisherId,
|
isScrollable: true,
|
||||||
),
|
tabs: [
|
||||||
|
Tab(
|
||||||
|
child: Text(
|
||||||
|
'All',
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).appBarTheme.foregroundColor!,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
...feeds.map(
|
||||||
|
(feed) => Tab(
|
||||||
|
child: Text(
|
||||||
|
feed.title,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).appBarTheme.foregroundColor!,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
|
body: TabBarView(
|
||||||
|
children: [
|
||||||
|
Center(
|
||||||
|
child: ConstrainedBox(
|
||||||
|
constraints: const BoxConstraints(maxWidth: 560),
|
||||||
|
child: CustomScrollView(
|
||||||
|
slivers: [
|
||||||
|
SliverPadding(
|
||||||
|
padding: const EdgeInsets.only(
|
||||||
|
top: 12,
|
||||||
|
left: 8,
|
||||||
|
right: 8,
|
||||||
|
),
|
||||||
|
sliver: SliverArticlesList(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
...feeds.map((feed) {
|
||||||
|
return Center(
|
||||||
|
child: ConstrainedBox(
|
||||||
|
constraints: const BoxConstraints(maxWidth: 560),
|
||||||
|
child: CustomScrollView(
|
||||||
|
slivers: [
|
||||||
|
SliverPadding(
|
||||||
|
padding: const EdgeInsets.only(
|
||||||
|
top: 8,
|
||||||
|
left: 8,
|
||||||
|
right: 8,
|
||||||
|
),
|
||||||
|
sliver: SliverArticlesList(feedId: feed.id),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
loading:
|
||||||
|
() => AppScaffold(
|
||||||
|
isNoBackground: false,
|
||||||
|
appBar: AppBar(title: const Text('Articles')),
|
||||||
|
body: const Center(child: CircularProgressIndicator()),
|
||||||
|
),
|
||||||
|
error:
|
||||||
|
(err, stack) => AppScaffold(
|
||||||
|
isNoBackground: false,
|
||||||
|
appBar: AppBar(title: const Text('Articles')),
|
||||||
|
body: Center(child: Text('Error: $err')),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -6,6 +6,25 @@ part of 'articles.dart';
|
|||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
|
String _$subscribedFeedsHash() => r'5c0c8c30c5f543f6ea1d39786a6778f77ba5b3df';
|
||||||
|
|
||||||
|
/// See also [subscribedFeeds].
|
||||||
|
@ProviderFor(subscribedFeeds)
|
||||||
|
final subscribedFeedsProvider =
|
||||||
|
AutoDisposeFutureProvider<List<SnWebFeed>>.internal(
|
||||||
|
subscribedFeeds,
|
||||||
|
name: r'subscribedFeedsProvider',
|
||||||
|
debugGetCreateSourceHash:
|
||||||
|
const bool.fromEnvironment('dart.vm.product')
|
||||||
|
? null
|
||||||
|
: _$subscribedFeedsHash,
|
||||||
|
dependencies: null,
|
||||||
|
allTransitiveDependencies: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
|
typedef SubscribedFeedsRef = AutoDisposeFutureProviderRef<List<SnWebFeed>>;
|
||||||
String _$articlesListNotifierHash() =>
|
String _$articlesListNotifierHash() =>
|
||||||
r'579741af4d90c7c81f2e2697e57c4895b7a9dabc';
|
r'579741af4d90c7c81f2e2697e57c4895b7a9dabc';
|
||||||
|
|
||||||
|
@@ -1,27 +1,75 @@
|
|||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:island/models/webfeed.dart';
|
import 'package:island/models/webfeed.dart';
|
||||||
import 'package:island/pods/network.dart';
|
import 'package:island/pods/network.dart';
|
||||||
import 'package:island/widgets/alert.dart';
|
import 'package:island/widgets/alert.dart';
|
||||||
import 'package:island/widgets/app_scaffold.dart';
|
import 'package:island/widgets/app_scaffold.dart';
|
||||||
|
import 'package:island/widgets/web_article_card.dart';
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
import 'package:riverpod_paging_utils/riverpod_paging_utils.dart';
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
|
|
||||||
part 'feed_detail.g.dart';
|
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');
|
||||||
|
return SnWebFeed.fromJson(resp.data);
|
||||||
|
}
|
||||||
|
|
||||||
/// Provider for web feed articles content
|
/// Provider for web feed articles content
|
||||||
@riverpod
|
@riverpod
|
||||||
Future<List<SnWebArticle>> marketplaceWebFeedContent(
|
class MarketplaceWebFeedContentNotifier
|
||||||
Ref ref, {
|
extends _$MarketplaceWebFeedContentNotifier
|
||||||
required String feedId,
|
with CursorPagingNotifierMixin<SnWebArticle> {
|
||||||
}) async {
|
static const int _pageSize = 20;
|
||||||
final apiClient = ref.watch(apiClientProvider);
|
|
||||||
final resp = await apiClient.get('/sphere/feeds/$feedId/articles');
|
@override
|
||||||
return (resp.data as List).map((e) => SnWebArticle.fromJson(e)).toList();
|
Future<CursorPagingData<SnWebArticle>> build(String feedId) async {
|
||||||
|
_feedId = feedId;
|
||||||
|
return fetch(cursor: null);
|
||||||
|
}
|
||||||
|
|
||||||
|
late final String _feedId;
|
||||||
|
ValueNotifier<int> totalCount = ValueNotifier(0);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<CursorPagingData<SnWebArticle>> fetch({
|
||||||
|
required String? cursor,
|
||||||
|
}) async {
|
||||||
|
final client = ref.read(apiClientProvider);
|
||||||
|
final offset = cursor == null ? 0 : int.parse(cursor);
|
||||||
|
|
||||||
|
final queryParams = {'offset': offset, 'take': _pageSize};
|
||||||
|
|
||||||
|
final response = await client.get(
|
||||||
|
'/sphere/feeds/$_feedId/articles',
|
||||||
|
queryParameters: queryParams,
|
||||||
|
);
|
||||||
|
final total = int.parse(response.headers.value('X-Total') ?? '0');
|
||||||
|
totalCount.value = total;
|
||||||
|
final List<dynamic> data = response.data;
|
||||||
|
final articles = data.map((json) => SnWebArticle.fromJson(json)).toList();
|
||||||
|
|
||||||
|
final hasMore = offset + articles.length < total;
|
||||||
|
final nextCursor = hasMore ? (offset + articles.length).toString() : null;
|
||||||
|
|
||||||
|
return CursorPagingData(
|
||||||
|
items: articles,
|
||||||
|
hasMore: hasMore,
|
||||||
|
nextCursor: nextCursor,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dispose() {
|
||||||
|
totalCount.dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Provider for web feed subscription status
|
/// Provider for web feed subscription status
|
||||||
@@ -49,11 +97,7 @@ class MarketplaceWebFeedDetailScreen extends HookConsumerWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
// TODO: Need to create a web feed provider similar to stickerPackProvider
|
final feed = ref.watch(marketplaceWebFeedProvider(id));
|
||||||
// For now, we'll fetch the feed directly
|
|
||||||
final feedContent = ref.watch(
|
|
||||||
marketplaceWebFeedContentProvider(feedId: id),
|
|
||||||
);
|
|
||||||
final subscribed = ref.watch(
|
final subscribed = ref.watch(
|
||||||
marketplaceWebFeedSubscriptionProvider(feedId: id),
|
marketplaceWebFeedSubscriptionProvider(feedId: id),
|
||||||
);
|
);
|
||||||
@@ -65,7 +109,7 @@ class MarketplaceWebFeedDetailScreen extends HookConsumerWidget {
|
|||||||
HapticFeedback.selectionClick();
|
HapticFeedback.selectionClick();
|
||||||
ref.invalidate(marketplaceWebFeedSubscriptionProvider(feedId: id));
|
ref.invalidate(marketplaceWebFeedSubscriptionProvider(feedId: id));
|
||||||
if (!context.mounted) return;
|
if (!context.mounted) return;
|
||||||
showSnackBar('feedSubscribed'.tr());
|
showSnackBar('webFeedSubscribed'.tr());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unsubscribe from web feed
|
// Unsubscribe from web feed
|
||||||
@@ -75,86 +119,94 @@ class MarketplaceWebFeedDetailScreen extends HookConsumerWidget {
|
|||||||
HapticFeedback.selectionClick();
|
HapticFeedback.selectionClick();
|
||||||
ref.invalidate(marketplaceWebFeedSubscriptionProvider(feedId: id));
|
ref.invalidate(marketplaceWebFeedSubscriptionProvider(feedId: id));
|
||||||
if (!context.mounted) return;
|
if (!context.mounted) return;
|
||||||
showSnackBar('feedUnsubscribed'.tr());
|
showSnackBar('webFeedUnsubscribed'.tr());
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Replace with actual feed data provider once created
|
final feedNotifier = ref.watch(
|
||||||
final dummyFeed = SnWebFeed(
|
marketplaceWebFeedContentNotifierProvider(id).notifier,
|
||||||
id: id,
|
|
||||||
url: 'https://example.com',
|
|
||||||
title: 'Loading...',
|
|
||||||
publisherId: 'publisher-id',
|
|
||||||
createdAt: DateTime.now(),
|
|
||||||
updatedAt: DateTime.now(),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
useEffect(() {
|
||||||
|
return feedNotifier.dispose;
|
||||||
|
}, []);
|
||||||
|
|
||||||
return AppScaffold(
|
return AppScaffold(
|
||||||
appBar: AppBar(title: Text(dummyFeed.title)),
|
appBar: AppBar(title: Text(feed.value?.title ?? 'loading'.tr())),
|
||||||
body: Column(
|
body: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: [
|
children: [
|
||||||
// Feed meta
|
// Feed meta
|
||||||
Column(
|
feed
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
.when(
|
||||||
children: [
|
data:
|
||||||
Text(dummyFeed.description ?? ''),
|
(data) => Column(
|
||||||
Row(
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
spacing: 4,
|
children: [
|
||||||
children: [
|
Text(data.description ?? 'descriptionNone'.tr()),
|
||||||
const Icon(Symbols.rss_feed, size: 16),
|
Row(
|
||||||
Text('${feedContent.value?.length ?? 0} articles'),
|
spacing: 4,
|
||||||
],
|
children: [
|
||||||
).opacity(0.85),
|
const Icon(Symbols.rss_feed, size: 16),
|
||||||
Row(
|
ListenableBuilder(
|
||||||
spacing: 4,
|
listenable: feedNotifier.totalCount,
|
||||||
children: [
|
builder:
|
||||||
const Icon(Symbols.link, size: 16),
|
(context, _) => Text(
|
||||||
SelectableText(dummyFeed.url),
|
'webFeedArticleCount'.plural(
|
||||||
],
|
feedNotifier.totalCount.value,
|
||||||
).opacity(0.85),
|
),
|
||||||
],
|
),
|
||||||
).padding(horizontal: 24, vertical: 24),
|
),
|
||||||
|
],
|
||||||
|
).opacity(0.85),
|
||||||
|
Row(
|
||||||
|
spacing: 4,
|
||||||
|
children: [
|
||||||
|
const Icon(Symbols.link, size: 16),
|
||||||
|
SelectableText(data.url),
|
||||||
|
],
|
||||||
|
).opacity(0.85),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
error: (err, _) => Text(err.toString()),
|
||||||
|
loading: () => CircularProgressIndicator().center(),
|
||||||
|
)
|
||||||
|
.padding(horizontal: 24, vertical: 24),
|
||||||
const Divider(height: 1),
|
const Divider(height: 1),
|
||||||
// Articles list
|
// Articles list
|
||||||
Expanded(
|
Expanded(
|
||||||
child: feedContent.when(
|
child: PagingHelperView(
|
||||||
data:
|
provider: marketplaceWebFeedContentNotifierProvider(id),
|
||||||
(articles) => RefreshIndicator(
|
futureRefreshable:
|
||||||
onRefresh:
|
marketplaceWebFeedContentNotifierProvider(id).future,
|
||||||
() => ref.refresh(
|
notifierRefreshable:
|
||||||
marketplaceWebFeedContentProvider(feedId: id).future,
|
marketplaceWebFeedContentNotifierProvider(id).notifier,
|
||||||
),
|
contentBuilder:
|
||||||
child: ListView.builder(
|
(data, widgetCount, endItemView) => ListView.separated(
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
horizontal: 24,
|
horizontal: 24,
|
||||||
vertical: 20,
|
vertical: 20,
|
||||||
),
|
|
||||||
itemCount: articles.length,
|
|
||||||
itemBuilder: (context, index) {
|
|
||||||
final article = articles[index];
|
|
||||||
return Card(
|
|
||||||
child: ListTile(
|
|
||||||
title: Text(article.title),
|
|
||||||
subtitle: Text(article.author ?? ''),
|
|
||||||
trailing: const Icon(Symbols.open_in_new),
|
|
||||||
onTap: () {
|
|
||||||
// TODO: Navigate to article detail or open URL
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
|
itemCount: widgetCount,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
if (index == widgetCount - 1) {
|
||||||
|
return endItemView;
|
||||||
|
}
|
||||||
|
|
||||||
|
final article = data.items[index];
|
||||||
|
return WebArticleCard(article: article);
|
||||||
|
},
|
||||||
|
separatorBuilder: (context, index) => const Gap(12),
|
||||||
),
|
),
|
||||||
error:
|
|
||||||
(err, _) =>
|
|
||||||
Text(
|
|
||||||
'Error: $err',
|
|
||||||
).textAlignment(TextAlign.center).center(),
|
|
||||||
loading: () => const CircularProgressIndicator().center(),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Padding(
|
Container(
|
||||||
padding: EdgeInsets.symmetric(horizontal: 24, vertical: 8),
|
padding: EdgeInsets.only(
|
||||||
|
bottom: 16 + MediaQuery.of(context).padding.bottom,
|
||||||
|
left: 24,
|
||||||
|
right: 24,
|
||||||
|
top: 16,
|
||||||
|
),
|
||||||
|
color: Theme.of(context).colorScheme.surfaceContainer,
|
||||||
child: subscribed.when(
|
child: subscribed.when(
|
||||||
data:
|
data:
|
||||||
(isSubscribed) => FilledButton.icon(
|
(isSubscribed) => FilledButton.icon(
|
||||||
@@ -181,7 +233,6 @@ class MarketplaceWebFeedDetailScreen extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Gap(MediaQuery.of(context).padding.bottom),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@@ -6,8 +6,8 @@ part of 'feed_detail.dart';
|
|||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$marketplaceWebFeedContentHash() =>
|
String _$marketplaceWebFeedHash() =>
|
||||||
r'4e65350bff4055302e15ec14266cdebb1cd89bbe';
|
r'8383f94f1bc272b903c341b8d95000313b69d14c';
|
||||||
|
|
||||||
/// Copied from Dart SDK
|
/// Copied from Dart SDK
|
||||||
class _SystemHash {
|
class _SystemHash {
|
||||||
@@ -30,34 +30,25 @@ class _SystemHash {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Provider for web feed articles content
|
/// See also [marketplaceWebFeed].
|
||||||
///
|
@ProviderFor(marketplaceWebFeed)
|
||||||
/// Copied from [marketplaceWebFeedContent].
|
const marketplaceWebFeedProvider = MarketplaceWebFeedFamily();
|
||||||
@ProviderFor(marketplaceWebFeedContent)
|
|
||||||
const marketplaceWebFeedContentProvider = MarketplaceWebFeedContentFamily();
|
|
||||||
|
|
||||||
/// Provider for web feed articles content
|
/// See also [marketplaceWebFeed].
|
||||||
///
|
class MarketplaceWebFeedFamily extends Family<AsyncValue<SnWebFeed>> {
|
||||||
/// Copied from [marketplaceWebFeedContent].
|
/// See also [marketplaceWebFeed].
|
||||||
class MarketplaceWebFeedContentFamily
|
const MarketplaceWebFeedFamily();
|
||||||
extends Family<AsyncValue<List<SnWebArticle>>> {
|
|
||||||
/// Provider for web feed articles content
|
|
||||||
///
|
|
||||||
/// Copied from [marketplaceWebFeedContent].
|
|
||||||
const MarketplaceWebFeedContentFamily();
|
|
||||||
|
|
||||||
/// Provider for web feed articles content
|
/// See also [marketplaceWebFeed].
|
||||||
///
|
MarketplaceWebFeedProvider call(String feedId) {
|
||||||
/// Copied from [marketplaceWebFeedContent].
|
return MarketplaceWebFeedProvider(feedId);
|
||||||
MarketplaceWebFeedContentProvider call({required String feedId}) {
|
|
||||||
return MarketplaceWebFeedContentProvider(feedId: feedId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
MarketplaceWebFeedContentProvider getProviderOverride(
|
MarketplaceWebFeedProvider getProviderOverride(
|
||||||
covariant MarketplaceWebFeedContentProvider provider,
|
covariant MarketplaceWebFeedProvider provider,
|
||||||
) {
|
) {
|
||||||
return call(feedId: provider.feedId);
|
return call(provider.feedId);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||||
@@ -72,36 +63,28 @@ class MarketplaceWebFeedContentFamily
|
|||||||
_allTransitiveDependencies;
|
_allTransitiveDependencies;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String? get name => r'marketplaceWebFeedContentProvider';
|
String? get name => r'marketplaceWebFeedProvider';
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Provider for web feed articles content
|
/// See also [marketplaceWebFeed].
|
||||||
///
|
class MarketplaceWebFeedProvider extends AutoDisposeFutureProvider<SnWebFeed> {
|
||||||
/// Copied from [marketplaceWebFeedContent].
|
/// See also [marketplaceWebFeed].
|
||||||
class MarketplaceWebFeedContentProvider
|
MarketplaceWebFeedProvider(String feedId)
|
||||||
extends AutoDisposeFutureProvider<List<SnWebArticle>> {
|
|
||||||
/// Provider for web feed articles content
|
|
||||||
///
|
|
||||||
/// Copied from [marketplaceWebFeedContent].
|
|
||||||
MarketplaceWebFeedContentProvider({required String feedId})
|
|
||||||
: this._internal(
|
: this._internal(
|
||||||
(ref) => marketplaceWebFeedContent(
|
(ref) => marketplaceWebFeed(ref as MarketplaceWebFeedRef, feedId),
|
||||||
ref as MarketplaceWebFeedContentRef,
|
from: marketplaceWebFeedProvider,
|
||||||
feedId: feedId,
|
name: r'marketplaceWebFeedProvider',
|
||||||
),
|
|
||||||
from: marketplaceWebFeedContentProvider,
|
|
||||||
name: r'marketplaceWebFeedContentProvider',
|
|
||||||
debugGetCreateSourceHash:
|
debugGetCreateSourceHash:
|
||||||
const bool.fromEnvironment('dart.vm.product')
|
const bool.fromEnvironment('dart.vm.product')
|
||||||
? null
|
? null
|
||||||
: _$marketplaceWebFeedContentHash,
|
: _$marketplaceWebFeedHash,
|
||||||
dependencies: MarketplaceWebFeedContentFamily._dependencies,
|
dependencies: MarketplaceWebFeedFamily._dependencies,
|
||||||
allTransitiveDependencies:
|
allTransitiveDependencies:
|
||||||
MarketplaceWebFeedContentFamily._allTransitiveDependencies,
|
MarketplaceWebFeedFamily._allTransitiveDependencies,
|
||||||
feedId: feedId,
|
feedId: feedId,
|
||||||
);
|
);
|
||||||
|
|
||||||
MarketplaceWebFeedContentProvider._internal(
|
MarketplaceWebFeedProvider._internal(
|
||||||
super._createNotifier, {
|
super._createNotifier, {
|
||||||
required super.name,
|
required super.name,
|
||||||
required super.dependencies,
|
required super.dependencies,
|
||||||
@@ -115,13 +98,12 @@ class MarketplaceWebFeedContentProvider
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Override overrideWith(
|
Override overrideWith(
|
||||||
FutureOr<List<SnWebArticle>> Function(MarketplaceWebFeedContentRef provider)
|
FutureOr<SnWebFeed> Function(MarketplaceWebFeedRef provider) create,
|
||||||
create,
|
|
||||||
) {
|
) {
|
||||||
return ProviderOverride(
|
return ProviderOverride(
|
||||||
origin: this,
|
origin: this,
|
||||||
override: MarketplaceWebFeedContentProvider._internal(
|
override: MarketplaceWebFeedProvider._internal(
|
||||||
(ref) => create(ref as MarketplaceWebFeedContentRef),
|
(ref) => create(ref as MarketplaceWebFeedRef),
|
||||||
from: from,
|
from: from,
|
||||||
name: null,
|
name: null,
|
||||||
dependencies: null,
|
dependencies: null,
|
||||||
@@ -133,13 +115,13 @@ class MarketplaceWebFeedContentProvider
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
AutoDisposeFutureProviderElement<List<SnWebArticle>> createElement() {
|
AutoDisposeFutureProviderElement<SnWebFeed> createElement() {
|
||||||
return _MarketplaceWebFeedContentProviderElement(this);
|
return _MarketplaceWebFeedProviderElement(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
return other is MarketplaceWebFeedContentProvider && other.feedId == feedId;
|
return other is MarketplaceWebFeedProvider && other.feedId == feedId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -153,19 +135,18 @@ class MarketplaceWebFeedContentProvider
|
|||||||
|
|
||||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
// ignore: unused_element
|
// ignore: unused_element
|
||||||
mixin MarketplaceWebFeedContentRef
|
mixin MarketplaceWebFeedRef on AutoDisposeFutureProviderRef<SnWebFeed> {
|
||||||
on AutoDisposeFutureProviderRef<List<SnWebArticle>> {
|
|
||||||
/// The parameter `feedId` of this provider.
|
/// The parameter `feedId` of this provider.
|
||||||
String get feedId;
|
String get feedId;
|
||||||
}
|
}
|
||||||
|
|
||||||
class _MarketplaceWebFeedContentProviderElement
|
class _MarketplaceWebFeedProviderElement
|
||||||
extends AutoDisposeFutureProviderElement<List<SnWebArticle>>
|
extends AutoDisposeFutureProviderElement<SnWebFeed>
|
||||||
with MarketplaceWebFeedContentRef {
|
with MarketplaceWebFeedRef {
|
||||||
_MarketplaceWebFeedContentProviderElement(super.provider);
|
_MarketplaceWebFeedProviderElement(super.provider);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get feedId => (origin as MarketplaceWebFeedContentProvider).feedId;
|
String get feedId => (origin as MarketplaceWebFeedProvider).feedId;
|
||||||
}
|
}
|
||||||
|
|
||||||
String _$marketplaceWebFeedSubscriptionHash() =>
|
String _$marketplaceWebFeedSubscriptionHash() =>
|
||||||
@@ -309,5 +290,169 @@ class _MarketplaceWebFeedSubscriptionProviderElement
|
|||||||
(origin as MarketplaceWebFeedSubscriptionProvider).feedId;
|
(origin as MarketplaceWebFeedSubscriptionProvider).feedId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String _$marketplaceWebFeedContentNotifierHash() =>
|
||||||
|
r'25688082884cb824eeff300888ba38c9748295dc';
|
||||||
|
|
||||||
|
abstract class _$MarketplaceWebFeedContentNotifier
|
||||||
|
extends BuildlessAutoDisposeAsyncNotifier<CursorPagingData<SnWebArticle>> {
|
||||||
|
late final String feedId;
|
||||||
|
|
||||||
|
FutureOr<CursorPagingData<SnWebArticle>> build(String feedId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Provider for web feed articles content
|
||||||
|
///
|
||||||
|
/// Copied from [MarketplaceWebFeedContentNotifier].
|
||||||
|
@ProviderFor(MarketplaceWebFeedContentNotifier)
|
||||||
|
const marketplaceWebFeedContentNotifierProvider =
|
||||||
|
MarketplaceWebFeedContentNotifierFamily();
|
||||||
|
|
||||||
|
/// Provider for web feed articles content
|
||||||
|
///
|
||||||
|
/// Copied from [MarketplaceWebFeedContentNotifier].
|
||||||
|
class MarketplaceWebFeedContentNotifierFamily
|
||||||
|
extends Family<AsyncValue<CursorPagingData<SnWebArticle>>> {
|
||||||
|
/// Provider for web feed articles content
|
||||||
|
///
|
||||||
|
/// Copied from [MarketplaceWebFeedContentNotifier].
|
||||||
|
const MarketplaceWebFeedContentNotifierFamily();
|
||||||
|
|
||||||
|
/// Provider for web feed articles content
|
||||||
|
///
|
||||||
|
/// Copied from [MarketplaceWebFeedContentNotifier].
|
||||||
|
MarketplaceWebFeedContentNotifierProvider call(String feedId) {
|
||||||
|
return MarketplaceWebFeedContentNotifierProvider(feedId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
MarketplaceWebFeedContentNotifierProvider getProviderOverride(
|
||||||
|
covariant MarketplaceWebFeedContentNotifierProvider provider,
|
||||||
|
) {
|
||||||
|
return call(provider.feedId);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
|
||||||
|
|
||||||
|
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
|
||||||
|
_allTransitiveDependencies;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String? get name => r'marketplaceWebFeedContentNotifierProvider';
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Provider for web feed articles content
|
||||||
|
///
|
||||||
|
/// Copied from [MarketplaceWebFeedContentNotifier].
|
||||||
|
class MarketplaceWebFeedContentNotifierProvider
|
||||||
|
extends
|
||||||
|
AutoDisposeAsyncNotifierProviderImpl<
|
||||||
|
MarketplaceWebFeedContentNotifier,
|
||||||
|
CursorPagingData<SnWebArticle>
|
||||||
|
> {
|
||||||
|
/// Provider for web feed articles content
|
||||||
|
///
|
||||||
|
/// Copied from [MarketplaceWebFeedContentNotifier].
|
||||||
|
MarketplaceWebFeedContentNotifierProvider(String feedId)
|
||||||
|
: this._internal(
|
||||||
|
() => MarketplaceWebFeedContentNotifier()..feedId = feedId,
|
||||||
|
from: marketplaceWebFeedContentNotifierProvider,
|
||||||
|
name: r'marketplaceWebFeedContentNotifierProvider',
|
||||||
|
debugGetCreateSourceHash:
|
||||||
|
const bool.fromEnvironment('dart.vm.product')
|
||||||
|
? null
|
||||||
|
: _$marketplaceWebFeedContentNotifierHash,
|
||||||
|
dependencies: MarketplaceWebFeedContentNotifierFamily._dependencies,
|
||||||
|
allTransitiveDependencies:
|
||||||
|
MarketplaceWebFeedContentNotifierFamily._allTransitiveDependencies,
|
||||||
|
feedId: feedId,
|
||||||
|
);
|
||||||
|
|
||||||
|
MarketplaceWebFeedContentNotifierProvider._internal(
|
||||||
|
super._createNotifier, {
|
||||||
|
required super.name,
|
||||||
|
required super.dependencies,
|
||||||
|
required super.allTransitiveDependencies,
|
||||||
|
required super.debugGetCreateSourceHash,
|
||||||
|
required super.from,
|
||||||
|
required this.feedId,
|
||||||
|
}) : super.internal();
|
||||||
|
|
||||||
|
final String feedId;
|
||||||
|
|
||||||
|
@override
|
||||||
|
FutureOr<CursorPagingData<SnWebArticle>> runNotifierBuild(
|
||||||
|
covariant MarketplaceWebFeedContentNotifier notifier,
|
||||||
|
) {
|
||||||
|
return notifier.build(feedId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Override overrideWith(MarketplaceWebFeedContentNotifier Function() create) {
|
||||||
|
return ProviderOverride(
|
||||||
|
origin: this,
|
||||||
|
override: MarketplaceWebFeedContentNotifierProvider._internal(
|
||||||
|
() => create()..feedId = feedId,
|
||||||
|
from: from,
|
||||||
|
name: null,
|
||||||
|
dependencies: null,
|
||||||
|
allTransitiveDependencies: null,
|
||||||
|
debugGetCreateSourceHash: null,
|
||||||
|
feedId: feedId,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
AutoDisposeAsyncNotifierProviderElement<
|
||||||
|
MarketplaceWebFeedContentNotifier,
|
||||||
|
CursorPagingData<SnWebArticle>
|
||||||
|
>
|
||||||
|
createElement() {
|
||||||
|
return _MarketplaceWebFeedContentNotifierProviderElement(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return other is MarketplaceWebFeedContentNotifierProvider &&
|
||||||
|
other.feedId == feedId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode {
|
||||||
|
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||||
|
hash = _SystemHash.combine(hash, feedId.hashCode);
|
||||||
|
|
||||||
|
return _SystemHash.finish(hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
|
mixin MarketplaceWebFeedContentNotifierRef
|
||||||
|
on AutoDisposeAsyncNotifierProviderRef<CursorPagingData<SnWebArticle>> {
|
||||||
|
/// The parameter `feedId` of this provider.
|
||||||
|
String get feedId;
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MarketplaceWebFeedContentNotifierProviderElement
|
||||||
|
extends
|
||||||
|
AutoDisposeAsyncNotifierProviderElement<
|
||||||
|
MarketplaceWebFeedContentNotifier,
|
||||||
|
CursorPagingData<SnWebArticle>
|
||||||
|
>
|
||||||
|
with MarketplaceWebFeedContentNotifierRef {
|
||||||
|
_MarketplaceWebFeedContentNotifierProviderElement(super.provider);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get feedId =>
|
||||||
|
(origin as MarketplaceWebFeedContentNotifierProvider).feedId;
|
||||||
|
}
|
||||||
|
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
||||||
|
@@ -7,7 +7,7 @@ part of 'feed_marketplace.dart';
|
|||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$marketplaceWebFeedsNotifierHash() =>
|
String _$marketplaceWebFeedsNotifierHash() =>
|
||||||
r'dbf885d95570ca9c2259a58998975db813b18cbb';
|
r'774b2985f2f7d61fe958f534f84e39f814327c4e';
|
||||||
|
|
||||||
/// Copied from Dart SDK
|
/// Copied from Dart SDK
|
||||||
class _SystemHash {
|
class _SystemHash {
|
||||||
|
@@ -8,6 +8,7 @@ import 'package:island/pods/network.dart';
|
|||||||
import 'package:island/widgets/app_scaffold.dart';
|
import 'package:island/widgets/app_scaffold.dart';
|
||||||
import 'package:island/widgets/post/post_list.dart';
|
import 'package:island/widgets/post/post_list.dart';
|
||||||
import 'package:island/widgets/response.dart';
|
import 'package:island/widgets/response.dart';
|
||||||
|
import 'package:material_symbols_icons/material_symbols_icons.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
|
|
||||||
@@ -27,6 +28,49 @@ Future<SnPostTag> postTag(Ref ref, String slug) async {
|
|||||||
return SnPostTag.fromJson(resp.data);
|
return SnPostTag.fromJson(resp.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@riverpod
|
||||||
|
Future<bool> postCategorySubscriptionStatus(
|
||||||
|
Ref ref,
|
||||||
|
String slug,
|
||||||
|
bool isCategory,
|
||||||
|
) async {
|
||||||
|
final apiClient = ref.watch(apiClientProvider);
|
||||||
|
try {
|
||||||
|
final resp = await apiClient.get(
|
||||||
|
'/sphere/posts/${isCategory ? 'categories' : 'tags'}/$slug/subscription',
|
||||||
|
);
|
||||||
|
return resp.statusCode == 200;
|
||||||
|
} catch (_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _subscribeToCategoryOrTag(
|
||||||
|
WidgetRef ref, {
|
||||||
|
required String slug,
|
||||||
|
required bool isCategory,
|
||||||
|
}) async {
|
||||||
|
final apiClient = ref.read(apiClientProvider);
|
||||||
|
await apiClient.post(
|
||||||
|
'/sphere/posts/${isCategory ? 'categories' : 'tags'}/$slug/subscribe',
|
||||||
|
);
|
||||||
|
// Invalidate the subscription status to refresh it
|
||||||
|
ref.invalidate(postCategorySubscriptionStatusProvider(slug, isCategory));
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _unsubscribeFromCategoryOrTag(
|
||||||
|
WidgetRef ref, {
|
||||||
|
required String slug,
|
||||||
|
required bool isCategory,
|
||||||
|
}) async {
|
||||||
|
final apiClient = ref.read(apiClientProvider);
|
||||||
|
await apiClient.post(
|
||||||
|
'/sphere/posts/${isCategory ? 'categories' : 'tags'}/$slug/unsubscribe',
|
||||||
|
);
|
||||||
|
// Invalidate the subscription status to refresh it
|
||||||
|
ref.invalidate(postCategorySubscriptionStatusProvider(slug, isCategory));
|
||||||
|
}
|
||||||
|
|
||||||
class PostCategoryDetailScreen extends HookConsumerWidget {
|
class PostCategoryDetailScreen extends HookConsumerWidget {
|
||||||
final String slug;
|
final String slug;
|
||||||
final bool isCategory;
|
final bool isCategory;
|
||||||
@@ -41,6 +85,9 @@ class PostCategoryDetailScreen extends HookConsumerWidget {
|
|||||||
final postCategory =
|
final postCategory =
|
||||||
isCategory ? ref.watch(postCategoryProvider(slug)) : null;
|
isCategory ? ref.watch(postCategoryProvider(slug)) : null;
|
||||||
final postTag = isCategory ? null : ref.watch(postTagProvider(slug));
|
final postTag = isCategory ? null : ref.watch(postTagProvider(slug));
|
||||||
|
final subscriptionStatus = ref.watch(
|
||||||
|
postCategorySubscriptionStatusProvider(slug, isCategory),
|
||||||
|
);
|
||||||
|
|
||||||
final postFilterTitle =
|
final postFilterTitle =
|
||||||
isCategory
|
isCategory
|
||||||
@@ -50,57 +97,158 @@ class PostCategoryDetailScreen extends HookConsumerWidget {
|
|||||||
return AppScaffold(
|
return AppScaffold(
|
||||||
isNoBackground: false,
|
isNoBackground: false,
|
||||||
appBar: AppBar(title: Text(postFilterTitle).tr()),
|
appBar: AppBar(title: Text(postFilterTitle).tr()),
|
||||||
body: Column(
|
body: Expanded(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
child: CustomScrollView(
|
||||||
children: [
|
slivers: [
|
||||||
if (isCategory)
|
if (isCategory)
|
||||||
postCategory!.when(
|
SliverToBoxAdapter(
|
||||||
data:
|
child: Center(
|
||||||
(category) => Column(
|
child: ConstrainedBox(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
constraints: const BoxConstraints(maxWidth: 540),
|
||||||
children: [
|
child: Card(
|
||||||
Text(category.categoryDisplayTitle).bold().fontSize(15),
|
margin: EdgeInsets.only(top: 8),
|
||||||
Text('A category'),
|
child: postCategory!.when(
|
||||||
],
|
data:
|
||||||
).padding(horizontal: 24, vertical: 16),
|
(category) => Column(
|
||||||
error:
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
(error, _) => ResponseErrorWidget(
|
children: [
|
||||||
error: error,
|
Text(
|
||||||
onRetry: () => ref.invalidate(postCategoryProvider(slug)),
|
category.categoryDisplayTitle,
|
||||||
|
).bold().fontSize(15),
|
||||||
|
Text('A category'),
|
||||||
|
const Gap(8),
|
||||||
|
subscriptionStatus.when(
|
||||||
|
data:
|
||||||
|
(isSubscribed) =>
|
||||||
|
isSubscribed
|
||||||
|
? FilledButton.icon(
|
||||||
|
onPressed: () async {
|
||||||
|
await _unsubscribeFromCategoryOrTag(
|
||||||
|
ref,
|
||||||
|
slug: slug,
|
||||||
|
isCategory: isCategory,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
icon: const Icon(
|
||||||
|
Symbols.remove_circle,
|
||||||
|
),
|
||||||
|
label: Text('unsubscribe'.tr()),
|
||||||
|
)
|
||||||
|
: FilledButton.icon(
|
||||||
|
onPressed: () async {
|
||||||
|
await _subscribeToCategoryOrTag(
|
||||||
|
ref,
|
||||||
|
slug: slug,
|
||||||
|
isCategory: isCategory,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
icon: const Icon(
|
||||||
|
Symbols.add_circle,
|
||||||
|
),
|
||||||
|
label: Text('subscribe'.tr()),
|
||||||
|
),
|
||||||
|
error:
|
||||||
|
(error, _) => Text(
|
||||||
|
'Error loading subscription status',
|
||||||
|
),
|
||||||
|
loading:
|
||||||
|
() =>
|
||||||
|
CircularProgressIndicator().center(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
).padding(horizontal: 24, vertical: 16),
|
||||||
|
error:
|
||||||
|
(error, _) => ResponseErrorWidget(
|
||||||
|
error: error,
|
||||||
|
onRetry:
|
||||||
|
() => ref.invalidate(
|
||||||
|
postCategoryProvider(slug),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
loading: () => ResponseLoadingWidget(),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
loading: () => ResponseLoadingWidget(),
|
|
||||||
)
|
|
||||||
else
|
|
||||||
postTag!.when(
|
|
||||||
data:
|
|
||||||
(tag) => Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(tag.name ?? '#${tag.slug}').bold().fontSize(15),
|
|
||||||
Text('A tag'),
|
|
||||||
],
|
|
||||||
).padding(horizontal: 24, vertical: 16),
|
|
||||||
error:
|
|
||||||
(error, _) => ResponseErrorWidget(
|
|
||||||
error: error,
|
|
||||||
onRetry: () => ref.invalidate(postTagProvider(slug)),
|
|
||||||
),
|
|
||||||
loading: () => ResponseLoadingWidget(),
|
|
||||||
),
|
|
||||||
const Divider(height: 1),
|
|
||||||
Expanded(
|
|
||||||
child: CustomScrollView(
|
|
||||||
slivers: [
|
|
||||||
const SliverGap(4),
|
|
||||||
SliverPostList(
|
|
||||||
categories: isCategory ? [slug] : null,
|
|
||||||
tags: isCategory ? null : [slug],
|
|
||||||
),
|
),
|
||||||
SliverGap(MediaQuery.of(context).padding.bottom + 8),
|
)
|
||||||
],
|
else
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: Center(
|
||||||
|
child: ConstrainedBox(
|
||||||
|
constraints: const BoxConstraints(maxWidth: 540),
|
||||||
|
child: Card(
|
||||||
|
margin: EdgeInsets.only(top: 8),
|
||||||
|
child: postTag!.when(
|
||||||
|
data:
|
||||||
|
(tag) => Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
tag.name ?? '#${tag.slug}',
|
||||||
|
).bold().fontSize(15),
|
||||||
|
Text('A tag'),
|
||||||
|
const Gap(8),
|
||||||
|
subscriptionStatus.when(
|
||||||
|
data:
|
||||||
|
(isSubscribed) =>
|
||||||
|
isSubscribed
|
||||||
|
? FilledButton.icon(
|
||||||
|
onPressed: () async {
|
||||||
|
await _unsubscribeFromCategoryOrTag(
|
||||||
|
ref,
|
||||||
|
slug: slug,
|
||||||
|
isCategory: isCategory,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
icon: const Icon(
|
||||||
|
Symbols.add_circle,
|
||||||
|
),
|
||||||
|
label: Text('unsubscribe'.tr()),
|
||||||
|
)
|
||||||
|
: FilledButton.icon(
|
||||||
|
onPressed: () async {
|
||||||
|
await _subscribeToCategoryOrTag(
|
||||||
|
ref,
|
||||||
|
slug: slug,
|
||||||
|
isCategory: isCategory,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
icon: const Icon(
|
||||||
|
Symbols.remove_circle,
|
||||||
|
),
|
||||||
|
label: Text('subscribe'.tr()),
|
||||||
|
),
|
||||||
|
error:
|
||||||
|
(error, _) => Text(
|
||||||
|
'Error loading subscription status',
|
||||||
|
),
|
||||||
|
loading:
|
||||||
|
() =>
|
||||||
|
CircularProgressIndicator().center(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
).padding(horizontal: 24, vertical: 16),
|
||||||
|
error:
|
||||||
|
(error, _) => ResponseErrorWidget(
|
||||||
|
error: error,
|
||||||
|
onRetry:
|
||||||
|
() => ref.invalidate(postTagProvider(slug)),
|
||||||
|
),
|
||||||
|
loading: () => ResponseLoadingWidget(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SliverGap(4),
|
||||||
|
SliverPostList(
|
||||||
|
categories: isCategory ? [slug] : null,
|
||||||
|
tags: isCategory ? null : [slug],
|
||||||
|
maxWidth: 540 + 16,
|
||||||
),
|
),
|
||||||
),
|
SliverGap(MediaQuery.of(context).padding.bottom + 8),
|
||||||
],
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -266,5 +266,146 @@ class _PostTagProviderElement
|
|||||||
String get slug => (origin as PostTagProvider).slug;
|
String get slug => (origin as PostTagProvider).slug;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String _$postCategorySubscriptionStatusHash() =>
|
||||||
|
r'407dc7fcaeffc461b591b4ee2418811aa4f0a63f';
|
||||||
|
|
||||||
|
/// See also [postCategorySubscriptionStatus].
|
||||||
|
@ProviderFor(postCategorySubscriptionStatus)
|
||||||
|
const postCategorySubscriptionStatusProvider =
|
||||||
|
PostCategorySubscriptionStatusFamily();
|
||||||
|
|
||||||
|
/// See also [postCategorySubscriptionStatus].
|
||||||
|
class PostCategorySubscriptionStatusFamily extends Family<AsyncValue<bool>> {
|
||||||
|
/// See also [postCategorySubscriptionStatus].
|
||||||
|
const PostCategorySubscriptionStatusFamily();
|
||||||
|
|
||||||
|
/// See also [postCategorySubscriptionStatus].
|
||||||
|
PostCategorySubscriptionStatusProvider call(String slug, bool isCategory) {
|
||||||
|
return PostCategorySubscriptionStatusProvider(slug, isCategory);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
PostCategorySubscriptionStatusProvider getProviderOverride(
|
||||||
|
covariant PostCategorySubscriptionStatusProvider provider,
|
||||||
|
) {
|
||||||
|
return call(provider.slug, provider.isCategory);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
|
||||||
|
|
||||||
|
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
|
||||||
|
_allTransitiveDependencies;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String? get name => r'postCategorySubscriptionStatusProvider';
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See also [postCategorySubscriptionStatus].
|
||||||
|
class PostCategorySubscriptionStatusProvider
|
||||||
|
extends AutoDisposeFutureProvider<bool> {
|
||||||
|
/// See also [postCategorySubscriptionStatus].
|
||||||
|
PostCategorySubscriptionStatusProvider(String slug, bool isCategory)
|
||||||
|
: this._internal(
|
||||||
|
(ref) => postCategorySubscriptionStatus(
|
||||||
|
ref as PostCategorySubscriptionStatusRef,
|
||||||
|
slug,
|
||||||
|
isCategory,
|
||||||
|
),
|
||||||
|
from: postCategorySubscriptionStatusProvider,
|
||||||
|
name: r'postCategorySubscriptionStatusProvider',
|
||||||
|
debugGetCreateSourceHash:
|
||||||
|
const bool.fromEnvironment('dart.vm.product')
|
||||||
|
? null
|
||||||
|
: _$postCategorySubscriptionStatusHash,
|
||||||
|
dependencies: PostCategorySubscriptionStatusFamily._dependencies,
|
||||||
|
allTransitiveDependencies:
|
||||||
|
PostCategorySubscriptionStatusFamily._allTransitiveDependencies,
|
||||||
|
slug: slug,
|
||||||
|
isCategory: isCategory,
|
||||||
|
);
|
||||||
|
|
||||||
|
PostCategorySubscriptionStatusProvider._internal(
|
||||||
|
super._createNotifier, {
|
||||||
|
required super.name,
|
||||||
|
required super.dependencies,
|
||||||
|
required super.allTransitiveDependencies,
|
||||||
|
required super.debugGetCreateSourceHash,
|
||||||
|
required super.from,
|
||||||
|
required this.slug,
|
||||||
|
required this.isCategory,
|
||||||
|
}) : super.internal();
|
||||||
|
|
||||||
|
final String slug;
|
||||||
|
final bool isCategory;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Override overrideWith(
|
||||||
|
FutureOr<bool> Function(PostCategorySubscriptionStatusRef provider) create,
|
||||||
|
) {
|
||||||
|
return ProviderOverride(
|
||||||
|
origin: this,
|
||||||
|
override: PostCategorySubscriptionStatusProvider._internal(
|
||||||
|
(ref) => create(ref as PostCategorySubscriptionStatusRef),
|
||||||
|
from: from,
|
||||||
|
name: null,
|
||||||
|
dependencies: null,
|
||||||
|
allTransitiveDependencies: null,
|
||||||
|
debugGetCreateSourceHash: null,
|
||||||
|
slug: slug,
|
||||||
|
isCategory: isCategory,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
AutoDisposeFutureProviderElement<bool> createElement() {
|
||||||
|
return _PostCategorySubscriptionStatusProviderElement(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return other is PostCategorySubscriptionStatusProvider &&
|
||||||
|
other.slug == slug &&
|
||||||
|
other.isCategory == isCategory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode {
|
||||||
|
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||||
|
hash = _SystemHash.combine(hash, slug.hashCode);
|
||||||
|
hash = _SystemHash.combine(hash, isCategory.hashCode);
|
||||||
|
|
||||||
|
return _SystemHash.finish(hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
|
mixin PostCategorySubscriptionStatusRef on AutoDisposeFutureProviderRef<bool> {
|
||||||
|
/// The parameter `slug` of this provider.
|
||||||
|
String get slug;
|
||||||
|
|
||||||
|
/// The parameter `isCategory` of this provider.
|
||||||
|
bool get isCategory;
|
||||||
|
}
|
||||||
|
|
||||||
|
class _PostCategorySubscriptionStatusProviderElement
|
||||||
|
extends AutoDisposeFutureProviderElement<bool>
|
||||||
|
with PostCategorySubscriptionStatusRef {
|
||||||
|
_PostCategorySubscriptionStatusProviderElement(super.provider);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get slug => (origin as PostCategorySubscriptionStatusProvider).slug;
|
||||||
|
@override
|
||||||
|
bool get isCategory =>
|
||||||
|
(origin as PostCategorySubscriptionStatusProvider).isCategory;
|
||||||
|
}
|
||||||
|
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
||||||
|
@@ -288,7 +288,11 @@ class PublisherProfileScreen extends HookConsumerWidget {
|
|||||||
controller: categoryTabController,
|
controller: categoryTabController,
|
||||||
dividerColor: Colors.transparent,
|
dividerColor: Colors.transparent,
|
||||||
splashBorderRadius: const BorderRadius.all(Radius.circular(8)),
|
splashBorderRadius: const BorderRadius.all(Radius.circular(8)),
|
||||||
tabs: [Tab(text: 'All'), Tab(text: 'Posts'), Tab(text: 'Articles')],
|
tabs: [
|
||||||
|
Tab(text: 'all'.tr()),
|
||||||
|
Tab(text: 'postTypePost'.tr()),
|
||||||
|
Tab(text: 'postArticle'.tr()),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -345,12 +349,14 @@ class PublisherProfileScreen extends HookConsumerWidget {
|
|||||||
child: CustomScrollView(
|
child: CustomScrollView(
|
||||||
slivers: [
|
slivers: [
|
||||||
SliverGap(16),
|
SliverGap(16),
|
||||||
|
SliverPostList(pubName: name, pinned: true),
|
||||||
SliverToBoxAdapter(
|
SliverToBoxAdapter(
|
||||||
child: publisherCategoryTabWidget(),
|
child: publisherCategoryTabWidget(),
|
||||||
),
|
),
|
||||||
SliverPostList(
|
SliverPostList(
|
||||||
key: ValueKey(categoryTab.value),
|
key: ValueKey(categoryTab.value),
|
||||||
pubName: name,
|
pubName: name,
|
||||||
|
pinned: false,
|
||||||
type: switch (categoryTab.value) {
|
type: switch (categoryTab.value) {
|
||||||
1 => 0,
|
1 => 0,
|
||||||
2 => 1,
|
2 => 1,
|
||||||
@@ -433,10 +439,12 @@ class PublisherProfileScreen extends HookConsumerWidget {
|
|||||||
child: publisherVerificationWidget(data),
|
child: publisherVerificationWidget(data),
|
||||||
),
|
),
|
||||||
SliverToBoxAdapter(child: publisherBioWidget(data)),
|
SliverToBoxAdapter(child: publisherBioWidget(data)),
|
||||||
|
SliverPostList(pubName: name, pinned: true),
|
||||||
SliverToBoxAdapter(child: publisherCategoryTabWidget()),
|
SliverToBoxAdapter(child: publisherCategoryTabWidget()),
|
||||||
SliverPostList(
|
SliverPostList(
|
||||||
key: ValueKey(categoryTab.value),
|
key: ValueKey(categoryTab.value),
|
||||||
pubName: name,
|
pubName: name,
|
||||||
|
pinned: false,
|
||||||
type: switch (categoryTab.value) {
|
type: switch (categoryTab.value) {
|
||||||
1 => 0,
|
1 => 0,
|
||||||
2 => 1,
|
2 => 1,
|
||||||
|
@@ -5,6 +5,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:island/models/chat.dart';
|
import 'package:island/models/chat.dart';
|
||||||
import 'package:island/services/color.dart';
|
import 'package:island/services/color.dart';
|
||||||
import 'package:island/services/responsive.dart';
|
import 'package:island/services/responsive.dart';
|
||||||
|
import 'package:island/widgets/account/account_pfc.dart';
|
||||||
import 'package:island/widgets/account/status.dart';
|
import 'package:island/widgets/account/status.dart';
|
||||||
import 'package:island/widgets/post/post_list.dart';
|
import 'package:island/widgets/post/post_list.dart';
|
||||||
import 'package:palette_generator/palette_generator.dart';
|
import 'package:palette_generator/palette_generator.dart';
|
||||||
@@ -244,7 +245,10 @@ class RealmDetailScreen extends HookConsumerWidget {
|
|||||||
Flexible(
|
Flexible(
|
||||||
flex: 3,
|
flex: 3,
|
||||||
child: CustomScrollView(
|
child: CustomScrollView(
|
||||||
slivers: [SliverPostList(realm: slug)],
|
slivers: [
|
||||||
|
SliverPostList(realm: slug, pinned: true),
|
||||||
|
SliverPostList(realm: slug, pinned: false),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Flexible(
|
Flexible(
|
||||||
@@ -359,7 +363,8 @@ class RealmDetailScreen extends HookConsumerWidget {
|
|||||||
SliverToBoxAdapter(
|
SliverToBoxAdapter(
|
||||||
child: realmChatRoomListWidget(realm),
|
child: realmChatRoomListWidget(realm),
|
||||||
),
|
),
|
||||||
SliverPostList(realm: slug),
|
SliverPostList(realm: slug, pinned: true),
|
||||||
|
SliverPostList(realm: slug, pinned: false),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -520,9 +525,11 @@ class _RealmActionMenu extends HookConsumerWidget {
|
|||||||
class RealmMemberListNotifier extends _$RealmMemberListNotifier
|
class RealmMemberListNotifier extends _$RealmMemberListNotifier
|
||||||
with CursorPagingNotifierMixin<SnRealmMember> {
|
with CursorPagingNotifierMixin<SnRealmMember> {
|
||||||
static const int _pageSize = 20;
|
static const int _pageSize = 20;
|
||||||
|
ValueNotifier<int> totalCount = ValueNotifier(0);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<CursorPagingData<SnRealmMember>> build(String realmSlug) async {
|
Future<CursorPagingData<SnRealmMember>> build(String realmSlug) async {
|
||||||
|
totalCount.value = 0;
|
||||||
return fetch();
|
return fetch();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -541,6 +548,7 @@ class RealmMemberListNotifier extends _$RealmMemberListNotifier
|
|||||||
);
|
);
|
||||||
|
|
||||||
final total = int.parse(response.headers.value('X-Total') ?? '0');
|
final total = int.parse(response.headers.value('X-Total') ?? '0');
|
||||||
|
totalCount.value = total;
|
||||||
final List<dynamic> data = response.data;
|
final List<dynamic> data = response.data;
|
||||||
final members = data.map((e) => SnRealmMember.fromJson(e)).toList();
|
final members = data.map((e) => SnRealmMember.fromJson(e)).toList();
|
||||||
|
|
||||||
@@ -553,52 +561,9 @@ class RealmMemberListNotifier extends _$RealmMemberListNotifier
|
|||||||
nextCursor: nextCursor,
|
nextCursor: nextCursor,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Keep the old provider for backward compatibility
|
void dispose() {
|
||||||
final realmMemberStateProvider =
|
totalCount.dispose();
|
||||||
StateNotifierProvider.family<RealmMemberNotifier, RealmMemberState, String>(
|
|
||||||
(ref, realmSlug) {
|
|
||||||
final apiClient = ref.watch(apiClientProvider);
|
|
||||||
return RealmMemberNotifier(apiClient, realmSlug);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
class RealmMemberNotifier extends StateNotifier<RealmMemberState> {
|
|
||||||
final String realmSlug;
|
|
||||||
final Dio _apiClient;
|
|
||||||
|
|
||||||
RealmMemberNotifier(this._apiClient, this.realmSlug)
|
|
||||||
: super(const RealmMemberState(members: [], isLoading: false, total: 0));
|
|
||||||
|
|
||||||
Future<void> loadMore({int offset = 0, int take = 20}) async {
|
|
||||||
if (state.isLoading) return;
|
|
||||||
if (state.total > 0 && state.members.length >= state.total) return;
|
|
||||||
|
|
||||||
state = state.copyWith(isLoading: true, error: null);
|
|
||||||
|
|
||||||
try {
|
|
||||||
final response = await _apiClient.get(
|
|
||||||
'/sphere/realms/$realmSlug/members',
|
|
||||||
queryParameters: {'offset': offset, 'take': take, 'withStatus': true},
|
|
||||||
);
|
|
||||||
|
|
||||||
final total = int.parse(response.headers.value('X-Total') ?? '0');
|
|
||||||
final List<dynamic> data = response.data;
|
|
||||||
final members = data.map((e) => SnRealmMember.fromJson(e)).toList();
|
|
||||||
|
|
||||||
state = state.copyWith(
|
|
||||||
members: [...state.members, ...members],
|
|
||||||
total: total,
|
|
||||||
isLoading: false,
|
|
||||||
);
|
|
||||||
} catch (e) {
|
|
||||||
state = state.copyWith(error: e.toString(), isLoading: false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void reset() {
|
|
||||||
state = const RealmMemberState(members: [], isLoading: false, total: 0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -610,18 +575,10 @@ class _RealmMemberListSheet extends HookConsumerWidget {
|
|||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final realmIdentity = ref.watch(realmIdentityProvider(realmSlug));
|
final realmIdentity = ref.watch(realmIdentityProvider(realmSlug));
|
||||||
final memberListProvider = realmMemberListNotifierProvider(realmSlug);
|
final memberListProvider = realmMemberListNotifierProvider(realmSlug);
|
||||||
|
final memberListNotifier = ref.watch(memberListProvider.notifier);
|
||||||
// For backward compatibility and to show total count in the header
|
|
||||||
final memberState = ref.watch(realmMemberStateProvider(realmSlug));
|
|
||||||
final memberNotifier = ref.read(
|
|
||||||
realmMemberStateProvider(realmSlug).notifier,
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() {
|
useEffect(() {
|
||||||
Future(() {
|
return memberListNotifier.dispose;
|
||||||
memberNotifier.loadMore();
|
|
||||||
});
|
|
||||||
return null;
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
Future<void> invitePerson() async {
|
Future<void> invitePerson() async {
|
||||||
@@ -638,9 +595,7 @@ class _RealmMemberListSheet extends HookConsumerWidget {
|
|||||||
'/sphere/realms/invites/$realmSlug',
|
'/sphere/realms/invites/$realmSlug',
|
||||||
data: {'related_user_id': result.id, 'role': 0},
|
data: {'related_user_id': result.id, 'role': 0},
|
||||||
);
|
);
|
||||||
// Refresh both providers
|
// Refresh the provider
|
||||||
memberNotifier.reset();
|
|
||||||
await memberNotifier.loadMore();
|
|
||||||
ref.invalidate(memberListProvider);
|
ref.invalidate(memberListProvider);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
showErrorAlert(err);
|
showErrorAlert(err);
|
||||||
@@ -652,12 +607,17 @@ class _RealmMemberListSheet extends HookConsumerWidget {
|
|||||||
padding: EdgeInsets.only(top: 16, left: 20, right: 16, bottom: 12),
|
padding: EdgeInsets.only(top: 16, left: 20, right: 16, bottom: 12),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Text(
|
ListenableBuilder(
|
||||||
'members'.plural(memberState.total),
|
listenable: memberListNotifier.totalCount,
|
||||||
style: Theme.of(context).textTheme.headlineSmall?.copyWith(
|
builder:
|
||||||
fontWeight: FontWeight.w600,
|
(context, _) => Text(
|
||||||
letterSpacing: -0.5,
|
'members'.plural(memberListNotifier.totalCount.value),
|
||||||
),
|
key: ValueKey(memberListNotifier),
|
||||||
|
style: Theme.of(context).textTheme.headlineSmall?.copyWith(
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
letterSpacing: -0.5,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
IconButton(
|
IconButton(
|
||||||
@@ -668,9 +628,7 @@ class _RealmMemberListSheet extends HookConsumerWidget {
|
|||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Symbols.refresh),
|
icon: const Icon(Symbols.refresh),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
// Refresh both providers
|
// Refresh the provider
|
||||||
memberNotifier.reset();
|
|
||||||
memberNotifier.loadMore();
|
|
||||||
ref.invalidate(memberListProvider);
|
ref.invalidate(memberListProvider);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@@ -701,8 +659,11 @@ class _RealmMemberListSheet extends HookConsumerWidget {
|
|||||||
final member = data.items[index];
|
final member = data.items[index];
|
||||||
return ListTile(
|
return ListTile(
|
||||||
contentPadding: EdgeInsets.only(left: 16, right: 12),
|
contentPadding: EdgeInsets.only(left: 16, right: 12),
|
||||||
leading: ProfilePictureWidget(
|
leading: AccountPfcGestureDetector(
|
||||||
fileId: member.account!.profile.picture?.id,
|
uname: member.account!.name,
|
||||||
|
child: ProfilePictureWidget(
|
||||||
|
fileId: member.account!.profile.picture?.id,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
title: Row(
|
title: Row(
|
||||||
spacing: 6,
|
spacing: 6,
|
||||||
@@ -744,9 +705,7 @@ class _RealmMemberListSheet extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
).then((value) {
|
).then((value) {
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
// Refresh both providers
|
// Refresh the provider
|
||||||
memberNotifier.reset();
|
|
||||||
memberNotifier.loadMore();
|
|
||||||
ref.invalidate(memberListProvider);
|
ref.invalidate(memberListProvider);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -766,9 +725,7 @@ class _RealmMemberListSheet extends HookConsumerWidget {
|
|||||||
await apiClient.delete(
|
await apiClient.delete(
|
||||||
'/sphere/realms/$realmSlug/members/${member.accountId}',
|
'/sphere/realms/$realmSlug/members/${member.accountId}',
|
||||||
);
|
);
|
||||||
// Refresh both providers
|
// Refresh the provider
|
||||||
memberNotifier.reset();
|
|
||||||
memberNotifier.loadMore();
|
|
||||||
ref.invalidate(memberListProvider);
|
ref.invalidate(memberListProvider);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
showErrorAlert(err);
|
showErrorAlert(err);
|
||||||
@@ -801,34 +758,6 @@ class _RealmMemberListSheet extends HookConsumerWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class RealmMemberState {
|
|
||||||
final List<SnRealmMember> members;
|
|
||||||
final bool isLoading;
|
|
||||||
final int total;
|
|
||||||
final String? error;
|
|
||||||
|
|
||||||
const RealmMemberState({
|
|
||||||
required this.members,
|
|
||||||
required this.isLoading,
|
|
||||||
required this.total,
|
|
||||||
this.error,
|
|
||||||
});
|
|
||||||
|
|
||||||
RealmMemberState copyWith({
|
|
||||||
List<SnRealmMember>? members,
|
|
||||||
bool? isLoading,
|
|
||||||
int? total,
|
|
||||||
String? error,
|
|
||||||
}) {
|
|
||||||
return RealmMemberState(
|
|
||||||
members: members ?? this.members,
|
|
||||||
isLoading: isLoading ?? this.isLoading,
|
|
||||||
total: total ?? this.total,
|
|
||||||
error: error ?? this.error,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class _RealmMemberRoleSheet extends HookConsumerWidget {
|
class _RealmMemberRoleSheet extends HookConsumerWidget {
|
||||||
final String realmSlug;
|
final String realmSlug;
|
||||||
final SnRealmMember member;
|
final SnRealmMember member;
|
||||||
|
@@ -399,7 +399,7 @@ class _RealmChatRoomsProviderElement
|
|||||||
}
|
}
|
||||||
|
|
||||||
String _$realmMemberListNotifierHash() =>
|
String _$realmMemberListNotifierHash() =>
|
||||||
r'2f88f803b2e61e7287ed8a43025173e56ff6ca3b';
|
r'db1fd8a6741dfb3d5bb921d5d965f0cfdc0e7bcc';
|
||||||
|
|
||||||
abstract class _$RealmMemberListNotifier
|
abstract class _$RealmMemberListNotifier
|
||||||
extends BuildlessAutoDisposeAsyncNotifier<CursorPagingData<SnRealmMember>> {
|
extends BuildlessAutoDisposeAsyncNotifier<CursorPagingData<SnRealmMember>> {
|
||||||
|
@@ -42,6 +42,16 @@ class AccountName extends StatelessWidget {
|
|||||||
StellarMembershipMark(membership: account.perkSubscription!),
|
StellarMembershipMark(membership: account.perkSubscription!),
|
||||||
if (account.profile.verification != null)
|
if (account.profile.verification != null)
|
||||||
VerificationMark(mark: account.profile.verification!),
|
VerificationMark(mark: account.profile.verification!),
|
||||||
|
if (account.automatedId != null)
|
||||||
|
Tooltip(
|
||||||
|
message: 'accountAutomated'.tr(),
|
||||||
|
child: Icon(
|
||||||
|
Symbols.smart_toy,
|
||||||
|
size: 16,
|
||||||
|
color: nameStyle.color,
|
||||||
|
fill: 1,
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -141,7 +151,7 @@ class VerificationStatusCard extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: [
|
children: [
|
||||||
Icon(
|
Icon(
|
||||||
mark.type == 4
|
mark.type == 4
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
import 'dart:math' as math;
|
import 'dart:math' as math;
|
||||||
|
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:flutter_popup_card/flutter_popup_card.dart';
|
import 'package:flutter_popup_card/flutter_popup_card.dart';
|
||||||
@@ -74,7 +75,42 @@ class AccountProfileCard extends HookConsumerWidget {
|
|||||||
uname: data.name,
|
uname: data.name,
|
||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
),
|
),
|
||||||
if (data.profile.timeZone.isNotEmpty)
|
Tooltip(
|
||||||
|
message: 'creditsStatus'.tr(),
|
||||||
|
child: Row(
|
||||||
|
spacing: 6,
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Symbols.star,
|
||||||
|
size: 17,
|
||||||
|
fill: 1,
|
||||||
|
).padding(right: 2),
|
||||||
|
Text(
|
||||||
|
'${data.profile.socialCredits.toStringAsFixed(2)} pts',
|
||||||
|
).fontSize(12),
|
||||||
|
switch (data.profile.socialCreditsLevel) {
|
||||||
|
-1 => Text('socialCreditsLevelPoor').tr(),
|
||||||
|
0 => Text('socialCreditsLevelNormal').tr(),
|
||||||
|
1 => Text('socialCreditsLevelGood').tr(),
|
||||||
|
2 => Text('socialCreditsLevelExcellent').tr(),
|
||||||
|
_ => Text('unknown').tr(),
|
||||||
|
}.fontSize(12),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (data.automatedId != null)
|
||||||
|
Row(
|
||||||
|
spacing: 6,
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Symbols.smart_toy,
|
||||||
|
size: 17,
|
||||||
|
fill: 1,
|
||||||
|
).padding(right: 2),
|
||||||
|
Text('accountAutomated').tr().fontSize(12),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
if (data.profile.timeZone.isNotEmpty && !kIsWeb)
|
||||||
Row(
|
Row(
|
||||||
spacing: 6,
|
spacing: 6,
|
||||||
children: [
|
children: [
|
||||||
|
@@ -2,7 +2,9 @@ import 'package:easy_localization/easy_localization.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:island/models/account.dart';
|
||||||
import 'package:island/models/activity.dart';
|
import 'package:island/models/activity.dart';
|
||||||
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
import 'package:island/widgets/account/event_details_widget.dart';
|
import 'package:island/widgets/account/event_details_widget.dart';
|
||||||
import 'package:table_calendar/table_calendar.dart';
|
import 'package:table_calendar/table_calendar.dart';
|
||||||
@@ -87,24 +89,56 @@ class EventCalendarWidget extends HookConsumerWidget {
|
|||||||
return Center(child: Text(text));
|
return Center(child: Text(text));
|
||||||
},
|
},
|
||||||
markerBuilder: (context, day, events) {
|
markerBuilder: (context, day, events) {
|
||||||
var checkInResult =
|
final checkInResult =
|
||||||
events.whereType<SnCheckInResult>().firstOrNull;
|
events.whereType<SnCheckInResult>().firstOrNull;
|
||||||
|
final statuses = events.whereType<SnAccountStatus>().toList();
|
||||||
|
|
||||||
|
final textColor =
|
||||||
|
isSameDay(selectedDay.value, day)
|
||||||
|
? Colors.white
|
||||||
|
: isSameDay(DateTime.now(), day)
|
||||||
|
? Colors.white
|
||||||
|
: Theme.of(context).colorScheme.onSurface;
|
||||||
|
|
||||||
|
final shadow =
|
||||||
|
isSameDay(selectedDay.value, day) ||
|
||||||
|
isSameDay(DateTime.now(), day)
|
||||||
|
? [
|
||||||
|
Shadow(
|
||||||
|
color: Colors.black.withOpacity(0.5),
|
||||||
|
offset: const Offset(0, 1),
|
||||||
|
blurRadius: 4,
|
||||||
|
),
|
||||||
|
]
|
||||||
|
: null;
|
||||||
|
|
||||||
if (checkInResult != null) {
|
if (checkInResult != null) {
|
||||||
return Positioned(
|
return Positioned(
|
||||||
top: 32,
|
top: 32,
|
||||||
child: Text(
|
child: Row(
|
||||||
'checkInResultT${checkInResult.level}'.tr(),
|
spacing: 2,
|
||||||
style: TextStyle(
|
children: [
|
||||||
fontSize: 9,
|
Text(
|
||||||
color:
|
'checkInResultT${checkInResult.level}'.tr(),
|
||||||
isSameDay(selectedDay.value, day)
|
style: TextStyle(
|
||||||
? Theme.of(context).colorScheme.onPrimaryContainer
|
fontSize: 9,
|
||||||
: isSameDay(DateTime.now(), day)
|
color: textColor,
|
||||||
? Theme.of(
|
shadows: shadow,
|
||||||
context,
|
),
|
||||||
).colorScheme.onSecondaryContainer
|
),
|
||||||
: Theme.of(context).colorScheme.onSurface,
|
if (statuses.isNotEmpty) ...[
|
||||||
),
|
Icon(
|
||||||
|
switch (statuses.first.attitude) {
|
||||||
|
0 => Symbols.sentiment_satisfied,
|
||||||
|
2 => Symbols.sentiment_dissatisfied,
|
||||||
|
_ => Symbols.sentiment_neutral,
|
||||||
|
},
|
||||||
|
size: 12,
|
||||||
|
color: textColor,
|
||||||
|
shadows: shadow,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -2,6 +2,7 @@ import 'package:easy_localization/easy_localization.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:island/models/activity.dart';
|
import 'package:island/models/activity.dart';
|
||||||
|
import 'package:island/services/time.dart';
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
|
|
||||||
@@ -53,6 +54,33 @@ class EventDetailsWidget extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
).padding(top: 8),
|
).padding(top: 8),
|
||||||
|
if (event!.statuses.isNotEmpty) ...[
|
||||||
|
const Gap(16),
|
||||||
|
Text('statusLabel').tr().fontSize(16).bold(),
|
||||||
|
],
|
||||||
|
for (final status in event!.statuses) ...[
|
||||||
|
Row(
|
||||||
|
spacing: 8,
|
||||||
|
children: [
|
||||||
|
Icon(switch (status.attitude) {
|
||||||
|
0 => Symbols.sentiment_satisfied,
|
||||||
|
2 => Symbols.sentiment_dissatisfied,
|
||||||
|
_ => Symbols.sentiment_neutral,
|
||||||
|
}),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(status.label),
|
||||||
|
Text(
|
||||||
|
'${status.createdAt.formatSystem()} - ${status.clearedAt?.formatSystem() ?? 'present'.tr()}',
|
||||||
|
).fontSize(11).opacity(0.8),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
).padding(vertical: 8),
|
||||||
|
],
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
if (event?.checkInResult == null && (event?.statuses.isEmpty ?? true))
|
if (event?.checkInResult == null && (event?.statuses.isEmpty ?? true))
|
||||||
|
@@ -1,9 +1,12 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
import 'dart:math' as math;
|
import 'dart:math' as math;
|
||||||
import 'dart:ui';
|
import 'dart:ui';
|
||||||
|
|
||||||
import 'package:dismissible_page/dismissible_page.dart';
|
import 'package:dismissible_page/dismissible_page.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:file_saver/file_saver.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_blurhash/flutter_blurhash.dart';
|
import 'package:flutter_blurhash/flutter_blurhash.dart';
|
||||||
@@ -321,7 +324,7 @@ class CloudFileZoomIn extends HookConsumerWidget {
|
|||||||
Future<void> saveToGallery() async {
|
Future<void> saveToGallery() async {
|
||||||
try {
|
try {
|
||||||
// Show loading indicator
|
// Show loading indicator
|
||||||
showSnackBar('Saving image to gallery...');
|
showSnackBar('Saving image...');
|
||||||
|
|
||||||
// Get the image URL
|
// Get the image URL
|
||||||
final client = ref.watch(apiClientProvider);
|
final client = ref.watch(apiClientProvider);
|
||||||
@@ -339,10 +342,18 @@ class CloudFileZoomIn extends HookConsumerWidget {
|
|||||||
filePath,
|
filePath,
|
||||||
queryParameters: {'original': true},
|
queryParameters: {'original': true},
|
||||||
);
|
);
|
||||||
await Gal.putImage(filePath, album: 'Solar Network');
|
if (!kIsWeb && (Platform.isAndroid || Platform.isIOS)) {
|
||||||
|
// Save to gallery
|
||||||
// Show success message
|
await Gal.putImage(filePath, album: 'Solar Network');
|
||||||
showSnackBar('Image saved to gallery');
|
// Show success message
|
||||||
|
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) {
|
} catch (e) {
|
||||||
showErrorAlert(e);
|
showErrorAlert(e);
|
||||||
}
|
}
|
||||||
@@ -437,7 +448,24 @@ class CloudFileZoomIn extends HookConsumerWidget {
|
|||||||
).padding(horizontal: 24, vertical: 16),
|
).padding(horizontal: 24, vertical: 16),
|
||||||
const Divider(height: 1),
|
const Divider(height: 1),
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: const Icon(Icons.file_present),
|
leading: const Icon(Symbols.tag),
|
||||||
|
title: Text('ID').tr(),
|
||||||
|
subtitle: Text(
|
||||||
|
item.id,
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
contentPadding: EdgeInsets.symmetric(horizontal: 24),
|
||||||
|
trailing: IconButton(
|
||||||
|
icon: const Icon(Icons.copy),
|
||||||
|
onPressed: () {
|
||||||
|
Clipboard.setData(ClipboardData(text: item.id));
|
||||||
|
showSnackBar('File ID copied to clipboard');
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
leading: const Icon(Symbols.file_present),
|
||||||
title: Text('Name').tr(),
|
title: Text('Name').tr(),
|
||||||
subtitle: Text(
|
subtitle: Text(
|
||||||
item.name,
|
item.name,
|
||||||
@@ -623,6 +651,10 @@ class CloudFileZoomIn extends HookConsumerWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final shadow = [
|
||||||
|
Shadow(color: Colors.black54, blurRadius: 5.0, offset: Offset(1.0, 1.0)),
|
||||||
|
];
|
||||||
|
|
||||||
return DismissiblePage(
|
return DismissiblePage(
|
||||||
isFullScreen: true,
|
isFullScreen: true,
|
||||||
backgroundColor: Colors.transparent,
|
backgroundColor: Colors.transparent,
|
||||||
@@ -660,22 +692,17 @@ class CloudFileZoomIn extends HookConsumerWidget {
|
|||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
IconButton(
|
if (!kIsWeb)
|
||||||
icon: Icon(
|
IconButton(
|
||||||
Icons.save_alt,
|
icon: Icon(
|
||||||
color: Colors.white,
|
Icons.save_alt,
|
||||||
shadows: [
|
color: Colors.white,
|
||||||
Shadow(
|
shadows: shadow,
|
||||||
color: Colors.black54,
|
),
|
||||||
blurRadius: 5.0,
|
onPressed: () async {
|
||||||
offset: Offset(1.0, 1.0),
|
saveToGallery();
|
||||||
),
|
},
|
||||||
],
|
|
||||||
),
|
),
|
||||||
onPressed: () async {
|
|
||||||
saveToGallery();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
showOriginal.value = !showOriginal.value;
|
showOriginal.value = !showOriginal.value;
|
||||||
@@ -683,29 +710,13 @@ class CloudFileZoomIn extends HookConsumerWidget {
|
|||||||
icon: Icon(
|
icon: Icon(
|
||||||
showOriginal.value ? Symbols.hd : Symbols.sd,
|
showOriginal.value ? Symbols.hd : Symbols.sd,
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
shadows: [
|
shadows: shadow,
|
||||||
Shadow(
|
|
||||||
color: Colors.black54,
|
|
||||||
blurRadius: 5.0,
|
|
||||||
offset: Offset(1.0, 1.0),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: Icon(
|
icon: Icon(Icons.close, color: Colors.white, shadows: shadow),
|
||||||
Icons.close,
|
|
||||||
color: Colors.white,
|
|
||||||
shadows: [
|
|
||||||
Shadow(
|
|
||||||
color: Colors.black54,
|
|
||||||
blurRadius: 5.0,
|
|
||||||
offset: Offset(1.0, 1.0),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
onPressed: () => Navigator.of(context).pop(),
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -722,26 +733,24 @@ class CloudFileZoomIn extends HookConsumerWidget {
|
|||||||
icon: Icon(
|
icon: Icon(
|
||||||
Icons.info_outline,
|
Icons.info_outline,
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
shadows: [
|
shadows: shadow,
|
||||||
Shadow(
|
|
||||||
color: Colors.black54,
|
|
||||||
blurRadius: 5.0,
|
|
||||||
offset: Offset(1.0, 1.0),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
onPressed: showInfoSheet,
|
onPressed: showInfoSheet,
|
||||||
),
|
),
|
||||||
Spacer(),
|
Spacer(),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: Icon(Icons.remove, color: Colors.white),
|
icon: Icon(
|
||||||
|
Icons.remove,
|
||||||
|
color: Colors.white,
|
||||||
|
shadows: shadow,
|
||||||
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
photoViewController.scale =
|
photoViewController.scale =
|
||||||
(photoViewController.scale ?? 1) - 0.05;
|
(photoViewController.scale ?? 1) - 0.05;
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: Icon(Icons.add, color: Colors.white),
|
icon: Icon(Icons.add, color: Colors.white, shadows: shadow),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
photoViewController.scale =
|
photoViewController.scale =
|
||||||
(photoViewController.scale ?? 1) + 0.05;
|
(photoViewController.scale ?? 1) + 0.05;
|
||||||
@@ -752,13 +761,7 @@ class CloudFileZoomIn extends HookConsumerWidget {
|
|||||||
icon: Icon(
|
icon: Icon(
|
||||||
Icons.rotate_left,
|
Icons.rotate_left,
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
shadows: [
|
shadows: shadow,
|
||||||
Shadow(
|
|
||||||
color: Colors.black54,
|
|
||||||
blurRadius: 5.0,
|
|
||||||
offset: Offset(1.0, 1.0),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
rotation.value = (rotation.value - 1) % 4;
|
rotation.value = (rotation.value - 1) % 4;
|
||||||
|
@@ -18,6 +18,7 @@ import 'package:island/screens/posts/compose.dart';
|
|||||||
import 'package:island/widgets/alert.dart';
|
import 'package:island/widgets/alert.dart';
|
||||||
import 'package:island/widgets/content/markdown.dart';
|
import 'package:island/widgets/content/markdown.dart';
|
||||||
import 'package:island/widgets/post/post_item_screenshot.dart';
|
import 'package:island/widgets/post/post_item_screenshot.dart';
|
||||||
|
import 'package:island/widgets/post/post_pin_sheet.dart';
|
||||||
import 'package:island/widgets/post/post_shared.dart';
|
import 'package:island/widgets/post/post_shared.dart';
|
||||||
import 'package:island/widgets/safety/abuse_report_helper.dart';
|
import 'package:island/widgets/safety/abuse_report_helper.dart';
|
||||||
import 'package:island/widgets/share/share_sheet.dart';
|
import 'package:island/widgets/share/share_sheet.dart';
|
||||||
@@ -202,6 +203,45 @@ class PostActionableItem extends HookConsumerWidget {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
if (isAuthor && item.pinMode == null)
|
||||||
|
MenuAction(
|
||||||
|
title: 'pinPost'.tr(),
|
||||||
|
image: MenuImage.icon(Symbols.keep),
|
||||||
|
callback: () {
|
||||||
|
showModalBottomSheet(
|
||||||
|
context: context,
|
||||||
|
isScrollControlled: true,
|
||||||
|
builder: (context) => PostPinSheet(post: item),
|
||||||
|
).then((value) {
|
||||||
|
if (value is int) {
|
||||||
|
onUpdate?.call(item.copyWith(pinMode: value));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
)
|
||||||
|
else if (isAuthor && item.pinMode != null)
|
||||||
|
MenuAction(
|
||||||
|
title: 'unpinPost'.tr(),
|
||||||
|
image: MenuImage.icon(Symbols.keep_off),
|
||||||
|
callback: () {
|
||||||
|
showConfirmAlert('unpinPostHint'.tr(), 'unpinPost'.tr()).then(
|
||||||
|
(confirm) async {
|
||||||
|
if (confirm) {
|
||||||
|
final client = ref.watch(apiClientProvider);
|
||||||
|
try {
|
||||||
|
if (context.mounted) showLoadingModal(context);
|
||||||
|
await client.delete('/sphere/posts/${item.id}/pin');
|
||||||
|
onUpdate?.call(item.copyWith(pinMode: null));
|
||||||
|
} catch (err) {
|
||||||
|
showErrorAlert(err);
|
||||||
|
} finally {
|
||||||
|
if (context.mounted) hideLoadingModal(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
MenuSeparator(),
|
MenuSeparator(),
|
||||||
MenuAction(
|
MenuAction(
|
||||||
title: 'share'.tr(),
|
title: 'share'.tr(),
|
||||||
|
@@ -21,6 +21,7 @@ class PostListNotifier extends _$PostListNotifier
|
|||||||
int? type,
|
int? type,
|
||||||
List<String>? categories,
|
List<String>? categories,
|
||||||
List<String>? tags,
|
List<String>? tags,
|
||||||
|
bool? pinned,
|
||||||
bool shuffle = false,
|
bool shuffle = false,
|
||||||
}) {
|
}) {
|
||||||
return fetch(cursor: null);
|
return fetch(cursor: null);
|
||||||
@@ -40,6 +41,7 @@ class PostListNotifier extends _$PostListNotifier
|
|||||||
if (tags != null) 'tags': tags,
|
if (tags != null) 'tags': tags,
|
||||||
if (categories != null) 'categories': categories,
|
if (categories != null) 'categories': categories,
|
||||||
if (shuffle) 'shuffle': true,
|
if (shuffle) 'shuffle': true,
|
||||||
|
if (pinned != null) 'pinned': pinned,
|
||||||
};
|
};
|
||||||
|
|
||||||
final response = await client.get(
|
final response = await client.get(
|
||||||
@@ -77,12 +79,14 @@ class SliverPostList extends HookConsumerWidget {
|
|||||||
final List<String>? categories;
|
final List<String>? categories;
|
||||||
final List<String>? tags;
|
final List<String>? tags;
|
||||||
final bool shuffle;
|
final bool shuffle;
|
||||||
|
final bool? pinned;
|
||||||
final PostItemType itemType;
|
final PostItemType itemType;
|
||||||
final Color? backgroundColor;
|
final Color? backgroundColor;
|
||||||
final EdgeInsets? padding;
|
final EdgeInsets? padding;
|
||||||
final bool isOpenable;
|
final bool isOpenable;
|
||||||
final Function? onRefresh;
|
final Function? onRefresh;
|
||||||
final Function(SnPost)? onUpdate;
|
final Function(SnPost)? onUpdate;
|
||||||
|
final double? maxWidth;
|
||||||
|
|
||||||
const SliverPostList({
|
const SliverPostList({
|
||||||
super.key,
|
super.key,
|
||||||
@@ -92,43 +96,31 @@ class SliverPostList extends HookConsumerWidget {
|
|||||||
this.categories,
|
this.categories,
|
||||||
this.tags,
|
this.tags,
|
||||||
this.shuffle = false,
|
this.shuffle = false,
|
||||||
|
this.pinned,
|
||||||
this.itemType = PostItemType.regular,
|
this.itemType = PostItemType.regular,
|
||||||
this.backgroundColor,
|
this.backgroundColor,
|
||||||
this.padding,
|
this.padding,
|
||||||
this.isOpenable = true,
|
this.isOpenable = true,
|
||||||
this.onRefresh,
|
this.onRefresh,
|
||||||
this.onUpdate,
|
this.onUpdate,
|
||||||
|
this.maxWidth,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final provider = postListNotifierProvider(
|
||||||
|
pubName: pubName,
|
||||||
|
realm: realm,
|
||||||
|
type: type,
|
||||||
|
categories: categories,
|
||||||
|
tags: tags,
|
||||||
|
shuffle: shuffle,
|
||||||
|
pinned: pinned,
|
||||||
|
);
|
||||||
return PagingHelperSliverView(
|
return PagingHelperSliverView(
|
||||||
provider: postListNotifierProvider(
|
provider: provider,
|
||||||
pubName: pubName,
|
futureRefreshable: provider.future,
|
||||||
realm: realm,
|
notifierRefreshable: provider.notifier,
|
||||||
type: type,
|
|
||||||
categories: categories,
|
|
||||||
tags: tags,
|
|
||||||
shuffle: shuffle,
|
|
||||||
),
|
|
||||||
futureRefreshable:
|
|
||||||
postListNotifierProvider(
|
|
||||||
pubName: pubName,
|
|
||||||
realm: realm,
|
|
||||||
type: type,
|
|
||||||
categories: categories,
|
|
||||||
tags: tags,
|
|
||||||
shuffle: shuffle,
|
|
||||||
).future,
|
|
||||||
notifierRefreshable:
|
|
||||||
postListNotifierProvider(
|
|
||||||
pubName: pubName,
|
|
||||||
realm: realm,
|
|
||||||
type: type,
|
|
||||||
categories: categories,
|
|
||||||
tags: tags,
|
|
||||||
shuffle: shuffle,
|
|
||||||
).notifier,
|
|
||||||
contentBuilder:
|
contentBuilder:
|
||||||
(data, widgetCount, endItemView) => SliverList.builder(
|
(data, widgetCount, endItemView) => SliverList.builder(
|
||||||
itemCount: widgetCount,
|
itemCount: widgetCount,
|
||||||
@@ -139,6 +131,15 @@ class SliverPostList extends HookConsumerWidget {
|
|||||||
|
|
||||||
final post = data.items[index];
|
final post = data.items[index];
|
||||||
|
|
||||||
|
if (maxWidth != null) {
|
||||||
|
return Center(
|
||||||
|
child: ConstrainedBox(
|
||||||
|
constraints: BoxConstraints(maxWidth: maxWidth!),
|
||||||
|
child: _buildPostItem(post),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return _buildPostItem(post);
|
return _buildPostItem(post);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@@ -6,7 +6,7 @@ part of 'post_list.dart';
|
|||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$postListNotifierHash() => r'faa0b939fae56367ff120ce63d9deb17b1995c9c';
|
String _$postListNotifierHash() => r'3c0a8154ded4bcd8f5456f7a4ea2e542f57efa85';
|
||||||
|
|
||||||
/// Copied from Dart SDK
|
/// Copied from Dart SDK
|
||||||
class _SystemHash {
|
class _SystemHash {
|
||||||
@@ -36,6 +36,7 @@ abstract class _$PostListNotifier
|
|||||||
late final int? type;
|
late final int? type;
|
||||||
late final List<String>? categories;
|
late final List<String>? categories;
|
||||||
late final List<String>? tags;
|
late final List<String>? tags;
|
||||||
|
late final bool? pinned;
|
||||||
late final bool shuffle;
|
late final bool shuffle;
|
||||||
|
|
||||||
FutureOr<CursorPagingData<SnPost>> build({
|
FutureOr<CursorPagingData<SnPost>> build({
|
||||||
@@ -44,6 +45,7 @@ abstract class _$PostListNotifier
|
|||||||
int? type,
|
int? type,
|
||||||
List<String>? categories,
|
List<String>? categories,
|
||||||
List<String>? tags,
|
List<String>? tags,
|
||||||
|
bool? pinned,
|
||||||
bool shuffle = false,
|
bool shuffle = false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -65,6 +67,7 @@ class PostListNotifierFamily
|
|||||||
int? type,
|
int? type,
|
||||||
List<String>? categories,
|
List<String>? categories,
|
||||||
List<String>? tags,
|
List<String>? tags,
|
||||||
|
bool? pinned,
|
||||||
bool shuffle = false,
|
bool shuffle = false,
|
||||||
}) {
|
}) {
|
||||||
return PostListNotifierProvider(
|
return PostListNotifierProvider(
|
||||||
@@ -73,6 +76,7 @@ class PostListNotifierFamily
|
|||||||
type: type,
|
type: type,
|
||||||
categories: categories,
|
categories: categories,
|
||||||
tags: tags,
|
tags: tags,
|
||||||
|
pinned: pinned,
|
||||||
shuffle: shuffle,
|
shuffle: shuffle,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -87,6 +91,7 @@ class PostListNotifierFamily
|
|||||||
type: provider.type,
|
type: provider.type,
|
||||||
categories: provider.categories,
|
categories: provider.categories,
|
||||||
tags: provider.tags,
|
tags: provider.tags,
|
||||||
|
pinned: provider.pinned,
|
||||||
shuffle: provider.shuffle,
|
shuffle: provider.shuffle,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -120,6 +125,7 @@ class PostListNotifierProvider
|
|||||||
int? type,
|
int? type,
|
||||||
List<String>? categories,
|
List<String>? categories,
|
||||||
List<String>? tags,
|
List<String>? tags,
|
||||||
|
bool? pinned,
|
||||||
bool shuffle = false,
|
bool shuffle = false,
|
||||||
}) : this._internal(
|
}) : this._internal(
|
||||||
() =>
|
() =>
|
||||||
@@ -129,6 +135,7 @@ class PostListNotifierProvider
|
|||||||
..type = type
|
..type = type
|
||||||
..categories = categories
|
..categories = categories
|
||||||
..tags = tags
|
..tags = tags
|
||||||
|
..pinned = pinned
|
||||||
..shuffle = shuffle,
|
..shuffle = shuffle,
|
||||||
from: postListNotifierProvider,
|
from: postListNotifierProvider,
|
||||||
name: r'postListNotifierProvider',
|
name: r'postListNotifierProvider',
|
||||||
@@ -144,6 +151,7 @@ class PostListNotifierProvider
|
|||||||
type: type,
|
type: type,
|
||||||
categories: categories,
|
categories: categories,
|
||||||
tags: tags,
|
tags: tags,
|
||||||
|
pinned: pinned,
|
||||||
shuffle: shuffle,
|
shuffle: shuffle,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -159,6 +167,7 @@ class PostListNotifierProvider
|
|||||||
required this.type,
|
required this.type,
|
||||||
required this.categories,
|
required this.categories,
|
||||||
required this.tags,
|
required this.tags,
|
||||||
|
required this.pinned,
|
||||||
required this.shuffle,
|
required this.shuffle,
|
||||||
}) : super.internal();
|
}) : super.internal();
|
||||||
|
|
||||||
@@ -167,6 +176,7 @@ class PostListNotifierProvider
|
|||||||
final int? type;
|
final int? type;
|
||||||
final List<String>? categories;
|
final List<String>? categories;
|
||||||
final List<String>? tags;
|
final List<String>? tags;
|
||||||
|
final bool? pinned;
|
||||||
final bool shuffle;
|
final bool shuffle;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -179,6 +189,7 @@ class PostListNotifierProvider
|
|||||||
type: type,
|
type: type,
|
||||||
categories: categories,
|
categories: categories,
|
||||||
tags: tags,
|
tags: tags,
|
||||||
|
pinned: pinned,
|
||||||
shuffle: shuffle,
|
shuffle: shuffle,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -195,6 +206,7 @@ class PostListNotifierProvider
|
|||||||
..type = type
|
..type = type
|
||||||
..categories = categories
|
..categories = categories
|
||||||
..tags = tags
|
..tags = tags
|
||||||
|
..pinned = pinned
|
||||||
..shuffle = shuffle,
|
..shuffle = shuffle,
|
||||||
from: from,
|
from: from,
|
||||||
name: null,
|
name: null,
|
||||||
@@ -206,6 +218,7 @@ class PostListNotifierProvider
|
|||||||
type: type,
|
type: type,
|
||||||
categories: categories,
|
categories: categories,
|
||||||
tags: tags,
|
tags: tags,
|
||||||
|
pinned: pinned,
|
||||||
shuffle: shuffle,
|
shuffle: shuffle,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -228,6 +241,7 @@ class PostListNotifierProvider
|
|||||||
other.type == type &&
|
other.type == type &&
|
||||||
other.categories == categories &&
|
other.categories == categories &&
|
||||||
other.tags == tags &&
|
other.tags == tags &&
|
||||||
|
other.pinned == pinned &&
|
||||||
other.shuffle == shuffle;
|
other.shuffle == shuffle;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -239,6 +253,7 @@ class PostListNotifierProvider
|
|||||||
hash = _SystemHash.combine(hash, type.hashCode);
|
hash = _SystemHash.combine(hash, type.hashCode);
|
||||||
hash = _SystemHash.combine(hash, categories.hashCode);
|
hash = _SystemHash.combine(hash, categories.hashCode);
|
||||||
hash = _SystemHash.combine(hash, tags.hashCode);
|
hash = _SystemHash.combine(hash, tags.hashCode);
|
||||||
|
hash = _SystemHash.combine(hash, pinned.hashCode);
|
||||||
hash = _SystemHash.combine(hash, shuffle.hashCode);
|
hash = _SystemHash.combine(hash, shuffle.hashCode);
|
||||||
|
|
||||||
return _SystemHash.finish(hash);
|
return _SystemHash.finish(hash);
|
||||||
@@ -264,6 +279,9 @@ mixin PostListNotifierRef
|
|||||||
/// The parameter `tags` of this provider.
|
/// The parameter `tags` of this provider.
|
||||||
List<String>? get tags;
|
List<String>? get tags;
|
||||||
|
|
||||||
|
/// The parameter `pinned` of this provider.
|
||||||
|
bool? get pinned;
|
||||||
|
|
||||||
/// The parameter `shuffle` of this provider.
|
/// The parameter `shuffle` of this provider.
|
||||||
bool get shuffle;
|
bool get shuffle;
|
||||||
}
|
}
|
||||||
@@ -289,6 +307,8 @@ class _PostListNotifierProviderElement
|
|||||||
@override
|
@override
|
||||||
List<String>? get tags => (origin as PostListNotifierProvider).tags;
|
List<String>? get tags => (origin as PostListNotifierProvider).tags;
|
||||||
@override
|
@override
|
||||||
|
bool? get pinned => (origin as PostListNotifierProvider).pinned;
|
||||||
|
@override
|
||||||
bool get shuffle => (origin as PostListNotifierProvider).shuffle;
|
bool get shuffle => (origin as PostListNotifierProvider).shuffle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
124
lib/widgets/post/post_pin_sheet.dart
Normal file
124
lib/widgets/post/post_pin_sheet.dart
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:island/models/post.dart';
|
||||||
|
import 'package:island/pods/network.dart';
|
||||||
|
import 'package:island/widgets/alert.dart';
|
||||||
|
import 'package:island/widgets/content/sheet.dart';
|
||||||
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
|
|
||||||
|
class PostPinSheet extends HookConsumerWidget {
|
||||||
|
final SnPost post;
|
||||||
|
const PostPinSheet({super.key, required this.post});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final mode = useState(0);
|
||||||
|
|
||||||
|
Future<void> pinPost() async {
|
||||||
|
try {
|
||||||
|
showLoadingModal(context);
|
||||||
|
final client = ref.watch(apiClientProvider);
|
||||||
|
await client.post(
|
||||||
|
'/sphere/posts/${post.id}/pin',
|
||||||
|
data: {'mode': mode.value},
|
||||||
|
);
|
||||||
|
|
||||||
|
if (context.mounted) Navigator.of(context).pop(mode.value);
|
||||||
|
} catch (e) {
|
||||||
|
showErrorAlert(e);
|
||||||
|
} finally {
|
||||||
|
if (context.mounted) hideLoadingModal(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return SheetScaffold(
|
||||||
|
titleText: 'pinPost'.tr(),
|
||||||
|
heightFactor: 0.6,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: [
|
||||||
|
// Publisher page pin option (always available)
|
||||||
|
ListTile(
|
||||||
|
leading: Radio<int>(
|
||||||
|
value: 0,
|
||||||
|
groupValue: mode.value,
|
||||||
|
onChanged: (value) {
|
||||||
|
mode.value = value!;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
title: Text('publisherPage'.tr()),
|
||||||
|
subtitle: Text('pinPostPublisherHint'.tr()),
|
||||||
|
onTap: () {
|
||||||
|
mode.value = 0;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
|
||||||
|
// Realm page pin option (show always, but disabled when not available)
|
||||||
|
ListTile(
|
||||||
|
leading: Radio<int>(
|
||||||
|
value: 1,
|
||||||
|
groupValue: mode.value,
|
||||||
|
onChanged:
|
||||||
|
post.realmId != null && post.realmId!.isNotEmpty
|
||||||
|
? (value) {
|
||||||
|
mode.value = value!;
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
),
|
||||||
|
title: Text('realmPage'.tr()),
|
||||||
|
subtitle:
|
||||||
|
post.realmId != null && post.realmId!.isNotEmpty
|
||||||
|
? Text('pinPostRealmHint'.tr())
|
||||||
|
: Text('pinPostRealmDisabledHint'.tr()),
|
||||||
|
onTap:
|
||||||
|
post.realmId != null && post.realmId!.isNotEmpty
|
||||||
|
? () {
|
||||||
|
mode.value = 1;
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
enabled: post.realmId != null && post.realmId!.isNotEmpty,
|
||||||
|
),
|
||||||
|
|
||||||
|
// Reply page pin option (show always, but disabled when not available)
|
||||||
|
// Disabled for now because im being lazy
|
||||||
|
// ListTile(
|
||||||
|
// leading: Radio<int>(
|
||||||
|
// value: 2,
|
||||||
|
// groupValue: mode.value,
|
||||||
|
// onChanged:
|
||||||
|
// post.repliedPostId != null && post.repliedPostId!.isNotEmpty
|
||||||
|
// ? (value) {
|
||||||
|
// mode.value = value!;
|
||||||
|
// }
|
||||||
|
// : null,
|
||||||
|
// ),
|
||||||
|
// title: Text('replyPage'.tr()),
|
||||||
|
// subtitle:
|
||||||
|
// post.repliedPostId != null && post.repliedPostId!.isNotEmpty
|
||||||
|
// ? Text('pinPostReplyHint'.tr())
|
||||||
|
// : Text('pinPostReplyDisabledHint'.tr()),
|
||||||
|
// onTap:
|
||||||
|
// post.repliedPostId != null && post.repliedPostId!.isNotEmpty
|
||||||
|
// ? () {
|
||||||
|
// mode.value = 2;
|
||||||
|
// }
|
||||||
|
// : null,
|
||||||
|
// enabled:
|
||||||
|
// post.repliedPostId != null && post.repliedPostId!.isNotEmpty,
|
||||||
|
// ),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
|
||||||
|
// Pin button
|
||||||
|
FilledButton.icon(
|
||||||
|
onPressed: pinPost,
|
||||||
|
icon: const Icon(Symbols.keep),
|
||||||
|
label: Text('pin'.tr()),
|
||||||
|
).padding(horizontal: 24),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@@ -545,107 +545,119 @@ class PostHeader extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Row(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
spacing: 12,
|
|
||||||
children: [
|
children: [
|
||||||
GestureDetector(
|
if (item.pinMode != null)
|
||||||
onTap:
|
Row(
|
||||||
isInteractive
|
spacing: 4,
|
||||||
? () {
|
|
||||||
context.pushNamed(
|
|
||||||
'publisherProfile',
|
|
||||||
pathParameters: {'name': item.publisher.name},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
: null,
|
|
||||||
child: ProfilePictureWidget(
|
|
||||||
file: item.publisher.picture,
|
|
||||||
radius: 16,
|
|
||||||
borderRadius: item.publisher.type == 0 ? null : 6,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
children: [
|
||||||
Row(
|
const Icon(Symbols.keep, size: 15, fill: 1),
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
Text('pinnedPost').tr().fontSize(13),
|
||||||
spacing: 4,
|
],
|
||||||
|
).opacity(0.8).padding(horizontal: 8, bottom: 4),
|
||||||
|
Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
spacing: 12,
|
||||||
|
children: [
|
||||||
|
GestureDetector(
|
||||||
|
onTap:
|
||||||
|
isInteractive
|
||||||
|
? () {
|
||||||
|
context.pushNamed(
|
||||||
|
'publisherProfile',
|
||||||
|
pathParameters: {'name': item.publisher.name},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
child: ProfilePictureWidget(
|
||||||
|
file: item.publisher.picture,
|
||||||
|
radius: 16,
|
||||||
|
borderRadius: item.publisher.type == 0 ? null : 6,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(item.publisher.nick).bold(),
|
Row(
|
||||||
if (item.publisher.verification != null)
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
VerificationMark(mark: item.publisher.verification!),
|
spacing: 4,
|
||||||
if (item.realm == null)
|
children: [
|
||||||
Text('@${item.publisher.name}').fontSize(11)
|
Text(item.publisher.nick).bold(),
|
||||||
else
|
if (item.publisher.verification != null)
|
||||||
...([
|
VerificationMark(mark: item.publisher.verification!),
|
||||||
const Icon(Symbols.arrow_right, size: 14),
|
if (item.realm == null)
|
||||||
Flexible(
|
Text('@${item.publisher.name}').fontSize(11)
|
||||||
child: InkWell(
|
else
|
||||||
child: Row(
|
...([
|
||||||
mainAxisSize: MainAxisSize.min,
|
const Icon(Symbols.arrow_right, size: 14),
|
||||||
spacing: 5,
|
Flexible(
|
||||||
children: [
|
child: InkWell(
|
||||||
Flexible(
|
child: Row(
|
||||||
child: Text(
|
mainAxisSize: MainAxisSize.min,
|
||||||
item.realm!.name,
|
spacing: 5,
|
||||||
maxLines: 1,
|
children: [
|
||||||
overflow: TextOverflow.ellipsis,
|
Flexible(
|
||||||
),
|
child: Text(
|
||||||
),
|
item.realm!.name,
|
||||||
ProfilePictureWidget(
|
maxLines: 1,
|
||||||
file: item.realm!.picture,
|
overflow: TextOverflow.ellipsis,
|
||||||
fallbackIcon: Symbols.group,
|
),
|
||||||
radius: 9,
|
),
|
||||||
|
ProfilePictureWidget(
|
||||||
|
file: item.realm!.picture,
|
||||||
|
fallbackIcon: Symbols.group,
|
||||||
|
radius: 9,
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
|
onTap: () {
|
||||||
|
GoRouter.of(context).pushNamed(
|
||||||
|
'realmDetail',
|
||||||
|
pathParameters: {'slug': item.realm!.slug},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
spacing: 6,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
!isFullPost && isRelativeTime
|
||||||
|
? (item.publishedAt ?? item.createdAt)!
|
||||||
|
.formatRelative(context)
|
||||||
|
: (item.publishedAt ?? item.createdAt)!
|
||||||
|
.formatSystem(),
|
||||||
|
).fontSize(10),
|
||||||
|
if (item.editedAt != null)
|
||||||
|
Text(
|
||||||
|
'editedAt'.tr(
|
||||||
|
args: [
|
||||||
|
!isFullPost && isRelativeTime
|
||||||
|
? item.editedAt!.formatRelative(context)
|
||||||
|
: item.editedAt!.formatSystem(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
onTap: () {
|
).fontSize(10),
|
||||||
GoRouter.of(context).pushNamed(
|
if (item.visibility != 0)
|
||||||
'realmDetail',
|
Text(
|
||||||
pathParameters: {'slug': item.realm!.slug},
|
PostVisibilityHelpers.getVisibilityText(
|
||||||
);
|
item.visibility,
|
||||||
},
|
).tr(),
|
||||||
),
|
).fontSize(10),
|
||||||
),
|
],
|
||||||
]),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Row(
|
),
|
||||||
spacing: 6,
|
if (trailing != null) trailing!,
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
],
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
!isFullPost && isRelativeTime
|
|
||||||
? (item.publishedAt ?? item.createdAt)!.formatRelative(
|
|
||||||
context,
|
|
||||||
)
|
|
||||||
: (item.publishedAt ?? item.createdAt)!.formatSystem(),
|
|
||||||
).fontSize(10),
|
|
||||||
if (item.editedAt != null)
|
|
||||||
Text(
|
|
||||||
'editedAt'.tr(
|
|
||||||
args: [
|
|
||||||
!isFullPost && isRelativeTime
|
|
||||||
? item.editedAt!.formatRelative(context)
|
|
||||||
: item.editedAt!.formatSystem(),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
).fontSize(10),
|
|
||||||
if (item.visibility != 0)
|
|
||||||
Text(
|
|
||||||
PostVisibilityHelpers.getVisibilityText(
|
|
||||||
item.visibility,
|
|
||||||
).tr(),
|
|
||||||
).fontSize(10),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
if (trailing != null) trailing!,
|
|
||||||
],
|
],
|
||||||
).padding(horizontal: renderingPadding.horizontal, bottom: 4);
|
).padding(horizontal: renderingPadding.horizontal, bottom: 4);
|
||||||
}
|
}
|
||||||
|
@@ -7,6 +7,7 @@
|
|||||||
#include "generated_plugin_registrant.h"
|
#include "generated_plugin_registrant.h"
|
||||||
|
|
||||||
#include <bitsdojo_window_linux/bitsdojo_window_plugin.h>
|
#include <bitsdojo_window_linux/bitsdojo_window_plugin.h>
|
||||||
|
#include <file_saver/file_saver_plugin.h>
|
||||||
#include <file_selector_linux/file_selector_plugin.h>
|
#include <file_selector_linux/file_selector_plugin.h>
|
||||||
#include <flutter_platform_alert/flutter_platform_alert_plugin.h>
|
#include <flutter_platform_alert/flutter_platform_alert_plugin.h>
|
||||||
#include <flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h>
|
#include <flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h>
|
||||||
@@ -28,6 +29,9 @@ void fl_register_plugins(FlPluginRegistry* registry) {
|
|||||||
g_autoptr(FlPluginRegistrar) bitsdojo_window_linux_registrar =
|
g_autoptr(FlPluginRegistrar) bitsdojo_window_linux_registrar =
|
||||||
fl_plugin_registry_get_registrar_for_plugin(registry, "BitsdojoWindowPlugin");
|
fl_plugin_registry_get_registrar_for_plugin(registry, "BitsdojoWindowPlugin");
|
||||||
bitsdojo_window_plugin_register_with_registrar(bitsdojo_window_linux_registrar);
|
bitsdojo_window_plugin_register_with_registrar(bitsdojo_window_linux_registrar);
|
||||||
|
g_autoptr(FlPluginRegistrar) file_saver_registrar =
|
||||||
|
fl_plugin_registry_get_registrar_for_plugin(registry, "FileSaverPlugin");
|
||||||
|
file_saver_plugin_register_with_registrar(file_saver_registrar);
|
||||||
g_autoptr(FlPluginRegistrar) file_selector_linux_registrar =
|
g_autoptr(FlPluginRegistrar) file_selector_linux_registrar =
|
||||||
fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin");
|
fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin");
|
||||||
file_selector_plugin_register_with_registrar(file_selector_linux_registrar);
|
file_selector_plugin_register_with_registrar(file_selector_linux_registrar);
|
||||||
|
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
bitsdojo_window_linux
|
bitsdojo_window_linux
|
||||||
|
file_saver
|
||||||
file_selector_linux
|
file_selector_linux
|
||||||
flutter_platform_alert
|
flutter_platform_alert
|
||||||
flutter_secure_storage_linux
|
flutter_secure_storage_linux
|
||||||
|
@@ -9,6 +9,7 @@ import bitsdojo_window_macos
|
|||||||
import connectivity_plus
|
import connectivity_plus
|
||||||
import device_info_plus
|
import device_info_plus
|
||||||
import file_picker
|
import file_picker
|
||||||
|
import file_saver
|
||||||
import file_selector_macos
|
import file_selector_macos
|
||||||
import firebase_analytics
|
import firebase_analytics
|
||||||
import firebase_core
|
import firebase_core
|
||||||
@@ -45,6 +46,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
|||||||
ConnectivityPlusPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlusPlugin"))
|
ConnectivityPlusPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlusPlugin"))
|
||||||
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
|
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
|
||||||
FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin"))
|
FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin"))
|
||||||
|
FileSaverPlugin.register(with: registry.registrar(forPlugin: "FileSaverPlugin"))
|
||||||
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
|
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
|
||||||
FirebaseAnalyticsPlugin.register(with: registry.registrar(forPlugin: "FirebaseAnalyticsPlugin"))
|
FirebaseAnalyticsPlugin.register(with: registry.registrar(forPlugin: "FirebaseAnalyticsPlugin"))
|
||||||
FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin"))
|
FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin"))
|
||||||
|
@@ -9,6 +9,8 @@ PODS:
|
|||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
- file_picker (0.0.1):
|
- file_picker (0.0.1):
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
|
- file_saver (0.0.1):
|
||||||
|
- FlutterMacOS
|
||||||
- file_selector_macos (0.0.1):
|
- file_selector_macos (0.0.1):
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
- Firebase/CoreOnly (12.0.0):
|
- Firebase/CoreOnly (12.0.0):
|
||||||
@@ -249,6 +251,7 @@ DEPENDENCIES:
|
|||||||
- croppy (from `Flutter/ephemeral/.symlinks/plugins/croppy/macos`)
|
- croppy (from `Flutter/ephemeral/.symlinks/plugins/croppy/macos`)
|
||||||
- device_info_plus (from `Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos`)
|
- device_info_plus (from `Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos`)
|
||||||
- file_picker (from `Flutter/ephemeral/.symlinks/plugins/file_picker/macos`)
|
- file_picker (from `Flutter/ephemeral/.symlinks/plugins/file_picker/macos`)
|
||||||
|
- file_saver (from `Flutter/ephemeral/.symlinks/plugins/file_saver/macos`)
|
||||||
- file_selector_macos (from `Flutter/ephemeral/.symlinks/plugins/file_selector_macos/macos`)
|
- file_selector_macos (from `Flutter/ephemeral/.symlinks/plugins/file_selector_macos/macos`)
|
||||||
- firebase_analytics (from `Flutter/ephemeral/.symlinks/plugins/firebase_analytics/macos`)
|
- firebase_analytics (from `Flutter/ephemeral/.symlinks/plugins/firebase_analytics/macos`)
|
||||||
- firebase_core (from `Flutter/ephemeral/.symlinks/plugins/firebase_core/macos`)
|
- firebase_core (from `Flutter/ephemeral/.symlinks/plugins/firebase_core/macos`)
|
||||||
@@ -315,6 +318,8 @@ EXTERNAL SOURCES:
|
|||||||
:path: Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos
|
:path: Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos
|
||||||
file_picker:
|
file_picker:
|
||||||
:path: Flutter/ephemeral/.symlinks/plugins/file_picker/macos
|
:path: Flutter/ephemeral/.symlinks/plugins/file_picker/macos
|
||||||
|
file_saver:
|
||||||
|
:path: Flutter/ephemeral/.symlinks/plugins/file_saver/macos
|
||||||
file_selector_macos:
|
file_selector_macos:
|
||||||
:path: Flutter/ephemeral/.symlinks/plugins/file_selector_macos/macos
|
:path: Flutter/ephemeral/.symlinks/plugins/file_selector_macos/macos
|
||||||
firebase_analytics:
|
firebase_analytics:
|
||||||
@@ -384,6 +389,7 @@ SPEC CHECKSUMS:
|
|||||||
croppy: d9bfc8c02f3cd1851f669a421df298a474b78f43
|
croppy: d9bfc8c02f3cd1851f669a421df298a474b78f43
|
||||||
device_info_plus: 4fb280989f669696856f8b129e4a5e3cd6c48f76
|
device_info_plus: 4fb280989f669696856f8b129e4a5e3cd6c48f76
|
||||||
file_picker: 7584aae6fa07a041af2b36a2655122d42f578c1a
|
file_picker: 7584aae6fa07a041af2b36a2655122d42f578c1a
|
||||||
|
file_saver: e35bd97de451dde55ff8c38862ed7ad0f3418d0f
|
||||||
file_selector_macos: 6280b52b459ae6c590af5d78fc35c7267a3c4b31
|
file_selector_macos: 6280b52b459ae6c590af5d78fc35c7267a3c4b31
|
||||||
Firebase: 800d487043c0557d9faed71477a38d9aafb08a41
|
Firebase: 800d487043c0557d9faed71477a38d9aafb08a41
|
||||||
firebase_analytics: 53f0dc87ad10f56a6df8746da60d8a5fe41f886f
|
firebase_analytics: 53f0dc87ad10f56a6df8746da60d8a5fe41f886f
|
||||||
|
20
pubspec.lock
20
pubspec.lock
@@ -569,6 +569,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "10.3.2"
|
version: "10.3.2"
|
||||||
|
file_saver:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: file_saver
|
||||||
|
sha256: "9d93db09bd4da9e43238f9dd485360fc51a5c138eea5ef5f407ec56e58079ac0"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.3.1"
|
||||||
file_selector_linux:
|
file_selector_linux:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1921,10 +1929,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: record_ios
|
name: record_ios
|
||||||
sha256: "895c9467faec72d8e718a3142b51114958f42f18053836a8b484a74f9372f51a"
|
sha256: "13e241ed9cbc220534a40ae6b66222e21288db364d96dd66fb762ebd3cb77c71"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.1"
|
version: "1.1.2"
|
||||||
record_linux:
|
record_linux:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -2041,10 +2049,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: screen_brightness_android
|
name: screen_brightness_android
|
||||||
sha256: fb5fa43cb89d0c9b8534556c427db1e97e46594ac5d66ebdcf16063b773d54ed
|
sha256: d34f5321abd03bc3474f4c381f53d189117eba0b039eac1916aa92cca5fd0a96
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.2"
|
version: "2.1.3"
|
||||||
screen_brightness_platform_interface:
|
screen_brightness_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -2640,10 +2648,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: watcher
|
name: watcher
|
||||||
sha256: "0b7fd4a0bbc4b92641dbf20adfd7e3fd1398fe17102d94b674234563e110088a"
|
sha256: "5bf046f41320ac97a469d506261797f35254fa61c641741ef32dacda98b7d39c"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.2"
|
version: "1.1.3"
|
||||||
waveform_flutter:
|
waveform_flutter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@@ -16,7 +16,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev
|
|||||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||||
# In Windows, build-name is used as the major, minor, and patch parts
|
# In Windows, build-name is used as the major, minor, and patch parts
|
||||||
# of the product and file versions while build-number is used as the build suffix.
|
# of the product and file versions while build-number is used as the build suffix.
|
||||||
version: 3.2.0+127
|
version: 3.2.0+129
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ^3.7.2
|
sdk: ^3.7.2
|
||||||
@@ -139,6 +139,7 @@ dependencies:
|
|||||||
material_color_utilities: ^0.11.1
|
material_color_utilities: ^0.11.1
|
||||||
screenshot: ^3.0.0
|
screenshot: ^3.0.0
|
||||||
flutter_card_swiper: ^7.0.2
|
flutter_card_swiper: ^7.0.2
|
||||||
|
file_saver: ^0.3.1
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
@@ -235,4 +236,5 @@ msix_config:
|
|||||||
identity_name: dev.solian.app
|
identity_name: dev.solian.app
|
||||||
msix_version: 3.2.0.0
|
msix_version: 3.2.0.0
|
||||||
logo_path: .\assets\icons\icon.png
|
logo_path: .\assets\icons\icon.png
|
||||||
capabilities: internetClientServer, location, microphone, webcam
|
capabilities: internetClientServer, location, microphone, webcam
|
||||||
|
|
||||||
|
1169
swagger.json
1169
swagger.json
File diff suppressed because it is too large
Load Diff
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#include <bitsdojo_window_windows/bitsdojo_window_plugin.h>
|
#include <bitsdojo_window_windows/bitsdojo_window_plugin.h>
|
||||||
#include <connectivity_plus/connectivity_plus_windows_plugin.h>
|
#include <connectivity_plus/connectivity_plus_windows_plugin.h>
|
||||||
|
#include <file_saver/file_saver_plugin.h>
|
||||||
#include <file_selector_windows/file_selector_windows.h>
|
#include <file_selector_windows/file_selector_windows.h>
|
||||||
#include <firebase_core/firebase_core_plugin_c_api.h>
|
#include <firebase_core/firebase_core_plugin_c_api.h>
|
||||||
#include <flutter_inappwebview_windows/flutter_inappwebview_windows_plugin_c_api.h>
|
#include <flutter_inappwebview_windows/flutter_inappwebview_windows_plugin_c_api.h>
|
||||||
@@ -35,6 +36,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
|
|||||||
registry->GetRegistrarForPlugin("BitsdojoWindowPlugin"));
|
registry->GetRegistrarForPlugin("BitsdojoWindowPlugin"));
|
||||||
ConnectivityPlusWindowsPluginRegisterWithRegistrar(
|
ConnectivityPlusWindowsPluginRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin"));
|
registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin"));
|
||||||
|
FileSaverPluginRegisterWithRegistrar(
|
||||||
|
registry->GetRegistrarForPlugin("FileSaverPlugin"));
|
||||||
FileSelectorWindowsRegisterWithRegistrar(
|
FileSelectorWindowsRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("FileSelectorWindows"));
|
registry->GetRegistrarForPlugin("FileSelectorWindows"));
|
||||||
FirebaseCorePluginCApiRegisterWithRegistrar(
|
FirebaseCorePluginCApiRegisterWithRegistrar(
|
||||||
|
@@ -5,6 +5,7 @@
|
|||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
bitsdojo_window_windows
|
bitsdojo_window_windows
|
||||||
connectivity_plus
|
connectivity_plus
|
||||||
|
file_saver
|
||||||
file_selector_windows
|
file_selector_windows
|
||||||
firebase_core
|
firebase_core
|
||||||
flutter_inappwebview_windows
|
flutter_inappwebview_windows
|
||||||
|
Reference in New Issue
Block a user