Compare commits
19 Commits
Author | SHA1 | Date | |
---|---|---|---|
88396647f3 | |||
335318ae3f | |||
da25fb9c29 | |||
c1aef89b84 | |||
0241c5f804 | |||
f6939d7c23 | |||
d654c162e3 | |||
25550ba197 | |||
3defd3a593 | |||
d62ed4c375 | |||
857f3cc832 | |||
e16bc80eea | |||
a4f6e8af56 | |||
060a97f5ec | |||
92f7e92018 | |||
5c483bd3b8 | |||
1c510d63fe | |||
115cb4adc1 | |||
54c098c274 |
BIN
assets/fonts/Nunito-Bold.ttf
Executable file
BIN
assets/fonts/Nunito-Bold.ttf
Executable file
Binary file not shown.
BIN
assets/fonts/Nunito-Italic.ttf
Executable file
BIN
assets/fonts/Nunito-Italic.ttf
Executable file
Binary file not shown.
BIN
assets/fonts/Nunito-Regular.ttf
Executable file
BIN
assets/fonts/Nunito-Regular.ttf
Executable file
Binary file not shown.
@ -153,6 +153,11 @@
|
|||||||
"publisherRunBy": "Run by {}",
|
"publisherRunBy": "Run by {}",
|
||||||
"fieldPublisherBelongToRealm": "Belongs to",
|
"fieldPublisherBelongToRealm": "Belongs to",
|
||||||
"fieldPublisherBelongToRealmUnset": "Unset Publisher Belongs to Realm",
|
"fieldPublisherBelongToRealmUnset": "Unset Publisher Belongs to Realm",
|
||||||
|
"writePost": "Compose",
|
||||||
|
"postTypeStory": "Story",
|
||||||
|
"postTypeArticle": "Article",
|
||||||
|
"postTypeQuestion": "Question",
|
||||||
|
"postTypeVideo": "Video",
|
||||||
"writePostTypeStory": "Post a story",
|
"writePostTypeStory": "Post a story",
|
||||||
"writePostTypeArticle": "Write an article",
|
"writePostTypeArticle": "Write an article",
|
||||||
"writePostTypeQuestion": "Ask a question",
|
"writePostTypeQuestion": "Ask a question",
|
||||||
@ -763,5 +768,28 @@
|
|||||||
"decrypting": "Decrypting……",
|
"decrypting": "Decrypting……",
|
||||||
"decryptingKeyNotFound": "Key not found or exchange failed, the other party may not be online",
|
"decryptingKeyNotFound": "Key not found or exchange failed, the other party may not be online",
|
||||||
"messageUnablePreview": "Unable preview",
|
"messageUnablePreview": "Unable preview",
|
||||||
"messageUnablePreviewEncrypted": "Unable preview encrypted message"
|
"messageUnablePreviewEncrypted": "Unable preview encrypted message",
|
||||||
|
"postViewInGlobalDescription": "Do not view the post in the specific realm.",
|
||||||
|
"postDraftSaved": "The draft has been saved.",
|
||||||
|
"postDraftBox": "Draft Box",
|
||||||
|
"postShuffle": "Read Randomly",
|
||||||
|
"checkInStreak": {
|
||||||
|
"zero": "No streak",
|
||||||
|
"one": "{} day streak",
|
||||||
|
"other": "{} days streak"
|
||||||
|
},
|
||||||
|
"accountChangeStatus": "Change Status",
|
||||||
|
"accountStatusSilent": "Do not Disturb",
|
||||||
|
"accountStatusSilentDesc": "The notification will stop popping up",
|
||||||
|
"accountStatusInvisible": "Invisible",
|
||||||
|
"accountStatusInvisibleDesc": "Will show as offline, but all features still remain normal",
|
||||||
|
"accountCustomStatus": "Custom Status",
|
||||||
|
"accountCustomStatusDescription": "Customize your status.",
|
||||||
|
"accountClearStatus": "Clear Status",
|
||||||
|
"accountClearStatusDescription": "Clear your status, and let server decide which status you are for you.",
|
||||||
|
"fieldAccountStatusLabel": "Status Text",
|
||||||
|
"fieldAccountStatusClearAt": "Clear At",
|
||||||
|
"accountStatusNegative": "Negative",
|
||||||
|
"accountStatusNeutral": "Neutral",
|
||||||
|
"accountStatusPositive": "Positive"
|
||||||
}
|
}
|
||||||
|
@ -137,6 +137,11 @@
|
|||||||
"publisherRunBy": "由 {} 管理",
|
"publisherRunBy": "由 {} 管理",
|
||||||
"fieldPublisherBelongToRealm": "所属领域",
|
"fieldPublisherBelongToRealm": "所属领域",
|
||||||
"fieldPublisherBelongToRealmUnset": "未设置发布者所属领域",
|
"fieldPublisherBelongToRealmUnset": "未设置发布者所属领域",
|
||||||
|
"writePost": "撰写",
|
||||||
|
"postTypeStory": "动态",
|
||||||
|
"postTypeArticle": "文章",
|
||||||
|
"postTypeQuestion": "问题",
|
||||||
|
"postTypeVideo": "视频",
|
||||||
"writePostTypeStory": "发动态",
|
"writePostTypeStory": "发动态",
|
||||||
"writePostTypeArticle": "写文章",
|
"writePostTypeArticle": "写文章",
|
||||||
"writePostTypeQuestion": "提问题",
|
"writePostTypeQuestion": "提问题",
|
||||||
@ -761,5 +766,28 @@
|
|||||||
"decrypting": "解密中……",
|
"decrypting": "解密中……",
|
||||||
"decryptingKeyNotFound": "未找到密钥对或交换失败,对方可能不在线",
|
"decryptingKeyNotFound": "未找到密钥对或交换失败,对方可能不在线",
|
||||||
"messageUnablePreview": "无法预览消息",
|
"messageUnablePreview": "无法预览消息",
|
||||||
"messageUnablePreviewEncrypted": "无法预览加密消息"
|
"messageUnablePreviewEncrypted": "无法预览加密消息",
|
||||||
|
"postViewInGlobalDescription": "不查看特定领域的帖子。",
|
||||||
|
"postDraftSaved": "已保存为草稿。",
|
||||||
|
"postDraftBox": "草稿箱",
|
||||||
|
"postShuffle": "随便看看",
|
||||||
|
"checkInStreak": {
|
||||||
|
"zero": "无连击",
|
||||||
|
"one": "连续签到 {} 天",
|
||||||
|
"other": "连续签到 {} 天"
|
||||||
|
},
|
||||||
|
"accountChangeStatus": "修改状态",
|
||||||
|
"accountStatusSilent": "请勿打扰",
|
||||||
|
"accountStatusSilentDesc": "将会暂停所有通知推送",
|
||||||
|
"accountStatusInvisible": "隐身",
|
||||||
|
"accountStatusInvisibleDesc": "将会在他人界面显示离线,但不影响功能使用",
|
||||||
|
"accountCustomStatus": "自定义状态",
|
||||||
|
"accountCustomStatusDescription": "客制化你的状态。",
|
||||||
|
"accountClearStatus": "清除状态",
|
||||||
|
"accountClearStatusDescription": "清除你的状态,并让服务器决定你的状态。",
|
||||||
|
"fieldAccountStatusLabel": "状态文字",
|
||||||
|
"fieldAccountStatusClearAt": "清除时间",
|
||||||
|
"accountStatusNegative": "负面",
|
||||||
|
"accountStatusNeutral": "中性",
|
||||||
|
"accountStatusPositive": "正面"
|
||||||
}
|
}
|
||||||
|
@ -137,6 +137,11 @@
|
|||||||
"publisherRunBy": "由 {} 管理",
|
"publisherRunBy": "由 {} 管理",
|
||||||
"fieldPublisherBelongToRealm": "所屬領域",
|
"fieldPublisherBelongToRealm": "所屬領域",
|
||||||
"fieldPublisherBelongToRealmUnset": "未設置發佈者所屬領域",
|
"fieldPublisherBelongToRealmUnset": "未設置發佈者所屬領域",
|
||||||
|
"writePost": "撰寫",
|
||||||
|
"postTypeStory": "動態",
|
||||||
|
"postTypeArticle": "文章",
|
||||||
|
"postTypeQuestion": "問題",
|
||||||
|
"postTypeVideo": "視頻",
|
||||||
"writePostTypeStory": "發動態",
|
"writePostTypeStory": "發動態",
|
||||||
"writePostTypeArticle": "寫文章",
|
"writePostTypeArticle": "寫文章",
|
||||||
"writePostTypeQuestion": "提問題",
|
"writePostTypeQuestion": "提問題",
|
||||||
@ -761,5 +766,28 @@
|
|||||||
"decrypting": "解密中……",
|
"decrypting": "解密中……",
|
||||||
"decryptingKeyNotFound": "未找到密鑰對或交換失敗,對方可能不在線",
|
"decryptingKeyNotFound": "未找到密鑰對或交換失敗,對方可能不在線",
|
||||||
"messageUnablePreview": "無法預覽消息",
|
"messageUnablePreview": "無法預覽消息",
|
||||||
"messageUnablePreviewEncrypted": "無法預覽加密消息"
|
"messageUnablePreviewEncrypted": "無法預覽加密消息",
|
||||||
|
"postViewInGlobalDescription": "不查看特定領域的帖子。",
|
||||||
|
"postDraftSaved": "已保存為草稿。",
|
||||||
|
"postDraftBox": "草稿箱",
|
||||||
|
"postShuffle": "隨便看看",
|
||||||
|
"checkInStreak": {
|
||||||
|
"zero": "無連擊",
|
||||||
|
"one": "連續簽到 {} 天",
|
||||||
|
"other": "連續簽到 {} 天"
|
||||||
|
},
|
||||||
|
"accountChangeStatus": "修改狀態",
|
||||||
|
"accountStatusSilent": "請勿打擾",
|
||||||
|
"accountStatusSilentDesc": "將會暫停所有通知推送",
|
||||||
|
"accountStatusInvisible": "隱身",
|
||||||
|
"accountStatusInvisibleDesc": "將會在他人界面顯示離線,但不影響功能使用",
|
||||||
|
"accountCustomStatus": "自定義狀態",
|
||||||
|
"accountCustomStatusDescription": "客製化你的狀態。",
|
||||||
|
"accountClearStatus": "清除狀態",
|
||||||
|
"accountClearStatusDescription": "清除你的狀態,並讓服務器決定你的狀態。",
|
||||||
|
"fieldAccountStatusLabel": "狀態文字",
|
||||||
|
"fieldAccountStatusClearAt": "清除時間",
|
||||||
|
"accountStatusNegative": "負面",
|
||||||
|
"accountStatusNeutral": "中性",
|
||||||
|
"accountStatusPositive": "正面"
|
||||||
}
|
}
|
||||||
|
@ -137,6 +137,11 @@
|
|||||||
"publisherRunBy": "由 {} 管理",
|
"publisherRunBy": "由 {} 管理",
|
||||||
"fieldPublisherBelongToRealm": "所屬領域",
|
"fieldPublisherBelongToRealm": "所屬領域",
|
||||||
"fieldPublisherBelongToRealmUnset": "未設置發佈者所屬領域",
|
"fieldPublisherBelongToRealmUnset": "未設置發佈者所屬領域",
|
||||||
|
"writePost": "撰寫",
|
||||||
|
"postTypeStory": "動態",
|
||||||
|
"postTypeArticle": "文章",
|
||||||
|
"postTypeQuestion": "問題",
|
||||||
|
"postTypeVideo": "視頻",
|
||||||
"writePostTypeStory": "發動態",
|
"writePostTypeStory": "發動態",
|
||||||
"writePostTypeArticle": "寫文章",
|
"writePostTypeArticle": "寫文章",
|
||||||
"writePostTypeQuestion": "提問題",
|
"writePostTypeQuestion": "提問題",
|
||||||
@ -761,5 +766,28 @@
|
|||||||
"decrypting": "解密中……",
|
"decrypting": "解密中……",
|
||||||
"decryptingKeyNotFound": "未找到密鑰對或交換失敗,對方可能不在線",
|
"decryptingKeyNotFound": "未找到密鑰對或交換失敗,對方可能不在線",
|
||||||
"messageUnablePreview": "無法預覽消息",
|
"messageUnablePreview": "無法預覽消息",
|
||||||
"messageUnablePreviewEncrypted": "無法預覽加密消息"
|
"messageUnablePreviewEncrypted": "無法預覽加密消息",
|
||||||
|
"postViewInGlobalDescription": "不查看特定領域的帖子。",
|
||||||
|
"postDraftSaved": "已保存為草稿。",
|
||||||
|
"postDraftBox": "草稿箱",
|
||||||
|
"postShuffle": "隨便看看",
|
||||||
|
"checkInStreak": {
|
||||||
|
"zero": "無連擊",
|
||||||
|
"one": "連續簽到 {} 天",
|
||||||
|
"other": "連續簽到 {} 天"
|
||||||
|
},
|
||||||
|
"accountChangeStatus": "修改狀態",
|
||||||
|
"accountStatusSilent": "請勿打擾",
|
||||||
|
"accountStatusSilentDesc": "將會暫停所有通知推送",
|
||||||
|
"accountStatusInvisible": "隱身",
|
||||||
|
"accountStatusInvisibleDesc": "將會在他人界面顯示離線,但不影響功能使用",
|
||||||
|
"accountCustomStatus": "自定義狀態",
|
||||||
|
"accountCustomStatusDescription": "客製化你的狀態。",
|
||||||
|
"accountClearStatus": "清除狀態",
|
||||||
|
"accountClearStatusDescription": "清除你的狀態,並讓服務器決定你的狀態。",
|
||||||
|
"fieldAccountStatusLabel": "狀態文字",
|
||||||
|
"fieldAccountStatusClearAt": "清除時間",
|
||||||
|
"accountStatusNegative": "負面",
|
||||||
|
"accountStatusNeutral": "中性",
|
||||||
|
"accountStatusPositive": "正面"
|
||||||
}
|
}
|
||||||
|
@ -71,7 +71,8 @@ class PostWriteMedia {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PostWriteMedia.fromBytes(this.raw, this.name, this.type, {this.attachment, this.file});
|
PostWriteMedia.fromBytes(this.raw, this.name, this.type,
|
||||||
|
{this.attachment, this.file});
|
||||||
|
|
||||||
bool get isEmpty => attachment == null && file == null && raw == null;
|
bool get isEmpty => attachment == null && file == null && raw == null;
|
||||||
|
|
||||||
@ -105,7 +106,8 @@ class PostWriteMedia {
|
|||||||
}) {
|
}) {
|
||||||
if (attachment != null) {
|
if (attachment != null) {
|
||||||
final sn = context.read<SnNetworkProvider>();
|
final sn = context.read<SnNetworkProvider>();
|
||||||
final ImageProvider provider = UniversalImage.provider(sn.getAttachmentUrl(attachment!.rid));
|
final ImageProvider provider =
|
||||||
|
UniversalImage.provider(sn.getAttachmentUrl(attachment!.rid));
|
||||||
if (width != null && height != null && !kIsWeb) {
|
if (width != null && height != null && !kIsWeb) {
|
||||||
return ResizeImage(
|
return ResizeImage(
|
||||||
provider,
|
provider,
|
||||||
@ -116,7 +118,8 @@ class PostWriteMedia {
|
|||||||
}
|
}
|
||||||
return provider;
|
return provider;
|
||||||
} else if (file != null) {
|
} else if (file != null) {
|
||||||
final ImageProvider provider = kIsWeb ? NetworkImage(file!.path) : FileImage(File(file!.path));
|
final ImageProvider provider =
|
||||||
|
kIsWeb ? NetworkImage(file!.path) : FileImage(File(file!.path));
|
||||||
if (width != null && height != null) {
|
if (width != null && height != null) {
|
||||||
return ResizeImage(
|
return ResizeImage(
|
||||||
provider,
|
provider,
|
||||||
@ -159,11 +162,14 @@ class PostWriteController extends ChangeNotifier {
|
|||||||
final TextEditingController aliasController = TextEditingController();
|
final TextEditingController aliasController = TextEditingController();
|
||||||
final TextEditingController rewardController = TextEditingController();
|
final TextEditingController rewardController = TextEditingController();
|
||||||
|
|
||||||
ContentInsertionConfiguration get contentInsertionConfiguration => ContentInsertionConfiguration(
|
ContentInsertionConfiguration get contentInsertionConfiguration =>
|
||||||
|
ContentInsertionConfiguration(
|
||||||
onContentInserted: (KeyboardInsertedContent content) {
|
onContentInserted: (KeyboardInsertedContent content) {
|
||||||
if (content.hasData) {
|
if (content.hasData) {
|
||||||
addAttachments(
|
addAttachments([
|
||||||
[PostWriteMedia.fromBytes(content.data!, 'attachmentInsertedImage'.tr(), SnMediaType.image)]);
|
PostWriteMedia.fromBytes(content.data!,
|
||||||
|
'attachmentInsertedImage'.tr(), SnMediaType.image)
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -193,7 +199,8 @@ class PostWriteController extends ChangeNotifier {
|
|||||||
|
|
||||||
String get description => descriptionController.text;
|
String get description => descriptionController.text;
|
||||||
|
|
||||||
bool get isRelatedNull => ![editingPost, repostingPost, replyingPost].any((ele) => ele != null);
|
bool get isRelatedNull =>
|
||||||
|
![editingPost, repostingPost, replyingPost].any((ele) => ele != null);
|
||||||
|
|
||||||
bool isLoading = false, isBusy = false;
|
bool isLoading = false, isBusy = false;
|
||||||
double? progress;
|
double? progress;
|
||||||
@ -201,6 +208,7 @@ class PostWriteController extends ChangeNotifier {
|
|||||||
SnRealm? realm;
|
SnRealm? realm;
|
||||||
SnPublisher? publisher;
|
SnPublisher? publisher;
|
||||||
SnPost? editingPost, repostingPost, replyingPost;
|
SnPost? editingPost, repostingPost, replyingPost;
|
||||||
|
bool editingDraft = false;
|
||||||
|
|
||||||
int visibility = 0;
|
int visibility = 0;
|
||||||
List<int> visibleUsers = List.empty();
|
List<int> visibleUsers = List.empty();
|
||||||
@ -237,14 +245,20 @@ class PostWriteController extends ChangeNotifier {
|
|||||||
publishedAt = post.publishedAt;
|
publishedAt = post.publishedAt;
|
||||||
publishedUntil = post.publishedUntil;
|
publishedUntil = post.publishedUntil;
|
||||||
visibleUsers = List.from(post.visibleUsersList ?? [], growable: true);
|
visibleUsers = List.from(post.visibleUsersList ?? [], growable: true);
|
||||||
invisibleUsers = List.from(post.invisibleUsersList ?? [], growable: true);
|
invisibleUsers =
|
||||||
|
List.from(post.invisibleUsersList ?? [], growable: true);
|
||||||
visibility = post.visibility;
|
visibility = post.visibility;
|
||||||
tags = List.from(post.tags.map((ele) => ele.alias), growable: true);
|
tags = List.from(post.tags.map((ele) => ele.alias), growable: true);
|
||||||
categories = List.from(post.categories.map((ele) => ele.alias), growable: true);
|
categories =
|
||||||
attachments.addAll(post.preload?.attachments?.map((ele) => PostWriteMedia(ele)) ?? []);
|
List.from(post.categories.map((ele) => ele.alias), growable: true);
|
||||||
|
attachments.addAll(
|
||||||
|
post.preload?.attachments?.map((ele) => PostWriteMedia(ele)) ?? []);
|
||||||
poll = post.preload?.poll;
|
poll = post.preload?.poll;
|
||||||
|
|
||||||
if (post.preload?.thumbnail != null && (post.preload?.thumbnail?.rid.isNotEmpty ?? false)) {
|
editingDraft = post.isDraft;
|
||||||
|
|
||||||
|
if (post.preload?.thumbnail != null &&
|
||||||
|
(post.preload?.thumbnail?.rid.isNotEmpty ?? false)) {
|
||||||
thumbnail = PostWriteMedia(post.preload!.thumbnail);
|
thumbnail = PostWriteMedia(post.preload!.thumbnail);
|
||||||
}
|
}
|
||||||
if (post.preload?.realm != null) {
|
if (post.preload?.realm != null) {
|
||||||
@ -272,7 +286,8 @@ class PostWriteController extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<SnAttachment> _uploadAttachment(BuildContext context, PostWriteMedia media,
|
Future<SnAttachment> _uploadAttachment(
|
||||||
|
BuildContext context, PostWriteMedia media,
|
||||||
{bool isCompressed = false}) async {
|
{bool isCompressed = false}) async {
|
||||||
final attach = context.read<SnAttachmentProvider>();
|
final attach = context.read<SnAttachmentProvider>();
|
||||||
|
|
||||||
@ -281,7 +296,9 @@ class PostWriteController extends ChangeNotifier {
|
|||||||
media.name,
|
media.name,
|
||||||
'interactive',
|
'interactive',
|
||||||
null,
|
null,
|
||||||
mimetype: media.raw != null && media.type == SnMediaType.image ? 'image/png' : null,
|
mimetype: media.raw != null && media.type == SnMediaType.image
|
||||||
|
? 'image/png'
|
||||||
|
: null,
|
||||||
);
|
);
|
||||||
|
|
||||||
var item = await attach.chunkedUploadParts(
|
var item = await attach.chunkedUploadParts(
|
||||||
@ -297,9 +314,11 @@ class PostWriteController extends ChangeNotifier {
|
|||||||
|
|
||||||
if (media.type == SnMediaType.video && !isCompressed && context.mounted) {
|
if (media.type == SnMediaType.video && !isCompressed && context.mounted) {
|
||||||
try {
|
try {
|
||||||
final compressedAttachment = await _tryCompressVideoCopy(context, media);
|
final compressedAttachment =
|
||||||
|
await _tryCompressVideoCopy(context, media);
|
||||||
if (compressedAttachment != null) {
|
if (compressedAttachment != null) {
|
||||||
item = await attach.updateOne(item, compressedId: compressedAttachment.id);
|
item = await attach.updateOne(item,
|
||||||
|
compressedId: compressedAttachment.id);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (context.mounted) context.showErrorDialog(err);
|
if (context.mounted) context.showErrorDialog(err);
|
||||||
@ -309,8 +328,10 @@ class PostWriteController extends ChangeNotifier {
|
|||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<SnAttachment?> _tryCompressVideoCopy(BuildContext context, PostWriteMedia media) async {
|
Future<SnAttachment?> _tryCompressVideoCopy(
|
||||||
if (kIsWeb || !(Platform.isAndroid || Platform.isIOS || Platform.isMacOS)) return null;
|
BuildContext context, PostWriteMedia media) async {
|
||||||
|
if (kIsWeb || !(Platform.isAndroid || Platform.isIOS || Platform.isMacOS))
|
||||||
|
return null;
|
||||||
if (media.type != SnMediaType.video) return null;
|
if (media.type != SnMediaType.video) return null;
|
||||||
if (media.file == null) return null;
|
if (media.file == null) return null;
|
||||||
if (VideoCompress.isCompressing) return null;
|
if (VideoCompress.isCompressing) return null;
|
||||||
@ -334,7 +355,8 @@ class PostWriteController extends ChangeNotifier {
|
|||||||
if (!context.mounted) return null;
|
if (!context.mounted) return null;
|
||||||
|
|
||||||
final compressedMedia = PostWriteMedia.fromFile(XFile(mediaInfo.path!));
|
final compressedMedia = PostWriteMedia.fromFile(XFile(mediaInfo.path!));
|
||||||
final compressedAttachment = await _uploadAttachment(context, compressedMedia, isCompressed: true);
|
final compressedAttachment =
|
||||||
|
await _uploadAttachment(context, compressedMedia, isCompressed: true);
|
||||||
|
|
||||||
return compressedAttachment;
|
return compressedAttachment;
|
||||||
}
|
}
|
||||||
@ -370,18 +392,25 @@ class PostWriteController extends ChangeNotifier {
|
|||||||
'content': contentController.text,
|
'content': contentController.text,
|
||||||
if (aliasController.text.isNotEmpty) 'alias': aliasController.text,
|
if (aliasController.text.isNotEmpty) 'alias': aliasController.text,
|
||||||
if (titleController.text.isNotEmpty) 'title': titleController.text,
|
if (titleController.text.isNotEmpty) 'title': titleController.text,
|
||||||
if (descriptionController.text.isNotEmpty) 'description': descriptionController.text,
|
if (descriptionController.text.isNotEmpty)
|
||||||
|
'description': descriptionController.text,
|
||||||
if (rewardController.text.isNotEmpty) 'reward': rewardController.text,
|
if (rewardController.text.isNotEmpty) 'reward': rewardController.text,
|
||||||
if (thumbnail != null && thumbnail!.attachment != null) 'thumbnail': thumbnail!.attachment!.toJson(),
|
if (thumbnail != null && thumbnail!.attachment != null)
|
||||||
'attachments':
|
'thumbnail': thumbnail!.attachment!.toJson(),
|
||||||
attachments.where((e) => e.attachment != null).map((e) => e.attachment!.toJson()).toList(growable: true),
|
'attachments': attachments
|
||||||
|
.where((e) => e.attachment != null)
|
||||||
|
.map((e) => e.attachment!.toJson())
|
||||||
|
.toList(growable: true),
|
||||||
'tags': tags.map((ele) => {'alias': ele}).toList(growable: true),
|
'tags': tags.map((ele) => {'alias': ele}).toList(growable: true),
|
||||||
'categories': categories.map((ele) => {'alias': ele}).toList(growable: true),
|
'categories':
|
||||||
|
categories.map((ele) => {'alias': ele}).toList(growable: true),
|
||||||
'visibility': visibility,
|
'visibility': visibility,
|
||||||
'visible_users_list': visibleUsers,
|
'visible_users_list': visibleUsers,
|
||||||
'invisible_users_list': invisibleUsers,
|
'invisible_users_list': invisibleUsers,
|
||||||
if (publishedAt != null) 'published_at': publishedAt!.toUtc().toIso8601String(),
|
if (publishedAt != null)
|
||||||
if (publishedUntil != null) 'published_until': publishedAt!.toUtc().toIso8601String(),
|
'published_at': publishedAt!.toUtc().toIso8601String(),
|
||||||
|
if (publishedUntil != null)
|
||||||
|
'published_until': publishedAt!.toUtc().toIso8601String(),
|
||||||
if (replyingPost != null) 'reply_to': replyingPost!.toJson(),
|
if (replyingPost != null) 'reply_to': replyingPost!.toJson(),
|
||||||
if (repostingPost != null) 'repost_to': repostingPost!.toJson(),
|
if (repostingPost != null) 'repost_to': repostingPost!.toJson(),
|
||||||
if (poll != null) 'poll': poll!.toJson(),
|
if (poll != null) 'poll': poll!.toJson(),
|
||||||
@ -391,6 +420,12 @@ class PostWriteController extends ChangeNotifier {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool get isNotEmpty =>
|
||||||
|
title.isNotEmpty ||
|
||||||
|
description.isNotEmpty ||
|
||||||
|
contentController.text.isNotEmpty ||
|
||||||
|
attachments.isNotEmpty;
|
||||||
|
|
||||||
bool temporaryRestored = false;
|
bool temporaryRestored = false;
|
||||||
|
|
||||||
void _temporaryLoad() {
|
void _temporaryLoad() {
|
||||||
@ -403,18 +438,24 @@ class PostWriteController extends ChangeNotifier {
|
|||||||
titleController.text = data['title'] ?? '';
|
titleController.text = data['title'] ?? '';
|
||||||
descriptionController.text = data['description'] ?? '';
|
descriptionController.text = data['description'] ?? '';
|
||||||
rewardController.text = data['reward']?.toString() ?? '';
|
rewardController.text = data['reward']?.toString() ?? '';
|
||||||
if (data['thumbnail'] != null) thumbnail = PostWriteMedia(SnAttachment.fromJson(data['thumbnail']));
|
if (data['thumbnail'] != null)
|
||||||
attachments
|
thumbnail = PostWriteMedia(SnAttachment.fromJson(data['thumbnail']));
|
||||||
.addAll(data['attachments'].map((ele) => PostWriteMedia(SnAttachment.fromJson(ele))).cast<PostWriteMedia>());
|
attachments.addAll(data['attachments']
|
||||||
|
.map((ele) => PostWriteMedia(SnAttachment.fromJson(ele)))
|
||||||
|
.cast<PostWriteMedia>());
|
||||||
tags = List.from(data['tags'].map((ele) => ele['alias']));
|
tags = List.from(data['tags'].map((ele) => ele['alias']));
|
||||||
categories = List.from(data['categories'].map((ele) => ele['alias']));
|
categories = List.from(data['categories'].map((ele) => ele['alias']));
|
||||||
visibility = data['visibility'];
|
visibility = data['visibility'];
|
||||||
visibleUsers = List.from(data['visible_users_list'] ?? []);
|
visibleUsers = List.from(data['visible_users_list'] ?? []);
|
||||||
invisibleUsers = List.from(data['invisible_users_list'] ?? []);
|
invisibleUsers = List.from(data['invisible_users_list'] ?? []);
|
||||||
if (data['published_at'] != null) publishedAt = DateTime.tryParse(data['published_at'])?.toLocal();
|
if (data['published_at'] != null)
|
||||||
if (data['published_until'] != null) publishedUntil = DateTime.tryParse(data['published_until'])?.toLocal();
|
publishedAt = DateTime.tryParse(data['published_at'])?.toLocal();
|
||||||
replyingPost = data['reply_to'] != null ? SnPost.fromJson(data['reply_to']) : null;
|
if (data['published_until'] != null)
|
||||||
repostingPost = data['repost_to'] != null ? SnPost.fromJson(data['repost_to']) : null;
|
publishedUntil = DateTime.tryParse(data['published_until'])?.toLocal();
|
||||||
|
replyingPost =
|
||||||
|
data['reply_to'] != null ? SnPost.fromJson(data['reply_to']) : null;
|
||||||
|
repostingPost =
|
||||||
|
data['repost_to'] != null ? SnPost.fromJson(data['repost_to']) : null;
|
||||||
poll = data['poll'] != null ? SnPoll.fromJson(data['poll']) : null;
|
poll = data['poll'] != null ? SnPoll.fromJson(data['poll']) : null;
|
||||||
realm = data['realm'] != null ? SnRealm.fromJson(data['realm']) : null;
|
realm = data['realm'] != null ? SnRealm.fromJson(data['realm']) : null;
|
||||||
temporaryRestored = true;
|
temporaryRestored = true;
|
||||||
@ -436,7 +477,10 @@ class PostWriteController extends ChangeNotifier {
|
|||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> sendPost(BuildContext context) async {
|
Future<void> sendPost(
|
||||||
|
BuildContext context, {
|
||||||
|
bool saveAsDraft = false,
|
||||||
|
}) async {
|
||||||
if (isBusy || publisher == null) return;
|
if (isBusy || publisher == null) return;
|
||||||
|
|
||||||
final sn = context.read<SnNetworkProvider>();
|
final sn = context.read<SnNetworkProvider>();
|
||||||
@ -463,7 +507,9 @@ class PostWriteController extends ChangeNotifier {
|
|||||||
media.name,
|
media.name,
|
||||||
'interactive',
|
'interactive',
|
||||||
null,
|
null,
|
||||||
mimetype: media.raw != null && media.type == SnMediaType.image ? 'image/png' : null,
|
mimetype: media.raw != null && media.type == SnMediaType.image
|
||||||
|
? 'image/png'
|
||||||
|
: null,
|
||||||
);
|
);
|
||||||
|
|
||||||
var item = await attach.chunkedUploadParts(
|
var item = await attach.chunkedUploadParts(
|
||||||
@ -472,16 +518,20 @@ class PostWriteController extends ChangeNotifier {
|
|||||||
place.$2,
|
place.$2,
|
||||||
onProgress: (value) {
|
onProgress: (value) {
|
||||||
// Calculate overall progress for attachments
|
// Calculate overall progress for attachments
|
||||||
progress = math.max(((i + value) / attachments.length) * kAttachmentProgressWeight, value);
|
progress = math.max(
|
||||||
|
((i + value) / attachments.length) * kAttachmentProgressWeight,
|
||||||
|
value);
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
final compressedAttachment = await _tryCompressVideoCopy(context, media);
|
final compressedAttachment =
|
||||||
|
await _tryCompressVideoCopy(context, media);
|
||||||
if (compressedAttachment != null) {
|
if (compressedAttachment != null) {
|
||||||
item = await attach.updateOne(item, compressedId: compressedAttachment.id);
|
item = await attach.updateOne(item,
|
||||||
|
compressedId: compressedAttachment.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@ -508,7 +558,7 @@ class PostWriteController extends ChangeNotifier {
|
|||||||
// Posting the content
|
// Posting the content
|
||||||
try {
|
try {
|
||||||
final baseProgressVal = progress!;
|
final baseProgressVal = progress!;
|
||||||
await sn.client.request(
|
final resp = await sn.client.request(
|
||||||
[
|
[
|
||||||
'/cgi/co/$mode',
|
'/cgi/co/$mode',
|
||||||
if (editingPost != null) '${editingPost!.id}',
|
if (editingPost != null) '${editingPost!.id}',
|
||||||
@ -518,36 +568,56 @@ class PostWriteController extends ChangeNotifier {
|
|||||||
'content': contentController.text,
|
'content': contentController.text,
|
||||||
if (aliasController.text.isNotEmpty) 'alias': aliasController.text,
|
if (aliasController.text.isNotEmpty) 'alias': aliasController.text,
|
||||||
if (titleController.text.isNotEmpty) 'title': titleController.text,
|
if (titleController.text.isNotEmpty) 'title': titleController.text,
|
||||||
if (descriptionController.text.isNotEmpty) 'description': descriptionController.text,
|
if (descriptionController.text.isNotEmpty)
|
||||||
if (thumbnail != null && thumbnail!.attachment != null) 'thumbnail': thumbnail!.attachment!.rid,
|
'description': descriptionController.text,
|
||||||
'attachments': attachments.where((e) => e.attachment != null).map((e) => e.attachment!.rid).toList(),
|
if (thumbnail != null && thumbnail!.attachment != null)
|
||||||
|
'thumbnail': thumbnail!.attachment!.rid,
|
||||||
|
'attachments': attachments
|
||||||
|
.where((e) => e.attachment != null)
|
||||||
|
.map((e) => e.attachment!.rid)
|
||||||
|
.toList(),
|
||||||
'tags': tags.map((ele) => {'alias': ele}).toList(),
|
'tags': tags.map((ele) => {'alias': ele}).toList(),
|
||||||
'categories': categories.map((ele) => {'alias': ele}).toList(),
|
'categories': categories.map((ele) => {'alias': ele}).toList(),
|
||||||
'visibility': visibility,
|
'visibility': visibility,
|
||||||
'visible_users_list': visibleUsers,
|
'visible_users_list': visibleUsers,
|
||||||
'invisible_users_list': invisibleUsers,
|
'invisible_users_list': invisibleUsers,
|
||||||
if (publishedAt != null) 'published_at': publishedAt!.toUtc().toIso8601String(),
|
if (publishedAt != null)
|
||||||
if (publishedUntil != null) 'published_until': publishedAt!.toUtc().toIso8601String(),
|
'published_at': publishedAt!.toUtc().toIso8601String(),
|
||||||
|
if (publishedUntil != null)
|
||||||
|
'published_until': publishedAt!.toUtc().toIso8601String(),
|
||||||
if (replyingPost != null) 'reply_to': replyingPost!.id,
|
if (replyingPost != null) 'reply_to': replyingPost!.id,
|
||||||
if (repostingPost != null) 'repost_to': repostingPost!.id,
|
if (repostingPost != null) 'repost_to': repostingPost!.id,
|
||||||
if (reward != null) 'reward': reward,
|
if (reward != null) 'reward': reward,
|
||||||
if (videoAttachment != null) 'video': videoAttachment!.rid,
|
if (videoAttachment != null) 'video': videoAttachment!.rid,
|
||||||
if (poll != null) 'poll': poll!.id,
|
if (poll != null) 'poll': poll!.id,
|
||||||
if (realm != null) 'realm': realm!.id,
|
if (realm != null) 'realm': realm!.id,
|
||||||
|
'is_draft': saveAsDraft,
|
||||||
},
|
},
|
||||||
onSendProgress: (count, total) {
|
onSendProgress: (count, total) {
|
||||||
progress = baseProgressVal + (count / total) * (kPostingProgressWeight / 2);
|
progress =
|
||||||
|
baseProgressVal + (count / total) * (kPostingProgressWeight / 2);
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
},
|
},
|
||||||
onReceiveProgress: (count, total) {
|
onReceiveProgress: (count, total) {
|
||||||
progress = baseProgressVal + (kPostingProgressWeight / 2) + (count / total) * (kPostingProgressWeight / 2);
|
progress = baseProgressVal +
|
||||||
|
(kPostingProgressWeight / 2) +
|
||||||
|
(count / total) * (kPostingProgressWeight / 2);
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
},
|
},
|
||||||
options: Options(
|
options: Options(
|
||||||
method: editingPost != null ? 'PUT' : 'POST',
|
method: editingPost != null ? 'PUT' : 'POST',
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
reset();
|
if (saveAsDraft) {
|
||||||
|
if (!context.mounted) return;
|
||||||
|
editingDraft = true;
|
||||||
|
final out = SnPost.fromJson(resp.data);
|
||||||
|
final pt = context.read<SnPostContentProvider>();
|
||||||
|
editingPost = await pt.completePostData(out);
|
||||||
|
notifyListeners();
|
||||||
|
} else {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (!context.mounted) return;
|
if (!context.mounted) return;
|
||||||
context.showErrorDialog(err);
|
context.showErrorDialog(err);
|
||||||
@ -683,7 +753,8 @@ class PostWriteController extends ChangeNotifier {
|
|||||||
repostingPost = null;
|
repostingPost = null;
|
||||||
mode = kTitleMap.keys.first;
|
mode = kTitleMap.keys.first;
|
||||||
temporaryRestored = false;
|
temporaryRestored = false;
|
||||||
SharedPreferences.getInstance().then((prefs) => prefs.remove(kTemporaryStorageKey));
|
SharedPreferences.getInstance()
|
||||||
|
.then((prefs) => prefs.remove(kTemporaryStorageKey));
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,8 +23,6 @@ class $SnLocalChatChannelTable extends SnLocalChatChannel
|
|||||||
late final GeneratedColumn<String> alias = GeneratedColumn<String>(
|
late final GeneratedColumn<String> alias = GeneratedColumn<String>(
|
||||||
'alias', aliasedName, false,
|
'alias', aliasedName, false,
|
||||||
type: DriftSqlType.string, requiredDuringInsert: true);
|
type: DriftSqlType.string, requiredDuringInsert: true);
|
||||||
static const VerificationMeta _contentMeta =
|
|
||||||
const VerificationMeta('content');
|
|
||||||
@override
|
@override
|
||||||
late final GeneratedColumnWithTypeConverter<SnChannel, String> content =
|
late final GeneratedColumnWithTypeConverter<SnChannel, String> content =
|
||||||
GeneratedColumn<String>('content', aliasedName, false,
|
GeneratedColumn<String>('content', aliasedName, false,
|
||||||
@ -60,7 +58,6 @@ class $SnLocalChatChannelTable extends SnLocalChatChannel
|
|||||||
} else if (isInserting) {
|
} else if (isInserting) {
|
||||||
context.missing(_aliasMeta);
|
context.missing(_aliasMeta);
|
||||||
}
|
}
|
||||||
context.handle(_contentMeta, const VerificationResult.success());
|
|
||||||
if (data.containsKey('created_at')) {
|
if (data.containsKey('created_at')) {
|
||||||
context.handle(_createdAtMeta,
|
context.handle(_createdAtMeta,
|
||||||
createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta));
|
createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta));
|
||||||
@ -295,8 +292,6 @@ class $SnLocalChatMessageTable extends SnLocalChatMessage
|
|||||||
late final GeneratedColumn<int> senderId = GeneratedColumn<int>(
|
late final GeneratedColumn<int> senderId = GeneratedColumn<int>(
|
||||||
'sender_id', aliasedName, true,
|
'sender_id', aliasedName, true,
|
||||||
type: DriftSqlType.int, requiredDuringInsert: false);
|
type: DriftSqlType.int, requiredDuringInsert: false);
|
||||||
static const VerificationMeta _contentMeta =
|
|
||||||
const VerificationMeta('content');
|
|
||||||
@override
|
@override
|
||||||
late final GeneratedColumnWithTypeConverter<SnChatMessage, String> content =
|
late final GeneratedColumnWithTypeConverter<SnChatMessage, String> content =
|
||||||
GeneratedColumn<String>('content', aliasedName, false,
|
GeneratedColumn<String>('content', aliasedName, false,
|
||||||
@ -338,7 +333,6 @@ class $SnLocalChatMessageTable extends SnLocalChatMessage
|
|||||||
context.handle(_senderIdMeta,
|
context.handle(_senderIdMeta,
|
||||||
senderId.isAcceptableOrUnknown(data['sender_id']!, _senderIdMeta));
|
senderId.isAcceptableOrUnknown(data['sender_id']!, _senderIdMeta));
|
||||||
}
|
}
|
||||||
context.handle(_contentMeta, const VerificationResult.success());
|
|
||||||
if (data.containsKey('created_at')) {
|
if (data.containsKey('created_at')) {
|
||||||
context.handle(_createdAtMeta,
|
context.handle(_createdAtMeta,
|
||||||
createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta));
|
createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta));
|
||||||
@ -604,8 +598,6 @@ class $SnLocalChannelMemberTable extends SnLocalChannelMember
|
|||||||
late final GeneratedColumn<int> accountId = GeneratedColumn<int>(
|
late final GeneratedColumn<int> accountId = GeneratedColumn<int>(
|
||||||
'account_id', aliasedName, false,
|
'account_id', aliasedName, false,
|
||||||
type: DriftSqlType.int, requiredDuringInsert: true);
|
type: DriftSqlType.int, requiredDuringInsert: true);
|
||||||
static const VerificationMeta _contentMeta =
|
|
||||||
const VerificationMeta('content');
|
|
||||||
@override
|
@override
|
||||||
late final GeneratedColumnWithTypeConverter<SnChannelMember, String> content =
|
late final GeneratedColumnWithTypeConverter<SnChannelMember, String> content =
|
||||||
GeneratedColumn<String>('content', aliasedName, false,
|
GeneratedColumn<String>('content', aliasedName, false,
|
||||||
@ -655,7 +647,6 @@ class $SnLocalChannelMemberTable extends SnLocalChannelMember
|
|||||||
} else if (isInserting) {
|
} else if (isInserting) {
|
||||||
context.missing(_accountIdMeta);
|
context.missing(_accountIdMeta);
|
||||||
}
|
}
|
||||||
context.handle(_contentMeta, const VerificationResult.success());
|
|
||||||
if (data.containsKey('created_at')) {
|
if (data.containsKey('created_at')) {
|
||||||
context.handle(_createdAtMeta,
|
context.handle(_createdAtMeta,
|
||||||
createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta));
|
createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta));
|
||||||
@ -1265,8 +1256,6 @@ class $SnLocalAccountTable extends SnLocalAccount
|
|||||||
late final GeneratedColumn<String> name = GeneratedColumn<String>(
|
late final GeneratedColumn<String> name = GeneratedColumn<String>(
|
||||||
'name', aliasedName, false,
|
'name', aliasedName, false,
|
||||||
type: DriftSqlType.string, requiredDuringInsert: true);
|
type: DriftSqlType.string, requiredDuringInsert: true);
|
||||||
static const VerificationMeta _contentMeta =
|
|
||||||
const VerificationMeta('content');
|
|
||||||
@override
|
@override
|
||||||
late final GeneratedColumnWithTypeConverter<SnAccount, String> content =
|
late final GeneratedColumnWithTypeConverter<SnAccount, String> content =
|
||||||
GeneratedColumn<String>('content', aliasedName, false,
|
GeneratedColumn<String>('content', aliasedName, false,
|
||||||
@ -1308,7 +1297,6 @@ class $SnLocalAccountTable extends SnLocalAccount
|
|||||||
} else if (isInserting) {
|
} else if (isInserting) {
|
||||||
context.missing(_nameMeta);
|
context.missing(_nameMeta);
|
||||||
}
|
}
|
||||||
context.handle(_contentMeta, const VerificationResult.success());
|
|
||||||
if (data.containsKey('created_at')) {
|
if (data.containsKey('created_at')) {
|
||||||
context.handle(_createdAtMeta,
|
context.handle(_createdAtMeta,
|
||||||
createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta));
|
createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta));
|
||||||
@ -1582,8 +1570,6 @@ class $SnLocalAttachmentTable extends SnLocalAttachment
|
|||||||
type: DriftSqlType.string,
|
type: DriftSqlType.string,
|
||||||
requiredDuringInsert: true,
|
requiredDuringInsert: true,
|
||||||
defaultConstraints: GeneratedColumn.constraintIsAlways('UNIQUE'));
|
defaultConstraints: GeneratedColumn.constraintIsAlways('UNIQUE'));
|
||||||
static const VerificationMeta _contentMeta =
|
|
||||||
const VerificationMeta('content');
|
|
||||||
@override
|
@override
|
||||||
late final GeneratedColumnWithTypeConverter<SnAttachment, String> content =
|
late final GeneratedColumnWithTypeConverter<SnAttachment, String> content =
|
||||||
GeneratedColumn<String>('content', aliasedName, false,
|
GeneratedColumn<String>('content', aliasedName, false,
|
||||||
@ -1639,7 +1625,6 @@ class $SnLocalAttachmentTable extends SnLocalAttachment
|
|||||||
} else if (isInserting) {
|
} else if (isInserting) {
|
||||||
context.missing(_uuidMeta);
|
context.missing(_uuidMeta);
|
||||||
}
|
}
|
||||||
context.handle(_contentMeta, const VerificationResult.success());
|
|
||||||
if (data.containsKey('account_id')) {
|
if (data.containsKey('account_id')) {
|
||||||
context.handle(_accountIdMeta,
|
context.handle(_accountIdMeta,
|
||||||
accountId.isAcceptableOrUnknown(data['account_id']!, _accountIdMeta));
|
accountId.isAcceptableOrUnknown(data['account_id']!, _accountIdMeta));
|
||||||
@ -1968,8 +1953,6 @@ class $SnLocalStickerTable extends SnLocalSticker
|
|||||||
late final GeneratedColumn<String> fullAlias = GeneratedColumn<String>(
|
late final GeneratedColumn<String> fullAlias = GeneratedColumn<String>(
|
||||||
'full_alias', aliasedName, false,
|
'full_alias', aliasedName, false,
|
||||||
type: DriftSqlType.string, requiredDuringInsert: true);
|
type: DriftSqlType.string, requiredDuringInsert: true);
|
||||||
static const VerificationMeta _contentMeta =
|
|
||||||
const VerificationMeta('content');
|
|
||||||
@override
|
@override
|
||||||
late final GeneratedColumnWithTypeConverter<SnSticker, String> content =
|
late final GeneratedColumnWithTypeConverter<SnSticker, String> content =
|
||||||
GeneratedColumn<String>('content', aliasedName, false,
|
GeneratedColumn<String>('content', aliasedName, false,
|
||||||
@ -2011,7 +1994,6 @@ class $SnLocalStickerTable extends SnLocalSticker
|
|||||||
} else if (isInserting) {
|
} else if (isInserting) {
|
||||||
context.missing(_fullAliasMeta);
|
context.missing(_fullAliasMeta);
|
||||||
}
|
}
|
||||||
context.handle(_contentMeta, const VerificationResult.success());
|
|
||||||
if (data.containsKey('created_at')) {
|
if (data.containsKey('created_at')) {
|
||||||
context.handle(_createdAtMeta,
|
context.handle(_createdAtMeta,
|
||||||
createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta));
|
createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta));
|
||||||
@ -2261,8 +2243,6 @@ class $SnLocalStickerPackTable extends SnLocalStickerPack
|
|||||||
requiredDuringInsert: false,
|
requiredDuringInsert: false,
|
||||||
defaultConstraints:
|
defaultConstraints:
|
||||||
GeneratedColumn.constraintIsAlways('PRIMARY KEY AUTOINCREMENT'));
|
GeneratedColumn.constraintIsAlways('PRIMARY KEY AUTOINCREMENT'));
|
||||||
static const VerificationMeta _contentMeta =
|
|
||||||
const VerificationMeta('content');
|
|
||||||
@override
|
@override
|
||||||
late final GeneratedColumnWithTypeConverter<SnStickerPack, String> content =
|
late final GeneratedColumnWithTypeConverter<SnStickerPack, String> content =
|
||||||
GeneratedColumn<String>('content', aliasedName, false,
|
GeneratedColumn<String>('content', aliasedName, false,
|
||||||
@ -2293,7 +2273,6 @@ class $SnLocalStickerPackTable extends SnLocalStickerPack
|
|||||||
if (data.containsKey('id')) {
|
if (data.containsKey('id')) {
|
||||||
context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta));
|
context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta));
|
||||||
}
|
}
|
||||||
context.handle(_contentMeta, const VerificationResult.success());
|
|
||||||
if (data.containsKey('created_at')) {
|
if (data.containsKey('created_at')) {
|
||||||
context.handle(_createdAtMeta,
|
context.handle(_createdAtMeta,
|
||||||
createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta));
|
createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta));
|
||||||
|
@ -60,16 +60,24 @@ class SnPostContentProvider {
|
|||||||
|
|
||||||
out[i] = out[i].copyWith(
|
out[i] = out[i].copyWith(
|
||||||
preload: SnPostPreload(
|
preload: SnPostPreload(
|
||||||
thumbnail: attachments.where((ele) => ele?.rid == out[i].body['thumbnail']).firstOrNull,
|
thumbnail: attachments
|
||||||
attachments: attachments.where((ele) => out[i].body['attachments']?.contains(ele?.rid) ?? false).toList(),
|
.where((ele) => ele?.rid == out[i].body['thumbnail'])
|
||||||
video: attachments.where((ele) => ele?.rid == out[i].body['video']).firstOrNull,
|
.firstOrNull,
|
||||||
|
attachments: attachments
|
||||||
|
.where((ele) =>
|
||||||
|
out[i].body['attachments']?.contains(ele?.rid) ?? false)
|
||||||
|
.toList(),
|
||||||
|
video: attachments
|
||||||
|
.where((ele) => ele?.rid == out[i].body['video'])
|
||||||
|
.firstOrNull,
|
||||||
poll: poll,
|
poll: poll,
|
||||||
realm: realm,
|
realm: realm,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
uids.addAll(attachments.where((ele) => ele != null).map((ele) => ele!.accountId));
|
uids.addAll(
|
||||||
|
attachments.where((ele) => ele != null).map((ele) => ele!.accountId));
|
||||||
await _ud.listAccount(uids);
|
await _ud.listAccount(uids);
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
@ -107,15 +115,23 @@ class SnPostContentProvider {
|
|||||||
|
|
||||||
out = out.copyWith(
|
out = out.copyWith(
|
||||||
preload: SnPostPreload(
|
preload: SnPostPreload(
|
||||||
thumbnail: attachments.where((ele) => ele?.rid == out.body['thumbnail']).firstOrNull,
|
thumbnail: attachments
|
||||||
attachments: attachments.where((ele) => out.body['attachments']?.contains(ele?.rid) ?? false).toList(),
|
.where((ele) => ele?.rid == out.body['thumbnail'])
|
||||||
video: attachments.where((ele) => ele?.rid == out.body['video']).firstOrNull,
|
.firstOrNull,
|
||||||
|
attachments: attachments
|
||||||
|
.where(
|
||||||
|
(ele) => out.body['attachments']?.contains(ele?.rid) ?? false)
|
||||||
|
.toList(),
|
||||||
|
video: attachments
|
||||||
|
.where((ele) => ele?.rid == out.body['video'])
|
||||||
|
.firstOrNull,
|
||||||
poll: poll,
|
poll: poll,
|
||||||
realm: realm,
|
realm: realm,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
uids.addAll(attachments.where((ele) => ele != null).map((ele) => ele!.accountId));
|
uids.addAll(
|
||||||
|
attachments.where((ele) => ele != null).map((ele) => ele!.accountId));
|
||||||
await _ud.listAccount(uids);
|
await _ud.listAccount(uids);
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
@ -138,17 +154,25 @@ class SnPostContentProvider {
|
|||||||
Iterable<String>? tags,
|
Iterable<String>? tags,
|
||||||
String? realm,
|
String? realm,
|
||||||
String? channel,
|
String? channel,
|
||||||
|
bool isDraft = false,
|
||||||
|
bool isShuffle = false,
|
||||||
}) async {
|
}) async {
|
||||||
final resp = await _sn.client.get('/cgi/co/posts', queryParameters: {
|
final resp = await _sn.client.get(
|
||||||
'take': take,
|
isShuffle
|
||||||
'offset': offset,
|
? '/cgi/co/recommendations/shuffle'
|
||||||
if (type != null) 'type': type,
|
: '/cgi/co/posts${isDraft ? '/drafts' : ''}',
|
||||||
if (author != null) 'author': author,
|
queryParameters: {
|
||||||
if (tags?.isNotEmpty ?? false) 'tags': tags!.join(','),
|
'take': take,
|
||||||
if (categories?.isNotEmpty ?? false) 'categories': categories!.join(','),
|
'offset': offset,
|
||||||
if (realm != null) 'realm': realm,
|
if (type != null) 'type': type,
|
||||||
if (channel != null) 'channel': channel,
|
if (author != null) 'author': author,
|
||||||
});
|
if (tags?.isNotEmpty ?? false) 'tags': tags!.join(','),
|
||||||
|
if (categories?.isNotEmpty ?? false)
|
||||||
|
'categories': categories!.join(','),
|
||||||
|
if (realm != null) 'realm': realm,
|
||||||
|
if (channel != null) 'channel': channel,
|
||||||
|
},
|
||||||
|
);
|
||||||
final List<SnPost> out = await _preloadRelatedDataInBatch(
|
final List<SnPost> out = await _preloadRelatedDataInBatch(
|
||||||
List.from(resp.data['data']?.map((e) => SnPost.fromJson(e)) ?? []),
|
List.from(resp.data['data']?.map((e) => SnPost.fromJson(e)) ?? []),
|
||||||
);
|
);
|
||||||
@ -161,7 +185,8 @@ class SnPostContentProvider {
|
|||||||
int take = 10,
|
int take = 10,
|
||||||
int offset = 0,
|
int offset = 0,
|
||||||
}) async {
|
}) async {
|
||||||
final resp = await _sn.client.get('/cgi/co/posts/$parentId/replies', queryParameters: {
|
final resp = await _sn.client
|
||||||
|
.get('/cgi/co/posts/$parentId/replies', queryParameters: {
|
||||||
'take': take,
|
'take': take,
|
||||||
'offset': offset,
|
'offset': offset,
|
||||||
});
|
});
|
||||||
@ -200,4 +225,9 @@ class SnPostContentProvider {
|
|||||||
);
|
);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<SnPost> completePostData(SnPost post) async {
|
||||||
|
final out = await _preloadRelatedDataSingle(post);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ class UserDirectoryProvider {
|
|||||||
|
|
||||||
final Map<String, int> _idCache = {};
|
final Map<String, int> _idCache = {};
|
||||||
final Map<int, SnAccount> _cache = {};
|
final Map<int, SnAccount> _cache = {};
|
||||||
|
DateTime? _cacheExpiredAt;
|
||||||
|
|
||||||
Future<int> loadAccountCache({int max = 100}) async {
|
Future<int> loadAccountCache({int max = 100}) async {
|
||||||
final out = await (_dt.db.snLocalAccount.select()..limit(max)).get();
|
final out = await (_dt.db.snLocalAccount.select()..limit(max)).get();
|
||||||
@ -26,11 +27,18 @@ class UserDirectoryProvider {
|
|||||||
_cache[ele.id] = ele.content;
|
_cache[ele.id] = ele.content;
|
||||||
_idCache[ele.name] = ele.id;
|
_idCache[ele.name] = ele.id;
|
||||||
}
|
}
|
||||||
|
_cacheExpiredAt = DateTime.now().add(const Duration(hours: 1));
|
||||||
return out.length;
|
return out.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<SnAccount?>> listAccount(Iterable<dynamic> id) async {
|
Future<List<SnAccount?>> listAccount(Iterable<dynamic> id) async {
|
||||||
// In-memory cache
|
// In-memory cache
|
||||||
|
if (_cacheExpiredAt != null && _cacheExpiredAt!.isAfter(DateTime.now())) {
|
||||||
|
_cache.clear();
|
||||||
|
_cacheExpiredAt = DateTime.now().add(const Duration(hours: 1));
|
||||||
|
} else {
|
||||||
|
_cacheExpiredAt ??= DateTime.now().add(const Duration(hours: 1));
|
||||||
|
}
|
||||||
final out = List<SnAccount?>.generate(id.length, (e) => null);
|
final out = List<SnAccount?>.generate(id.length, (e) => null);
|
||||||
final plannedQuery = <int>{};
|
final plannedQuery = <int>{};
|
||||||
for (var idx = 0; idx < out.length; idx++) {
|
for (var idx = 0; idx < out.length; idx++) {
|
||||||
@ -62,6 +70,7 @@ class UserDirectoryProvider {
|
|||||||
plannedQuery.remove(dbResp[idx].id);
|
plannedQuery.remove(dbResp[idx].id);
|
||||||
}
|
}
|
||||||
// Remote server
|
// Remote server
|
||||||
|
_saveToLocal(out.where((ele) => ele != null).cast());
|
||||||
if (plannedQuery.isEmpty) return out;
|
if (plannedQuery.isEmpty) return out;
|
||||||
final resp = await _sn.client
|
final resp = await _sn.client
|
||||||
.get('/cgi/id/users', queryParameters: {'id': plannedQuery.join(',')});
|
.get('/cgi/id/users', queryParameters: {'id': plannedQuery.join(',')});
|
||||||
|
@ -28,7 +28,9 @@ import 'package:surface/screens/news/news_detail.dart';
|
|||||||
import 'package:surface/screens/news/news_list.dart';
|
import 'package:surface/screens/news/news_list.dart';
|
||||||
import 'package:surface/screens/notification.dart';
|
import 'package:surface/screens/notification.dart';
|
||||||
import 'package:surface/screens/post/post_detail.dart';
|
import 'package:surface/screens/post/post_detail.dart';
|
||||||
|
import 'package:surface/screens/post/post_draft.dart';
|
||||||
import 'package:surface/screens/post/post_editor.dart';
|
import 'package:surface/screens/post/post_editor.dart';
|
||||||
|
import 'package:surface/screens/post/post_shuffle.dart';
|
||||||
import 'package:surface/screens/post/publisher_page.dart';
|
import 'package:surface/screens/post/publisher_page.dart';
|
||||||
import 'package:surface/screens/post/post_search.dart';
|
import 'package:surface/screens/post/post_search.dart';
|
||||||
import 'package:surface/screens/realm.dart';
|
import 'package:surface/screens/realm.dart';
|
||||||
@ -66,10 +68,15 @@ final _appRoutes = [
|
|||||||
builder: (context, state) => const ExploreScreen(),
|
builder: (context, state) => const ExploreScreen(),
|
||||||
routes: [
|
routes: [
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: '/write/:mode',
|
path: '/draft',
|
||||||
|
name: 'postDraftBox',
|
||||||
|
builder: (context, state) => const PostDraftBox(),
|
||||||
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: '/write',
|
||||||
name: 'postEditor',
|
name: 'postEditor',
|
||||||
builder: (context, state) => PostEditorScreen(
|
builder: (context, state) => PostEditorScreen(
|
||||||
mode: state.pathParameters['mode']!,
|
mode: state.uri.queryParameters['mode'],
|
||||||
postEditId: int.tryParse(
|
postEditId: int.tryParse(
|
||||||
state.uri.queryParameters['editing'] ?? '',
|
state.uri.queryParameters['editing'] ?? '',
|
||||||
),
|
),
|
||||||
@ -82,6 +89,11 @@ final _appRoutes = [
|
|||||||
extraProps: state.extra as PostEditorExtra?,
|
extraProps: state.extra as PostEditorExtra?,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: '/shuffle',
|
||||||
|
name: 'postShuffle',
|
||||||
|
builder: (context, state) => const PostShuffleScreen(),
|
||||||
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: '/search',
|
path: '/search',
|
||||||
name: 'postSearch',
|
name: 'postSearch',
|
||||||
|
@ -11,7 +11,9 @@ import 'package:surface/providers/database.dart';
|
|||||||
import 'package:surface/providers/sn_network.dart';
|
import 'package:surface/providers/sn_network.dart';
|
||||||
import 'package:surface/providers/userinfo.dart';
|
import 'package:surface/providers/userinfo.dart';
|
||||||
import 'package:surface/providers/websocket.dart';
|
import 'package:surface/providers/websocket.dart';
|
||||||
|
import 'package:surface/types/account.dart';
|
||||||
import 'package:surface/widgets/account/account_image.dart';
|
import 'package:surface/widgets/account/account_image.dart';
|
||||||
|
import 'package:surface/widgets/account/account_status.dart';
|
||||||
import 'package:surface/widgets/app_bar_leading.dart';
|
import 'package:surface/widgets/app_bar_leading.dart';
|
||||||
import 'package:surface/widgets/dialog.dart';
|
import 'package:surface/widgets/dialog.dart';
|
||||||
import 'package:surface/widgets/navigation/app_scaffold.dart';
|
import 'package:surface/widgets/navigation/app_scaffold.dart';
|
||||||
@ -112,7 +114,14 @@ class _AuthorizedAccountScreen extends StatelessWidget {
|
|||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
AccountImage(content: ua.user!.avatar, radius: 28),
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
AccountImage(content: ua.user!.avatar, radius: 28),
|
||||||
|
_AccountStatusWidget(account: ua.user!),
|
||||||
|
],
|
||||||
|
),
|
||||||
const Gap(8),
|
const Gap(8),
|
||||||
Row(
|
Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.baseline,
|
crossAxisAlignment: CrossAxisAlignment.baseline,
|
||||||
@ -290,3 +299,81 @@ class _UnauthorizedAccountScreen extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _AccountStatusWidget extends StatefulWidget {
|
||||||
|
final SnAccount account;
|
||||||
|
const _AccountStatusWidget({required this.account});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<_AccountStatusWidget> createState() => _AccountStatusWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _AccountStatusWidgetState extends State<_AccountStatusWidget> {
|
||||||
|
SnAccountStatusInfo? _status;
|
||||||
|
|
||||||
|
Future<void> _fetchStatus() async {
|
||||||
|
try {
|
||||||
|
final sn = context.read<SnNetworkProvider>();
|
||||||
|
final resp =
|
||||||
|
await sn.client.get('/cgi/id/users/${widget.account.name}/status');
|
||||||
|
setState(() {
|
||||||
|
_status = SnAccountStatusInfo.fromJson(resp.data);
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
if (!mounted) return;
|
||||||
|
context.showErrorDialog(err);
|
||||||
|
} finally {
|
||||||
|
setState(() {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_fetchStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return InkWell(
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
_status != null
|
||||||
|
? (_status!.status?.label.isNotEmpty ?? false)
|
||||||
|
? _status!.status!.label
|
||||||
|
: _status!.isOnline
|
||||||
|
? 'accountStatusOnline'.tr()
|
||||||
|
: 'accountStatusOffline'.tr()
|
||||||
|
: 'loading'.tr(),
|
||||||
|
),
|
||||||
|
const Gap(4),
|
||||||
|
Icon(
|
||||||
|
(_status?.isDisturbable ?? true)
|
||||||
|
? Symbols.circle
|
||||||
|
: Symbols.do_not_disturb_on,
|
||||||
|
fill: (_status?.isOnline ?? false) ? 1 : 0,
|
||||||
|
size: 16,
|
||||||
|
color: (_status?.isOnline ?? false)
|
||||||
|
? (_status?.isDisturbable ?? true)
|
||||||
|
? Colors.green
|
||||||
|
: Colors.red
|
||||||
|
: Colors.grey,
|
||||||
|
).padding(all: 4),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
onTap: () {
|
||||||
|
showModalBottomSheet(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => AccountStatusActionPopup(
|
||||||
|
currentStatus: _status,
|
||||||
|
),
|
||||||
|
).then((value) {
|
||||||
|
if (value == true && mounted) {
|
||||||
|
_fetchStatus();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -18,6 +18,7 @@ import 'package:surface/types/account.dart';
|
|||||||
import 'package:surface/types/check_in.dart';
|
import 'package:surface/types/check_in.dart';
|
||||||
import 'package:surface/types/post.dart';
|
import 'package:surface/types/post.dart';
|
||||||
import 'package:surface/widgets/account/account_image.dart';
|
import 'package:surface/widgets/account/account_image.dart';
|
||||||
|
import 'package:surface/widgets/account/badge.dart';
|
||||||
import 'package:surface/widgets/dialog.dart';
|
import 'package:surface/widgets/dialog.dart';
|
||||||
import 'package:surface/widgets/universal_image.dart';
|
import 'package:surface/widgets/universal_image.dart';
|
||||||
import 'package:surface/theme.dart';
|
import 'package:surface/theme.dart';
|
||||||
@ -450,19 +451,25 @@ class _UserScreenState extends State<UserScreen>
|
|||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Icon(
|
Icon(
|
||||||
Symbols.circle,
|
(_status?.isDisturbable ?? true)
|
||||||
fill: 1,
|
? Symbols.circle
|
||||||
|
: Symbols.do_not_disturb_on,
|
||||||
|
fill: (_status?.isOnline ?? false) ? 1 : 0,
|
||||||
size: 16,
|
size: 16,
|
||||||
color: (_status?.isOnline ?? false)
|
color: (_status?.isOnline ?? false)
|
||||||
? Colors.green
|
? (_status?.isDisturbable ?? true)
|
||||||
|
? Colors.green
|
||||||
|
: Colors.red
|
||||||
: Colors.grey,
|
: Colors.grey,
|
||||||
).padding(all: 4),
|
).padding(all: 4),
|
||||||
const Gap(8),
|
const Gap(8),
|
||||||
Text(
|
Text(
|
||||||
_status != null
|
_status != null
|
||||||
? _status!.isOnline
|
? (_status!.status?.label.isNotEmpty ?? false)
|
||||||
? 'accountStatusOnline'.tr()
|
? _status!.status!.label
|
||||||
: 'accountStatusOffline'.tr()
|
: _status!.isOnline
|
||||||
|
? 'accountStatusOnline'.tr()
|
||||||
|
: 'accountStatusOffline'.tr()
|
||||||
: 'loading'.tr(),
|
: 'loading'.tr(),
|
||||||
),
|
),
|
||||||
if (_status != null &&
|
if (_status != null &&
|
||||||
@ -484,34 +491,7 @@ class _UserScreenState extends State<UserScreen>
|
|||||||
Wrap(
|
Wrap(
|
||||||
children: _account!.badges
|
children: _account!.badges
|
||||||
.map(
|
.map(
|
||||||
(ele) => Tooltip(
|
(ele) => AccountBadge(badge: ele),
|
||||||
richMessage: TextSpan(
|
|
||||||
children: [
|
|
||||||
TextSpan(
|
|
||||||
text: kBadgesMeta[ele.type]?.$1.tr() ??
|
|
||||||
'unknown'.tr(),
|
|
||||||
),
|
|
||||||
if (ele.metadata['title'] != null)
|
|
||||||
TextSpan(
|
|
||||||
text: '\n${ele.metadata['title']}',
|
|
||||||
style: const TextStyle(
|
|
||||||
fontWeight: FontWeight.bold),
|
|
||||||
),
|
|
||||||
TextSpan(text: '\n'),
|
|
||||||
TextSpan(
|
|
||||||
text: DateFormat.yMEd().format(ele.createdAt),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
child: Icon(
|
|
||||||
kBadgesMeta[ele.type]?.$2 ??
|
|
||||||
Symbols.question_mark,
|
|
||||||
color: ele.metadata['color'] != null
|
|
||||||
? HexColor.fromHex(ele.metadata['color']!)
|
|
||||||
: kBadgesMeta[ele.type]?.$3,
|
|
||||||
fill: 1,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.toList(),
|
.toList(),
|
||||||
).padding(horizontal: 8),
|
).padding(horizontal: 8),
|
||||||
|
@ -204,7 +204,6 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||||||
Theme.of(context).floatingActionButtonTheme.foregroundColor,
|
Theme.of(context).floatingActionButtonTheme.foregroundColor,
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
Theme.of(context).floatingActionButtonTheme.backgroundColor,
|
Theme.of(context).floatingActionButtonTheme.backgroundColor,
|
||||||
shape: const CircleBorder(),
|
|
||||||
),
|
),
|
||||||
closeButtonBuilder: DefaultFloatingActionButtonBuilder(
|
closeButtonBuilder: DefaultFloatingActionButtonBuilder(
|
||||||
child: const Icon(Symbols.close, size: 28),
|
child: const Icon(Symbols.close, size: 28),
|
||||||
@ -213,7 +212,6 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||||||
Theme.of(context).floatingActionButtonTheme.foregroundColor,
|
Theme.of(context).floatingActionButtonTheme.foregroundColor,
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
Theme.of(context).floatingActionButtonTheme.backgroundColor,
|
Theme.of(context).floatingActionButtonTheme.backgroundColor,
|
||||||
shape: const CircleBorder(),
|
|
||||||
),
|
),
|
||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import 'package:dropdown_button2/dropdown_button2.dart';
|
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_expandable_fab/flutter_expandable_fab.dart';
|
import 'package:flutter_expandable_fab/flutter_expandable_fab.dart';
|
||||||
@ -19,6 +18,9 @@ import 'package:surface/widgets/navigation/app_scaffold.dart';
|
|||||||
import 'package:surface/widgets/post/post_item.dart';
|
import 'package:surface/widgets/post/post_item.dart';
|
||||||
import 'package:very_good_infinite_list/very_good_infinite_list.dart';
|
import 'package:very_good_infinite_list/very_good_infinite_list.dart';
|
||||||
|
|
||||||
|
const kPostChannels = ['Global', 'Friends', 'Following'];
|
||||||
|
const kPostChannelIcons = [Symbols.globe, Symbols.group, Symbols.subscriptions];
|
||||||
|
|
||||||
const Map<String, IconData> kCategoryIcons = {
|
const Map<String, IconData> kCategoryIcons = {
|
||||||
'technology': Symbols.tools_wrench,
|
'technology': Symbols.tools_wrench,
|
||||||
'gaming': Symbols.gamepad,
|
'gaming': Symbols.gamepad,
|
||||||
@ -39,17 +41,17 @@ class ExploreScreen extends StatefulWidget {
|
|||||||
State<ExploreScreen> createState() => _ExploreScreenState();
|
State<ExploreScreen> createState() => _ExploreScreenState();
|
||||||
}
|
}
|
||||||
|
|
||||||
// You know what? I'm not going to make this a global variable.
|
|
||||||
// Cuz the global key make the selected category not update to child widget when the category is changed.
|
|
||||||
SnPostCategory? _selectedCategory;
|
|
||||||
|
|
||||||
class _ExploreScreenState extends State<ExploreScreen>
|
class _ExploreScreenState extends State<ExploreScreen>
|
||||||
with SingleTickerProviderStateMixin {
|
with TickerProviderStateMixin {
|
||||||
late final TabController _tabController =
|
late TabController _tabController = TabController(
|
||||||
TabController(length: 4, vsync: this);
|
length: kPostChannels.length,
|
||||||
|
vsync: this,
|
||||||
|
);
|
||||||
|
|
||||||
final _fabKey = GlobalKey<ExpandableFabState>();
|
final _fabKey = GlobalKey<ExpandableFabState>();
|
||||||
final _listKeys = List.generate(4, (_) => GlobalKey<_PostListWidgetState>());
|
final _listKey = GlobalKey<_PostListWidgetState>();
|
||||||
|
|
||||||
|
bool _showCategories = false;
|
||||||
|
|
||||||
final List<SnPostCategory> _categories = List.empty(growable: true);
|
final List<SnPostCategory> _categories = List.empty(growable: true);
|
||||||
|
|
||||||
@ -69,14 +71,68 @@ class _ExploreScreenState extends State<ExploreScreen>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _clearFilter() {
|
final List<SnRealm> _realms = List.empty(growable: true);
|
||||||
_selectedCategory = null;
|
|
||||||
|
Future<void> _fetchRealms() async {
|
||||||
|
try {
|
||||||
|
final rels = context.read<SnRealmProvider>();
|
||||||
|
final out = await rels.listAvailableRealms();
|
||||||
|
setState(() {
|
||||||
|
_realms.addAll(out);
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
if (!mounted) return;
|
||||||
|
context.showErrorDialog(err);
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _toggleShowCategories() {
|
||||||
|
_showCategories = !_showCategories;
|
||||||
|
if (_showCategories) {
|
||||||
|
_tabController = TabController(length: _categories.length, vsync: this);
|
||||||
|
_listKey.currentState?.setCategory(_categories[_tabController.index]);
|
||||||
|
_listKey.currentState?.refreshPosts();
|
||||||
|
} else {
|
||||||
|
_tabController = TabController(length: kPostChannels.length, vsync: this);
|
||||||
|
_listKey.currentState?.setCategory(null);
|
||||||
|
_listKey.currentState?.refreshPosts();
|
||||||
|
}
|
||||||
|
_tabListen();
|
||||||
|
setState(() {});
|
||||||
|
}
|
||||||
|
|
||||||
|
void _tabListen() {
|
||||||
|
_tabController.addListener(() {
|
||||||
|
if (_tabController.indexIsChanging) {
|
||||||
|
if (_showCategories) {
|
||||||
|
_listKey.currentState?.setCategory(_categories[_tabController.index]);
|
||||||
|
_listKey.currentState?.refreshPosts();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (_tabController.index) {
|
||||||
|
case 0:
|
||||||
|
case 3:
|
||||||
|
_listKey.currentState?.setChannel(null);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
_listKey.currentState?.setChannel('friends');
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
_listKey.currentState?.setChannel('following');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_listKey.currentState?.refreshPosts();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
_fetchCategories();
|
|
||||||
super.initState();
|
super.initState();
|
||||||
|
_tabListen();
|
||||||
|
_fetchCategories();
|
||||||
|
_fetchRealms();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -86,7 +142,7 @@ class _ExploreScreenState extends State<ExploreScreen>
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> refreshPosts() async {
|
Future<void> refreshPosts() async {
|
||||||
await _listKeys[_tabController.index].currentState?.refreshPosts();
|
await _listKey.currentState?.refreshPosts();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -111,7 +167,6 @@ class _ExploreScreenState extends State<ExploreScreen>
|
|||||||
Theme.of(context).floatingActionButtonTheme.foregroundColor,
|
Theme.of(context).floatingActionButtonTheme.foregroundColor,
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
Theme.of(context).floatingActionButtonTheme.backgroundColor,
|
Theme.of(context).floatingActionButtonTheme.backgroundColor,
|
||||||
shape: const CircleBorder(),
|
|
||||||
),
|
),
|
||||||
closeButtonBuilder: DefaultFloatingActionButtonBuilder(
|
closeButtonBuilder: DefaultFloatingActionButtonBuilder(
|
||||||
child: const Icon(Symbols.close, size: 28),
|
child: const Icon(Symbols.close, size: 28),
|
||||||
@ -120,90 +175,39 @@ class _ExploreScreenState extends State<ExploreScreen>
|
|||||||
Theme.of(context).floatingActionButtonTheme.foregroundColor,
|
Theme.of(context).floatingActionButtonTheme.foregroundColor,
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
Theme.of(context).floatingActionButtonTheme.backgroundColor,
|
Theme.of(context).floatingActionButtonTheme.backgroundColor,
|
||||||
shape: const CircleBorder(),
|
|
||||||
),
|
),
|
||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Text('writePostTypeStory').tr(),
|
Text('writePost').tr(),
|
||||||
const Gap(20),
|
const Gap(20),
|
||||||
FloatingActionButton(
|
FloatingActionButton(
|
||||||
heroTag: null,
|
heroTag: null,
|
||||||
tooltip: 'writePostTypeStory'.tr(),
|
tooltip: 'writePost'.tr(),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
GoRouter.of(context).pushNamed('postEditor', pathParameters: {
|
GoRouter.of(context).pushNamed('postEditor').then((value) {
|
||||||
'mode': 'stories',
|
|
||||||
}).then((value) {
|
|
||||||
if (value == true) {
|
if (value == true) {
|
||||||
refreshPosts();
|
refreshPosts();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
_fabKey.currentState!.toggle();
|
_fabKey.currentState!.toggle();
|
||||||
},
|
},
|
||||||
child: const Icon(Symbols.post_rounded),
|
child: const Icon(Symbols.edit),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Text('writePostTypeArticle').tr(),
|
Text('postDraftBox').tr(),
|
||||||
const Gap(20),
|
const Gap(20),
|
||||||
FloatingActionButton(
|
FloatingActionButton(
|
||||||
heroTag: null,
|
heroTag: null,
|
||||||
tooltip: 'writePostTypeArticle'.tr(),
|
tooltip: 'postDraftBox'.tr(),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
GoRouter.of(context).pushNamed('postEditor', pathParameters: {
|
GoRouter.of(context).pushNamed('postDraftBox');
|
||||||
'mode': 'articles',
|
|
||||||
}).then((value) {
|
|
||||||
if (value == true) {
|
|
||||||
refreshPosts();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
_fabKey.currentState!.toggle();
|
_fabKey.currentState!.toggle();
|
||||||
},
|
},
|
||||||
child: const Icon(Symbols.news),
|
child: const Icon(Symbols.box_edit),
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Text('writePostTypeQuestion').tr(),
|
|
||||||
const Gap(20),
|
|
||||||
FloatingActionButton(
|
|
||||||
heroTag: null,
|
|
||||||
tooltip: 'writePostTypeQuestion'.tr(),
|
|
||||||
onPressed: () {
|
|
||||||
GoRouter.of(context).pushNamed('postEditor', pathParameters: {
|
|
||||||
'mode': 'questions',
|
|
||||||
}).then((value) {
|
|
||||||
if (value == true) {
|
|
||||||
refreshPosts();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
_fabKey.currentState!.toggle();
|
|
||||||
},
|
|
||||||
child: const Icon(Symbols.question_answer),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Text('writePostTypeVideo').tr(),
|
|
||||||
const Gap(20),
|
|
||||||
FloatingActionButton(
|
|
||||||
heroTag: null,
|
|
||||||
tooltip: 'writePostTypeVideo'.tr(),
|
|
||||||
onPressed: () {
|
|
||||||
GoRouter.of(context).pushNamed('postEditor', pathParameters: {
|
|
||||||
'mode': 'videos',
|
|
||||||
}).then((value) {
|
|
||||||
if (value == true) {
|
|
||||||
refreshPosts();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
_fabKey.currentState!.toggle();
|
|
||||||
},
|
|
||||||
child: const Icon(Symbols.video_call),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -216,25 +220,74 @@ class _ExploreScreenState extends State<ExploreScreen>
|
|||||||
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
|
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
|
||||||
sliver: SliverAppBar(
|
sliver: SliverAppBar(
|
||||||
leading: AutoAppBarLeading(),
|
leading: AutoAppBarLeading(),
|
||||||
title: Text('screenExplore').tr(),
|
titleSpacing: 0,
|
||||||
|
title: Row(
|
||||||
|
children: [
|
||||||
|
IconButton(
|
||||||
|
icon: const Icon(Symbols.shuffle),
|
||||||
|
onPressed: () {
|
||||||
|
GoRouter.of(context).pushNamed('postShuffle');
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Center(
|
||||||
|
child: IconButton(
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
constraints: const BoxConstraints(),
|
||||||
|
visualDensity: VisualDensity.compact,
|
||||||
|
icon: _listKey.currentState?.realm != null
|
||||||
|
? AccountImage(
|
||||||
|
content: _listKey.currentState!.realm!.avatar,
|
||||||
|
radius: 14,
|
||||||
|
)
|
||||||
|
: Image.asset(
|
||||||
|
'assets/icon/icon-dark.png',
|
||||||
|
width: 32,
|
||||||
|
height: 32,
|
||||||
|
color: Theme.of(context)
|
||||||
|
.appBarTheme
|
||||||
|
.foregroundColor,
|
||||||
|
),
|
||||||
|
onPressed: () {
|
||||||
|
showModalBottomSheet(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => _PostListRealmPopup(
|
||||||
|
realms: _realms,
|
||||||
|
onUpdate: (realm) {
|
||||||
|
_listKey.currentState?.setRealm(realm);
|
||||||
|
_listKey.currentState?.refreshPosts();
|
||||||
|
Future.delayed(
|
||||||
|
const Duration(milliseconds: 100), () {
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
floating: true,
|
floating: true,
|
||||||
snap: true,
|
snap: true,
|
||||||
actions: [
|
actions: [
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Symbols.category),
|
icon: const Icon(Symbols.category),
|
||||||
|
style: _showCategories
|
||||||
|
? ButtonStyle(
|
||||||
|
foregroundColor: WidgetStateProperty.all(
|
||||||
|
Theme.of(context).colorScheme.primary,
|
||||||
|
),
|
||||||
|
backgroundColor: MaterialStateProperty.all(
|
||||||
|
Theme.of(context).colorScheme.secondaryContainer,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: null,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
showModalBottomSheet(
|
_toggleShowCategories();
|
||||||
context: context,
|
|
||||||
builder: (context) => _PostCategoryPickerPopup(
|
|
||||||
categories: _categories,
|
|
||||||
selected: _selectedCategory,
|
|
||||||
),
|
|
||||||
).then((value) {
|
|
||||||
if (value != null && context.mounted) {
|
|
||||||
_selectedCategory = value == false ? null : value;
|
|
||||||
refreshPosts();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
@ -246,122 +299,79 @@ class _ExploreScreenState extends State<ExploreScreen>
|
|||||||
const Gap(8),
|
const Gap(8),
|
||||||
],
|
],
|
||||||
bottom: TabBar(
|
bottom: TabBar(
|
||||||
|
isScrollable: _showCategories,
|
||||||
controller: _tabController,
|
controller: _tabController,
|
||||||
tabs: [
|
tabs: _showCategories
|
||||||
Tab(
|
? [
|
||||||
child: Row(
|
for (final category in _categories)
|
||||||
mainAxisSize: MainAxisSize.min,
|
Tab(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
child: Row(
|
||||||
children: [
|
mainAxisSize: MainAxisSize.min,
|
||||||
Icon(Symbols.globe,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
size: 20,
|
children: [
|
||||||
color: Theme.of(context)
|
Icon(
|
||||||
.appBarTheme
|
kCategoryIcons[category.alias] ??
|
||||||
.foregroundColor),
|
Symbols.question_mark,
|
||||||
const Gap(8),
|
color: Theme.of(context)
|
||||||
Flexible(
|
.appBarTheme
|
||||||
child: Text(
|
.foregroundColor!,
|
||||||
'postChannelGlobal',
|
),
|
||||||
maxLines: 1,
|
const Gap(8),
|
||||||
).tr().textColor(
|
Flexible(
|
||||||
Theme.of(context).appBarTheme.foregroundColor),
|
child: Text(
|
||||||
),
|
'postCategory${category.alias.capitalize()}'
|
||||||
|
.trExists()
|
||||||
|
? 'postCategory${category.alias.capitalize()}'
|
||||||
|
.tr()
|
||||||
|
: category.name,
|
||||||
|
maxLines: 1,
|
||||||
|
).textColor(
|
||||||
|
Theme.of(context)
|
||||||
|
.appBarTheme
|
||||||
|
.foregroundColor!,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
: [
|
||||||
|
for (final channel in kPostChannels)
|
||||||
|
Tab(
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
kPostChannelIcons[
|
||||||
|
kPostChannels.indexOf(channel)],
|
||||||
|
size: 20,
|
||||||
|
color: Theme.of(context)
|
||||||
|
.appBarTheme
|
||||||
|
.foregroundColor,
|
||||||
|
),
|
||||||
|
const Gap(8),
|
||||||
|
Flexible(
|
||||||
|
child: Text(
|
||||||
|
'postChannel$channel',
|
||||||
|
maxLines: 1,
|
||||||
|
).tr().textColor(
|
||||||
|
Theme.of(context)
|
||||||
|
.appBarTheme
|
||||||
|
.foregroundColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
|
||||||
),
|
|
||||||
Tab(
|
|
||||||
child: Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Icon(Symbols.group,
|
|
||||||
size: 20,
|
|
||||||
color: Theme.of(context)
|
|
||||||
.appBarTheme
|
|
||||||
.foregroundColor),
|
|
||||||
const Gap(8),
|
|
||||||
Flexible(
|
|
||||||
child: Text(
|
|
||||||
'postChannelFriends',
|
|
||||||
maxLines: 1,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
).tr().textColor(
|
|
||||||
Theme.of(context).appBarTheme.foregroundColor),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Tab(
|
|
||||||
child: Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Icon(Symbols.subscriptions,
|
|
||||||
size: 20,
|
|
||||||
color: Theme.of(context)
|
|
||||||
.appBarTheme
|
|
||||||
.foregroundColor),
|
|
||||||
const Gap(8),
|
|
||||||
Flexible(
|
|
||||||
child: Text(
|
|
||||||
'postChannelFollowing',
|
|
||||||
maxLines: 1,
|
|
||||||
).tr().textColor(
|
|
||||||
Theme.of(context).appBarTheme.foregroundColor),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Tab(
|
|
||||||
child: Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Icon(Symbols.workspaces,
|
|
||||||
size: 20,
|
|
||||||
color: Theme.of(context)
|
|
||||||
.appBarTheme
|
|
||||||
.foregroundColor),
|
|
||||||
const Gap(8),
|
|
||||||
Flexible(
|
|
||||||
child: Text(
|
|
||||||
'postChannelRealm',
|
|
||||||
maxLines: 1,
|
|
||||||
).tr().textColor(
|
|
||||||
Theme.of(context).appBarTheme.foregroundColor),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
body: TabBarView(
|
body: _PostListWidget(
|
||||||
controller: _tabController,
|
key: _listKey,
|
||||||
children: [
|
|
||||||
_PostListWidget(
|
|
||||||
key: _listKeys[0],
|
|
||||||
onClearFilter: _clearFilter,
|
|
||||||
),
|
|
||||||
_PostListWidget(
|
|
||||||
key: _listKeys[1],
|
|
||||||
channel: 'friends',
|
|
||||||
onClearFilter: _clearFilter,
|
|
||||||
),
|
|
||||||
_PostListWidget(
|
|
||||||
key: _listKeys[2],
|
|
||||||
channel: 'following',
|
|
||||||
onClearFilter: _clearFilter,
|
|
||||||
),
|
|
||||||
_PostListWidget(
|
|
||||||
key: _listKeys[3],
|
|
||||||
withRealm: true,
|
|
||||||
onClearFilter: _clearFilter,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -369,15 +379,7 @@ class _ExploreScreenState extends State<ExploreScreen>
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _PostListWidget extends StatefulWidget {
|
class _PostListWidget extends StatefulWidget {
|
||||||
final String? channel;
|
const _PostListWidget({super.key});
|
||||||
final bool withRealm;
|
|
||||||
final Function onClearFilter;
|
|
||||||
|
|
||||||
const _PostListWidget(
|
|
||||||
{super.key,
|
|
||||||
this.channel,
|
|
||||||
this.withRealm = false,
|
|
||||||
required this.onClearFilter});
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<_PostListWidget> createState() => _PostListWidgetState();
|
State<_PostListWidget> createState() => _PostListWidgetState();
|
||||||
@ -386,25 +388,13 @@ class _PostListWidget extends StatefulWidget {
|
|||||||
class _PostListWidgetState extends State<_PostListWidget> {
|
class _PostListWidgetState extends State<_PostListWidget> {
|
||||||
bool _isBusy = false;
|
bool _isBusy = false;
|
||||||
|
|
||||||
final List<SnPost> _posts = List.empty(growable: true);
|
SnRealm? get realm => _selectedRealm;
|
||||||
final List<SnRealm> _realms = List.empty(growable: true);
|
|
||||||
SnRealm? _selectedRealm;
|
|
||||||
int? _postCount;
|
|
||||||
|
|
||||||
Future<void> _fetchRealms() async {
|
final List<SnPost> _posts = List.empty(growable: true);
|
||||||
try {
|
SnRealm? _selectedRealm;
|
||||||
final rels = context.read<SnRealmProvider>();
|
String? _selectedChannel;
|
||||||
final out = await rels.listAvailableRealms();
|
SnPostCategory? _selectedCategory;
|
||||||
setState(() {
|
int? _postCount;
|
||||||
_realms.addAll(out);
|
|
||||||
_selectedRealm = out.firstOrNull;
|
|
||||||
});
|
|
||||||
} catch (err) {
|
|
||||||
if (!mounted) return;
|
|
||||||
context.showErrorDialog(err);
|
|
||||||
rethrow;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _fetchPosts() async {
|
Future<void> _fetchPosts() async {
|
||||||
if (_postCount != null && _posts.length >= _postCount!) return;
|
if (_postCount != null && _posts.length >= _postCount!) return;
|
||||||
@ -416,7 +406,7 @@ class _PostListWidgetState extends State<_PostListWidget> {
|
|||||||
take: 10,
|
take: 10,
|
||||||
offset: _posts.length,
|
offset: _posts.length,
|
||||||
categories: _selectedCategory != null ? [_selectedCategory!.alias] : null,
|
categories: _selectedCategory != null ? [_selectedCategory!.alias] : null,
|
||||||
channel: widget.channel,
|
channel: _selectedChannel,
|
||||||
realm: _selectedRealm?.alias,
|
realm: _selectedRealm?.alias,
|
||||||
);
|
);
|
||||||
final out = result.$1;
|
final out = result.$1;
|
||||||
@ -429,6 +419,21 @@ class _PostListWidgetState extends State<_PostListWidget> {
|
|||||||
if (mounted) setState(() => _isBusy = false);
|
if (mounted) setState(() => _isBusy = false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setChannel(String? channel) {
|
||||||
|
_selectedChannel = channel;
|
||||||
|
setState(() {});
|
||||||
|
}
|
||||||
|
|
||||||
|
void setRealm(SnRealm? realm) {
|
||||||
|
_selectedRealm = realm;
|
||||||
|
setState(() {});
|
||||||
|
}
|
||||||
|
|
||||||
|
void setCategory(SnPostCategory? category) {
|
||||||
|
_selectedCategory = category;
|
||||||
|
setState(() {});
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> refreshPosts() {
|
Future<void> refreshPosts() {
|
||||||
_postCount = null;
|
_postCount = null;
|
||||||
_posts.clear();
|
_posts.clear();
|
||||||
@ -438,13 +443,7 @@ class _PostListWidgetState extends State<_PostListWidget> {
|
|||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
if (widget.withRealm) {
|
_fetchPosts();
|
||||||
_fetchRealms().then((_) {
|
|
||||||
_fetchPosts();
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
_fetchPosts();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -467,52 +466,13 @@ class _PostListWidgetState extends State<_PostListWidget> {
|
|||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Symbols.clear),
|
icon: const Icon(Symbols.clear),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
widget.onClearFilter.call();
|
setState(() => _selectedCategory = null);
|
||||||
refreshPosts();
|
refreshPosts();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
padding: const EdgeInsets.only(left: 20, right: 4),
|
padding: const EdgeInsets.only(left: 20, right: 4),
|
||||||
),
|
),
|
||||||
if (widget.withRealm)
|
|
||||||
DropdownButtonHideUnderline(
|
|
||||||
child: DropdownButton2<SnRealm>(
|
|
||||||
isExpanded: true,
|
|
||||||
items: _realms
|
|
||||||
.map(
|
|
||||||
(ele) => DropdownMenuItem<SnRealm>(
|
|
||||||
value: ele,
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
AccountImage(
|
|
||||||
content: ele.avatar,
|
|
||||||
fallbackWidget: const Icon(Symbols.group, size: 16),
|
|
||||||
radius: 14,
|
|
||||||
),
|
|
||||||
const Gap(8),
|
|
||||||
Text(
|
|
||||||
ele.name,
|
|
||||||
style: Theme.of(context).textTheme.bodyMedium,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.toList(),
|
|
||||||
value: _selectedRealm,
|
|
||||||
onChanged: (SnRealm? value) {
|
|
||||||
setState(() => _selectedRealm = value);
|
|
||||||
refreshPosts();
|
|
||||||
},
|
|
||||||
buttonStyleData: const ButtonStyleData(
|
|
||||||
padding: EdgeInsets.only(left: 4, right: 12),
|
|
||||||
),
|
|
||||||
menuItemStyleData: const MenuItemStyleData(
|
|
||||||
height: 48,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (widget.withRealm) const Divider(height: 1),
|
|
||||||
Expanded(
|
Expanded(
|
||||||
child: MediaQuery.removePadding(
|
child: MediaQuery.removePadding(
|
||||||
context: context,
|
context: context,
|
||||||
@ -521,6 +481,7 @@ class _PostListWidgetState extends State<_PostListWidget> {
|
|||||||
displacement: 40 + MediaQuery.of(context).padding.top,
|
displacement: 40 + MediaQuery.of(context).padding.top,
|
||||||
onRefresh: () => refreshPosts(),
|
onRefresh: () => refreshPosts(),
|
||||||
child: InfiniteList(
|
child: InfiniteList(
|
||||||
|
padding: EdgeInsets.only(top: 8),
|
||||||
itemCount: _posts.length,
|
itemCount: _posts.length,
|
||||||
isLoading: _isBusy,
|
isLoading: _isBusy,
|
||||||
centerLoading: true,
|
centerLoading: true,
|
||||||
@ -542,18 +503,21 @@ class _PostListWidgetState extends State<_PostListWidget> {
|
|||||||
separatorBuilder: (_, __) => const Gap(8),
|
separatorBuilder: (_, __) => const Gap(8),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
).padding(top: 8),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _PostCategoryPickerPopup extends StatelessWidget {
|
class _PostListRealmPopup extends StatelessWidget {
|
||||||
final List<SnPostCategory> categories;
|
final List<SnRealm>? realms;
|
||||||
final SnPostCategory? selected;
|
final Function(SnRealm?) onUpdate;
|
||||||
|
|
||||||
const _PostCategoryPickerPopup({required this.categories, this.selected});
|
const _PostListRealmPopup({
|
||||||
|
required this.realms,
|
||||||
|
required this.onUpdate,
|
||||||
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -563,62 +527,38 @@ class _PostCategoryPickerPopup extends StatelessWidget {
|
|||||||
Row(
|
Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
const Icon(Symbols.category, size: 24),
|
const Icon(Symbols.face, size: 24),
|
||||||
const Gap(16),
|
const Gap(16),
|
||||||
Text('postCategory')
|
Text('accountRealms', style: Theme.of(context).textTheme.titleLarge)
|
||||||
.tr()
|
.tr(),
|
||||||
.textStyle(Theme.of(context).textTheme.titleLarge!),
|
|
||||||
],
|
],
|
||||||
).padding(horizontal: 20, top: 16, bottom: 12),
|
).padding(horizontal: 20, top: 16, bottom: 12),
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: const Icon(Symbols.clear),
|
leading: const Icon(Symbols.close),
|
||||||
title: Text('postFilterReset').tr(),
|
title: Text('postInGlobal').tr(),
|
||||||
subtitle: Text('postFilterResetDescription').tr(),
|
subtitle: Text('postViewInGlobalDescription').tr(),
|
||||||
contentPadding: const EdgeInsets.symmetric(horizontal: 20),
|
contentPadding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Navigator.pop(context, false);
|
onUpdate.call(null);
|
||||||
|
Navigator.pop(context);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
const Divider(height: 1),
|
const Divider(height: 1),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: GridView.count(
|
child: ListView.builder(
|
||||||
crossAxisCount: 4,
|
itemCount: realms?.length ?? 0,
|
||||||
shrinkWrap: true,
|
itemBuilder: (context, idx) {
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
final realm = realms![idx];
|
||||||
childAspectRatio: 1,
|
return ListTile(
|
||||||
children: categories
|
title: Text(realm.name),
|
||||||
.map(
|
subtitle: Text('@${realm.alias}'),
|
||||||
(ele) => InkWell(
|
leading: AccountImage(content: realm.avatar, radius: 18),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
_selectedCategory = ele;
|
onUpdate.call(realm);
|
||||||
Navigator.pop(context, ele);
|
Navigator.pop(context);
|
||||||
},
|
},
|
||||||
child: Column(
|
);
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
},
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
Icon(
|
|
||||||
kCategoryIcons[ele.alias] ?? Symbols.question_mark,
|
|
||||||
color: selected == ele
|
|
||||||
? Theme.of(context).colorScheme.primary
|
|
||||||
: null,
|
|
||||||
),
|
|
||||||
const Gap(4),
|
|
||||||
Text(
|
|
||||||
'postCategory${ele.alias.capitalize()}'.trExists()
|
|
||||||
? 'postCategory${ele.alias.capitalize()}'.tr()
|
|
||||||
: ele.name,
|
|
||||||
)
|
|
||||||
.textStyle(Theme.of(context).textTheme.titleMedium!)
|
|
||||||
.textColor(selected == ele
|
|
||||||
? Theme.of(context).colorScheme.primary
|
|
||||||
: null),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.toList(),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -546,11 +546,26 @@ class _HomeDashCheckInWidgetState extends State<_HomeDashCheckInWidget> {
|
|||||||
'+${_todayRecord!.resultExperience} EXP',
|
'+${_todayRecord!.resultExperience} EXP',
|
||||||
style: Theme.of(context).textTheme.bodyLarge,
|
style: Theme.of(context).textTheme.bodyLarge,
|
||||||
),
|
),
|
||||||
if (_todayRecord!.resultCoin >= 0)
|
if (_todayRecord!.resultCoin > 0)
|
||||||
Text(
|
Text(
|
||||||
'+${_todayRecord!.resultCoin} ${'walletCurrencyShort'.tr()}',
|
'+${_todayRecord!.resultCoin} ${'walletCurrencyShort'.tr()}',
|
||||||
style: Theme.of(context).textTheme.bodyLarge,
|
style: Theme.of(context).textTheme.bodyLarge,
|
||||||
)
|
),
|
||||||
|
if (_todayRecord!.currentStreak > 0)
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
const Icon(
|
||||||
|
Symbols.local_fire_department,
|
||||||
|
size: 14,
|
||||||
|
).padding(bottom: 2),
|
||||||
|
const Gap(4),
|
||||||
|
Text(
|
||||||
|
'checkInStreak'
|
||||||
|
.plural(_todayRecord!.currentStreak),
|
||||||
|
style: Theme.of(context).textTheme.bodySmall,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
).padding(top: 4),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
88
lib/screens/post/post_draft.dart
Normal file
88
lib/screens/post/post_draft.dart
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:gap/gap.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:surface/providers/post.dart';
|
||||||
|
import 'package:surface/types/post.dart';
|
||||||
|
import 'package:surface/widgets/dialog.dart';
|
||||||
|
import 'package:surface/widgets/loading_indicator.dart';
|
||||||
|
import 'package:surface/widgets/navigation/app_scaffold.dart';
|
||||||
|
import 'package:surface/widgets/post/post_item.dart';
|
||||||
|
import 'package:very_good_infinite_list/very_good_infinite_list.dart';
|
||||||
|
|
||||||
|
class PostDraftBox extends StatefulWidget {
|
||||||
|
const PostDraftBox({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<PostDraftBox> createState() => _PostDraftBoxState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _PostDraftBoxState extends State<PostDraftBox> {
|
||||||
|
bool _isBusy = false;
|
||||||
|
final List<SnPost> _posts = List.empty(growable: true);
|
||||||
|
int? _totalCount;
|
||||||
|
|
||||||
|
Future<void> _fetchPosts() async {
|
||||||
|
setState(() => _isBusy = true);
|
||||||
|
try {
|
||||||
|
final pt = context.read<SnPostContentProvider>();
|
||||||
|
final resp = await pt.listPosts(
|
||||||
|
take: 10,
|
||||||
|
offset: _posts.length,
|
||||||
|
isDraft: true,
|
||||||
|
);
|
||||||
|
final out = resp.$1;
|
||||||
|
_totalCount = resp.$2;
|
||||||
|
if (!mounted) return;
|
||||||
|
_posts.addAll(out);
|
||||||
|
} catch (err) {
|
||||||
|
if (!mounted) return;
|
||||||
|
context.showErrorDialog(err);
|
||||||
|
} finally {
|
||||||
|
setState(() => _isBusy = false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return AppScaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text('postDraftBox').tr(),
|
||||||
|
),
|
||||||
|
body: Column(
|
||||||
|
children: [
|
||||||
|
LoadingIndicator(isActive: _isBusy),
|
||||||
|
Expanded(
|
||||||
|
child: RefreshIndicator(
|
||||||
|
onRefresh: () {
|
||||||
|
_posts.clear();
|
||||||
|
return _fetchPosts();
|
||||||
|
},
|
||||||
|
child: InfiniteList(
|
||||||
|
padding: EdgeInsets.only(top: 8),
|
||||||
|
hasReachedMax:
|
||||||
|
_totalCount != null && _posts.length >= _totalCount!,
|
||||||
|
itemCount: _posts.length,
|
||||||
|
onFetchData: () => _fetchPosts(),
|
||||||
|
itemBuilder: (context, idx) {
|
||||||
|
final ele = _posts[idx];
|
||||||
|
return OpenablePostItem(
|
||||||
|
data: ele,
|
||||||
|
onChanged: (data) {
|
||||||
|
_posts[idx] = data;
|
||||||
|
},
|
||||||
|
onDeleted: () {
|
||||||
|
_posts.clear();
|
||||||
|
_fetchPosts();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
separatorBuilder: (_, __) => const Gap(8),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -18,6 +18,7 @@ import 'package:surface/controllers/post_write_controller.dart';
|
|||||||
import 'package:surface/providers/config.dart';
|
import 'package:surface/providers/config.dart';
|
||||||
import 'package:surface/providers/sn_attachment.dart';
|
import 'package:surface/providers/sn_attachment.dart';
|
||||||
import 'package:surface/providers/sn_network.dart';
|
import 'package:surface/providers/sn_network.dart';
|
||||||
|
import 'package:surface/providers/sn_realm.dart';
|
||||||
import 'package:surface/types/attachment.dart';
|
import 'package:surface/types/attachment.dart';
|
||||||
import 'package:surface/types/post.dart';
|
import 'package:surface/types/post.dart';
|
||||||
import 'package:surface/types/realm.dart';
|
import 'package:surface/types/realm.dart';
|
||||||
@ -36,7 +37,8 @@ import 'package:provider/provider.dart';
|
|||||||
import 'package:surface/widgets/post/post_poll_editor.dart';
|
import 'package:surface/widgets/post/post_poll_editor.dart';
|
||||||
import 'package:uuid/uuid.dart';
|
import 'package:uuid/uuid.dart';
|
||||||
|
|
||||||
import '../../providers/sn_realm.dart';
|
const kPostTypes = ['Story', 'Article', 'Question', 'Video'];
|
||||||
|
const kPostTypeAliases = ['stories', 'articles', 'questions', 'videos'];
|
||||||
|
|
||||||
class PostEditorExtra {
|
class PostEditorExtra {
|
||||||
final String? text;
|
final String? text;
|
||||||
@ -53,7 +55,7 @@ class PostEditorExtra {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class PostEditorScreen extends StatefulWidget {
|
class PostEditorScreen extends StatefulWidget {
|
||||||
final String mode;
|
final String? mode;
|
||||||
final int? postEditId;
|
final int? postEditId;
|
||||||
final int? postReplyId;
|
final int? postReplyId;
|
||||||
final int? postRepostId;
|
final int? postRepostId;
|
||||||
@ -72,7 +74,10 @@ class PostEditorScreen extends StatefulWidget {
|
|||||||
State<PostEditorScreen> createState() => _PostEditorScreenState();
|
State<PostEditorScreen> createState() => _PostEditorScreenState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _PostEditorScreenState extends State<PostEditorScreen> {
|
class _PostEditorScreenState extends State<PostEditorScreen>
|
||||||
|
with SingleTickerProviderStateMixin {
|
||||||
|
late final TabController _tabController =
|
||||||
|
TabController(length: 4, vsync: this);
|
||||||
late final PostWriteController _writeController = PostWriteController(
|
late final PostWriteController _writeController = PostWriteController(
|
||||||
doLoadFromTemporary: widget.postEditId == null,
|
doLoadFromTemporary: widget.postEditId == null,
|
||||||
);
|
);
|
||||||
@ -133,6 +138,15 @@ class _PostEditorScreenState extends State<PostEditorScreen> {
|
|||||||
],
|
],
|
||||||
scope: HotKeyScope.inapp,
|
scope: HotKeyScope.inapp,
|
||||||
);
|
);
|
||||||
|
final HotKey _saveDraftHotKey = HotKey(
|
||||||
|
key: PhysicalKeyboardKey.keyS,
|
||||||
|
modifiers: [
|
||||||
|
(!kIsWeb && Platform.isMacOS)
|
||||||
|
? HotKeyModifier.meta
|
||||||
|
: HotKeyModifier.control
|
||||||
|
],
|
||||||
|
scope: HotKeyScope.inapp,
|
||||||
|
);
|
||||||
|
|
||||||
void _registerHotKey() {
|
void _registerHotKey() {
|
||||||
if (kIsWeb || Platform.isAndroid || Platform.isIOS) return;
|
if (kIsWeb || Platform.isAndroid || Platform.isIOS) return;
|
||||||
@ -148,6 +162,11 @@ class _PostEditorScreenState extends State<PostEditorScreen> {
|
|||||||
]);
|
]);
|
||||||
setState(() {});
|
setState(() {});
|
||||||
});
|
});
|
||||||
|
hotKeyManager.register(_saveDraftHotKey, keyDownHandler: (_) async {
|
||||||
|
if (mounted) {
|
||||||
|
_writeController.sendPost(context);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void _showPublisherPopup() {
|
void _showPublisherPopup() {
|
||||||
@ -209,9 +228,11 @@ class _PostEditorScreenState extends State<PostEditorScreen> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
|
_tabController.dispose();
|
||||||
_writeController.dispose();
|
_writeController.dispose();
|
||||||
if (!kIsWeb && !(Platform.isAndroid || Platform.isIOS)) {
|
if (!kIsWeb && !(Platform.isAndroid || Platform.isIOS)) {
|
||||||
hotKeyManager.unregister(_pasteHotKey);
|
hotKeyManager.unregister(_pasteHotKey);
|
||||||
|
hotKeyManager.unregister(_saveDraftHotKey);
|
||||||
}
|
}
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
@ -220,14 +241,16 @@ class _PostEditorScreenState extends State<PostEditorScreen> {
|
|||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_registerHotKey();
|
_registerHotKey();
|
||||||
if (!PostWriteController.kTitleMap.keys.contains(widget.mode)) {
|
|
||||||
context.showErrorDialog('Unknown post type');
|
|
||||||
Navigator.pop(context);
|
|
||||||
} else {
|
|
||||||
_writeController.setMode(widget.mode);
|
|
||||||
}
|
|
||||||
_fetchRealms();
|
_fetchRealms();
|
||||||
_fetchPublishers();
|
_fetchPublishers();
|
||||||
|
if (widget.mode != null) {
|
||||||
|
_writeController.setMode(widget.mode!);
|
||||||
|
}
|
||||||
|
_tabController.addListener(() {
|
||||||
|
if (_tabController.indexIsChanging) {
|
||||||
|
_writeController.setMode(kPostTypeAliases[_tabController.index]);
|
||||||
|
}
|
||||||
|
});
|
||||||
_writeController.fetchRelatedPost(
|
_writeController.fetchRelatedPost(
|
||||||
context,
|
context,
|
||||||
editing: widget.postEditId,
|
editing: widget.postEditId,
|
||||||
@ -255,38 +278,55 @@ class _PostEditorScreenState extends State<PostEditorScreen> {
|
|||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
title: RichText(
|
title: Text(
|
||||||
textAlign: TextAlign.center,
|
_writeController.title.isNotEmpty
|
||||||
text: TextSpan(children: [
|
? _writeController.title
|
||||||
TextSpan(
|
: 'untitled'.tr(),
|
||||||
text: _writeController.title.isNotEmpty
|
|
||||||
? _writeController.title
|
|
||||||
: 'untitled'.tr(),
|
|
||||||
style: Theme.of(context).textTheme.titleLarge!.copyWith(
|
|
||||||
color: Theme.of(context).appBarTheme.foregroundColor!,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const TextSpan(text: '\n'),
|
|
||||||
TextSpan(
|
|
||||||
text: PostWriteController.kTitleMap[widget.mode]!.tr(),
|
|
||||||
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
|
||||||
color: Theme.of(context).appBarTheme.foregroundColor!,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
]),
|
|
||||||
maxLines: 2,
|
|
||||||
),
|
),
|
||||||
actions: [
|
actions: [
|
||||||
|
IconButton(
|
||||||
|
icon: _writeController.editingDraft
|
||||||
|
? const Icon(Icons.save)
|
||||||
|
: const Icon(Symbols.save_as),
|
||||||
|
onPressed: () {
|
||||||
|
_writeController.sendPost(context, saveAsDraft: true).then(
|
||||||
|
(_) {
|
||||||
|
if (!context.mounted) return;
|
||||||
|
context.showSnackbar('postDraftSaved'.tr());
|
||||||
|
HapticFeedback.mediumImpact();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Symbols.tune),
|
icon: const Icon(Symbols.tune),
|
||||||
onPressed: _writeController.isBusy ? null : _updateMeta,
|
onPressed: _writeController.isBusy ? null : _updateMeta,
|
||||||
),
|
),
|
||||||
const Gap(8),
|
const Gap(8),
|
||||||
],
|
],
|
||||||
|
bottom: _writeController.isNotEmpty || widget.mode != null
|
||||||
|
? null
|
||||||
|
: TabBar(
|
||||||
|
controller: _tabController,
|
||||||
|
tabs: [
|
||||||
|
for (final type in kPostTypes)
|
||||||
|
Tab(
|
||||||
|
child: Text(
|
||||||
|
'postType$type'.tr(),
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context)
|
||||||
|
.appBarTheme
|
||||||
|
.foregroundColor!,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
body: Column(
|
body: Column(
|
||||||
children: [
|
children: [
|
||||||
if (_writeController.editingPost != null)
|
if (_writeController.editingPost != null &&
|
||||||
|
!_writeController.editingDraft)
|
||||||
Container(
|
Container(
|
||||||
padding: const EdgeInsets.only(
|
padding: const EdgeInsets.only(
|
||||||
top: 4, bottom: 4, left: 20, right: 20),
|
top: 4, bottom: 4, left: 20, right: 20),
|
||||||
@ -374,7 +414,7 @@ class _PostEditorScreenState extends State<PostEditorScreen> {
|
|||||||
children: [
|
children: [
|
||||||
SingleChildScrollView(
|
SingleChildScrollView(
|
||||||
padding: EdgeInsets.only(bottom: 160),
|
padding: EdgeInsets.only(bottom: 160),
|
||||||
child: StyledWidget(switch (_writeController.mode) {
|
child: switch (_writeController.mode) {
|
||||||
'stories' => _PostStoryEditor(
|
'stories' => _PostStoryEditor(
|
||||||
controller: _writeController,
|
controller: _writeController,
|
||||||
onTapPublisher: _showPublisherPopup,
|
onTapPublisher: _showPublisherPopup,
|
||||||
@ -396,8 +436,7 @@ class _PostEditorScreenState extends State<PostEditorScreen> {
|
|||||||
onTapRealm: _showRealmPopup,
|
onTapRealm: _showRealmPopup,
|
||||||
),
|
),
|
||||||
_ => const Placeholder(),
|
_ => const Placeholder(),
|
||||||
})
|
},
|
||||||
.padding(top: 8),
|
|
||||||
),
|
),
|
||||||
if (_writeController.attachments.isNotEmpty ||
|
if (_writeController.attachments.isNotEmpty ||
|
||||||
_writeController.thumbnail != null)
|
_writeController.thumbnail != null)
|
||||||
@ -720,7 +759,7 @@ class _PostStoryEditor extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
padding: const EdgeInsets.only(left: 12, right: 12, top: 8),
|
||||||
constraints: const BoxConstraints(maxWidth: 640),
|
constraints: const BoxConstraints(maxWidth: 640),
|
||||||
child: Row(
|
child: Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@ -969,7 +1008,7 @@ class _PostQuestionEditor extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
padding: const EdgeInsets.only(left: 12, right: 12, top: 8),
|
||||||
constraints: const BoxConstraints(maxWidth: 640),
|
constraints: const BoxConstraints(maxWidth: 640),
|
||||||
child: Row(
|
child: Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@ -1053,7 +1092,7 @@ class _PostQuestionEditor extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
).padding(top: 8),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1154,7 +1193,7 @@ class _PostVideoEditor extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
padding: const EdgeInsets.only(left: 12, right: 12, top: 8),
|
||||||
constraints: const BoxConstraints(maxWidth: 640),
|
constraints: const BoxConstraints(maxWidth: 640),
|
||||||
child: Row(
|
child: Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
132
lib/screens/post/post_shuffle.dart
Normal file
132
lib/screens/post/post_shuffle.dart
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_card_swiper/flutter_card_swiper.dart';
|
||||||
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
|
import 'package:surface/providers/post.dart';
|
||||||
|
import 'package:surface/types/post.dart';
|
||||||
|
import 'package:surface/widgets/dialog.dart';
|
||||||
|
import 'package:surface/widgets/navigation/app_scaffold.dart';
|
||||||
|
import 'package:surface/widgets/post/post_item.dart';
|
||||||
|
|
||||||
|
class PostShuffleScreen extends StatefulWidget {
|
||||||
|
const PostShuffleScreen({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<PostShuffleScreen> createState() => _PostShuffleScreenState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _PostShuffleScreenState extends State<PostShuffleScreen> {
|
||||||
|
late final CardSwiperController _cardController = CardSwiperController();
|
||||||
|
|
||||||
|
bool _isBusy = false;
|
||||||
|
final List<SnPost> _posts = List.empty(growable: true);
|
||||||
|
|
||||||
|
Future<void> _fetchPosts() async {
|
||||||
|
_posts.clear();
|
||||||
|
setState(() => _isBusy = true);
|
||||||
|
try {
|
||||||
|
final pt = context.read<SnPostContentProvider>();
|
||||||
|
final result = await pt.listPosts(
|
||||||
|
take: 10,
|
||||||
|
offset: _posts.length,
|
||||||
|
isShuffle: true,
|
||||||
|
);
|
||||||
|
_posts.addAll(result.$1);
|
||||||
|
} catch (err) {
|
||||||
|
if (!mounted) return;
|
||||||
|
context.showErrorDialog(err);
|
||||||
|
} finally {
|
||||||
|
setState(() => _isBusy = false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_fetchPosts();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
super.dispose();
|
||||||
|
_cardController.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return AppScaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text('postShuffle').tr(),
|
||||||
|
),
|
||||||
|
body: Stack(
|
||||||
|
children: [
|
||||||
|
Column(
|
||||||
|
children: [
|
||||||
|
if (_isBusy || _posts.isEmpty)
|
||||||
|
const Expanded(
|
||||||
|
child: Center(
|
||||||
|
child: CircularProgressIndicator(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
else
|
||||||
|
Expanded(
|
||||||
|
child: CardSwiper(
|
||||||
|
controller: _cardController,
|
||||||
|
isLoop: false,
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
cardsCount: _posts.length,
|
||||||
|
cardBuilder: (context, idx, _, __) {
|
||||||
|
final ele = _posts[idx];
|
||||||
|
return SingleChildScrollView(
|
||||||
|
child: Center(
|
||||||
|
child: OpenablePostItem(
|
||||||
|
key: ValueKey(ele),
|
||||||
|
data: ele,
|
||||||
|
maxWidth: 640,
|
||||||
|
onChanged: (ele) {
|
||||||
|
_posts[idx] = ele;
|
||||||
|
setState(() {});
|
||||||
|
},
|
||||||
|
onDeleted: () {
|
||||||
|
_fetchPosts();
|
||||||
|
},
|
||||||
|
).padding(
|
||||||
|
all: 24,
|
||||||
|
bottom:
|
||||||
|
MediaQuery.of(context).padding.bottom + 16 + 50,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
onEnd: () {
|
||||||
|
_fetchPosts();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
if (!_isBusy && _posts.isNotEmpty)
|
||||||
|
Positioned(
|
||||||
|
bottom: MediaQuery.of(context).padding.bottom + 16,
|
||||||
|
left: 16,
|
||||||
|
right: 16,
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
IconButton.filled(
|
||||||
|
icon: const Icon(Symbols.next_plan),
|
||||||
|
color: Theme.of(context).colorScheme.onPrimary,
|
||||||
|
onPressed: () {
|
||||||
|
_cardController.swipe(CardSwiperDirection.right);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -61,7 +61,7 @@ class _AppSharingListenerState extends State<AppSharingListener> {
|
|||||||
onTap: () {
|
onTap: () {
|
||||||
GoRouter.of(context).pushNamed(
|
GoRouter.of(context).pushNamed(
|
||||||
'postEditor',
|
'postEditor',
|
||||||
pathParameters: {
|
queryParameters: {
|
||||||
'mode': 'stories',
|
'mode': 'stories',
|
||||||
},
|
},
|
||||||
extra: PostEditorExtra(
|
extra: PostEditorExtra(
|
||||||
|
@ -50,16 +50,17 @@ Future<ThemeData> createAppTheme(
|
|||||||
useMaterial3 ?? (prefs.getBool(kMaterialYouToggleStoreKey) ?? true);
|
useMaterial3 ?? (prefs.getBool(kMaterialYouToggleStoreKey) ?? true);
|
||||||
|
|
||||||
final inUseFonts = (customFonts ?? prefs.getString(kAppCustomFonts))
|
final inUseFonts = (customFonts ?? prefs.getString(kAppCustomFonts))
|
||||||
?.split(',')
|
?.split(',')
|
||||||
.map((ele) => ele.trim())
|
.map((ele) => ele.trim())
|
||||||
.toList();
|
.toList() ??
|
||||||
|
['Nunito'];
|
||||||
|
|
||||||
return ThemeData(
|
return ThemeData(
|
||||||
useMaterial3: useM3,
|
useMaterial3: useM3,
|
||||||
colorScheme: colorScheme,
|
colorScheme: colorScheme,
|
||||||
brightness: brightness,
|
brightness: brightness,
|
||||||
fontFamily: inUseFonts?.firstOrNull,
|
fontFamily: inUseFonts.firstOrNull,
|
||||||
fontFamilyFallback: inUseFonts?.sublist(1),
|
fontFamilyFallback: inUseFonts.sublist(1),
|
||||||
iconTheme: IconThemeData(
|
iconTheme: IconThemeData(
|
||||||
fill: 0,
|
fill: 0,
|
||||||
weight: 400,
|
weight: 400,
|
||||||
|
@ -119,13 +119,33 @@ abstract class SnAccountStatusInfo with _$SnAccountStatusInfo {
|
|||||||
required bool isDisturbable,
|
required bool isDisturbable,
|
||||||
required bool isOnline,
|
required bool isOnline,
|
||||||
required DateTime? lastSeenAt,
|
required DateTime? lastSeenAt,
|
||||||
required dynamic status,
|
required SnAccountStatus? status,
|
||||||
}) = _SnAccountStatusInfo;
|
}) = _SnAccountStatusInfo;
|
||||||
|
|
||||||
factory SnAccountStatusInfo.fromJson(Map<String, Object?> json) =>
|
factory SnAccountStatusInfo.fromJson(Map<String, Object?> json) =>
|
||||||
_$SnAccountStatusInfoFromJson(json);
|
_$SnAccountStatusInfoFromJson(json);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
abstract class SnAccountStatus with _$SnAccountStatus {
|
||||||
|
const factory SnAccountStatus({
|
||||||
|
required int id,
|
||||||
|
required DateTime createdAt,
|
||||||
|
required DateTime updatedAt,
|
||||||
|
required DateTime? deletedAt,
|
||||||
|
required String type,
|
||||||
|
required String label,
|
||||||
|
required int attitude,
|
||||||
|
required bool isNoDisturb,
|
||||||
|
required bool isInvisible,
|
||||||
|
required DateTime? clearAt,
|
||||||
|
required int accountId,
|
||||||
|
}) = _SnAccountStatus;
|
||||||
|
|
||||||
|
factory SnAccountStatus.fromJson(Map<String, Object?> json) =>
|
||||||
|
_$SnAccountStatusFromJson(json);
|
||||||
|
}
|
||||||
|
|
||||||
@freezed
|
@freezed
|
||||||
abstract class SnAbuseReport with _$SnAbuseReport {
|
abstract class SnAbuseReport with _$SnAbuseReport {
|
||||||
const factory SnAbuseReport({
|
const factory SnAbuseReport({
|
||||||
|
@ -2139,7 +2139,7 @@ mixin _$SnAccountStatusInfo {
|
|||||||
bool get isDisturbable;
|
bool get isDisturbable;
|
||||||
bool get isOnline;
|
bool get isOnline;
|
||||||
DateTime? get lastSeenAt;
|
DateTime? get lastSeenAt;
|
||||||
dynamic get status;
|
SnAccountStatus? get status;
|
||||||
|
|
||||||
/// Create a copy of SnAccountStatusInfo
|
/// Create a copy of SnAccountStatusInfo
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@ -2163,13 +2163,13 @@ mixin _$SnAccountStatusInfo {
|
|||||||
other.isOnline == isOnline) &&
|
other.isOnline == isOnline) &&
|
||||||
(identical(other.lastSeenAt, lastSeenAt) ||
|
(identical(other.lastSeenAt, lastSeenAt) ||
|
||||||
other.lastSeenAt == lastSeenAt) &&
|
other.lastSeenAt == lastSeenAt) &&
|
||||||
const DeepCollectionEquality().equals(other.status, status));
|
(identical(other.status, status) || other.status == status));
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(runtimeType, isDisturbable, isOnline,
|
int get hashCode =>
|
||||||
lastSeenAt, const DeepCollectionEquality().hash(status));
|
Object.hash(runtimeType, isDisturbable, isOnline, lastSeenAt, status);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
@ -2187,7 +2187,9 @@ abstract mixin class $SnAccountStatusInfoCopyWith<$Res> {
|
|||||||
{bool isDisturbable,
|
{bool isDisturbable,
|
||||||
bool isOnline,
|
bool isOnline,
|
||||||
DateTime? lastSeenAt,
|
DateTime? lastSeenAt,
|
||||||
dynamic status});
|
SnAccountStatus? status});
|
||||||
|
|
||||||
|
$SnAccountStatusCopyWith<$Res>? get status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
@ -2224,9 +2226,23 @@ class _$SnAccountStatusInfoCopyWithImpl<$Res>
|
|||||||
status: freezed == status
|
status: freezed == status
|
||||||
? _self.status
|
? _self.status
|
||||||
: status // ignore: cast_nullable_to_non_nullable
|
: status // ignore: cast_nullable_to_non_nullable
|
||||||
as dynamic,
|
as SnAccountStatus?,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a copy of SnAccountStatusInfo
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$SnAccountStatusCopyWith<$Res>? get status {
|
||||||
|
if (_self.status == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $SnAccountStatusCopyWith<$Res>(_self.status!, (value) {
|
||||||
|
return _then(_self.copyWith(status: value));
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
@ -2247,7 +2263,7 @@ class _SnAccountStatusInfo implements SnAccountStatusInfo {
|
|||||||
@override
|
@override
|
||||||
final DateTime? lastSeenAt;
|
final DateTime? lastSeenAt;
|
||||||
@override
|
@override
|
||||||
final dynamic status;
|
final SnAccountStatus? status;
|
||||||
|
|
||||||
/// Create a copy of SnAccountStatusInfo
|
/// Create a copy of SnAccountStatusInfo
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@ -2276,13 +2292,13 @@ class _SnAccountStatusInfo implements SnAccountStatusInfo {
|
|||||||
other.isOnline == isOnline) &&
|
other.isOnline == isOnline) &&
|
||||||
(identical(other.lastSeenAt, lastSeenAt) ||
|
(identical(other.lastSeenAt, lastSeenAt) ||
|
||||||
other.lastSeenAt == lastSeenAt) &&
|
other.lastSeenAt == lastSeenAt) &&
|
||||||
const DeepCollectionEquality().equals(other.status, status));
|
(identical(other.status, status) || other.status == status));
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(runtimeType, isDisturbable, isOnline,
|
int get hashCode =>
|
||||||
lastSeenAt, const DeepCollectionEquality().hash(status));
|
Object.hash(runtimeType, isDisturbable, isOnline, lastSeenAt, status);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
@ -2302,7 +2318,10 @@ abstract mixin class _$SnAccountStatusInfoCopyWith<$Res>
|
|||||||
{bool isDisturbable,
|
{bool isDisturbable,
|
||||||
bool isOnline,
|
bool isOnline,
|
||||||
DateTime? lastSeenAt,
|
DateTime? lastSeenAt,
|
||||||
dynamic status});
|
SnAccountStatus? status});
|
||||||
|
|
||||||
|
@override
|
||||||
|
$SnAccountStatusCopyWith<$Res>? get status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
@ -2339,7 +2358,386 @@ class __$SnAccountStatusInfoCopyWithImpl<$Res>
|
|||||||
status: freezed == status
|
status: freezed == status
|
||||||
? _self.status
|
? _self.status
|
||||||
: status // ignore: cast_nullable_to_non_nullable
|
: status // ignore: cast_nullable_to_non_nullable
|
||||||
as dynamic,
|
as SnAccountStatus?,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a copy of SnAccountStatusInfo
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$SnAccountStatusCopyWith<$Res>? get status {
|
||||||
|
if (_self.status == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $SnAccountStatusCopyWith<$Res>(_self.status!, (value) {
|
||||||
|
return _then(_self.copyWith(status: value));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
mixin _$SnAccountStatus {
|
||||||
|
int get id;
|
||||||
|
DateTime get createdAt;
|
||||||
|
DateTime get updatedAt;
|
||||||
|
DateTime? get deletedAt;
|
||||||
|
String get type;
|
||||||
|
String get label;
|
||||||
|
int get attitude;
|
||||||
|
bool get isNoDisturb;
|
||||||
|
bool get isInvisible;
|
||||||
|
DateTime? get clearAt;
|
||||||
|
int get accountId;
|
||||||
|
|
||||||
|
/// Create a copy of SnAccountStatus
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$SnAccountStatusCopyWith<SnAccountStatus> get copyWith =>
|
||||||
|
_$SnAccountStatusCopyWithImpl<SnAccountStatus>(
|
||||||
|
this as SnAccountStatus, _$identity);
|
||||||
|
|
||||||
|
/// Serializes this SnAccountStatus to a JSON map.
|
||||||
|
Map<String, dynamic> toJson();
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return identical(this, other) ||
|
||||||
|
(other.runtimeType == runtimeType &&
|
||||||
|
other is SnAccountStatus &&
|
||||||
|
(identical(other.id, id) || other.id == id) &&
|
||||||
|
(identical(other.createdAt, createdAt) ||
|
||||||
|
other.createdAt == createdAt) &&
|
||||||
|
(identical(other.updatedAt, updatedAt) ||
|
||||||
|
other.updatedAt == updatedAt) &&
|
||||||
|
(identical(other.deletedAt, deletedAt) ||
|
||||||
|
other.deletedAt == deletedAt) &&
|
||||||
|
(identical(other.type, type) || other.type == type) &&
|
||||||
|
(identical(other.label, label) || other.label == label) &&
|
||||||
|
(identical(other.attitude, attitude) ||
|
||||||
|
other.attitude == attitude) &&
|
||||||
|
(identical(other.isNoDisturb, isNoDisturb) ||
|
||||||
|
other.isNoDisturb == isNoDisturb) &&
|
||||||
|
(identical(other.isInvisible, isInvisible) ||
|
||||||
|
other.isInvisible == isInvisible) &&
|
||||||
|
(identical(other.clearAt, clearAt) || other.clearAt == clearAt) &&
|
||||||
|
(identical(other.accountId, accountId) ||
|
||||||
|
other.accountId == accountId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(
|
||||||
|
runtimeType,
|
||||||
|
id,
|
||||||
|
createdAt,
|
||||||
|
updatedAt,
|
||||||
|
deletedAt,
|
||||||
|
type,
|
||||||
|
label,
|
||||||
|
attitude,
|
||||||
|
isNoDisturb,
|
||||||
|
isInvisible,
|
||||||
|
clearAt,
|
||||||
|
accountId);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'SnAccountStatus(id: $id, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, type: $type, label: $label, attitude: $attitude, isNoDisturb: $isNoDisturb, isInvisible: $isInvisible, clearAt: $clearAt, accountId: $accountId)';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract mixin class $SnAccountStatusCopyWith<$Res> {
|
||||||
|
factory $SnAccountStatusCopyWith(
|
||||||
|
SnAccountStatus value, $Res Function(SnAccountStatus) _then) =
|
||||||
|
_$SnAccountStatusCopyWithImpl;
|
||||||
|
@useResult
|
||||||
|
$Res call(
|
||||||
|
{int id,
|
||||||
|
DateTime createdAt,
|
||||||
|
DateTime updatedAt,
|
||||||
|
DateTime? deletedAt,
|
||||||
|
String type,
|
||||||
|
String label,
|
||||||
|
int attitude,
|
||||||
|
bool isNoDisturb,
|
||||||
|
bool isInvisible,
|
||||||
|
DateTime? clearAt,
|
||||||
|
int accountId});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class _$SnAccountStatusCopyWithImpl<$Res>
|
||||||
|
implements $SnAccountStatusCopyWith<$Res> {
|
||||||
|
_$SnAccountStatusCopyWithImpl(this._self, this._then);
|
||||||
|
|
||||||
|
final SnAccountStatus _self;
|
||||||
|
final $Res Function(SnAccountStatus) _then;
|
||||||
|
|
||||||
|
/// Create a copy of SnAccountStatus
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
@override
|
||||||
|
$Res call({
|
||||||
|
Object? id = null,
|
||||||
|
Object? createdAt = null,
|
||||||
|
Object? updatedAt = null,
|
||||||
|
Object? deletedAt = freezed,
|
||||||
|
Object? type = null,
|
||||||
|
Object? label = null,
|
||||||
|
Object? attitude = null,
|
||||||
|
Object? isNoDisturb = null,
|
||||||
|
Object? isInvisible = null,
|
||||||
|
Object? clearAt = freezed,
|
||||||
|
Object? accountId = null,
|
||||||
|
}) {
|
||||||
|
return _then(_self.copyWith(
|
||||||
|
id: null == id
|
||||||
|
? _self.id
|
||||||
|
: id // ignore: cast_nullable_to_non_nullable
|
||||||
|
as int,
|
||||||
|
createdAt: null == createdAt
|
||||||
|
? _self.createdAt
|
||||||
|
: createdAt // ignore: cast_nullable_to_non_nullable
|
||||||
|
as DateTime,
|
||||||
|
updatedAt: null == updatedAt
|
||||||
|
? _self.updatedAt
|
||||||
|
: updatedAt // ignore: cast_nullable_to_non_nullable
|
||||||
|
as DateTime,
|
||||||
|
deletedAt: freezed == deletedAt
|
||||||
|
? _self.deletedAt
|
||||||
|
: deletedAt // ignore: cast_nullable_to_non_nullable
|
||||||
|
as DateTime?,
|
||||||
|
type: null == type
|
||||||
|
? _self.type
|
||||||
|
: type // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
label: null == label
|
||||||
|
? _self.label
|
||||||
|
: label // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
attitude: null == attitude
|
||||||
|
? _self.attitude
|
||||||
|
: attitude // ignore: cast_nullable_to_non_nullable
|
||||||
|
as int,
|
||||||
|
isNoDisturb: null == isNoDisturb
|
||||||
|
? _self.isNoDisturb
|
||||||
|
: isNoDisturb // ignore: cast_nullable_to_non_nullable
|
||||||
|
as bool,
|
||||||
|
isInvisible: null == isInvisible
|
||||||
|
? _self.isInvisible
|
||||||
|
: isInvisible // ignore: cast_nullable_to_non_nullable
|
||||||
|
as bool,
|
||||||
|
clearAt: freezed == clearAt
|
||||||
|
? _self.clearAt
|
||||||
|
: clearAt // ignore: cast_nullable_to_non_nullable
|
||||||
|
as DateTime?,
|
||||||
|
accountId: null == accountId
|
||||||
|
? _self.accountId
|
||||||
|
: accountId // ignore: cast_nullable_to_non_nullable
|
||||||
|
as int,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
@JsonSerializable()
|
||||||
|
class _SnAccountStatus implements SnAccountStatus {
|
||||||
|
const _SnAccountStatus(
|
||||||
|
{required this.id,
|
||||||
|
required this.createdAt,
|
||||||
|
required this.updatedAt,
|
||||||
|
required this.deletedAt,
|
||||||
|
required this.type,
|
||||||
|
required this.label,
|
||||||
|
required this.attitude,
|
||||||
|
required this.isNoDisturb,
|
||||||
|
required this.isInvisible,
|
||||||
|
required this.clearAt,
|
||||||
|
required this.accountId});
|
||||||
|
factory _SnAccountStatus.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$SnAccountStatusFromJson(json);
|
||||||
|
|
||||||
|
@override
|
||||||
|
final int id;
|
||||||
|
@override
|
||||||
|
final DateTime createdAt;
|
||||||
|
@override
|
||||||
|
final DateTime updatedAt;
|
||||||
|
@override
|
||||||
|
final DateTime? deletedAt;
|
||||||
|
@override
|
||||||
|
final String type;
|
||||||
|
@override
|
||||||
|
final String label;
|
||||||
|
@override
|
||||||
|
final int attitude;
|
||||||
|
@override
|
||||||
|
final bool isNoDisturb;
|
||||||
|
@override
|
||||||
|
final bool isInvisible;
|
||||||
|
@override
|
||||||
|
final DateTime? clearAt;
|
||||||
|
@override
|
||||||
|
final int accountId;
|
||||||
|
|
||||||
|
/// Create a copy of SnAccountStatus
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
_$SnAccountStatusCopyWith<_SnAccountStatus> get copyWith =>
|
||||||
|
__$SnAccountStatusCopyWithImpl<_SnAccountStatus>(this, _$identity);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return _$SnAccountStatusToJson(
|
||||||
|
this,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return identical(this, other) ||
|
||||||
|
(other.runtimeType == runtimeType &&
|
||||||
|
other is _SnAccountStatus &&
|
||||||
|
(identical(other.id, id) || other.id == id) &&
|
||||||
|
(identical(other.createdAt, createdAt) ||
|
||||||
|
other.createdAt == createdAt) &&
|
||||||
|
(identical(other.updatedAt, updatedAt) ||
|
||||||
|
other.updatedAt == updatedAt) &&
|
||||||
|
(identical(other.deletedAt, deletedAt) ||
|
||||||
|
other.deletedAt == deletedAt) &&
|
||||||
|
(identical(other.type, type) || other.type == type) &&
|
||||||
|
(identical(other.label, label) || other.label == label) &&
|
||||||
|
(identical(other.attitude, attitude) ||
|
||||||
|
other.attitude == attitude) &&
|
||||||
|
(identical(other.isNoDisturb, isNoDisturb) ||
|
||||||
|
other.isNoDisturb == isNoDisturb) &&
|
||||||
|
(identical(other.isInvisible, isInvisible) ||
|
||||||
|
other.isInvisible == isInvisible) &&
|
||||||
|
(identical(other.clearAt, clearAt) || other.clearAt == clearAt) &&
|
||||||
|
(identical(other.accountId, accountId) ||
|
||||||
|
other.accountId == accountId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(
|
||||||
|
runtimeType,
|
||||||
|
id,
|
||||||
|
createdAt,
|
||||||
|
updatedAt,
|
||||||
|
deletedAt,
|
||||||
|
type,
|
||||||
|
label,
|
||||||
|
attitude,
|
||||||
|
isNoDisturb,
|
||||||
|
isInvisible,
|
||||||
|
clearAt,
|
||||||
|
accountId);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'SnAccountStatus(id: $id, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, type: $type, label: $label, attitude: $attitude, isNoDisturb: $isNoDisturb, isInvisible: $isInvisible, clearAt: $clearAt, accountId: $accountId)';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract mixin class _$SnAccountStatusCopyWith<$Res>
|
||||||
|
implements $SnAccountStatusCopyWith<$Res> {
|
||||||
|
factory _$SnAccountStatusCopyWith(
|
||||||
|
_SnAccountStatus value, $Res Function(_SnAccountStatus) _then) =
|
||||||
|
__$SnAccountStatusCopyWithImpl;
|
||||||
|
@override
|
||||||
|
@useResult
|
||||||
|
$Res call(
|
||||||
|
{int id,
|
||||||
|
DateTime createdAt,
|
||||||
|
DateTime updatedAt,
|
||||||
|
DateTime? deletedAt,
|
||||||
|
String type,
|
||||||
|
String label,
|
||||||
|
int attitude,
|
||||||
|
bool isNoDisturb,
|
||||||
|
bool isInvisible,
|
||||||
|
DateTime? clearAt,
|
||||||
|
int accountId});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class __$SnAccountStatusCopyWithImpl<$Res>
|
||||||
|
implements _$SnAccountStatusCopyWith<$Res> {
|
||||||
|
__$SnAccountStatusCopyWithImpl(this._self, this._then);
|
||||||
|
|
||||||
|
final _SnAccountStatus _self;
|
||||||
|
final $Res Function(_SnAccountStatus) _then;
|
||||||
|
|
||||||
|
/// Create a copy of SnAccountStatus
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$Res call({
|
||||||
|
Object? id = null,
|
||||||
|
Object? createdAt = null,
|
||||||
|
Object? updatedAt = null,
|
||||||
|
Object? deletedAt = freezed,
|
||||||
|
Object? type = null,
|
||||||
|
Object? label = null,
|
||||||
|
Object? attitude = null,
|
||||||
|
Object? isNoDisturb = null,
|
||||||
|
Object? isInvisible = null,
|
||||||
|
Object? clearAt = freezed,
|
||||||
|
Object? accountId = null,
|
||||||
|
}) {
|
||||||
|
return _then(_SnAccountStatus(
|
||||||
|
id: null == id
|
||||||
|
? _self.id
|
||||||
|
: id // ignore: cast_nullable_to_non_nullable
|
||||||
|
as int,
|
||||||
|
createdAt: null == createdAt
|
||||||
|
? _self.createdAt
|
||||||
|
: createdAt // ignore: cast_nullable_to_non_nullable
|
||||||
|
as DateTime,
|
||||||
|
updatedAt: null == updatedAt
|
||||||
|
? _self.updatedAt
|
||||||
|
: updatedAt // ignore: cast_nullable_to_non_nullable
|
||||||
|
as DateTime,
|
||||||
|
deletedAt: freezed == deletedAt
|
||||||
|
? _self.deletedAt
|
||||||
|
: deletedAt // ignore: cast_nullable_to_non_nullable
|
||||||
|
as DateTime?,
|
||||||
|
type: null == type
|
||||||
|
? _self.type
|
||||||
|
: type // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
label: null == label
|
||||||
|
? _self.label
|
||||||
|
: label // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
attitude: null == attitude
|
||||||
|
? _self.attitude
|
||||||
|
: attitude // ignore: cast_nullable_to_non_nullable
|
||||||
|
as int,
|
||||||
|
isNoDisturb: null == isNoDisturb
|
||||||
|
? _self.isNoDisturb
|
||||||
|
: isNoDisturb // ignore: cast_nullable_to_non_nullable
|
||||||
|
as bool,
|
||||||
|
isInvisible: null == isInvisible
|
||||||
|
? _self.isInvisible
|
||||||
|
: isInvisible // ignore: cast_nullable_to_non_nullable
|
||||||
|
as bool,
|
||||||
|
clearAt: freezed == clearAt
|
||||||
|
? _self.clearAt
|
||||||
|
: clearAt // ignore: cast_nullable_to_non_nullable
|
||||||
|
as DateTime?,
|
||||||
|
accountId: null == accountId
|
||||||
|
? _self.accountId
|
||||||
|
: accountId // ignore: cast_nullable_to_non_nullable
|
||||||
|
as int,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -210,7 +210,9 @@ _SnAccountStatusInfo _$SnAccountStatusInfoFromJson(Map<String, dynamic> json) =>
|
|||||||
lastSeenAt: json['last_seen_at'] == null
|
lastSeenAt: json['last_seen_at'] == null
|
||||||
? null
|
? null
|
||||||
: DateTime.parse(json['last_seen_at'] as String),
|
: DateTime.parse(json['last_seen_at'] as String),
|
||||||
status: json['status'],
|
status: json['status'] == null
|
||||||
|
? null
|
||||||
|
: SnAccountStatus.fromJson(json['status'] as Map<String, dynamic>),
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> _$SnAccountStatusInfoToJson(
|
Map<String, dynamic> _$SnAccountStatusInfoToJson(
|
||||||
@ -219,7 +221,41 @@ Map<String, dynamic> _$SnAccountStatusInfoToJson(
|
|||||||
'is_disturbable': instance.isDisturbable,
|
'is_disturbable': instance.isDisturbable,
|
||||||
'is_online': instance.isOnline,
|
'is_online': instance.isOnline,
|
||||||
'last_seen_at': instance.lastSeenAt?.toIso8601String(),
|
'last_seen_at': instance.lastSeenAt?.toIso8601String(),
|
||||||
'status': instance.status,
|
'status': instance.status?.toJson(),
|
||||||
|
};
|
||||||
|
|
||||||
|
_SnAccountStatus _$SnAccountStatusFromJson(Map<String, dynamic> json) =>
|
||||||
|
_SnAccountStatus(
|
||||||
|
id: (json['id'] as num).toInt(),
|
||||||
|
createdAt: DateTime.parse(json['created_at'] as String),
|
||||||
|
updatedAt: DateTime.parse(json['updated_at'] as String),
|
||||||
|
deletedAt: json['deleted_at'] == null
|
||||||
|
? null
|
||||||
|
: DateTime.parse(json['deleted_at'] as String),
|
||||||
|
type: json['type'] as String,
|
||||||
|
label: json['label'] as String,
|
||||||
|
attitude: (json['attitude'] as num).toInt(),
|
||||||
|
isNoDisturb: json['is_no_disturb'] as bool,
|
||||||
|
isInvisible: json['is_invisible'] as bool,
|
||||||
|
clearAt: json['clear_at'] == null
|
||||||
|
? null
|
||||||
|
: DateTime.parse(json['clear_at'] as String),
|
||||||
|
accountId: (json['account_id'] as num).toInt(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$SnAccountStatusToJson(_SnAccountStatus instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'id': instance.id,
|
||||||
|
'created_at': instance.createdAt.toIso8601String(),
|
||||||
|
'updated_at': instance.updatedAt.toIso8601String(),
|
||||||
|
'deleted_at': instance.deletedAt?.toIso8601String(),
|
||||||
|
'type': instance.type,
|
||||||
|
'label': instance.label,
|
||||||
|
'attitude': instance.attitude,
|
||||||
|
'is_no_disturb': instance.isNoDisturb,
|
||||||
|
'is_invisible': instance.isInvisible,
|
||||||
|
'clear_at': instance.clearAt?.toIso8601String(),
|
||||||
|
'account_id': instance.accountId,
|
||||||
};
|
};
|
||||||
|
|
||||||
_SnAbuseReport _$SnAbuseReportFromJson(Map<String, dynamic> json) =>
|
_SnAbuseReport _$SnAbuseReportFromJson(Map<String, dynamic> json) =>
|
||||||
|
@ -25,11 +25,13 @@ abstract class SnCheckInRecord with _$SnCheckInRecord {
|
|||||||
required int resultTier,
|
required int resultTier,
|
||||||
required int resultExperience,
|
required int resultExperience,
|
||||||
required double resultCoin,
|
required double resultCoin,
|
||||||
|
@Default(0) int currentStreak,
|
||||||
required List<int> resultModifiers,
|
required List<int> resultModifiers,
|
||||||
required int accountId,
|
required int accountId,
|
||||||
}) = _SnCheckInRecord;
|
}) = _SnCheckInRecord;
|
||||||
|
|
||||||
factory SnCheckInRecord.fromJson(Map<String, dynamic> json) => _$SnCheckInRecordFromJson(json);
|
factory SnCheckInRecord.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$SnCheckInRecordFromJson(json);
|
||||||
|
|
||||||
String get symbol => kCheckInResultTierSymbols[resultTier];
|
String get symbol => kCheckInResultTierSymbols[resultTier];
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ mixin _$SnCheckInRecord {
|
|||||||
int get resultTier;
|
int get resultTier;
|
||||||
int get resultExperience;
|
int get resultExperience;
|
||||||
double get resultCoin;
|
double get resultCoin;
|
||||||
|
int get currentStreak;
|
||||||
List<int> get resultModifiers;
|
List<int> get resultModifiers;
|
||||||
int get accountId;
|
int get accountId;
|
||||||
|
|
||||||
@ -54,6 +55,8 @@ mixin _$SnCheckInRecord {
|
|||||||
other.resultExperience == resultExperience) &&
|
other.resultExperience == resultExperience) &&
|
||||||
(identical(other.resultCoin, resultCoin) ||
|
(identical(other.resultCoin, resultCoin) ||
|
||||||
other.resultCoin == resultCoin) &&
|
other.resultCoin == resultCoin) &&
|
||||||
|
(identical(other.currentStreak, currentStreak) ||
|
||||||
|
other.currentStreak == currentStreak) &&
|
||||||
const DeepCollectionEquality()
|
const DeepCollectionEquality()
|
||||||
.equals(other.resultModifiers, resultModifiers) &&
|
.equals(other.resultModifiers, resultModifiers) &&
|
||||||
(identical(other.accountId, accountId) ||
|
(identical(other.accountId, accountId) ||
|
||||||
@ -71,12 +74,13 @@ mixin _$SnCheckInRecord {
|
|||||||
resultTier,
|
resultTier,
|
||||||
resultExperience,
|
resultExperience,
|
||||||
resultCoin,
|
resultCoin,
|
||||||
|
currentStreak,
|
||||||
const DeepCollectionEquality().hash(resultModifiers),
|
const DeepCollectionEquality().hash(resultModifiers),
|
||||||
accountId);
|
accountId);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'SnCheckInRecord(id: $id, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, resultTier: $resultTier, resultExperience: $resultExperience, resultCoin: $resultCoin, resultModifiers: $resultModifiers, accountId: $accountId)';
|
return 'SnCheckInRecord(id: $id, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, resultTier: $resultTier, resultExperience: $resultExperience, resultCoin: $resultCoin, currentStreak: $currentStreak, resultModifiers: $resultModifiers, accountId: $accountId)';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,6 +98,7 @@ abstract mixin class $SnCheckInRecordCopyWith<$Res> {
|
|||||||
int resultTier,
|
int resultTier,
|
||||||
int resultExperience,
|
int resultExperience,
|
||||||
double resultCoin,
|
double resultCoin,
|
||||||
|
int currentStreak,
|
||||||
List<int> resultModifiers,
|
List<int> resultModifiers,
|
||||||
int accountId});
|
int accountId});
|
||||||
}
|
}
|
||||||
@ -118,6 +123,7 @@ class _$SnCheckInRecordCopyWithImpl<$Res>
|
|||||||
Object? resultTier = null,
|
Object? resultTier = null,
|
||||||
Object? resultExperience = null,
|
Object? resultExperience = null,
|
||||||
Object? resultCoin = null,
|
Object? resultCoin = null,
|
||||||
|
Object? currentStreak = null,
|
||||||
Object? resultModifiers = null,
|
Object? resultModifiers = null,
|
||||||
Object? accountId = null,
|
Object? accountId = null,
|
||||||
}) {
|
}) {
|
||||||
@ -150,6 +156,10 @@ class _$SnCheckInRecordCopyWithImpl<$Res>
|
|||||||
? _self.resultCoin
|
? _self.resultCoin
|
||||||
: resultCoin // ignore: cast_nullable_to_non_nullable
|
: resultCoin // ignore: cast_nullable_to_non_nullable
|
||||||
as double,
|
as double,
|
||||||
|
currentStreak: null == currentStreak
|
||||||
|
? _self.currentStreak
|
||||||
|
: currentStreak // ignore: cast_nullable_to_non_nullable
|
||||||
|
as int,
|
||||||
resultModifiers: null == resultModifiers
|
resultModifiers: null == resultModifiers
|
||||||
? _self.resultModifiers
|
? _self.resultModifiers
|
||||||
: resultModifiers // ignore: cast_nullable_to_non_nullable
|
: resultModifiers // ignore: cast_nullable_to_non_nullable
|
||||||
@ -173,6 +183,7 @@ class _SnCheckInRecord extends SnCheckInRecord {
|
|||||||
required this.resultTier,
|
required this.resultTier,
|
||||||
required this.resultExperience,
|
required this.resultExperience,
|
||||||
required this.resultCoin,
|
required this.resultCoin,
|
||||||
|
this.currentStreak = 0,
|
||||||
required final List<int> resultModifiers,
|
required final List<int> resultModifiers,
|
||||||
required this.accountId})
|
required this.accountId})
|
||||||
: _resultModifiers = resultModifiers,
|
: _resultModifiers = resultModifiers,
|
||||||
@ -194,6 +205,9 @@ class _SnCheckInRecord extends SnCheckInRecord {
|
|||||||
final int resultExperience;
|
final int resultExperience;
|
||||||
@override
|
@override
|
||||||
final double resultCoin;
|
final double resultCoin;
|
||||||
|
@override
|
||||||
|
@JsonKey()
|
||||||
|
final int currentStreak;
|
||||||
final List<int> _resultModifiers;
|
final List<int> _resultModifiers;
|
||||||
@override
|
@override
|
||||||
List<int> get resultModifiers {
|
List<int> get resultModifiers {
|
||||||
@ -238,6 +252,8 @@ class _SnCheckInRecord extends SnCheckInRecord {
|
|||||||
other.resultExperience == resultExperience) &&
|
other.resultExperience == resultExperience) &&
|
||||||
(identical(other.resultCoin, resultCoin) ||
|
(identical(other.resultCoin, resultCoin) ||
|
||||||
other.resultCoin == resultCoin) &&
|
other.resultCoin == resultCoin) &&
|
||||||
|
(identical(other.currentStreak, currentStreak) ||
|
||||||
|
other.currentStreak == currentStreak) &&
|
||||||
const DeepCollectionEquality()
|
const DeepCollectionEquality()
|
||||||
.equals(other._resultModifiers, _resultModifiers) &&
|
.equals(other._resultModifiers, _resultModifiers) &&
|
||||||
(identical(other.accountId, accountId) ||
|
(identical(other.accountId, accountId) ||
|
||||||
@ -255,12 +271,13 @@ class _SnCheckInRecord extends SnCheckInRecord {
|
|||||||
resultTier,
|
resultTier,
|
||||||
resultExperience,
|
resultExperience,
|
||||||
resultCoin,
|
resultCoin,
|
||||||
|
currentStreak,
|
||||||
const DeepCollectionEquality().hash(_resultModifiers),
|
const DeepCollectionEquality().hash(_resultModifiers),
|
||||||
accountId);
|
accountId);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'SnCheckInRecord(id: $id, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, resultTier: $resultTier, resultExperience: $resultExperience, resultCoin: $resultCoin, resultModifiers: $resultModifiers, accountId: $accountId)';
|
return 'SnCheckInRecord(id: $id, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, resultTier: $resultTier, resultExperience: $resultExperience, resultCoin: $resultCoin, currentStreak: $currentStreak, resultModifiers: $resultModifiers, accountId: $accountId)';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -280,6 +297,7 @@ abstract mixin class _$SnCheckInRecordCopyWith<$Res>
|
|||||||
int resultTier,
|
int resultTier,
|
||||||
int resultExperience,
|
int resultExperience,
|
||||||
double resultCoin,
|
double resultCoin,
|
||||||
|
int currentStreak,
|
||||||
List<int> resultModifiers,
|
List<int> resultModifiers,
|
||||||
int accountId});
|
int accountId});
|
||||||
}
|
}
|
||||||
@ -304,6 +322,7 @@ class __$SnCheckInRecordCopyWithImpl<$Res>
|
|||||||
Object? resultTier = null,
|
Object? resultTier = null,
|
||||||
Object? resultExperience = null,
|
Object? resultExperience = null,
|
||||||
Object? resultCoin = null,
|
Object? resultCoin = null,
|
||||||
|
Object? currentStreak = null,
|
||||||
Object? resultModifiers = null,
|
Object? resultModifiers = null,
|
||||||
Object? accountId = null,
|
Object? accountId = null,
|
||||||
}) {
|
}) {
|
||||||
@ -336,6 +355,10 @@ class __$SnCheckInRecordCopyWithImpl<$Res>
|
|||||||
? _self.resultCoin
|
? _self.resultCoin
|
||||||
: resultCoin // ignore: cast_nullable_to_non_nullable
|
: resultCoin // ignore: cast_nullable_to_non_nullable
|
||||||
as double,
|
as double,
|
||||||
|
currentStreak: null == currentStreak
|
||||||
|
? _self.currentStreak
|
||||||
|
: currentStreak // ignore: cast_nullable_to_non_nullable
|
||||||
|
as int,
|
||||||
resultModifiers: null == resultModifiers
|
resultModifiers: null == resultModifiers
|
||||||
? _self._resultModifiers
|
? _self._resultModifiers
|
||||||
: resultModifiers // ignore: cast_nullable_to_non_nullable
|
: resultModifiers // ignore: cast_nullable_to_non_nullable
|
||||||
|
@ -17,6 +17,7 @@ _SnCheckInRecord _$SnCheckInRecordFromJson(Map<String, dynamic> json) =>
|
|||||||
resultTier: (json['result_tier'] as num).toInt(),
|
resultTier: (json['result_tier'] as num).toInt(),
|
||||||
resultExperience: (json['result_experience'] as num).toInt(),
|
resultExperience: (json['result_experience'] as num).toInt(),
|
||||||
resultCoin: (json['result_coin'] as num).toDouble(),
|
resultCoin: (json['result_coin'] as num).toDouble(),
|
||||||
|
currentStreak: (json['current_streak'] as num?)?.toInt() ?? 0,
|
||||||
resultModifiers: (json['result_modifiers'] as List<dynamic>)
|
resultModifiers: (json['result_modifiers'] as List<dynamic>)
|
||||||
.map((e) => (e as num).toInt())
|
.map((e) => (e as num).toInt())
|
||||||
.toList(),
|
.toList(),
|
||||||
@ -32,6 +33,7 @@ Map<String, dynamic> _$SnCheckInRecordToJson(_SnCheckInRecord instance) =>
|
|||||||
'result_tier': instance.resultTier,
|
'result_tier': instance.resultTier,
|
||||||
'result_experience': instance.resultExperience,
|
'result_experience': instance.resultExperience,
|
||||||
'result_coin': instance.resultCoin,
|
'result_coin': instance.resultCoin,
|
||||||
|
'current_streak': instance.currentStreak,
|
||||||
'result_modifiers': instance.resultModifiers,
|
'result_modifiers': instance.resultModifiers,
|
||||||
'account_id': instance.accountId,
|
'account_id': instance.accountId,
|
||||||
};
|
};
|
||||||
|
@ -13,6 +13,7 @@ class AccountImage extends StatelessWidget {
|
|||||||
final double? borderRadius;
|
final double? borderRadius;
|
||||||
final Widget? fallbackWidget;
|
final Widget? fallbackWidget;
|
||||||
final Widget? badge;
|
final Widget? badge;
|
||||||
|
final Offset? badgeOffset;
|
||||||
|
|
||||||
const AccountImage({
|
const AccountImage({
|
||||||
super.key,
|
super.key,
|
||||||
@ -23,6 +24,7 @@ class AccountImage extends StatelessWidget {
|
|||||||
this.borderRadius,
|
this.borderRadius,
|
||||||
this.fallbackWidget,
|
this.fallbackWidget,
|
||||||
this.badge,
|
this.badge,
|
||||||
|
this.badgeOffset,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -40,7 +42,8 @@ class AccountImage extends StatelessWidget {
|
|||||||
borderRadius: BorderRadius.circular(borderRadius ?? radius ?? 20),
|
borderRadius: BorderRadius.circular(borderRadius ?? radius ?? 20),
|
||||||
child: (content?.isEmpty ?? true)
|
child: (content?.isEmpty ?? true)
|
||||||
? Container(
|
? Container(
|
||||||
color: backgroundColor ?? Theme.of(context).colorScheme.primaryContainer,
|
color: backgroundColor ??
|
||||||
|
Theme.of(context).colorScheme.primaryContainer,
|
||||||
child: (fallbackWidget ??
|
child: (fallbackWidget ??
|
||||||
Icon(
|
Icon(
|
||||||
Symbols.account_circle,
|
Symbols.account_circle,
|
||||||
@ -58,8 +61,8 @@ class AccountImage extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
if (badge != null)
|
if (badge != null)
|
||||||
Positioned(
|
Positioned(
|
||||||
right: -4,
|
right: badgeOffset?.dx ?? -4,
|
||||||
bottom: -2,
|
bottom: badgeOffset?.dy ?? -2,
|
||||||
child: badge!,
|
child: badge!,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -8,9 +8,9 @@ import 'package:relative_time/relative_time.dart';
|
|||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
import 'package:surface/providers/experience.dart';
|
import 'package:surface/providers/experience.dart';
|
||||||
import 'package:surface/providers/sn_network.dart';
|
import 'package:surface/providers/sn_network.dart';
|
||||||
import 'package:surface/screens/account/profile_page.dart';
|
|
||||||
import 'package:surface/types/account.dart';
|
import 'package:surface/types/account.dart';
|
||||||
import 'package:surface/widgets/account/account_image.dart';
|
import 'package:surface/widgets/account/account_image.dart';
|
||||||
|
import 'package:surface/widgets/account/badge.dart';
|
||||||
import 'package:surface/widgets/universal_image.dart';
|
import 'package:surface/widgets/universal_image.dart';
|
||||||
|
|
||||||
class AccountPopoverCard extends StatelessWidget {
|
class AccountPopoverCard extends StatelessWidget {
|
||||||
@ -72,37 +72,21 @@ class AccountPopoverCard extends StatelessWidget {
|
|||||||
const Gap(8)
|
const Gap(8)
|
||||||
],
|
],
|
||||||
).padding(horizontal: 16),
|
).padding(horizontal: 16),
|
||||||
if (data.badges.isNotEmpty) const Gap(12),
|
|
||||||
if (data.badges.isNotEmpty)
|
if (data.badges.isNotEmpty)
|
||||||
Wrap(
|
Wrap(
|
||||||
spacing: 4,
|
spacing: 4,
|
||||||
children: data.badges
|
children: data.badges
|
||||||
.map(
|
.map(
|
||||||
(ele) => Tooltip(
|
(ele) => AccountBadge(badge: ele),
|
||||||
richMessage: TextSpan(
|
|
||||||
children: [
|
|
||||||
TextSpan(text: kBadgesMeta[ele.type]?.$1.tr() ?? 'unknown'.tr()),
|
|
||||||
if (ele.metadata['title'] != null)
|
|
||||||
TextSpan(
|
|
||||||
text: '\n${ele.metadata['title']}',
|
|
||||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
|
||||||
),
|
|
||||||
TextSpan(text: '\n'),
|
|
||||||
TextSpan(
|
|
||||||
text: DateFormat.yMEd().format(ele.createdAt),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
child: Icon(
|
|
||||||
kBadgesMeta[ele.type]?.$2 ?? Symbols.question_mark,
|
|
||||||
color: kBadgesMeta[ele.type]?.$3,
|
|
||||||
fill: 1,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.toList(),
|
.toList(),
|
||||||
).padding(horizontal: 24),
|
).padding(horizontal: 24, bottom: 12, top: 12),
|
||||||
const Gap(8),
|
if (data.profile?.description.isNotEmpty ?? false)
|
||||||
|
Text(
|
||||||
|
data.profile?.description ?? '',
|
||||||
|
maxLines: 2,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
).padding(horizontal: 26, bottom: 8),
|
||||||
Row(
|
Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
@ -110,7 +94,9 @@ class AccountPopoverCard extends StatelessWidget {
|
|||||||
const Gap(8),
|
const Gap(8),
|
||||||
Text('Lv${getLevelFromExp(data.profile?.experience ?? 0)}'),
|
Text('Lv${getLevelFromExp(data.profile?.experience ?? 0)}'),
|
||||||
const Gap(8),
|
const Gap(8),
|
||||||
Text(calcLevelUpProgressLevel(data.profile?.experience ?? 0)).fontSize(11).opacity(0.5),
|
Text(calcLevelUpProgressLevel(data.profile?.experience ?? 0))
|
||||||
|
.fontSize(11)
|
||||||
|
.opacity(0.5),
|
||||||
const Gap(8),
|
const Gap(8),
|
||||||
Container(
|
Container(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
@ -126,25 +112,36 @@ class AccountPopoverCard extends StatelessWidget {
|
|||||||
FutureBuilder(
|
FutureBuilder(
|
||||||
future: sn.client.get('/cgi/id/users/${data.name}/status'),
|
future: sn.client.get('/cgi/id/users/${data.name}/status'),
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
final SnAccountStatusInfo? status =
|
final SnAccountStatusInfo? status = snapshot.hasData
|
||||||
snapshot.hasData ? SnAccountStatusInfo.fromJson(snapshot.data!.data) : null;
|
? SnAccountStatusInfo.fromJson(snapshot.data!.data)
|
||||||
|
: null;
|
||||||
return Row(
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
Icon(
|
Icon(
|
||||||
Symbols.circle,
|
(status?.isDisturbable ?? true)
|
||||||
fill: 1,
|
? Symbols.circle
|
||||||
|
: Symbols.do_not_disturb_on,
|
||||||
|
fill: (status?.isOnline ?? false) ? 1 : 0,
|
||||||
size: 16,
|
size: 16,
|
||||||
color: (status?.isOnline ?? false) ? Colors.green : Colors.grey,
|
color: (status?.isOnline ?? false)
|
||||||
|
? (status?.isDisturbable ?? true)
|
||||||
|
? Colors.green
|
||||||
|
: Colors.red
|
||||||
|
: Colors.grey,
|
||||||
).padding(all: 4),
|
).padding(all: 4),
|
||||||
const Gap(8),
|
const Gap(8),
|
||||||
Text(
|
Text(
|
||||||
status != null
|
status != null
|
||||||
? status.isOnline
|
? (status.status?.label.isNotEmpty ?? false)
|
||||||
? 'accountStatusOnline'.tr()
|
? status.status!.label
|
||||||
: 'accountStatusOffline'.tr()
|
: status.isOnline
|
||||||
|
? 'accountStatusOnline'.tr()
|
||||||
|
: 'accountStatusOffline'.tr()
|
||||||
: 'loading'.tr(),
|
: 'loading'.tr(),
|
||||||
),
|
),
|
||||||
if (status != null && !status.isOnline && status.lastSeenAt != null)
|
if (status != null &&
|
||||||
|
!status.isOnline &&
|
||||||
|
status.lastSeenAt != null)
|
||||||
Text(
|
Text(
|
||||||
'accountStatusLastSeen'.tr(args: [
|
'accountStatusLastSeen'.tr(args: [
|
||||||
status.lastSeenAt != null
|
status.lastSeenAt != null
|
||||||
|
391
lib/widgets/account/account_status.dart
Normal file
391
lib/widgets/account/account_status.dart
Normal file
@ -0,0 +1,391 @@
|
|||||||
|
import 'package:dio/dio.dart';
|
||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:gap/gap.dart';
|
||||||
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
|
import 'package:surface/providers/sn_network.dart';
|
||||||
|
import 'package:surface/types/account.dart';
|
||||||
|
import 'package:surface/widgets/dialog.dart';
|
||||||
|
import 'package:surface/widgets/loading_indicator.dart';
|
||||||
|
|
||||||
|
final Map<String, (Widget, String, String?)> kPresetStatus = {
|
||||||
|
'online': (
|
||||||
|
const Icon(Symbols.circle, color: Colors.green, fill: 1),
|
||||||
|
'accountStatusOnline'.tr(),
|
||||||
|
null,
|
||||||
|
),
|
||||||
|
'silent': (
|
||||||
|
const Icon(Symbols.do_not_disturb_on, color: Colors.red),
|
||||||
|
'accountStatusSilent'.tr(),
|
||||||
|
'accountStatusSilentDesc'.tr(),
|
||||||
|
),
|
||||||
|
'invisible': (
|
||||||
|
const Icon(Symbols.circle, color: Colors.grey),
|
||||||
|
'accountStatusInvisible'.tr(),
|
||||||
|
'accountStatusInvisibleDesc'.tr(),
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
class AccountStatusActionPopup extends StatefulWidget {
|
||||||
|
final SnAccountStatusInfo? currentStatus;
|
||||||
|
const AccountStatusActionPopup({super.key, this.currentStatus});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<AccountStatusActionPopup> createState() =>
|
||||||
|
_AccountStatusActionPopupState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _AccountStatusActionPopupState extends State<AccountStatusActionPopup> {
|
||||||
|
bool _isBusy = false;
|
||||||
|
|
||||||
|
Future<void> setStatus(
|
||||||
|
String type,
|
||||||
|
String? label,
|
||||||
|
int attitude, {
|
||||||
|
bool isUpdate = false,
|
||||||
|
bool isSilent = false,
|
||||||
|
bool isInvisible = false,
|
||||||
|
DateTime? clearAt,
|
||||||
|
}) async {
|
||||||
|
setState(() => _isBusy = true);
|
||||||
|
final sn = context.read<SnNetworkProvider>();
|
||||||
|
|
||||||
|
final payload = {
|
||||||
|
'type': type,
|
||||||
|
'label': label,
|
||||||
|
'attitude': attitude,
|
||||||
|
'is_no_disturb': isSilent,
|
||||||
|
'is_invisible': isInvisible,
|
||||||
|
'clear_at': clearAt?.toUtc().toIso8601String()
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
await sn.client.request(
|
||||||
|
'/cgi/id/users/me/status',
|
||||||
|
data: payload,
|
||||||
|
options: Options(method: isUpdate ? 'PUT' : 'POST'),
|
||||||
|
);
|
||||||
|
if (!mounted) return;
|
||||||
|
Navigator.pop(context, true);
|
||||||
|
} catch (err) {
|
||||||
|
if (!mounted) return;
|
||||||
|
context.showErrorDialog(err);
|
||||||
|
} finally {
|
||||||
|
setState(() => _isBusy = false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _clearStatus() async {
|
||||||
|
if (_isBusy) return;
|
||||||
|
|
||||||
|
setState(() => _isBusy = true);
|
||||||
|
try {
|
||||||
|
final sn = context.read<SnNetworkProvider>();
|
||||||
|
await sn.client.delete('/cgi/id/users/me/status');
|
||||||
|
if (!mounted) return;
|
||||||
|
Navigator.of(context).pop(true);
|
||||||
|
} catch (err) {
|
||||||
|
if (!mounted) return;
|
||||||
|
context.showErrorDialog(err);
|
||||||
|
} finally {
|
||||||
|
setState(() => _isBusy = false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
const Icon(Symbols.mood, size: 24),
|
||||||
|
const Gap(16),
|
||||||
|
Text('accountChangeStatus',
|
||||||
|
style: Theme.of(context).textTheme.titleLarge)
|
||||||
|
.tr(),
|
||||||
|
],
|
||||||
|
).padding(horizontal: 20, top: 16, bottom: 12),
|
||||||
|
LoadingIndicator(isActive: _isBusy),
|
||||||
|
SizedBox(
|
||||||
|
height: 48,
|
||||||
|
child: ListView(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 18),
|
||||||
|
scrollDirection: Axis.horizontal,
|
||||||
|
children: kPresetStatus.entries
|
||||||
|
.map(
|
||||||
|
(x) => StyledWidget(ActionChip(
|
||||||
|
avatar: x.value.$1,
|
||||||
|
label: Text(x.value.$2),
|
||||||
|
tooltip: x.value.$3,
|
||||||
|
onPressed: _isBusy
|
||||||
|
? null
|
||||||
|
: () {
|
||||||
|
setStatus(
|
||||||
|
x.key,
|
||||||
|
x.value.$2,
|
||||||
|
0,
|
||||||
|
isInvisible: x.key == 'invisible',
|
||||||
|
isSilent: x.key == 'silent',
|
||||||
|
);
|
||||||
|
},
|
||||||
|
)).padding(right: 6),
|
||||||
|
)
|
||||||
|
.toList(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Gap(16),
|
||||||
|
const Divider(thickness: 0.3, height: 0.3),
|
||||||
|
ListTile(
|
||||||
|
contentPadding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
|
leading: widget.currentStatus != null
|
||||||
|
? const Icon(Icons.edit)
|
||||||
|
: const Icon(Icons.add),
|
||||||
|
title: Text('accountCustomStatus').tr(),
|
||||||
|
subtitle: Text('accountCustomStatusDescription').tr(),
|
||||||
|
onTap: _isBusy
|
||||||
|
? null
|
||||||
|
: () async {
|
||||||
|
final val = await showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => _AccountStatusEditorDialog(
|
||||||
|
currentStatus: widget.currentStatus,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
if (val == true && context.mounted) {
|
||||||
|
Navigator.of(context).pop(true);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
if (widget.currentStatus != null)
|
||||||
|
ListTile(
|
||||||
|
contentPadding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
|
leading: const Icon(Icons.clear),
|
||||||
|
title: Text('accountClearStatus').tr(),
|
||||||
|
subtitle: Text('accountClearStatusDescription').tr(),
|
||||||
|
onTap: _isBusy
|
||||||
|
? null
|
||||||
|
: () {
|
||||||
|
_clearStatus();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _AccountStatusEditorDialog extends StatefulWidget {
|
||||||
|
final SnAccountStatusInfo? currentStatus;
|
||||||
|
const _AccountStatusEditorDialog({this.currentStatus});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<_AccountStatusEditorDialog> createState() =>
|
||||||
|
_AccountStatusEditorDialogState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _AccountStatusEditorDialogState
|
||||||
|
extends State<_AccountStatusEditorDialog> {
|
||||||
|
bool _isBusy = false;
|
||||||
|
|
||||||
|
final TextEditingController _labelController = TextEditingController();
|
||||||
|
final TextEditingController _clearAtController = TextEditingController();
|
||||||
|
|
||||||
|
int _attitude = 0;
|
||||||
|
bool _isSilent = false;
|
||||||
|
bool _isInvisible = false;
|
||||||
|
DateTime? _clearAt;
|
||||||
|
|
||||||
|
Future<void> _selectClearAt() async {
|
||||||
|
final DateTime? pickedDate = await showDatePicker(
|
||||||
|
context: context,
|
||||||
|
initialDate: _clearAt?.toLocal() ?? DateTime.now(),
|
||||||
|
firstDate: DateTime.now(),
|
||||||
|
lastDate: DateTime.now().add(const Duration(days: 365)),
|
||||||
|
);
|
||||||
|
if (pickedDate == null) return;
|
||||||
|
if (!mounted) return;
|
||||||
|
final TimeOfDay? pickedTime = await showTimePicker(
|
||||||
|
context: context,
|
||||||
|
initialTime: TimeOfDay.now(),
|
||||||
|
);
|
||||||
|
if (pickedTime == null) return;
|
||||||
|
if (!mounted) return;
|
||||||
|
final picked = pickedDate.copyWith(
|
||||||
|
hour: pickedTime.hour,
|
||||||
|
minute: pickedTime.minute,
|
||||||
|
);
|
||||||
|
setState(() {
|
||||||
|
_clearAt = picked;
|
||||||
|
_clearAtController.text = DateFormat('y/M/d HH:mm').format(_clearAt!);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _applyStatus() async {
|
||||||
|
if (_isBusy) return;
|
||||||
|
|
||||||
|
setState(() => _isBusy = true);
|
||||||
|
try {
|
||||||
|
final sn = context.read<SnNetworkProvider>();
|
||||||
|
await sn.client.request(
|
||||||
|
'/cgi/id/users/me/status',
|
||||||
|
data: {
|
||||||
|
'type': 'custom',
|
||||||
|
'label': _labelController.text,
|
||||||
|
'attitude': _attitude,
|
||||||
|
'is_no_disturb': _isSilent,
|
||||||
|
'is_invisible': _isInvisible,
|
||||||
|
'clear_at': _clearAt?.toUtc().toIso8601String(),
|
||||||
|
},
|
||||||
|
options: Options(
|
||||||
|
method: widget.currentStatus?.status != null ? 'PUT' : 'POST',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
if (!mounted) return;
|
||||||
|
Navigator.of(context).pop(true);
|
||||||
|
} catch (err) {
|
||||||
|
if (!mounted) return;
|
||||||
|
context.showErrorDialog(err);
|
||||||
|
} finally {
|
||||||
|
setState(() => _isBusy = false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _syncWidget() {
|
||||||
|
if (widget.currentStatus?.status != null) {
|
||||||
|
_clearAt = widget.currentStatus!.status!.clearAt;
|
||||||
|
if (_clearAt != null) {
|
||||||
|
_clearAtController.text = DateFormat('y/M/d HH:mm').format(_clearAt!);
|
||||||
|
}
|
||||||
|
|
||||||
|
_labelController.text = widget.currentStatus!.status!.label;
|
||||||
|
_attitude = widget.currentStatus!.status!.attitude;
|
||||||
|
_isInvisible = widget.currentStatus!.status!.isInvisible;
|
||||||
|
_isSilent = widget.currentStatus!.status!.isNoDisturb;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
_syncWidget();
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return AlertDialog(
|
||||||
|
title: Text('accountCustomStatus').tr(),
|
||||||
|
content: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
LoadingIndicator(isActive: _isBusy),
|
||||||
|
TextField(
|
||||||
|
controller: _labelController,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
isDense: true,
|
||||||
|
prefixIcon: const Icon(Icons.label),
|
||||||
|
border: const OutlineInputBorder(),
|
||||||
|
labelText: 'fieldAccountStatusLabel'.tr(),
|
||||||
|
),
|
||||||
|
onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(),
|
||||||
|
),
|
||||||
|
const Gap(8),
|
||||||
|
TextField(
|
||||||
|
controller: _clearAtController,
|
||||||
|
readOnly: true,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
isDense: true,
|
||||||
|
prefixIcon: const Icon(Icons.event_busy),
|
||||||
|
border: const OutlineInputBorder(),
|
||||||
|
labelText: 'fieldAccountStatusClearAt'.tr(),
|
||||||
|
),
|
||||||
|
onTap: () => _selectClearAt(),
|
||||||
|
),
|
||||||
|
const Gap(8),
|
||||||
|
SingleChildScrollView(
|
||||||
|
scrollDirection: Axis.horizontal,
|
||||||
|
child: Wrap(
|
||||||
|
spacing: 6,
|
||||||
|
runSpacing: 0,
|
||||||
|
children: [
|
||||||
|
ChoiceChip(
|
||||||
|
avatar: Icon(
|
||||||
|
Symbols.radio_button_unchecked,
|
||||||
|
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
|
),
|
||||||
|
selected: _attitude == 2,
|
||||||
|
label: Text('accountStatusNegative'.tr()),
|
||||||
|
onSelected: (val) {
|
||||||
|
if (val) setState(() => _attitude = 2);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
ChoiceChip(
|
||||||
|
avatar: Icon(
|
||||||
|
Symbols.contrast,
|
||||||
|
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
|
),
|
||||||
|
selected: _attitude == 0,
|
||||||
|
label: Text('accountStatusNeutral'.tr()),
|
||||||
|
onSelected: (val) {
|
||||||
|
if (val) setState(() => _attitude = 0);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
ChoiceChip(
|
||||||
|
avatar: Icon(
|
||||||
|
Symbols.circle,
|
||||||
|
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
|
),
|
||||||
|
selected: _attitude == 1,
|
||||||
|
label: Text('accountStatusPositive'.tr()),
|
||||||
|
onSelected: (val) {
|
||||||
|
if (val) setState(() => _attitude = 1);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Gap(4),
|
||||||
|
SingleChildScrollView(
|
||||||
|
scrollDirection: Axis.horizontal,
|
||||||
|
child: Wrap(
|
||||||
|
spacing: 6,
|
||||||
|
runSpacing: 0,
|
||||||
|
children: [
|
||||||
|
ChoiceChip(
|
||||||
|
selected: _isSilent,
|
||||||
|
label: Text('accountStatusSilent').tr(),
|
||||||
|
onSelected: (val) {
|
||||||
|
setState(() => _isSilent = val);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
ChoiceChip(
|
||||||
|
selected: _isInvisible,
|
||||||
|
label: Text('accountStatusInvisible').tr(),
|
||||||
|
onSelected: (val) {
|
||||||
|
setState(() => _isInvisible = val);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
actions: <Widget>[
|
||||||
|
TextButton(
|
||||||
|
style: TextButton.styleFrom(
|
||||||
|
foregroundColor:
|
||||||
|
Theme.of(context).colorScheme.onSurface.withOpacity(0.8),
|
||||||
|
),
|
||||||
|
onPressed: _isBusy ? null : () => Navigator.pop(context),
|
||||||
|
child: Text('dialogCancel').tr(),
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
onPressed: _isBusy ? null : () => _applyStatus(),
|
||||||
|
child: Text('dialogConfirm').tr(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
50
lib/widgets/account/badge.dart
Normal file
50
lib/widgets/account/badge.dart
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
|
import 'package:surface/screens/account/profile_page.dart' show kBadgesMeta;
|
||||||
|
import 'package:surface/types/account.dart';
|
||||||
|
|
||||||
|
class AccountBadge extends StatelessWidget {
|
||||||
|
final SnAccountBadge badge;
|
||||||
|
final double radius;
|
||||||
|
final EdgeInsets? padding;
|
||||||
|
const AccountBadge({
|
||||||
|
super.key,
|
||||||
|
required this.badge,
|
||||||
|
this.radius = 20,
|
||||||
|
this.padding,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Tooltip(
|
||||||
|
richMessage: TextSpan(
|
||||||
|
children: [
|
||||||
|
TextSpan(text: kBadgesMeta[badge.type]?.$1.tr() ?? 'unknown'.tr()),
|
||||||
|
if (badge.metadata['title'] != null)
|
||||||
|
TextSpan(
|
||||||
|
text: '\n${badge.metadata['title']}',
|
||||||
|
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
TextSpan(text: '\n'),
|
||||||
|
TextSpan(
|
||||||
|
text: DateFormat.yMEd().format(badge.createdAt),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: Container(
|
||||||
|
padding: padding ?? EdgeInsets.all(3),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(radius),
|
||||||
|
color: kBadgesMeta[badge.type]?.$3,
|
||||||
|
),
|
||||||
|
child: Icon(
|
||||||
|
kBadgesMeta[badge.type]?.$2 ?? Symbols.question_mark,
|
||||||
|
color: Colors.white,
|
||||||
|
fill: 1,
|
||||||
|
size: radius - 4,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -22,12 +22,14 @@ class AttachmentItem extends StatelessWidget {
|
|||||||
final SnAttachment? data;
|
final SnAttachment? data;
|
||||||
final String? heroTag;
|
final String? heroTag;
|
||||||
final BoxFit fit;
|
final BoxFit fit;
|
||||||
|
final FilterQuality? filterQuality;
|
||||||
|
|
||||||
const AttachmentItem({
|
const AttachmentItem({
|
||||||
super.key,
|
super.key,
|
||||||
this.fit = BoxFit.cover,
|
this.fit = BoxFit.cover,
|
||||||
required this.data,
|
required this.data,
|
||||||
required this.heroTag,
|
required this.heroTag,
|
||||||
|
this.filterQuality,
|
||||||
});
|
});
|
||||||
|
|
||||||
Widget _buildContent(BuildContext context) {
|
Widget _buildContent(BuildContext context) {
|
||||||
@ -47,6 +49,7 @@ class AttachmentItem extends StatelessWidget {
|
|||||||
sn.getAttachmentUrl(data!.rid),
|
sn.getAttachmentUrl(data!.rid),
|
||||||
key: Key('attachment-${data!.rid}-$tag'),
|
key: Key('attachment-${data!.rid}-$tag'),
|
||||||
fit: fit,
|
fit: fit,
|
||||||
|
filterQuality: filterQuality,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
case 'video':
|
case 'video':
|
||||||
@ -83,13 +86,16 @@ class _AttachmentItemSensitiveBlur extends StatefulWidget {
|
|||||||
final Widget child;
|
final Widget child;
|
||||||
final bool isCompact;
|
final bool isCompact;
|
||||||
|
|
||||||
const _AttachmentItemSensitiveBlur({required this.child, this.isCompact = false});
|
const _AttachmentItemSensitiveBlur(
|
||||||
|
{required this.child, this.isCompact = false});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<_AttachmentItemSensitiveBlur> createState() => _AttachmentItemSensitiveBlurState();
|
State<_AttachmentItemSensitiveBlur> createState() =>
|
||||||
|
_AttachmentItemSensitiveBlurState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _AttachmentItemSensitiveBlurState extends State<_AttachmentItemSensitiveBlur> {
|
class _AttachmentItemSensitiveBlurState
|
||||||
|
extends State<_AttachmentItemSensitiveBlur> {
|
||||||
bool _doesShow = false;
|
bool _doesShow = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -124,10 +130,15 @@ class _AttachmentItemSensitiveBlurState extends State<_AttachmentItemSensitiveBl
|
|||||||
Text(
|
Text(
|
||||||
'sensitiveContentDescription',
|
'sensitiveContentDescription',
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
).tr().fontSize(14).textColor(Colors.white.withOpacity(0.8)),
|
)
|
||||||
|
.tr()
|
||||||
|
.fontSize(14)
|
||||||
|
.textColor(Colors.white.withOpacity(0.8)),
|
||||||
if (!widget.isCompact) const Gap(16),
|
if (!widget.isCompact) const Gap(16),
|
||||||
InkWell(
|
InkWell(
|
||||||
child: Text('sensitiveContentReveal').tr().textColor(Colors.white),
|
child: Text('sensitiveContentReveal')
|
||||||
|
.tr()
|
||||||
|
.textColor(Colors.white),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
setState(() => _doesShow = !_doesShow);
|
setState(() => _doesShow = !_doesShow);
|
||||||
},
|
},
|
||||||
@ -137,7 +148,9 @@ class _AttachmentItemSensitiveBlurState extends State<_AttachmentItemSensitiveBl
|
|||||||
).center(),
|
).center(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
).opacity(_doesShow ? 0 : 1, animate: true).animate(const Duration(milliseconds: 300), Curves.easeInOut),
|
)
|
||||||
|
.opacity(_doesShow ? 0 : 1, animate: true)
|
||||||
|
.animate(const Duration(milliseconds: 300), Curves.easeInOut),
|
||||||
if (_doesShow)
|
if (_doesShow)
|
||||||
Positioned(
|
Positioned(
|
||||||
top: 0,
|
top: 0,
|
||||||
@ -174,10 +187,12 @@ class _AttachmentItemContentVideo extends StatefulWidget {
|
|||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<_AttachmentItemContentVideo> createState() => _AttachmentItemContentVideoState();
|
State<_AttachmentItemContentVideo> createState() =>
|
||||||
|
_AttachmentItemContentVideoState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _AttachmentItemContentVideoState extends State<_AttachmentItemContentVideo> {
|
class _AttachmentItemContentVideoState
|
||||||
|
extends State<_AttachmentItemContentVideo> {
|
||||||
bool _showContent = false;
|
bool _showContent = false;
|
||||||
bool _showOriginal = false;
|
bool _showOriginal = false;
|
||||||
|
|
||||||
@ -188,7 +203,9 @@ class _AttachmentItemContentVideoState extends State<_AttachmentItemContentVideo
|
|||||||
setState(() => _showContent = true);
|
setState(() => _showContent = true);
|
||||||
MediaKit.ensureInitialized();
|
MediaKit.ensureInitialized();
|
||||||
final sn = context.read<SnNetworkProvider>();
|
final sn = context.read<SnNetworkProvider>();
|
||||||
final url = _showOriginal ? sn.getAttachmentUrl(widget.data.rid) : sn.getAttachmentUrl(widget.data.compressed!.rid);
|
final url = _showOriginal
|
||||||
|
? sn.getAttachmentUrl(widget.data.rid)
|
||||||
|
: sn.getAttachmentUrl(widget.data.compressed!.rid);
|
||||||
_videoPlayer = Player();
|
_videoPlayer = Player();
|
||||||
_videoController = VideoController(_videoPlayer!);
|
_videoController = VideoController(_videoPlayer!);
|
||||||
_videoPlayer!.open(Media(url), play: !widget.isAutoload);
|
_videoPlayer!.open(Media(url), play: !widget.isAutoload);
|
||||||
@ -201,7 +218,9 @@ class _AttachmentItemContentVideoState extends State<_AttachmentItemContentVideo
|
|||||||
final sn = context.read<SnNetworkProvider>();
|
final sn = context.read<SnNetworkProvider>();
|
||||||
_videoPlayer?.open(
|
_videoPlayer?.open(
|
||||||
Media(
|
Media(
|
||||||
_showOriginal ? sn.getAttachmentUrl(widget.data.rid) : sn.getAttachmentUrl(widget.data.compressed!.rid),
|
_showOriginal
|
||||||
|
? sn.getAttachmentUrl(widget.data.rid)
|
||||||
|
: sn.getAttachmentUrl(widget.data.compressed!.rid),
|
||||||
),
|
),
|
||||||
play: true,
|
play: true,
|
||||||
);
|
);
|
||||||
@ -283,7 +302,9 @@ class _AttachmentItemContentVideoState extends State<_AttachmentItemContentVideo
|
|||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
Duration(
|
Duration(
|
||||||
milliseconds: (widget.data.data['duration'] ?? 0).toInt() * 1000,
|
milliseconds:
|
||||||
|
(widget.data.data['duration'] ?? 0).toInt() *
|
||||||
|
1000,
|
||||||
).toString(),
|
).toString(),
|
||||||
style: GoogleFonts.robotoMono(
|
style: GoogleFonts.robotoMono(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
@ -346,7 +367,9 @@ class _AttachmentItemContentVideoState extends State<_AttachmentItemContentVideo
|
|||||||
MaterialDesktopCustomButton(
|
MaterialDesktopCustomButton(
|
||||||
iconSize: 24,
|
iconSize: 24,
|
||||||
onPressed: _toggleOriginal,
|
onPressed: _toggleOriginal,
|
||||||
icon: _showOriginal ? const Icon(Symbols.high_quality, size: 24) : const Icon(Symbols.sd, size: 24),
|
icon: _showOriginal
|
||||||
|
? const Icon(Symbols.high_quality, size: 24)
|
||||||
|
: const Icon(Symbols.sd, size: 24),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -354,8 +377,9 @@ class _AttachmentItemContentVideoState extends State<_AttachmentItemContentVideo
|
|||||||
child: Video(
|
child: Video(
|
||||||
controller: _videoController!,
|
controller: _videoController!,
|
||||||
aspectRatio: ratio,
|
aspectRatio: ratio,
|
||||||
controls:
|
controls: !kIsWeb && (Platform.isAndroid || Platform.isIOS)
|
||||||
!kIsWeb && (Platform.isAndroid || Platform.isIOS) ? MaterialVideoControls : MaterialDesktopVideoControls,
|
? MaterialVideoControls
|
||||||
|
: MaterialDesktopVideoControls,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -378,10 +402,12 @@ class _AttachmentItemContentAudio extends StatefulWidget {
|
|||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<_AttachmentItemContentAudio> createState() => _AttachmentItemContentAudioState();
|
State<_AttachmentItemContentAudio> createState() =>
|
||||||
|
_AttachmentItemContentAudioState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _AttachmentItemContentAudioState extends State<_AttachmentItemContentAudio> {
|
class _AttachmentItemContentAudioState
|
||||||
|
extends State<_AttachmentItemContentAudio> {
|
||||||
bool _showContent = false;
|
bool _showContent = false;
|
||||||
|
|
||||||
double? _draggingValue;
|
double? _draggingValue;
|
||||||
@ -552,8 +578,12 @@ class _AttachmentItemContentAudioState extends State<_AttachmentItemContentAudio
|
|||||||
overlayShape: SliderComponentShape.noOverlay,
|
overlayShape: SliderComponentShape.noOverlay,
|
||||||
),
|
),
|
||||||
child: Slider(
|
child: Slider(
|
||||||
secondaryTrackValue: _bufferedPosition.inMilliseconds.abs().toDouble(),
|
secondaryTrackValue: _bufferedPosition
|
||||||
value: _draggingValue?.abs() ?? _position.inMilliseconds.toDouble().abs(),
|
.inMilliseconds
|
||||||
|
.abs()
|
||||||
|
.toDouble(),
|
||||||
|
value: _draggingValue?.abs() ??
|
||||||
|
_position.inMilliseconds.toDouble().abs(),
|
||||||
min: 0,
|
min: 0,
|
||||||
max: math
|
max: math
|
||||||
.max(
|
.max(
|
||||||
@ -593,7 +623,9 @@ class _AttachmentItemContentAudioState extends State<_AttachmentItemContentAudio
|
|||||||
),
|
),
|
||||||
const Gap(16),
|
const Gap(16),
|
||||||
IconButton.filled(
|
IconButton.filled(
|
||||||
icon: _isPlaying ? const Icon(Symbols.pause) : const Icon(Symbols.play_arrow),
|
icon: _isPlaying
|
||||||
|
? const Icon(Symbols.pause)
|
||||||
|
: const Icon(Symbols.play_arrow),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
_audioPlayer!.playOrPause();
|
_audioPlayer!.playOrPause();
|
||||||
},
|
},
|
||||||
|
@ -21,6 +21,7 @@ class AttachmentList extends StatefulWidget {
|
|||||||
final double? minWidth;
|
final double? minWidth;
|
||||||
final double? maxWidth;
|
final double? maxWidth;
|
||||||
final EdgeInsets? padding;
|
final EdgeInsets? padding;
|
||||||
|
final FilterQuality? filterQuality;
|
||||||
|
|
||||||
const AttachmentList({
|
const AttachmentList({
|
||||||
super.key,
|
super.key,
|
||||||
@ -33,23 +34,27 @@ class AttachmentList extends StatefulWidget {
|
|||||||
this.minWidth,
|
this.minWidth,
|
||||||
this.maxWidth,
|
this.maxWidth,
|
||||||
this.padding,
|
this.padding,
|
||||||
|
this.filterQuality,
|
||||||
});
|
});
|
||||||
|
|
||||||
static const BorderRadius kDefaultRadius = BorderRadius.all(Radius.circular(8));
|
static const BorderRadius kDefaultRadius =
|
||||||
|
BorderRadius.all(Radius.circular(8));
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<AttachmentList> createState() => _AttachmentListState();
|
State<AttachmentList> createState() => _AttachmentListState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _AttachmentListState extends State<AttachmentList> {
|
class _AttachmentListState extends State<AttachmentList> {
|
||||||
late final List<String> heroTags = List.generate(widget.data.length, (_) => const Uuid().v4());
|
late final List<String> heroTags =
|
||||||
|
List.generate(widget.data.length, (_) => const Uuid().v4());
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return LayoutBuilder(
|
return LayoutBuilder(
|
||||||
builder: (context, layoutConstraints) {
|
builder: (context, layoutConstraints) {
|
||||||
final borderSide =
|
final borderSide = widget.bordered
|
||||||
widget.bordered ? BorderSide(width: 1, color: Theme.of(context).dividerColor) : BorderSide.none;
|
? BorderSide(width: 1, color: Theme.of(context).dividerColor)
|
||||||
|
: BorderSide.none;
|
||||||
final backgroundColor = Theme.of(context).colorScheme.surfaceContainer;
|
final backgroundColor = Theme.of(context).colorScheme.surfaceContainer;
|
||||||
final constraints = BoxConstraints(
|
final constraints = BoxConstraints(
|
||||||
minWidth: widget.minWidth ?? 80,
|
minWidth: widget.minWidth ?? 80,
|
||||||
@ -58,13 +63,13 @@ class _AttachmentListState extends State<AttachmentList> {
|
|||||||
|
|
||||||
if (widget.data.isEmpty) return const SizedBox.shrink();
|
if (widget.data.isEmpty) return const SizedBox.shrink();
|
||||||
if (widget.data.length == 1) {
|
if (widget.data.length == 1) {
|
||||||
final singleAspectRatio =
|
final singleAspectRatio = widget.data[0]?.data['ratio']?.toDouble() ??
|
||||||
widget.data[0]?.data['ratio']?.toDouble() ??
|
|
||||||
switch (widget.data[0]?.mimetype.split('/').firstOrNull) {
|
switch (widget.data[0]?.mimetype.split('/').firstOrNull) {
|
||||||
'audio' => 16 / 9,
|
'audio' => 16 / 9,
|
||||||
'video' => 16 / 9,
|
'video' => 16 / 9,
|
||||||
_ => 1,
|
_ => 1,
|
||||||
}.toDouble();
|
}
|
||||||
|
.toDouble();
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
padding: widget.padding ?? EdgeInsets.zero,
|
padding: widget.padding ?? EdgeInsets.zero,
|
||||||
@ -80,12 +85,18 @@ class _AttachmentListState extends State<AttachmentList> {
|
|||||||
),
|
),
|
||||||
child: ClipRRect(
|
child: ClipRRect(
|
||||||
borderRadius: AttachmentList.kDefaultRadius,
|
borderRadius: AttachmentList.kDefaultRadius,
|
||||||
child: AttachmentItem(data: widget.data[0], heroTag: heroTags[0], fit: widget.fit),
|
child: AttachmentItem(
|
||||||
|
data: widget.data[0],
|
||||||
|
heroTag: heroTags[0],
|
||||||
|
fit: widget.fit,
|
||||||
|
filterQuality: widget.filterQuality,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (widget.data.firstOrNull?.mediaType != SnMediaType.image) return;
|
if (widget.data.firstOrNull?.mediaType != SnMediaType.image)
|
||||||
|
return;
|
||||||
context.pushTransparentRoute(
|
context.pushTransparentRoute(
|
||||||
AttachmentZoomView(
|
AttachmentZoomView(
|
||||||
data: widget.data.where((ele) => ele != null).cast(),
|
data: widget.data.where((ele) => ele != null).cast(),
|
||||||
@ -100,8 +111,10 @@ class _AttachmentListState extends State<AttachmentList> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final fullOfImage =
|
final fullOfImage = widget.data
|
||||||
widget.data.where((ele) => ele?.mediaType == SnMediaType.image).length == widget.data.length;
|
.where((ele) => ele?.mediaType == SnMediaType.image)
|
||||||
|
.length ==
|
||||||
|
widget.data.length;
|
||||||
|
|
||||||
if (widget.gridded && fullOfImage) {
|
if (widget.gridded && fullOfImage) {
|
||||||
return Container(
|
return Container(
|
||||||
@ -117,29 +130,38 @@ class _AttachmentListState extends State<AttachmentList> {
|
|||||||
crossAxisCount: math.min(widget.data.length, 2),
|
crossAxisCount: math.min(widget.data.length, 2),
|
||||||
crossAxisSpacing: 4,
|
crossAxisSpacing: 4,
|
||||||
mainAxisSpacing: 4,
|
mainAxisSpacing: 4,
|
||||||
children:
|
children: widget.data
|
||||||
widget.data
|
.mapIndexed(
|
||||||
.mapIndexed(
|
(idx, ele) => GestureDetector(
|
||||||
(idx, ele) => GestureDetector(
|
child: Container(
|
||||||
child: Container(
|
constraints: constraints,
|
||||||
constraints: constraints,
|
child: AttachmentItem(
|
||||||
child: AttachmentItem(data: ele, heroTag: heroTags[idx], fit: BoxFit.cover),
|
data: ele,
|
||||||
),
|
heroTag: heroTags[idx],
|
||||||
onTap: () {
|
fit: BoxFit.cover,
|
||||||
if (widget.data[idx]!.mediaType != SnMediaType.image) return;
|
filterQuality: widget.filterQuality,
|
||||||
context.pushTransparentRoute(
|
|
||||||
AttachmentZoomView(
|
|
||||||
data: widget.data.where((ele) => ele != null).cast(),
|
|
||||||
initialIndex: idx,
|
|
||||||
heroTags: heroTags,
|
|
||||||
),
|
|
||||||
backgroundColor: Colors.black.withOpacity(0.7),
|
|
||||||
rootNavigator: true,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
)
|
),
|
||||||
.toList(),
|
onTap: () {
|
||||||
|
if (widget.data[idx]!.mediaType !=
|
||||||
|
SnMediaType.image) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
context.pushTransparentRoute(
|
||||||
|
AttachmentZoomView(
|
||||||
|
data: widget.data
|
||||||
|
.where((ele) => ele != null)
|
||||||
|
.cast(),
|
||||||
|
initialIndex: idx,
|
||||||
|
heroTags: heroTags,
|
||||||
|
),
|
||||||
|
backgroundColor: Colors.black.withOpacity(0.7),
|
||||||
|
rootNavigator: true,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -156,22 +178,26 @@ class _AttachmentListState extends State<AttachmentList> {
|
|||||||
child: ClipRRect(
|
child: ClipRRect(
|
||||||
borderRadius: AttachmentList.kDefaultRadius,
|
borderRadius: AttachmentList.kDefaultRadius,
|
||||||
child: Column(
|
child: Column(
|
||||||
children:
|
children: widget.data
|
||||||
widget.data
|
.mapIndexed(
|
||||||
.mapIndexed(
|
(idx, ele) => GestureDetector(
|
||||||
(idx, ele) => GestureDetector(
|
child: AspectRatio(
|
||||||
child: AspectRatio(
|
aspectRatio: ele?.data['ratio']?.toDouble() ?? 1,
|
||||||
aspectRatio: ele?.data['ratio']?.toDouble() ?? 1,
|
child: Container(
|
||||||
child: Container(
|
constraints: constraints,
|
||||||
constraints: constraints,
|
child: AttachmentItem(
|
||||||
child: AttachmentItem(data: ele, heroTag: heroTags[idx], fit: BoxFit.cover),
|
data: ele,
|
||||||
),
|
heroTag: heroTags[idx],
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
filterQuality: widget.filterQuality,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
),
|
||||||
.expand((ele) => [ele, const Divider(height: 1)])
|
),
|
||||||
.toList()
|
)
|
||||||
..removeLast(),
|
.expand((ele) => [ele, const Divider(height: 1)])
|
||||||
|
.toList()
|
||||||
|
..removeLast(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -179,6 +205,7 @@ class _AttachmentListState extends State<AttachmentList> {
|
|||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
constraints: BoxConstraints(maxHeight: constraints.maxHeight),
|
constraints: BoxConstraints(maxHeight: constraints.maxHeight),
|
||||||
|
width: double.infinity,
|
||||||
child: AspectRatio(
|
child: AspectRatio(
|
||||||
aspectRatio: widget.data[0]?.data['ratio']?.toDouble() ?? 1,
|
aspectRatio: widget.data[0]?.data['ratio']?.toDouble() ?? 1,
|
||||||
child: ScrollConfiguration(
|
child: ScrollConfiguration(
|
||||||
@ -189,16 +216,22 @@ class _AttachmentListState extends State<AttachmentList> {
|
|||||||
itemCount: widget.data.length,
|
itemCount: widget.data.length,
|
||||||
itemBuilder: (context, idx) {
|
itemBuilder: (context, idx) {
|
||||||
return Container(
|
return Container(
|
||||||
constraints: constraints.copyWith(maxWidth: widget.maxWidth),
|
constraints:
|
||||||
|
constraints.copyWith(maxWidth: widget.maxWidth),
|
||||||
child: AspectRatio(
|
child: AspectRatio(
|
||||||
aspectRatio: (widget.data[idx]?.data['ratio'] ?? 1).toDouble(),
|
aspectRatio:
|
||||||
|
(widget.data[idx]?.data['ratio'] ?? 1).toDouble(),
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (widget.data[idx]?.mediaType != SnMediaType.image) return;
|
if (widget.data[idx]?.mediaType != SnMediaType.image)
|
||||||
|
return;
|
||||||
context.pushTransparentRoute(
|
context.pushTransparentRoute(
|
||||||
AttachmentZoomView(
|
AttachmentZoomView(
|
||||||
data:
|
data: widget.data
|
||||||
widget.data.where((ele) => ele != null && ele.mediaType == SnMediaType.image).cast(),
|
.where((ele) =>
|
||||||
|
ele != null &&
|
||||||
|
ele.mediaType == SnMediaType.image)
|
||||||
|
.cast(),
|
||||||
initialIndex: idx,
|
initialIndex: idx,
|
||||||
heroTags: heroTags,
|
heroTags: heroTags,
|
||||||
),
|
),
|
||||||
@ -212,18 +245,25 @@ class _AttachmentListState extends State<AttachmentList> {
|
|||||||
Container(
|
Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: backgroundColor,
|
color: backgroundColor,
|
||||||
border: Border(top: borderSide, bottom: borderSide),
|
border:
|
||||||
|
Border(top: borderSide, bottom: borderSide),
|
||||||
borderRadius: AttachmentList.kDefaultRadius,
|
borderRadius: AttachmentList.kDefaultRadius,
|
||||||
),
|
),
|
||||||
child: ClipRRect(
|
child: ClipRRect(
|
||||||
borderRadius: AttachmentList.kDefaultRadius,
|
borderRadius: AttachmentList.kDefaultRadius,
|
||||||
child: AttachmentItem(data: widget.data[idx], heroTag: heroTags[idx]),
|
child: AttachmentItem(
|
||||||
|
data: widget.data[idx],
|
||||||
|
heroTag: heroTags[idx],
|
||||||
|
filterQuality: widget.filterQuality,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Positioned(
|
Positioned(
|
||||||
right: 8,
|
right: 8,
|
||||||
bottom: 8,
|
bottom: 8,
|
||||||
child: Chip(label: Text('${idx + 1}/${widget.data.length}')),
|
child: Chip(
|
||||||
|
label:
|
||||||
|
Text('${idx + 1}/${widget.data.length}')),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -245,5 +285,6 @@ class _AttachmentListState extends State<AttachmentList> {
|
|||||||
|
|
||||||
class _AttachmentListScrollBehavior extends MaterialScrollBehavior {
|
class _AttachmentListScrollBehavior extends MaterialScrollBehavior {
|
||||||
@override
|
@override
|
||||||
Set<PointerDeviceKind> get dragDevices => {PointerDeviceKind.touch, PointerDeviceKind.mouse};
|
Set<PointerDeviceKind> get dragDevices =>
|
||||||
|
{PointerDeviceKind.touch, PointerDeviceKind.mouse};
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'dart:math' show max;
|
|
||||||
|
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:dismissible_page/dismissible_page.dart';
|
import 'package:dismissible_page/dismissible_page.dart';
|
||||||
@ -48,11 +47,14 @@ class _AttachmentZoomViewState extends State<AttachmentZoomView> {
|
|||||||
bool _showOverlay = true;
|
bool _showOverlay = true;
|
||||||
bool _dismissable = true;
|
bool _dismissable = true;
|
||||||
|
|
||||||
|
int _page = 0;
|
||||||
|
|
||||||
void _updatePage() {
|
void _updatePage() {
|
||||||
setState(() {
|
setState(() {
|
||||||
if (_isCompletedDownload) {
|
if (_isCompletedDownload) {
|
||||||
setState(() => _isCompletedDownload = false);
|
setState(() => _isCompletedDownload = false);
|
||||||
}
|
}
|
||||||
|
_page = _pageController.page?.round() ?? 0;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,7 +157,7 @@ class _AttachmentZoomViewState extends State<AttachmentZoomView> {
|
|||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
},
|
},
|
||||||
direction: _dismissable
|
direction: _dismissable
|
||||||
? DismissiblePageDismissDirection.multi
|
? DismissiblePageDismissDirection.down
|
||||||
: DismissiblePageDismissDirection.none,
|
: DismissiblePageDismissDirection.none,
|
||||||
backgroundColor: Colors.transparent,
|
backgroundColor: Colors.transparent,
|
||||||
isFullScreen: true,
|
isFullScreen: true,
|
||||||
@ -222,31 +224,11 @@ class _AttachmentZoomViewState extends State<AttachmentZoomView> {
|
|||||||
BoxDecoration(color: Colors.transparent),
|
BoxDecoration(color: Colors.transparent),
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
Positioned(
|
|
||||||
top: max(MediaQuery.of(context).padding.top, 8),
|
|
||||||
left: 14,
|
|
||||||
child: IgnorePointer(
|
|
||||||
ignoring: !_showOverlay,
|
|
||||||
child: IconButton(
|
|
||||||
constraints: const BoxConstraints(),
|
|
||||||
icon: const Icon(Icons.close),
|
|
||||||
style: ButtonStyle(
|
|
||||||
backgroundColor: MaterialStateProperty.all(
|
|
||||||
Theme.of(context).colorScheme.surface.withOpacity(0.5),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
},
|
|
||||||
).opacity(_showOverlay ? 1 : 0, animate: true).animate(
|
|
||||||
const Duration(milliseconds: 300), Curves.easeInOut),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Align(
|
Align(
|
||||||
alignment: Alignment.bottomCenter,
|
alignment: Alignment.bottomCenter,
|
||||||
child: IgnorePointer(
|
child: IgnorePointer(
|
||||||
child: Container(
|
child: Container(
|
||||||
height: 300,
|
height: 200,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
gradient: LinearGradient(
|
gradient: LinearGradient(
|
||||||
begin: Alignment.bottomCenter,
|
begin: Alignment.bottomCenter,
|
||||||
@ -269,153 +251,130 @@ class _AttachmentZoomViewState extends State<AttachmentZoomView> {
|
|||||||
child: Material(
|
child: Material(
|
||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
child: Builder(builder: (context) {
|
child: Builder(builder: (context) {
|
||||||
final ud = context.read<UserDirectoryProvider>();
|
return Row(
|
||||||
final item = widget.data.elementAt(
|
|
||||||
widget.data.length > 1
|
|
||||||
? _pageController.page?.round() ?? 0
|
|
||||||
: 0,
|
|
||||||
);
|
|
||||||
final account = ud.getFromCache(item.accountId);
|
|
||||||
|
|
||||||
return Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
children: [
|
||||||
if (item.accountId > 0)
|
IconButton(
|
||||||
Row(
|
iconSize: 18,
|
||||||
children: [
|
constraints: const BoxConstraints(),
|
||||||
IgnorePointer(
|
icon: const Icon(Icons.close),
|
||||||
child: AccountImage(
|
style: ButtonStyle(
|
||||||
content: account?.avatar,
|
backgroundColor: MaterialStateProperty.all(
|
||||||
radius: 19,
|
Theme.of(context)
|
||||||
),
|
.colorScheme
|
||||||
),
|
.surface
|
||||||
const Gap(8),
|
.withOpacity(0.5),
|
||||||
Expanded(
|
|
||||||
child: IgnorePointer(
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment:
|
|
||||||
CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
'attachmentUploadBy'.tr(),
|
|
||||||
style: Theme.of(context)
|
|
||||||
.textTheme
|
|
||||||
.bodySmall,
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
account?.nick ?? 'unknown'.tr(),
|
|
||||||
style: Theme.of(context)
|
|
||||||
.textTheme
|
|
||||||
.bodyMedium,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (widget.data.length > 1)
|
|
||||||
IgnorePointer(
|
|
||||||
child: Text(
|
|
||||||
'${(_pageController.page?.round() ?? 0) + 1}/${widget.data.length}',
|
|
||||||
style: GoogleFonts.robotoMono(fontSize: 13),
|
|
||||||
).padding(right: 8),
|
|
||||||
),
|
|
||||||
InkWell(
|
|
||||||
borderRadius:
|
|
||||||
const BorderRadius.all(Radius.circular(16)),
|
|
||||||
onTap: _isDownloading
|
|
||||||
? null
|
|
||||||
: () => _saveToAlbum(widget.data.length > 1
|
|
||||||
? _pageController.page?.round() ?? 0
|
|
||||||
: 0),
|
|
||||||
child: Container(
|
|
||||||
padding: const EdgeInsets.all(6),
|
|
||||||
child: !_isDownloading
|
|
||||||
? !_isCompletedDownload
|
|
||||||
? const Icon(Symbols.save_alt)
|
|
||||||
: const Icon(Symbols.download_done)
|
|
||||||
: SizedBox(
|
|
||||||
width: 24,
|
|
||||||
height: 24,
|
|
||||||
child: CircularProgressIndicator(
|
|
||||||
value: _progressOfDownload,
|
|
||||||
strokeWidth: 3,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
const Gap(4),
|
|
||||||
IgnorePointer(
|
|
||||||
child: Text(
|
|
||||||
item.alt,
|
|
||||||
maxLines: 2,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 15,
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
),
|
),
|
||||||
const Gap(2),
|
IconButton(
|
||||||
IgnorePointer(
|
iconSize: 20,
|
||||||
child: Wrap(
|
constraints: const BoxConstraints(),
|
||||||
spacing: 6,
|
padding: EdgeInsets.zero,
|
||||||
children: [
|
visualDensity: VisualDensity.compact,
|
||||||
if (item.metadata['exif'] == null)
|
icon: const Icon(Symbols.hide).padding(all: 6),
|
||||||
Text(
|
onPressed: () {
|
||||||
'#${item.rid}',
|
setState(() => _showOverlay = false);
|
||||||
style: metaTextStyle,
|
}),
|
||||||
),
|
Expanded(
|
||||||
if (item.metadata['exif']?['Model'] != null)
|
child: IgnorePointer(
|
||||||
Text(
|
child: Builder(builder: (context) {
|
||||||
'attachmentShotOn'.tr(args: [
|
final item = widget.data.elementAt(_page);
|
||||||
item.metadata['exif']?['Model'],
|
final doShowCameraInfo =
|
||||||
]),
|
item.metadata['exif']?['Model'] != null;
|
||||||
style: metaTextStyle,
|
final exif = item.metadata['exif'];
|
||||||
).padding(right: 2),
|
return Column(
|
||||||
if (item.metadata['exif']?['Megapixels'] !=
|
children: [
|
||||||
null &&
|
if (widget.data.length > 1)
|
||||||
item.metadata['exif']?['Model'] != null)
|
Text(
|
||||||
Text(
|
'${_page + 1}/${widget.data.length}',
|
||||||
'${item.metadata['exif']?['Megapixels']}MP',
|
style:
|
||||||
style: metaTextStyle,
|
GoogleFonts.robotoMono(fontSize: 13),
|
||||||
)
|
).padding(right: 8),
|
||||||
else
|
if (doShowCameraInfo)
|
||||||
Text(
|
Text(
|
||||||
item.size.formatBytes(),
|
'attachmentShotOn'
|
||||||
style: metaTextStyle,
|
.tr(args: [exif?['Model']]),
|
||||||
),
|
style: metaTextStyle,
|
||||||
if (item.metadata['width'] != null &&
|
textAlign: TextAlign.center,
|
||||||
item.metadata['height'] != null)
|
),
|
||||||
Text(
|
if (doShowCameraInfo)
|
||||||
'${item.metadata['width']}x${item.metadata['height']}',
|
Row(
|
||||||
style: metaTextStyle,
|
spacing: 4,
|
||||||
),
|
mainAxisSize: MainAxisSize.min,
|
||||||
],
|
children: [
|
||||||
|
if (exif?['Megapixels'] != null)
|
||||||
|
Text(
|
||||||
|
'${exif?['Megapixels']}MP',
|
||||||
|
style: metaTextStyle,
|
||||||
|
),
|
||||||
|
if (exif?['ISO'] != null)
|
||||||
|
Text(
|
||||||
|
'ISO${exif['ISO']}',
|
||||||
|
style: metaTextStyle,
|
||||||
|
),
|
||||||
|
if (exif?['FNumber'] != null)
|
||||||
|
Text(
|
||||||
|
'f/${exif['FNumber']}',
|
||||||
|
style: metaTextStyle,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const Gap(4),
|
IconButton(
|
||||||
InkWell(
|
constraints: const BoxConstraints(),
|
||||||
onTap: () {
|
padding: EdgeInsets.zero,
|
||||||
|
visualDensity: VisualDensity.compact,
|
||||||
|
icon: Container(
|
||||||
|
padding: const EdgeInsets.all(6),
|
||||||
|
child: !_isDownloading
|
||||||
|
? !_isCompletedDownload
|
||||||
|
? const Icon(Symbols.save_alt)
|
||||||
|
: const Icon(Symbols.download_done)
|
||||||
|
: SizedBox(
|
||||||
|
width: 20,
|
||||||
|
height: 20,
|
||||||
|
child: CircularProgressIndicator(
|
||||||
|
backgroundColor: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.surfaceContainerHighest,
|
||||||
|
value: _progressOfDownload,
|
||||||
|
strokeWidth: 3,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onPressed:
|
||||||
|
_isDownloading ? null : () => _saveToAlbum(_page),
|
||||||
|
),
|
||||||
|
IconButton(
|
||||||
|
iconSize: 18,
|
||||||
|
constraints: const BoxConstraints(),
|
||||||
|
icon: const Icon(Icons.info_outline),
|
||||||
|
style: ButtonStyle(
|
||||||
|
backgroundColor: MaterialStateProperty.all(
|
||||||
|
Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.surface
|
||||||
|
.withOpacity(0.5),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onPressed: () {
|
||||||
_showDetail = true;
|
_showDetail = true;
|
||||||
showModalBottomSheet(
|
showModalBottomSheet(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) => _AttachmentZoomDetailPopup(
|
builder: (context) => _AttachmentZoomDetailPopup(
|
||||||
data: widget.data.elementAt(
|
data: widget.data.elementAt(_page),
|
||||||
widget.data.length > 1
|
|
||||||
? _pageController.page?.round() ?? 0
|
|
||||||
: 0),
|
|
||||||
),
|
),
|
||||||
).then((_) {
|
).then((_) {
|
||||||
_showDetail = false;
|
_showDetail = false;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
child: Text(
|
|
||||||
'viewDetailedAttachment'.tr(),
|
|
||||||
style: metaTextStyle.copyWith(
|
|
||||||
decoration: TextDecoration.underline),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@ -427,18 +386,20 @@ class _AttachmentZoomViewState extends State<AttachmentZoomView> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
|
if (_showOverlay) {
|
||||||
|
Navigator.pop(context);
|
||||||
|
return;
|
||||||
|
}
|
||||||
setState(() => _showOverlay = !_showOverlay);
|
setState(() => _showOverlay = !_showOverlay);
|
||||||
},
|
},
|
||||||
onVerticalDragUpdate: (details) {
|
onVerticalDragUpdate: (details) {
|
||||||
if (_showDetail) return;
|
if (_showDetail || !_dismissable) return;
|
||||||
if (details.delta.dy <= -20) {
|
if (details.delta.dy <= -20) {
|
||||||
_showDetail = true;
|
_showDetail = true;
|
||||||
showModalBottomSheet(
|
showModalBottomSheet(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) => _AttachmentZoomDetailPopup(
|
builder: (context) => _AttachmentZoomDetailPopup(
|
||||||
data: widget.data.elementAt(widget.data.length > 1
|
data: widget.data.elementAt(_page),
|
||||||
? _pageController.page?.round() ?? 0
|
|
||||||
: 0),
|
|
||||||
),
|
),
|
||||||
).then((_) {
|
).then((_) {
|
||||||
_showDetail = false;
|
_showDetail = false;
|
||||||
|
@ -12,10 +12,10 @@ import 'package:surface/providers/config.dart';
|
|||||||
import 'package:surface/providers/keypair.dart';
|
import 'package:surface/providers/keypair.dart';
|
||||||
import 'package:surface/providers/user_directory.dart';
|
import 'package:surface/providers/user_directory.dart';
|
||||||
import 'package:surface/providers/userinfo.dart';
|
import 'package:surface/providers/userinfo.dart';
|
||||||
import 'package:surface/screens/account/profile_page.dart';
|
|
||||||
import 'package:surface/types/chat.dart';
|
import 'package:surface/types/chat.dart';
|
||||||
import 'package:surface/widgets/account/account_image.dart';
|
import 'package:surface/widgets/account/account_image.dart';
|
||||||
import 'package:surface/widgets/account/account_popover.dart';
|
import 'package:surface/widgets/account/account_popover.dart';
|
||||||
|
import 'package:surface/widgets/account/badge.dart';
|
||||||
import 'package:surface/widgets/attachment/attachment_list.dart';
|
import 'package:surface/widgets/attachment/attachment_list.dart';
|
||||||
import 'package:surface/widgets/context_menu.dart';
|
import 'package:surface/widgets/context_menu.dart';
|
||||||
import 'package:surface/widgets/link_preview.dart';
|
import 'package:surface/widgets/link_preview.dart';
|
||||||
@ -109,18 +109,10 @@ class ChatMessage extends StatelessWidget {
|
|||||||
child: AccountImage(
|
child: AccountImage(
|
||||||
content: user?.avatar,
|
content: user?.avatar,
|
||||||
badge: (user?.badges.isNotEmpty ?? false)
|
badge: (user?.badges.isNotEmpty ?? false)
|
||||||
? Icon(
|
? AccountBadge(
|
||||||
kBadgesMeta[user!.badges.first.type]?.$2 ??
|
badge: user!.badges.first,
|
||||||
Symbols.question_mark,
|
radius: 16,
|
||||||
color: kBadgesMeta[user.badges.first.type]?.$3,
|
padding: EdgeInsets.all(2),
|
||||||
fill: 1,
|
|
||||||
size: 18,
|
|
||||||
shadows: [
|
|
||||||
Shadow(
|
|
||||||
offset: Offset(1, 1),
|
|
||||||
blurRadius: 5.0,
|
|
||||||
color: Color.fromARGB(200, 0, 0, 0)),
|
|
||||||
],
|
|
||||||
)
|
)
|
||||||
: null,
|
: null,
|
||||||
),
|
),
|
||||||
@ -214,7 +206,8 @@ class ChatMessage extends StatelessWidget {
|
|||||||
data.type == 'messages.new' &&
|
data.type == 'messages.new' &&
|
||||||
(data.body['text']?.isNotEmpty ?? false) &&
|
(data.body['text']?.isNotEmpty ?? false) &&
|
||||||
(cfg.prefs.getBool(kAppExpandChatLink) ?? true))
|
(cfg.prefs.getBool(kAppExpandChatLink) ?? true))
|
||||||
LinkPreviewWidget(text: data.body['text']!).padding(left: 48),
|
LinkPreviewWidget(text: data.body['text']!)
|
||||||
|
.padding(left: isCompact ? 0 : 48),
|
||||||
if (data.preload?.attachments?.isNotEmpty ?? false)
|
if (data.preload?.attachments?.isNotEmpty ?? false)
|
||||||
AttachmentList(
|
AttachmentList(
|
||||||
data: data.preload!.attachments!,
|
data: data.preload!.attachments!,
|
||||||
|
@ -29,6 +29,7 @@ import 'package:surface/types/attachment.dart';
|
|||||||
import 'package:surface/types/post.dart';
|
import 'package:surface/types/post.dart';
|
||||||
import 'package:surface/types/reaction.dart';
|
import 'package:surface/types/reaction.dart';
|
||||||
import 'package:surface/widgets/account/account_image.dart';
|
import 'package:surface/widgets/account/account_image.dart';
|
||||||
|
import 'package:surface/widgets/account/badge.dart';
|
||||||
import 'package:surface/widgets/attachment/attachment_item.dart';
|
import 'package:surface/widgets/attachment/attachment_item.dart';
|
||||||
import 'package:surface/widgets/attachment/attachment_list.dart';
|
import 'package:surface/widgets/attachment/attachment_list.dart';
|
||||||
import 'package:surface/widgets/dialog.dart';
|
import 'package:surface/widgets/dialog.dart';
|
||||||
@ -43,8 +44,6 @@ import 'package:surface/widgets/post/publisher_popover.dart';
|
|||||||
import 'package:surface/widgets/universal_image.dart';
|
import 'package:surface/widgets/universal_image.dart';
|
||||||
import 'package:xml/xml.dart';
|
import 'package:xml/xml.dart';
|
||||||
|
|
||||||
import '../../screens/account/profile_page.dart' show kBadgesMeta;
|
|
||||||
|
|
||||||
class OpenablePostItem extends StatelessWidget {
|
class OpenablePostItem extends StatelessWidget {
|
||||||
final SnPost data;
|
final SnPost data;
|
||||||
final bool showReactions;
|
final bool showReactions;
|
||||||
@ -149,7 +148,6 @@ class PostItem extends StatelessWidget {
|
|||||||
|
|
||||||
void _doShareViaPicture(BuildContext context) async {
|
void _doShareViaPicture(BuildContext context) async {
|
||||||
final box = context.findRenderObject() as RenderBox?;
|
final box = context.findRenderObject() as RenderBox?;
|
||||||
context.showSnackbar('postSharingViaPicture'.tr());
|
|
||||||
|
|
||||||
final controller = ScreenshotController();
|
final controller = ScreenshotController();
|
||||||
final capturedImage = await controller.captureFromLongWidget(
|
final capturedImage = await controller.captureFromLongWidget(
|
||||||
@ -160,9 +158,9 @@ class PostItem extends StatelessWidget {
|
|||||||
child: Material(
|
child: Material(
|
||||||
child: MultiProvider(
|
child: MultiProvider(
|
||||||
providers: [
|
providers: [
|
||||||
|
// Create a copy of environments
|
||||||
Provider<SnNetworkProvider>(create: (_) => context.read()),
|
Provider<SnNetworkProvider>(create: (_) => context.read()),
|
||||||
ChangeNotifierProvider<ConfigProvider>(
|
Provider<UserDirectoryProvider>(create: (_) => context.read()),
|
||||||
create: (_) => context.read()),
|
|
||||||
],
|
],
|
||||||
child: ResponsiveBreakpoints.builder(
|
child: ResponsiveBreakpoints.builder(
|
||||||
breakpoints: ResponsiveBreakpoints.of(context).breakpoints,
|
breakpoints: ResponsiveBreakpoints.of(context).breakpoints,
|
||||||
@ -224,7 +222,7 @@ class PostItem extends StatelessWidget {
|
|||||||
onShareImage: () => _doShareViaPicture(context),
|
onShareImage: () => _doShareViaPicture(context),
|
||||||
onSelectAnswer: onSelectAnswer,
|
onSelectAnswer: onSelectAnswer,
|
||||||
onDeleted: () {
|
onDeleted: () {
|
||||||
if (onDeleted != null) {}
|
onDeleted?.call();
|
||||||
},
|
},
|
||||||
).padding(bottom: 8),
|
).padding(bottom: 8),
|
||||||
if (data.preload?.video != null)
|
if (data.preload?.video != null)
|
||||||
@ -273,7 +271,7 @@ class PostItem extends StatelessWidget {
|
|||||||
onShareImage: () => _doShareViaPicture(context),
|
onShareImage: () => _doShareViaPicture(context),
|
||||||
onSelectAnswer: onSelectAnswer,
|
onSelectAnswer: onSelectAnswer,
|
||||||
onDeleted: () {
|
onDeleted: () {
|
||||||
if (onDeleted != null) {}
|
onDeleted?.call();
|
||||||
},
|
},
|
||||||
).padding(horizontal: 12, top: 8, bottom: 8),
|
).padding(horizontal: 12, top: 8, bottom: 8),
|
||||||
if (data.preload?.video != null)
|
if (data.preload?.video != null)
|
||||||
@ -364,7 +362,7 @@ class PostItem extends StatelessWidget {
|
|||||||
onShareImage: () => _doShareViaPicture(context),
|
onShareImage: () => _doShareViaPicture(context),
|
||||||
onSelectAnswer: onSelectAnswer,
|
onSelectAnswer: onSelectAnswer,
|
||||||
onDeleted: () {
|
onDeleted: () {
|
||||||
if (onDeleted != null) onDeleted!();
|
onDeleted?.call();
|
||||||
},
|
},
|
||||||
).padding(horizontal: 12, vertical: 8),
|
).padding(horizontal: 12, vertical: 8),
|
||||||
if (data.preload?.video != null)
|
if (data.preload?.video != null)
|
||||||
@ -507,6 +505,8 @@ class PostShareImageWidget extends StatelessWidget {
|
|||||||
StyledWidget(AttachmentList(
|
StyledWidget(AttachmentList(
|
||||||
data: data.preload!.attachments!,
|
data: data.preload!.attachments!,
|
||||||
columned: true,
|
columned: true,
|
||||||
|
fit: BoxFit.contain,
|
||||||
|
filterQuality: FilterQuality.high,
|
||||||
)).padding(horizontal: 16, bottom: 8),
|
)).padding(horizontal: 16, bottom: 8),
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@ -886,7 +886,7 @@ class _PostContentHeader extends StatelessWidget {
|
|||||||
'publisherId': data.publisherId,
|
'publisherId': data.publisherId,
|
||||||
});
|
});
|
||||||
if (!context.mounted) return;
|
if (!context.mounted) return;
|
||||||
context.showSnackbar('postDeleted'.tr(args: ['#${data.id}']));
|
onDeleted.call();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (!context.mounted) return;
|
if (!context.mounted) return;
|
||||||
context.showErrorDialog(err);
|
context.showErrorDialog(err);
|
||||||
@ -922,27 +922,39 @@ class _PostContentHeader extends StatelessWidget {
|
|||||||
return Row(
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
child: AccountImage(
|
child: data.preload?.realm == null
|
||||||
content: data.publisher.avatar,
|
? AccountImage(
|
||||||
radius: isCompact ? 12 : 20,
|
content: data.publisher.avatar,
|
||||||
borderRadius: data.publisher.type == 1 ? (isCompact ? 4 : 8) : 20,
|
radius: isCompact ? 12 : 20,
|
||||||
badge: (user?.badges.isNotEmpty ?? false)
|
borderRadius:
|
||||||
? Icon(
|
data.publisher.type == 1 ? (isCompact ? 4 : 8) : 20,
|
||||||
kBadgesMeta[user!.badges.first.type]?.$2 ??
|
badge: (user?.badges.isNotEmpty ?? false)
|
||||||
Symbols.question_mark,
|
? AccountBadge(
|
||||||
color: kBadgesMeta[user.badges.first.type]?.$3,
|
badge: user!.badges.first,
|
||||||
fill: 1,
|
radius: 16,
|
||||||
size: 18,
|
padding: EdgeInsets.all(2),
|
||||||
shadows: [
|
)
|
||||||
Shadow(
|
: null,
|
||||||
offset: Offset(1, 1),
|
)
|
||||||
blurRadius: 5.0,
|
: AccountImage(
|
||||||
color: Color.fromARGB(200, 0, 0, 0),
|
content: data.preload!.realm!.avatar,
|
||||||
|
radius: isCompact ? 12 : 20,
|
||||||
|
borderRadius: isCompact ? 4 : 8,
|
||||||
|
badgeOffset: Offset(-6, -4),
|
||||||
|
badge: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border.all(
|
||||||
|
color: Theme.of(context).colorScheme.surface,
|
||||||
|
width: 2,
|
||||||
),
|
),
|
||||||
],
|
borderRadius: BorderRadius.circular(10),
|
||||||
)
|
),
|
||||||
: null,
|
child: AccountImage(
|
||||||
),
|
content: data.publisher.avatar,
|
||||||
|
radius: 10,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
showPopover(
|
showPopover(
|
||||||
backgroundColor: Theme.of(context).colorScheme.surface,
|
backgroundColor: Theme.of(context).colorScheme.surface,
|
||||||
@ -987,7 +999,17 @@ class _PostContentHeader extends StatelessWidget {
|
|||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(data.publisher.nick).bold(),
|
Row(
|
||||||
|
children: [
|
||||||
|
Text(data.publisher.nick).bold(),
|
||||||
|
if (data.preload?.realm != null)
|
||||||
|
const Icon(Symbols.arrow_right, size: 16)
|
||||||
|
.padding(horizontal: 2)
|
||||||
|
.opacity(0.5),
|
||||||
|
if (data.preload?.realm != null)
|
||||||
|
Text(data.preload!.realm!.name),
|
||||||
|
],
|
||||||
|
),
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Text('@${data.publisher.name}').fontSize(13),
|
Text('@${data.publisher.name}').fontSize(13),
|
||||||
@ -1037,8 +1059,10 @@ class _PostContentHeader extends StatelessWidget {
|
|||||||
onTap: () {
|
onTap: () {
|
||||||
GoRouter.of(context).pushNamed(
|
GoRouter.of(context).pushNamed(
|
||||||
'postEditor',
|
'postEditor',
|
||||||
pathParameters: {'mode': data.typePlural},
|
queryParameters: {
|
||||||
queryParameters: {'editing': data.id.toString()},
|
'editing': data.id.toString(),
|
||||||
|
'mode': data.typePlural,
|
||||||
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -1065,8 +1089,10 @@ class _PostContentHeader extends StatelessWidget {
|
|||||||
onTap: () {
|
onTap: () {
|
||||||
GoRouter.of(context).pushNamed(
|
GoRouter.of(context).pushNamed(
|
||||||
'postEditor',
|
'postEditor',
|
||||||
pathParameters: {'mode': 'stories'},
|
queryParameters: {
|
||||||
queryParameters: {'replying': data.id.toString()},
|
'replying': data.id.toString(),
|
||||||
|
'mode': data.typePlural,
|
||||||
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -1081,8 +1107,10 @@ class _PostContentHeader extends StatelessWidget {
|
|||||||
onTap: () {
|
onTap: () {
|
||||||
GoRouter.of(context).pushNamed(
|
GoRouter.of(context).pushNamed(
|
||||||
'postEditor',
|
'postEditor',
|
||||||
pathParameters: {'mode': 'stories'},
|
queryParameters: {
|
||||||
queryParameters: {'reposting': data.id.toString()},
|
'reposting': data.id.toString(),
|
||||||
|
'mode': 'stories',
|
||||||
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -25,7 +25,8 @@ class PostMiniEditor extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _PostMiniEditorState extends State<PostMiniEditor> {
|
class _PostMiniEditorState extends State<PostMiniEditor> {
|
||||||
final PostWriteController _writeController = PostWriteController(doLoadFromTemporary: false);
|
final PostWriteController _writeController =
|
||||||
|
PostWriteController(doLoadFromTemporary: false);
|
||||||
|
|
||||||
bool _isFetching = false;
|
bool _isFetching = false;
|
||||||
|
|
||||||
@ -44,8 +45,9 @@ class _PostMiniEditorState extends State<PostMiniEditor> {
|
|||||||
resp.data?.map((e) => SnPublisher.fromJson(e)) ?? [],
|
resp.data?.map((e) => SnPublisher.fromJson(e)) ?? [],
|
||||||
);
|
);
|
||||||
final beforeId = config.prefs.getInt('int_last_publisher_id');
|
final beforeId = config.prefs.getInt('int_last_publisher_id');
|
||||||
_writeController
|
_writeController.setPublisher(
|
||||||
.setPublisher(_publishers?.where((ele) => ele.id == beforeId).firstOrNull ?? _publishers?.firstOrNull);
|
_publishers?.where((ele) => ele.id == beforeId).firstOrNull ??
|
||||||
|
_publishers?.firstOrNull);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
context.showErrorDialog(err);
|
context.showErrorDialog(err);
|
||||||
@ -99,11 +101,17 @@ class _PostMiniEditorState extends State<PostMiniEditor> {
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment:
|
||||||
|
CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(item.nick).textStyle(Theme.of(context).textTheme.bodyMedium!),
|
Text(item.nick).textStyle(
|
||||||
|
Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.bodyMedium!),
|
||||||
Text('@${item.name}')
|
Text('@${item.name}')
|
||||||
.textStyle(Theme.of(context).textTheme.bodySmall!)
|
.textStyle(Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.bodySmall!)
|
||||||
.fontSize(12),
|
.fontSize(12),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -120,7 +128,8 @@ class _PostMiniEditorState extends State<PostMiniEditor> {
|
|||||||
CircleAvatar(
|
CircleAvatar(
|
||||||
radius: 16,
|
radius: 16,
|
||||||
backgroundColor: Colors.transparent,
|
backgroundColor: Colors.transparent,
|
||||||
foregroundColor: Theme.of(context).colorScheme.onSurface,
|
foregroundColor:
|
||||||
|
Theme.of(context).colorScheme.onSurface,
|
||||||
child: const Icon(Symbols.add),
|
child: const Icon(Symbols.add),
|
||||||
),
|
),
|
||||||
const Gap(8),
|
const Gap(8),
|
||||||
@ -129,7 +138,8 @@ class _PostMiniEditorState extends State<PostMiniEditor> {
|
|||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text('publishersNew').tr().textStyle(Theme.of(context).textTheme.bodyMedium!),
|
Text('publishersNew').tr().textStyle(
|
||||||
|
Theme.of(context).textTheme.bodyMedium!),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -140,7 +150,9 @@ class _PostMiniEditorState extends State<PostMiniEditor> {
|
|||||||
value: _writeController.publisher,
|
value: _writeController.publisher,
|
||||||
onChanged: (SnPublisher? value) {
|
onChanged: (SnPublisher? value) {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
GoRouter.of(context).pushNamed('accountPublisherNew').then((value) {
|
GoRouter.of(context)
|
||||||
|
.pushNamed('accountPublisherNew')
|
||||||
|
.then((value) {
|
||||||
if (value == true) {
|
if (value == true) {
|
||||||
_publishers = null;
|
_publishers = null;
|
||||||
_fetchPublishers();
|
_fetchPublishers();
|
||||||
@ -176,7 +188,8 @@ class _PostMiniEditorState extends State<PostMiniEditor> {
|
|||||||
),
|
),
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
),
|
),
|
||||||
onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(),
|
onTapOutside: (_) =>
|
||||||
|
FocusManager.instance.primaryFocus?.unfocus(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const Gap(8),
|
const Gap(8),
|
||||||
@ -185,7 +198,8 @@ class _PostMiniEditorState extends State<PostMiniEditor> {
|
|||||||
TweenAnimationBuilder<double>(
|
TweenAnimationBuilder<double>(
|
||||||
tween: Tween(begin: 0, end: _writeController.progress),
|
tween: Tween(begin: 0, end: _writeController.progress),
|
||||||
duration: Duration(milliseconds: 300),
|
duration: Duration(milliseconds: 300),
|
||||||
builder: (context, value, _) => LinearProgressIndicator(value: value, minHeight: 2),
|
builder: (context, value, _) =>
|
||||||
|
LinearProgressIndicator(value: value, minHeight: 2),
|
||||||
)
|
)
|
||||||
else if (_writeController.isBusy)
|
else if (_writeController.isBusy)
|
||||||
const LinearProgressIndicator(value: null, minHeight: 2),
|
const LinearProgressIndicator(value: null, minHeight: 2),
|
||||||
@ -200,15 +214,17 @@ class _PostMiniEditorState extends State<PostMiniEditor> {
|
|||||||
onPressed: () {
|
onPressed: () {
|
||||||
GoRouter.of(context).pushNamed(
|
GoRouter.of(context).pushNamed(
|
||||||
'postEditor',
|
'postEditor',
|
||||||
pathParameters: {'mode': 'stories'},
|
|
||||||
queryParameters: {
|
queryParameters: {
|
||||||
if (widget.postReplyId != null) 'replying': widget.postReplyId.toString(),
|
if (widget.postReplyId != null)
|
||||||
|
'replying': widget.postReplyId.toString(),
|
||||||
|
'mode': 'stories',
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
TextButton.icon(
|
TextButton.icon(
|
||||||
onPressed: (_writeController.isBusy || _writeController.publisher == null)
|
onPressed: (_writeController.isBusy ||
|
||||||
|
_writeController.publisher == null)
|
||||||
? null
|
? null
|
||||||
: () {
|
: () {
|
||||||
_writeController.sendPost(context).then((_) {
|
_writeController.sendPost(context).then((_) {
|
||||||
|
@ -9,10 +9,9 @@ import 'package:surface/providers/sn_network.dart';
|
|||||||
import 'package:surface/providers/user_directory.dart';
|
import 'package:surface/providers/user_directory.dart';
|
||||||
import 'package:surface/types/post.dart';
|
import 'package:surface/types/post.dart';
|
||||||
import 'package:surface/widgets/account/account_image.dart';
|
import 'package:surface/widgets/account/account_image.dart';
|
||||||
|
import 'package:surface/widgets/account/badge.dart';
|
||||||
import 'package:surface/widgets/universal_image.dart';
|
import 'package:surface/widgets/universal_image.dart';
|
||||||
|
|
||||||
import '../../screens/account/profile_page.dart' show kBadgesMeta;
|
|
||||||
|
|
||||||
class PublisherPopoverCard extends StatelessWidget {
|
class PublisherPopoverCard extends StatelessWidget {
|
||||||
final SnPublisher data;
|
final SnPublisher data;
|
||||||
|
|
||||||
@ -76,39 +75,22 @@ class PublisherPopoverCard extends StatelessWidget {
|
|||||||
const Gap(8)
|
const Gap(8)
|
||||||
],
|
],
|
||||||
).padding(horizontal: 16),
|
).padding(horizontal: 16),
|
||||||
if (user != null && user.badges.isNotEmpty) const Gap(16),
|
|
||||||
if (user != null && user.badges.isNotEmpty)
|
if (user != null && user.badges.isNotEmpty)
|
||||||
Wrap(
|
Wrap(
|
||||||
spacing: 4,
|
spacing: 4,
|
||||||
children: user.badges
|
children: user.badges
|
||||||
.map(
|
.map(
|
||||||
(ele) => Tooltip(
|
(ele) => AccountBadge(badge: ele),
|
||||||
richMessage: TextSpan(
|
|
||||||
children: [
|
|
||||||
TextSpan(
|
|
||||||
text: kBadgesMeta[ele.type]?.$1.tr() ??
|
|
||||||
'unknown'.tr()),
|
|
||||||
if (ele.metadata['title'] != null)
|
|
||||||
TextSpan(
|
|
||||||
text: '\n${ele.metadata['title']}',
|
|
||||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
|
||||||
),
|
|
||||||
TextSpan(text: '\n'),
|
|
||||||
TextSpan(
|
|
||||||
text: DateFormat.yMEd().format(ele.createdAt),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
child: Icon(
|
|
||||||
kBadgesMeta[ele.type]?.$2 ?? Symbols.question_mark,
|
|
||||||
color: kBadgesMeta[ele.type]?.$3,
|
|
||||||
fill: 1,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.toList(),
|
.toList(),
|
||||||
).padding(horizontal: 24),
|
).padding(horizontal: 24, top: 16),
|
||||||
const Gap(16),
|
const Gap(16),
|
||||||
|
if (data.description.isNotEmpty)
|
||||||
|
Text(
|
||||||
|
data.description,
|
||||||
|
maxLines: 2,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
).padding(horizontal: 26, bottom: 20),
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
|
@ -34,11 +34,14 @@ class UniversalImage extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final devicePixelRatio = MediaQuery.of(context).devicePixelRatio;
|
final devicePixelRatio = MediaQuery.of(context).devicePixelRatio;
|
||||||
final double? resizeHeight = cacheHeight != null ? (cacheHeight! * devicePixelRatio) : null;
|
final double? resizeHeight =
|
||||||
final double? resizeWidth = cacheWidth != null ? (cacheWidth! * devicePixelRatio) : null;
|
cacheHeight != null ? (cacheHeight! * devicePixelRatio) : null;
|
||||||
|
final double? resizeWidth =
|
||||||
|
cacheWidth != null ? (cacheWidth! * devicePixelRatio) : null;
|
||||||
|
|
||||||
return Image(
|
return Image(
|
||||||
filterQuality: filterQuality ?? context.read<ConfigProvider>().imageQuality,
|
filterQuality:
|
||||||
|
filterQuality ?? context.read<ConfigProvider>().imageQuality,
|
||||||
image: kIsWeb
|
image: kIsWeb
|
||||||
? UniversalImage.provider(url)
|
? UniversalImage.provider(url)
|
||||||
: ResizeImage(
|
: ResizeImage(
|
||||||
@ -52,7 +55,8 @@ class UniversalImage extends StatelessWidget {
|
|||||||
fit: fit,
|
fit: fit,
|
||||||
loadingBuilder: noProgressIndicator
|
loadingBuilder: noProgressIndicator
|
||||||
? null
|
? null
|
||||||
: (BuildContext context, Widget child, ImageChunkEvent? loadingProgress) {
|
: (BuildContext context, Widget child,
|
||||||
|
ImageChunkEvent? loadingProgress) {
|
||||||
if (loadingProgress == null) return child;
|
if (loadingProgress == null) return child;
|
||||||
return Container(
|
return Container(
|
||||||
constraints: BoxConstraints(maxHeight: 80),
|
constraints: BoxConstraints(maxHeight: 80),
|
||||||
@ -61,12 +65,15 @@ class UniversalImage extends StatelessWidget {
|
|||||||
tween: Tween(
|
tween: Tween(
|
||||||
begin: 0,
|
begin: 0,
|
||||||
end: loadingProgress.expectedTotalBytes != null
|
end: loadingProgress.expectedTotalBytes != null
|
||||||
? loadingProgress.cumulativeBytesLoaded / loadingProgress.expectedTotalBytes!
|
? loadingProgress.cumulativeBytesLoaded /
|
||||||
|
loadingProgress.expectedTotalBytes!
|
||||||
: 0,
|
: 0,
|
||||||
),
|
),
|
||||||
duration: const Duration(milliseconds: 300),
|
duration: const Duration(milliseconds: 300),
|
||||||
builder: (context, value, _) => CircularProgressIndicator(
|
builder: (context, value, _) => CircularProgressIndicator(
|
||||||
value: loadingProgress.expectedTotalBytes != null ? value.toDouble() : null,
|
value: loadingProgress.expectedTotalBytes != null
|
||||||
|
? value.toDouble()
|
||||||
|
: null,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -114,6 +121,7 @@ class AutoResizeUniversalImage extends StatelessWidget {
|
|||||||
final BoxFit? fit;
|
final BoxFit? fit;
|
||||||
final bool noProgressIndicator;
|
final bool noProgressIndicator;
|
||||||
final bool noErrorWidget;
|
final bool noErrorWidget;
|
||||||
|
final FilterQuality? filterQuality;
|
||||||
|
|
||||||
const AutoResizeUniversalImage(
|
const AutoResizeUniversalImage(
|
||||||
this.url, {
|
this.url, {
|
||||||
@ -123,6 +131,7 @@ class AutoResizeUniversalImage extends StatelessWidget {
|
|||||||
this.fit,
|
this.fit,
|
||||||
this.noProgressIndicator = false,
|
this.noProgressIndicator = false,
|
||||||
this.noErrorWidget = false,
|
this.noErrorWidget = false,
|
||||||
|
this.filterQuality,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -137,6 +146,7 @@ class AutoResizeUniversalImage extends StatelessWidget {
|
|||||||
noErrorWidget: noErrorWidget,
|
noErrorWidget: noErrorWidget,
|
||||||
cacheHeight: constraints.maxHeight,
|
cacheHeight: constraints.maxHeight,
|
||||||
cacheWidth: constraints.maxWidth,
|
cacheWidth: constraints.maxWidth,
|
||||||
|
filterQuality: filterQuality,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
56
pubspec.lock
56
pubspec.lock
@ -173,10 +173,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: built_value
|
name: built_value
|
||||||
sha256: "8b158ab94ec6913e480dc3f752418348b5ae099eb75868b5f4775f0572999c61"
|
sha256: ea90e81dc4a25a043d9bee692d20ed6d1c4a1662a28c03a96417446c093ed6b4
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "8.9.4"
|
version: "8.9.5"
|
||||||
cached_network_image:
|
cached_network_image:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -301,10 +301,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: croppy
|
name: croppy
|
||||||
sha256: bf99b00023df0d7d047e04d27d496d87cbefd968f578d0bd30f342ff75570a12
|
sha256: "99f4fbb4a4b44d2712e8dcd61c57c1acac151bd53cab11de3babec80407ed266"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.3"
|
version: "1.3.5"
|
||||||
cross_file:
|
cross_file:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -429,18 +429,18 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: drift
|
name: drift
|
||||||
sha256: "97d5832657d49f26e7a8e07de397ddc63790b039372878d5117af816d0fdb5cb"
|
sha256: "14a61af39d4584faf1d73b5b35e4b758a43008cf4c0fdb0576ec8e7032c0d9a5"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.25.1"
|
version: "2.26.0"
|
||||||
drift_dev:
|
drift_dev:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: drift_dev
|
name: drift_dev
|
||||||
sha256: f1db88482dbb016b9bbddddf746d5d0a6938b156ff20e07320052981f97388cc
|
sha256: "0d3f8b33b76cf1c6a82ee34d9511c40957549c4674b8f1688609e6d6c7306588"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.25.2"
|
version: "2.26.0"
|
||||||
drift_flutter:
|
drift_flutter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -710,6 +710,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.4.1"
|
version: "3.4.1"
|
||||||
|
flutter_card_swiper:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_card_swiper
|
||||||
|
sha256: "1eacbfab31b572223042e03409726553aec431abe48af48c8d591d376d070d3d"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "7.0.2"
|
||||||
flutter_colorpicker:
|
flutter_colorpicker:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -831,10 +839,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: flutter_map
|
name: flutter_map
|
||||||
sha256: bbf145e8220531f2f727608c431871c7457f3b134e513543913afd00fdc1cd47
|
sha256: f7d0379477274f323c3f3bc12d369a2b42eb86d1e7bd2970ae1ea3cff782449a
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "8.1.0"
|
version: "8.1.1"
|
||||||
flutter_markdown:
|
flutter_markdown:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -1177,10 +1185,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: image_picker_android
|
name: image_picker_android
|
||||||
sha256: "82652a75e3dd667a91187769a6a2cc81bd8c111bbead698d8e938d2b63e5e89a"
|
sha256: "8bd392ba8b0c8957a157ae0dc9fcf48c58e6c20908d5880aea1d79734df090e9"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.8.12+21"
|
version: "0.8.12+22"
|
||||||
image_picker_for_web:
|
image_picker_for_web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1409,10 +1417,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: material_symbols_icons
|
name: material_symbols_icons
|
||||||
sha256: "1403944c2a68dbdf934fca2b2115a372e70a4a185c136ab71a9d16e2108d0b14"
|
sha256: ca30ccbd97763353bde6bb1076aa4f4d17a40db0804384da77df142102aa225d
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.2805.1"
|
version: "4.2808.0"
|
||||||
media_kit:
|
media_kit:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -1601,10 +1609,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: path_provider_android
|
name: path_provider_android
|
||||||
sha256: "4adf4fd5423ec60a29506c76581bc05854c55e3a0b72d35bb28d661c9686edf2"
|
sha256: "0ca7359dad67fd7063cb2892ab0c0737b2daafd807cf1acecd62374c8fae6c12"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.15"
|
version: "2.2.16"
|
||||||
path_provider_foundation:
|
path_provider_foundation:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1785,10 +1793,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: pub_semver
|
name: pub_semver
|
||||||
sha256: "7b3cfbf654f3edd0c6298ecd5be782ce997ddf0e00531b9464b55245185bbbbd"
|
sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.5"
|
version: "2.2.0"
|
||||||
pubspec_parse:
|
pubspec_parse:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1953,10 +1961,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shared_preferences_android
|
name: shared_preferences_android
|
||||||
sha256: a768fc8ede5f0c8e6150476e14f38e2417c0864ca36bb4582be8e21925a03c22
|
sha256: "3ec7210872c4ba945e3244982918e502fa2bfb5230dff6832459ca0e1879b7ad"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.6"
|
version: "2.4.8"
|
||||||
shared_preferences_foundation:
|
shared_preferences_foundation:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -2118,10 +2126,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: sqlite3
|
name: sqlite3
|
||||||
sha256: "32b632dda27d664f85520093ed6f735ae5c49b5b75345afb8b19411bc59bb53d"
|
sha256: "310af39c40dd0bb2058538333c9d9840a2725ae0b9f77e4fd09ad6696aa8f66e"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.7.4"
|
version: "2.7.5"
|
||||||
sqlite3_flutter_libs:
|
sqlite3_flutter_libs:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -2326,10 +2334,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: url_launcher_android
|
name: url_launcher_android
|
||||||
sha256: "6fc2f56536ee873eeb867ad176ae15f304ccccc357848b351f6f0d8d4a40d193"
|
sha256: "1d0eae19bd7606ef60fe69ef3b312a437a16549476c42321d5dc1506c9ca3bf4"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.3.14"
|
version: "6.3.15"
|
||||||
url_launcher_ios:
|
url_launcher_ios:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
23
pubspec.yaml
23
pubspec.yaml
@ -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: 2.4.2+76
|
version: 2.4.2+78
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ^3.5.4
|
sdk: ^3.5.4
|
||||||
@ -138,6 +138,7 @@ dependencies:
|
|||||||
flutter_map: ^8.1.0
|
flutter_map: ^8.1.0
|
||||||
geolocator: ^13.0.2
|
geolocator: ^13.0.2
|
||||||
fast_rsa: ^3.8.0
|
fast_rsa: ^3.8.0
|
||||||
|
flutter_card_swiper: ^7.0.2
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
@ -187,18 +188,14 @@ flutter:
|
|||||||
# "family" key with the font family name, and a "fonts" key with a
|
# "family" key with the font family name, and a "fonts" key with a
|
||||||
# list giving the asset and other descriptors for the font. For
|
# list giving the asset and other descriptors for the font. For
|
||||||
# example:
|
# example:
|
||||||
# fonts:
|
fonts:
|
||||||
# - family: Schyler
|
- family: Nunito
|
||||||
# fonts:
|
fonts:
|
||||||
# - asset: fonts/Schyler-Regular.ttf
|
- asset: assets/fonts/Nunito-Regular.ttf
|
||||||
# - asset: fonts/Schyler-Italic.ttf
|
- asset: assets/fonts/Nunito-Bold.ttf
|
||||||
# style: italic
|
weight: 700
|
||||||
# - family: Trajan Pro
|
- asset: assets/fonts/Nunito-Italic.ttf
|
||||||
# fonts:
|
style: italic
|
||||||
# - asset: fonts/TrajanPro.ttf
|
|
||||||
# - asset: fonts/TrajanPro_Bold.ttf
|
|
||||||
# weight: 700
|
|
||||||
#
|
|
||||||
# For details regarding fonts from package dependencies,
|
# For details regarding fonts from package dependencies,
|
||||||
# see https://flutter.dev/to/font-from-package
|
# see https://flutter.dev/to/font-from-package
|
||||||
|
|
||||||
|
@ -1,192 +0,0 @@
|
|||||||
|
|
||||||
var CanvasKitInit = (() => {
|
|
||||||
var _scriptName = import.meta.url;
|
|
||||||
|
|
||||||
return (
|
|
||||||
function(moduleArg = {}) {
|
|
||||||
var moduleRtn;
|
|
||||||
|
|
||||||
var r=moduleArg,aa,ca,da=new Promise((a,b)=>{aa=a;ca=b}),ea="object"==typeof window,ha="function"==typeof importScripts;
|
|
||||||
(function(a){a.ce=a.ce||[];a.ce.push(function(){a.MakeSWCanvasSurface=function(b){var c=b,e="undefined"!==typeof OffscreenCanvas&&c instanceof OffscreenCanvas;if(!("undefined"!==typeof HTMLCanvasElement&&c instanceof HTMLCanvasElement||e||(c=document.getElementById(b),c)))throw"Canvas with id "+b+" was not found";if(b=a.MakeSurface(c.width,c.height))b.Ae=c;return b};a.MakeCanvasSurface||(a.MakeCanvasSurface=a.MakeSWCanvasSurface);a.MakeSurface=function(b,c){var e={width:b,height:c,colorType:a.ColorType.RGBA_8888,
|
|
||||||
alphaType:a.AlphaType.Unpremul,colorSpace:a.ColorSpace.SRGB},f=b*c*4,k=a._malloc(f);if(e=a.Surface._makeRasterDirect(e,k,4*b))e.Ae=null,e.$e=b,e.Xe=c,e.Ye=f,e.He=k,e.getCanvas().clear(a.TRANSPARENT);return e};a.MakeRasterDirectSurface=function(b,c,e){return a.Surface._makeRasterDirect(b,c.byteOffset,e)};a.Surface.prototype.flush=function(b){a.$d(this.Zd);this._flush();if(this.Ae){var c=new Uint8ClampedArray(a.HEAPU8.buffer,this.He,this.Ye);c=new ImageData(c,this.$e,this.Xe);b?this.Ae.getContext("2d").putImageData(c,
|
|
||||||
0,0,b[0],b[1],b[2]-b[0],b[3]-b[1]):this.Ae.getContext("2d").putImageData(c,0,0)}};a.Surface.prototype.dispose=function(){this.He&&a._free(this.He);this.delete()};a.$d=a.$d||function(){};a.Be=a.Be||function(){return null}})})(r);
|
|
||||||
(function(a){a.ce=a.ce||[];a.ce.push(function(){function b(l,p,v){return l&&l.hasOwnProperty(p)?l[p]:v}function c(l){var p=ja(ka);ka[p]=l;return p}function e(l){return l.naturalHeight||l.videoHeight||l.displayHeight||l.height}function f(l){return l.naturalWidth||l.videoWidth||l.displayWidth||l.width}function k(l,p,v,w){l.bindTexture(l.TEXTURE_2D,p);w||v.alphaType!==a.AlphaType.Premul||l.pixelStorei(l.UNPACK_PREMULTIPLY_ALPHA_WEBGL,!0);return p}function n(l,p,v){v||p.alphaType!==a.AlphaType.Premul||
|
|
||||||
l.pixelStorei(l.UNPACK_PREMULTIPLY_ALPHA_WEBGL,!1);l.bindTexture(l.TEXTURE_2D,null)}a.GetWebGLContext=function(l,p){if(!l)throw"null canvas passed into makeWebGLContext";var v={alpha:b(p,"alpha",1),depth:b(p,"depth",1),stencil:b(p,"stencil",8),antialias:b(p,"antialias",0),premultipliedAlpha:b(p,"premultipliedAlpha",1),preserveDrawingBuffer:b(p,"preserveDrawingBuffer",0),preferLowPowerToHighPerformance:b(p,"preferLowPowerToHighPerformance",0),failIfMajorPerformanceCaveat:b(p,"failIfMajorPerformanceCaveat",
|
|
||||||
0),enableExtensionsByDefault:b(p,"enableExtensionsByDefault",1),explicitSwapControl:b(p,"explicitSwapControl",0),renderViaOffscreenBackBuffer:b(p,"renderViaOffscreenBackBuffer",0)};v.majorVersion=p&&p.majorVersion?p.majorVersion:"undefined"!==typeof WebGL2RenderingContext?2:1;if(v.explicitSwapControl)throw"explicitSwapControl is not supported";l=la(l,v);if(!l)return 0;oa(l);z.le.getExtension("WEBGL_debug_renderer_info");return l};a.deleteContext=function(l){z===pa[l]&&(z=null);"object"==typeof JSEvents&&
|
|
||||||
JSEvents.Af(pa[l].le.canvas);pa[l]&&pa[l].le.canvas&&(pa[l].le.canvas.Ve=void 0);pa[l]=null};a._setTextureCleanup({deleteTexture:function(l,p){var v=ka[p];v&&pa[l].le.deleteTexture(v);ka[p]=null}});a.MakeWebGLContext=function(l){if(!this.$d(l))return null;var p=this._MakeGrContext();if(!p)return null;p.Zd=l;var v=p.delete.bind(p);p["delete"]=function(){a.$d(this.Zd);v()}.bind(p);return z.Je=p};a.MakeGrContext=a.MakeWebGLContext;a.GrDirectContext.prototype.getResourceCacheLimitBytes=function(){a.$d(this.Zd);
|
|
||||||
this._getResourceCacheLimitBytes()};a.GrDirectContext.prototype.getResourceCacheUsageBytes=function(){a.$d(this.Zd);this._getResourceCacheUsageBytes()};a.GrDirectContext.prototype.releaseResourcesAndAbandonContext=function(){a.$d(this.Zd);this._releaseResourcesAndAbandonContext()};a.GrDirectContext.prototype.setResourceCacheLimitBytes=function(l){a.$d(this.Zd);this._setResourceCacheLimitBytes(l)};a.MakeOnScreenGLSurface=function(l,p,v,w,A,D){if(!this.$d(l.Zd))return null;p=void 0===A||void 0===D?
|
|
||||||
this._MakeOnScreenGLSurface(l,p,v,w):this._MakeOnScreenGLSurface(l,p,v,w,A,D);if(!p)return null;p.Zd=l.Zd;return p};a.MakeRenderTarget=function(){var l=arguments[0];if(!this.$d(l.Zd))return null;if(3===arguments.length){var p=this._MakeRenderTargetWH(l,arguments[1],arguments[2]);if(!p)return null}else if(2===arguments.length){if(p=this._MakeRenderTargetII(l,arguments[1]),!p)return null}else return null;p.Zd=l.Zd;return p};a.MakeWebGLCanvasSurface=function(l,p,v){p=p||null;var w=l,A="undefined"!==
|
|
||||||
typeof OffscreenCanvas&&w instanceof OffscreenCanvas;if(!("undefined"!==typeof HTMLCanvasElement&&w instanceof HTMLCanvasElement||A||(w=document.getElementById(l),w)))throw"Canvas with id "+l+" was not found";l=this.GetWebGLContext(w,v);if(!l||0>l)throw"failed to create webgl context: err "+l;l=this.MakeWebGLContext(l);p=this.MakeOnScreenGLSurface(l,w.width,w.height,p);return p?p:(p=w.cloneNode(!0),w.parentNode.replaceChild(p,w),p.classList.add("ck-replaced"),a.MakeSWCanvasSurface(p))};a.MakeCanvasSurface=
|
|
||||||
a.MakeWebGLCanvasSurface;a.Surface.prototype.makeImageFromTexture=function(l,p){a.$d(this.Zd);l=c(l);if(p=this._makeImageFromTexture(this.Zd,l,p))p.ue=l;return p};a.Surface.prototype.makeImageFromTextureSource=function(l,p,v){p||={height:e(l),width:f(l),colorType:a.ColorType.RGBA_8888,alphaType:v?a.AlphaType.Premul:a.AlphaType.Unpremul};p.colorSpace||(p.colorSpace=a.ColorSpace.SRGB);a.$d(this.Zd);var w=z.le;v=k(w,w.createTexture(),p,v);2===z.version?w.texImage2D(w.TEXTURE_2D,0,w.RGBA,p.width,p.height,
|
|
||||||
0,w.RGBA,w.UNSIGNED_BYTE,l):w.texImage2D(w.TEXTURE_2D,0,w.RGBA,w.RGBA,w.UNSIGNED_BYTE,l);n(w,p);this._resetContext();return this.makeImageFromTexture(v,p)};a.Surface.prototype.updateTextureFromSource=function(l,p,v){if(l.ue){a.$d(this.Zd);var w=l.getImageInfo(),A=z.le,D=k(A,ka[l.ue],w,v);2===z.version?A.texImage2D(A.TEXTURE_2D,0,A.RGBA,f(p),e(p),0,A.RGBA,A.UNSIGNED_BYTE,p):A.texImage2D(A.TEXTURE_2D,0,A.RGBA,A.RGBA,A.UNSIGNED_BYTE,p);n(A,w,v);this._resetContext();ka[l.ue]=null;l.ue=c(D);w.colorSpace=
|
|
||||||
l.getColorSpace();p=this._makeImageFromTexture(this.Zd,l.ue,w);v=l.Yd.ae;A=l.Yd.ee;l.Yd.ae=p.Yd.ae;l.Yd.ee=p.Yd.ee;p.Yd.ae=v;p.Yd.ee=A;p.delete();w.colorSpace.delete()}};a.MakeLazyImageFromTextureSource=function(l,p,v){p||={height:e(l),width:f(l),colorType:a.ColorType.RGBA_8888,alphaType:v?a.AlphaType.Premul:a.AlphaType.Unpremul};p.colorSpace||(p.colorSpace=a.ColorSpace.SRGB);var w={makeTexture:function(){var A=z,D=A.le,I=k(D,D.createTexture(),p,v);2===A.version?D.texImage2D(D.TEXTURE_2D,0,D.RGBA,
|
|
||||||
p.width,p.height,0,D.RGBA,D.UNSIGNED_BYTE,l):D.texImage2D(D.TEXTURE_2D,0,D.RGBA,D.RGBA,D.UNSIGNED_BYTE,l);n(D,p,v);return c(I)},freeSrc:function(){}};"VideoFrame"===l.constructor.name&&(w.freeSrc=function(){l.close()});return a.Image._makeFromGenerator(p,w)};a.$d=function(l){return l?oa(l):!1};a.Be=function(){return z&&z.Je&&!z.Je.isDeleted()?z.Je:null}})})(r);
|
|
||||||
(function(a){function b(g){return(f(255*g[3])<<24|f(255*g[0])<<16|f(255*g[1])<<8|f(255*g[2])<<0)>>>0}function c(g){if(g&&g._ck)return g;if(g instanceof Float32Array){for(var d=Math.floor(g.length/4),h=new Uint32Array(d),m=0;m<d;m++)h[m]=b(g.slice(4*m,4*(m+1)));return h}if(g instanceof Uint32Array)return g;if(g instanceof Array&&g[0]instanceof Float32Array)return g.map(b)}function e(g){if(void 0===g)return 1;var d=parseFloat(g);return g&&-1!==g.indexOf("%")?d/100:d}function f(g){return Math.round(Math.max(0,
|
|
||||||
Math.min(g||0,255)))}function k(g,d){d&&d._ck||a._free(g)}function n(g,d,h){if(!g||!g.length)return K;if(g&&g._ck)return g.byteOffset;var m=a[d].BYTES_PER_ELEMENT;h||=a._malloc(g.length*m);a[d].set(g,h/m);return h}function l(g){var d={he:K,count:g.length,colorType:a.ColorType.RGBA_F32};if(g instanceof Float32Array)d.he=n(g,"HEAPF32"),d.count=g.length/4;else if(g instanceof Uint32Array)d.he=n(g,"HEAPU32"),d.colorType=a.ColorType.RGBA_8888;else if(g instanceof Array){if(g&&g.length){for(var h=a._malloc(16*
|
|
||||||
g.length),m=0,t=h/4,u=0;u<g.length;u++)for(var x=0;4>x;x++)a.HEAPF32[t+m]=g[u][x],m++;g=h}else g=K;d.he=g}else throw"Invalid argument to copyFlexibleColorArray, Not a color array "+typeof g;return d}function p(g){if(!g)return K;var d=ba.toTypedArray();if(g.length){if(6===g.length||9===g.length)return n(g,"HEAPF32",P),6===g.length&&a.HEAPF32.set(Wc,6+P/4),P;if(16===g.length)return d[0]=g[0],d[1]=g[1],d[2]=g[3],d[3]=g[4],d[4]=g[5],d[5]=g[7],d[6]=g[12],d[7]=g[13],d[8]=g[15],P;throw"invalid matrix size";
|
|
||||||
}if(void 0===g.m11)throw"invalid matrix argument";d[0]=g.m11;d[1]=g.m21;d[2]=g.m41;d[3]=g.m12;d[4]=g.m22;d[5]=g.m42;d[6]=g.m14;d[7]=g.m24;d[8]=g.m44;return P}function v(g){if(!g)return K;var d=Y.toTypedArray();if(g.length){if(16!==g.length&&6!==g.length&&9!==g.length)throw"invalid matrix size";if(16===g.length)return n(g,"HEAPF32",ma);d.fill(0);d[0]=g[0];d[1]=g[1];d[3]=g[2];d[4]=g[3];d[5]=g[4];d[7]=g[5];d[10]=1;d[12]=g[6];d[13]=g[7];d[15]=g[8];6===g.length&&(d[12]=0,d[13]=0,d[15]=1);return ma}if(void 0===
|
|
||||||
g.m11)throw"invalid matrix argument";d[0]=g.m11;d[1]=g.m21;d[2]=g.m31;d[3]=g.m41;d[4]=g.m12;d[5]=g.m22;d[6]=g.m32;d[7]=g.m42;d[8]=g.m13;d[9]=g.m23;d[10]=g.m33;d[11]=g.m43;d[12]=g.m14;d[13]=g.m24;d[14]=g.m34;d[15]=g.m44;return ma}function w(g,d){return n(g,"HEAPF32",d||ia)}function A(g,d,h,m){var t=Ea.toTypedArray();t[0]=g;t[1]=d;t[2]=h;t[3]=m;return ia}function D(g){for(var d=new Float32Array(4),h=0;4>h;h++)d[h]=a.HEAPF32[g/4+h];return d}function I(g,d){return n(g,"HEAPF32",d||W)}function R(g,d){return n(g,
|
|
||||||
"HEAPF32",d||ub)}a.Color=function(g,d,h,m){void 0===m&&(m=1);return a.Color4f(f(g)/255,f(d)/255,f(h)/255,m)};a.ColorAsInt=function(g,d,h,m){void 0===m&&(m=255);return(f(m)<<24|f(g)<<16|f(d)<<8|f(h)<<0&268435455)>>>0};a.Color4f=function(g,d,h,m){void 0===m&&(m=1);return Float32Array.of(g,d,h,m)};Object.defineProperty(a,"TRANSPARENT",{get:function(){return a.Color4f(0,0,0,0)}});Object.defineProperty(a,"BLACK",{get:function(){return a.Color4f(0,0,0,1)}});Object.defineProperty(a,"WHITE",{get:function(){return a.Color4f(1,
|
|
||||||
1,1,1)}});Object.defineProperty(a,"RED",{get:function(){return a.Color4f(1,0,0,1)}});Object.defineProperty(a,"GREEN",{get:function(){return a.Color4f(0,1,0,1)}});Object.defineProperty(a,"BLUE",{get:function(){return a.Color4f(0,0,1,1)}});Object.defineProperty(a,"YELLOW",{get:function(){return a.Color4f(1,1,0,1)}});Object.defineProperty(a,"CYAN",{get:function(){return a.Color4f(0,1,1,1)}});Object.defineProperty(a,"MAGENTA",{get:function(){return a.Color4f(1,0,1,1)}});a.getColorComponents=function(g){return[Math.floor(255*
|
|
||||||
g[0]),Math.floor(255*g[1]),Math.floor(255*g[2]),g[3]]};a.parseColorString=function(g,d){g=g.toLowerCase();if(g.startsWith("#")){d=255;switch(g.length){case 9:d=parseInt(g.slice(7,9),16);case 7:var h=parseInt(g.slice(1,3),16);var m=parseInt(g.slice(3,5),16);var t=parseInt(g.slice(5,7),16);break;case 5:d=17*parseInt(g.slice(4,5),16);case 4:h=17*parseInt(g.slice(1,2),16),m=17*parseInt(g.slice(2,3),16),t=17*parseInt(g.slice(3,4),16)}return a.Color(h,m,t,d/255)}return g.startsWith("rgba")?(g=g.slice(5,
|
|
||||||
-1),g=g.split(","),a.Color(+g[0],+g[1],+g[2],e(g[3]))):g.startsWith("rgb")?(g=g.slice(4,-1),g=g.split(","),a.Color(+g[0],+g[1],+g[2],e(g[3]))):g.startsWith("gray(")||g.startsWith("hsl")||!d||(g=d[g],void 0===g)?a.BLACK:g};a.multiplyByAlpha=function(g,d){g=g.slice();g[3]=Math.max(0,Math.min(g[3]*d,1));return g};a.Malloc=function(g,d){var h=a._malloc(d*g.BYTES_PER_ELEMENT);return{_ck:!0,length:d,byteOffset:h,qe:null,subarray:function(m,t){m=this.toTypedArray().subarray(m,t);m._ck=!0;return m},toTypedArray:function(){if(this.qe&&
|
|
||||||
this.qe.length)return this.qe;this.qe=new g(a.HEAPU8.buffer,h,d);this.qe._ck=!0;return this.qe}}};a.Free=function(g){a._free(g.byteOffset);g.byteOffset=K;g.toTypedArray=null;g.qe=null};var P=K,ba,ma=K,Y,ia=K,Ea,fa,W=K,Ub,Ba=K,Vb,vb=K,Wb,wb=K,$a,Na=K,Xb,ub=K,Yb,Zb=K,Wc=Float32Array.of(0,0,1),K=0;a.onRuntimeInitialized=function(){function g(d,h,m,t,u,x,C){x||(x=4*t.width,t.colorType===a.ColorType.RGBA_F16?x*=2:t.colorType===a.ColorType.RGBA_F32&&(x*=4));var G=x*t.height;var F=u?u.byteOffset:a._malloc(G);
|
|
||||||
if(C?!d._readPixels(t,F,x,h,m,C):!d._readPixels(t,F,x,h,m))return u||a._free(F),null;if(u)return u.toTypedArray();switch(t.colorType){case a.ColorType.RGBA_8888:case a.ColorType.RGBA_F16:d=(new Uint8Array(a.HEAPU8.buffer,F,G)).slice();break;case a.ColorType.RGBA_F32:d=(new Float32Array(a.HEAPU8.buffer,F,G)).slice();break;default:return null}a._free(F);return d}Ea=a.Malloc(Float32Array,4);ia=Ea.byteOffset;Y=a.Malloc(Float32Array,16);ma=Y.byteOffset;ba=a.Malloc(Float32Array,9);P=ba.byteOffset;Xb=a.Malloc(Float32Array,
|
|
||||||
12);ub=Xb.byteOffset;Yb=a.Malloc(Float32Array,12);Zb=Yb.byteOffset;fa=a.Malloc(Float32Array,4);W=fa.byteOffset;Ub=a.Malloc(Float32Array,4);Ba=Ub.byteOffset;Vb=a.Malloc(Float32Array,3);vb=Vb.byteOffset;Wb=a.Malloc(Float32Array,3);wb=Wb.byteOffset;$a=a.Malloc(Int32Array,4);Na=$a.byteOffset;a.ColorSpace.SRGB=a.ColorSpace._MakeSRGB();a.ColorSpace.DISPLAY_P3=a.ColorSpace._MakeDisplayP3();a.ColorSpace.ADOBE_RGB=a.ColorSpace._MakeAdobeRGB();a.GlyphRunFlags={IsWhiteSpace:a._GlyphRunFlags_isWhiteSpace};a.Path.MakeFromCmds=
|
|
||||||
function(d){var h=n(d,"HEAPF32"),m=a.Path._MakeFromCmds(h,d.length);k(h,d);return m};a.Path.MakeFromVerbsPointsWeights=function(d,h,m){var t=n(d,"HEAPU8"),u=n(h,"HEAPF32"),x=n(m,"HEAPF32"),C=a.Path._MakeFromVerbsPointsWeights(t,d.length,u,h.length,x,m&&m.length||0);k(t,d);k(u,h);k(x,m);return C};a.Path.prototype.addArc=function(d,h,m){d=I(d);this._addArc(d,h,m);return this};a.Path.prototype.addCircle=function(d,h,m,t){this._addCircle(d,h,m,!!t);return this};a.Path.prototype.addOval=function(d,h,m){void 0===
|
|
||||||
m&&(m=1);d=I(d);this._addOval(d,!!h,m);return this};a.Path.prototype.addPath=function(){var d=Array.prototype.slice.call(arguments),h=d[0],m=!1;"boolean"===typeof d[d.length-1]&&(m=d.pop());if(1===d.length)this._addPath(h,1,0,0,0,1,0,0,0,1,m);else if(2===d.length)d=d[1],this._addPath(h,d[0],d[1],d[2],d[3],d[4],d[5],d[6]||0,d[7]||0,d[8]||1,m);else if(7===d.length||10===d.length)this._addPath(h,d[1],d[2],d[3],d[4],d[5],d[6],d[7]||0,d[8]||0,d[9]||1,m);else return null;return this};a.Path.prototype.addPoly=
|
|
||||||
function(d,h){var m=n(d,"HEAPF32");this._addPoly(m,d.length/2,h);k(m,d);return this};a.Path.prototype.addRect=function(d,h){d=I(d);this._addRect(d,!!h);return this};a.Path.prototype.addRRect=function(d,h){d=R(d);this._addRRect(d,!!h);return this};a.Path.prototype.addVerbsPointsWeights=function(d,h,m){var t=n(d,"HEAPU8"),u=n(h,"HEAPF32"),x=n(m,"HEAPF32");this._addVerbsPointsWeights(t,d.length,u,h.length,x,m&&m.length||0);k(t,d);k(u,h);k(x,m)};a.Path.prototype.arc=function(d,h,m,t,u,x){d=a.LTRBRect(d-
|
|
||||||
m,h-m,d+m,h+m);u=(u-t)/Math.PI*180-360*!!x;x=new a.Path;x.addArc(d,t/Math.PI*180,u);this.addPath(x,!0);x.delete();return this};a.Path.prototype.arcToOval=function(d,h,m,t){d=I(d);this._arcToOval(d,h,m,t);return this};a.Path.prototype.arcToRotated=function(d,h,m,t,u,x,C){this._arcToRotated(d,h,m,!!t,!!u,x,C);return this};a.Path.prototype.arcToTangent=function(d,h,m,t,u){this._arcToTangent(d,h,m,t,u);return this};a.Path.prototype.close=function(){this._close();return this};a.Path.prototype.conicTo=
|
|
||||||
function(d,h,m,t,u){this._conicTo(d,h,m,t,u);return this};a.Path.prototype.computeTightBounds=function(d){this._computeTightBounds(W);var h=fa.toTypedArray();return d?(d.set(h),d):h.slice()};a.Path.prototype.cubicTo=function(d,h,m,t,u,x){this._cubicTo(d,h,m,t,u,x);return this};a.Path.prototype.dash=function(d,h,m){return this._dash(d,h,m)?this:null};a.Path.prototype.getBounds=function(d){this._getBounds(W);var h=fa.toTypedArray();return d?(d.set(h),d):h.slice()};a.Path.prototype.lineTo=function(d,
|
|
||||||
h){this._lineTo(d,h);return this};a.Path.prototype.moveTo=function(d,h){this._moveTo(d,h);return this};a.Path.prototype.offset=function(d,h){this._transform(1,0,d,0,1,h,0,0,1);return this};a.Path.prototype.quadTo=function(d,h,m,t){this._quadTo(d,h,m,t);return this};a.Path.prototype.rArcTo=function(d,h,m,t,u,x,C){this._rArcTo(d,h,m,t,u,x,C);return this};a.Path.prototype.rConicTo=function(d,h,m,t,u){this._rConicTo(d,h,m,t,u);return this};a.Path.prototype.rCubicTo=function(d,h,m,t,u,x){this._rCubicTo(d,
|
|
||||||
h,m,t,u,x);return this};a.Path.prototype.rLineTo=function(d,h){this._rLineTo(d,h);return this};a.Path.prototype.rMoveTo=function(d,h){this._rMoveTo(d,h);return this};a.Path.prototype.rQuadTo=function(d,h,m,t){this._rQuadTo(d,h,m,t);return this};a.Path.prototype.stroke=function(d){d=d||{};d.width=d.width||1;d.miter_limit=d.miter_limit||4;d.cap=d.cap||a.StrokeCap.Butt;d.join=d.join||a.StrokeJoin.Miter;d.precision=d.precision||1;return this._stroke(d)?this:null};a.Path.prototype.transform=function(){if(1===
|
|
||||||
arguments.length){var d=arguments[0];this._transform(d[0],d[1],d[2],d[3],d[4],d[5],d[6]||0,d[7]||0,d[8]||1)}else if(6===arguments.length||9===arguments.length)d=arguments,this._transform(d[0],d[1],d[2],d[3],d[4],d[5],d[6]||0,d[7]||0,d[8]||1);else throw"transform expected to take 1 or 9 arguments. Got "+arguments.length;return this};a.Path.prototype.trim=function(d,h,m){return this._trim(d,h,!!m)?this:null};a.Image.prototype.encodeToBytes=function(d,h){var m=a.Be();d=d||a.ImageFormat.PNG;h=h||100;
|
|
||||||
return m?this._encodeToBytes(d,h,m):this._encodeToBytes(d,h)};a.Image.prototype.makeShaderCubic=function(d,h,m,t,u){u=p(u);return this._makeShaderCubic(d,h,m,t,u)};a.Image.prototype.makeShaderOptions=function(d,h,m,t,u){u=p(u);return this._makeShaderOptions(d,h,m,t,u)};a.Image.prototype.readPixels=function(d,h,m,t,u){var x=a.Be();return g(this,d,h,m,t,u,x)};a.Canvas.prototype.clear=function(d){a.$d(this.Zd);d=w(d);this._clear(d)};a.Canvas.prototype.clipRRect=function(d,h,m){a.$d(this.Zd);d=R(d);this._clipRRect(d,
|
|
||||||
h,m)};a.Canvas.prototype.clipRect=function(d,h,m){a.$d(this.Zd);d=I(d);this._clipRect(d,h,m)};a.Canvas.prototype.concat=function(d){a.$d(this.Zd);d=v(d);this._concat(d)};a.Canvas.prototype.drawArc=function(d,h,m,t,u){a.$d(this.Zd);d=I(d);this._drawArc(d,h,m,t,u)};a.Canvas.prototype.drawAtlas=function(d,h,m,t,u,x,C){if(d&&t&&h&&m&&h.length===m.length){a.$d(this.Zd);u||(u=a.BlendMode.SrcOver);var G=n(h,"HEAPF32"),F=n(m,"HEAPF32"),T=m.length/4,U=n(c(x),"HEAPU32");if(C&&"B"in C&&"C"in C)this._drawAtlasCubic(d,
|
|
||||||
F,G,U,T,u,C.B,C.C,t);else{let q=a.FilterMode.Linear,y=a.MipmapMode.None;C&&(q=C.filter,"mipmap"in C&&(y=C.mipmap));this._drawAtlasOptions(d,F,G,U,T,u,q,y,t)}k(G,h);k(F,m);k(U,x)}};a.Canvas.prototype.drawCircle=function(d,h,m,t){a.$d(this.Zd);this._drawCircle(d,h,m,t)};a.Canvas.prototype.drawColor=function(d,h){a.$d(this.Zd);d=w(d);void 0!==h?this._drawColor(d,h):this._drawColor(d)};a.Canvas.prototype.drawColorInt=function(d,h){a.$d(this.Zd);this._drawColorInt(d,h||a.BlendMode.SrcOver)};a.Canvas.prototype.drawColorComponents=
|
|
||||||
function(d,h,m,t,u){a.$d(this.Zd);d=A(d,h,m,t);void 0!==u?this._drawColor(d,u):this._drawColor(d)};a.Canvas.prototype.drawDRRect=function(d,h,m){a.$d(this.Zd);d=R(d,ub);h=R(h,Zb);this._drawDRRect(d,h,m)};a.Canvas.prototype.drawImage=function(d,h,m,t){a.$d(this.Zd);this._drawImage(d,h,m,t||null)};a.Canvas.prototype.drawImageCubic=function(d,h,m,t,u,x){a.$d(this.Zd);this._drawImageCubic(d,h,m,t,u,x||null)};a.Canvas.prototype.drawImageOptions=function(d,h,m,t,u,x){a.$d(this.Zd);this._drawImageOptions(d,
|
|
||||||
h,m,t,u,x||null)};a.Canvas.prototype.drawImageNine=function(d,h,m,t,u){a.$d(this.Zd);h=n(h,"HEAP32",Na);m=I(m);this._drawImageNine(d,h,m,t,u||null)};a.Canvas.prototype.drawImageRect=function(d,h,m,t,u){a.$d(this.Zd);I(h,W);I(m,Ba);this._drawImageRect(d,W,Ba,t,!!u)};a.Canvas.prototype.drawImageRectCubic=function(d,h,m,t,u,x){a.$d(this.Zd);I(h,W);I(m,Ba);this._drawImageRectCubic(d,W,Ba,t,u,x||null)};a.Canvas.prototype.drawImageRectOptions=function(d,h,m,t,u,x){a.$d(this.Zd);I(h,W);I(m,Ba);this._drawImageRectOptions(d,
|
|
||||||
W,Ba,t,u,x||null)};a.Canvas.prototype.drawLine=function(d,h,m,t,u){a.$d(this.Zd);this._drawLine(d,h,m,t,u)};a.Canvas.prototype.drawOval=function(d,h){a.$d(this.Zd);d=I(d);this._drawOval(d,h)};a.Canvas.prototype.drawPaint=function(d){a.$d(this.Zd);this._drawPaint(d)};a.Canvas.prototype.drawParagraph=function(d,h,m){a.$d(this.Zd);this._drawParagraph(d,h,m)};a.Canvas.prototype.drawPatch=function(d,h,m,t,u){if(24>d.length)throw"Need 12 cubic points";if(h&&4>h.length)throw"Need 4 colors";if(m&&8>m.length)throw"Need 4 shader coordinates";
|
|
||||||
a.$d(this.Zd);const x=n(d,"HEAPF32"),C=h?n(c(h),"HEAPU32"):K,G=m?n(m,"HEAPF32"):K;t||(t=a.BlendMode.Modulate);this._drawPatch(x,C,G,t,u);k(G,m);k(C,h);k(x,d)};a.Canvas.prototype.drawPath=function(d,h){a.$d(this.Zd);this._drawPath(d,h)};a.Canvas.prototype.drawPicture=function(d){a.$d(this.Zd);this._drawPicture(d)};a.Canvas.prototype.drawPoints=function(d,h,m){a.$d(this.Zd);var t=n(h,"HEAPF32");this._drawPoints(d,t,h.length/2,m);k(t,h)};a.Canvas.prototype.drawRRect=function(d,h){a.$d(this.Zd);d=R(d);
|
|
||||||
this._drawRRect(d,h)};a.Canvas.prototype.drawRect=function(d,h){a.$d(this.Zd);d=I(d);this._drawRect(d,h)};a.Canvas.prototype.drawRect4f=function(d,h,m,t,u){a.$d(this.Zd);this._drawRect4f(d,h,m,t,u)};a.Canvas.prototype.drawShadow=function(d,h,m,t,u,x,C){a.$d(this.Zd);var G=n(u,"HEAPF32"),F=n(x,"HEAPF32");h=n(h,"HEAPF32",vb);m=n(m,"HEAPF32",wb);this._drawShadow(d,h,m,t,G,F,C);k(G,u);k(F,x)};a.getShadowLocalBounds=function(d,h,m,t,u,x,C){d=p(d);m=n(m,"HEAPF32",vb);t=n(t,"HEAPF32",wb);if(!this._getShadowLocalBounds(d,
|
|
||||||
h,m,t,u,x,W))return null;h=fa.toTypedArray();return C?(C.set(h),C):h.slice()};a.Canvas.prototype.drawTextBlob=function(d,h,m,t){a.$d(this.Zd);this._drawTextBlob(d,h,m,t)};a.Canvas.prototype.drawVertices=function(d,h,m){a.$d(this.Zd);this._drawVertices(d,h,m)};a.Canvas.prototype.getDeviceClipBounds=function(d){this._getDeviceClipBounds(Na);var h=$a.toTypedArray();d?d.set(h):d=h.slice();return d};a.Canvas.prototype.quickReject=function(d){d=I(d);return this._quickReject(d)};a.Canvas.prototype.getLocalToDevice=
|
|
||||||
function(){this._getLocalToDevice(ma);for(var d=ma,h=Array(16),m=0;16>m;m++)h[m]=a.HEAPF32[d/4+m];return h};a.Canvas.prototype.getTotalMatrix=function(){this._getTotalMatrix(P);for(var d=Array(9),h=0;9>h;h++)d[h]=a.HEAPF32[P/4+h];return d};a.Canvas.prototype.makeSurface=function(d){d=this._makeSurface(d);d.Zd=this.Zd;return d};a.Canvas.prototype.readPixels=function(d,h,m,t,u){a.$d(this.Zd);return g(this,d,h,m,t,u)};a.Canvas.prototype.saveLayer=function(d,h,m,t,u){h=I(h);return this._saveLayer(d||
|
|
||||||
null,h,m||null,t||0,u||a.TileMode.Clamp)};a.Canvas.prototype.writePixels=function(d,h,m,t,u,x,C,G){if(d.byteLength%(h*m))throw"pixels length must be a multiple of the srcWidth * srcHeight";a.$d(this.Zd);var F=d.byteLength/(h*m);x=x||a.AlphaType.Unpremul;C=C||a.ColorType.RGBA_8888;G=G||a.ColorSpace.SRGB;var T=F*h;F=n(d,"HEAPU8");h=this._writePixels({width:h,height:m,colorType:C,alphaType:x,colorSpace:G},F,T,t,u);k(F,d);return h};a.ColorFilter.MakeBlend=function(d,h,m){d=w(d);m=m||a.ColorSpace.SRGB;
|
|
||||||
return a.ColorFilter._MakeBlend(d,h,m)};a.ColorFilter.MakeMatrix=function(d){if(!d||20!==d.length)throw"invalid color matrix";var h=n(d,"HEAPF32"),m=a.ColorFilter._makeMatrix(h);k(h,d);return m};a.ContourMeasure.prototype.getPosTan=function(d,h){this._getPosTan(d,W);d=fa.toTypedArray();return h?(h.set(d),h):d.slice()};a.ImageFilter.prototype.getOutputBounds=function(d,h,m){d=I(d,W);h=p(h);this._getOutputBounds(d,h,Na);h=$a.toTypedArray();return m?(m.set(h),m):h.slice()};a.ImageFilter.MakeDropShadow=
|
|
||||||
function(d,h,m,t,u,x){u=w(u,ia);return a.ImageFilter._MakeDropShadow(d,h,m,t,u,x)};a.ImageFilter.MakeDropShadowOnly=function(d,h,m,t,u,x){u=w(u,ia);return a.ImageFilter._MakeDropShadowOnly(d,h,m,t,u,x)};a.ImageFilter.MakeImage=function(d,h,m,t){m=I(m,W);t=I(t,Ba);if("B"in h&&"C"in h)return a.ImageFilter._MakeImageCubic(d,h.B,h.C,m,t);const u=h.filter;let x=a.MipmapMode.None;"mipmap"in h&&(x=h.mipmap);return a.ImageFilter._MakeImageOptions(d,u,x,m,t)};a.ImageFilter.MakeMatrixTransform=function(d,h,
|
|
||||||
m){d=p(d);if("B"in h&&"C"in h)return a.ImageFilter._MakeMatrixTransformCubic(d,h.B,h.C,m);const t=h.filter;let u=a.MipmapMode.None;"mipmap"in h&&(u=h.mipmap);return a.ImageFilter._MakeMatrixTransformOptions(d,t,u,m)};a.Paint.prototype.getColor=function(){this._getColor(ia);return D(ia)};a.Paint.prototype.setColor=function(d,h){h=h||null;d=w(d);this._setColor(d,h)};a.Paint.prototype.setColorComponents=function(d,h,m,t,u){u=u||null;d=A(d,h,m,t);this._setColor(d,u)};a.Path.prototype.getPoint=function(d,
|
|
||||||
h){this._getPoint(d,W);d=fa.toTypedArray();return h?(h[0]=d[0],h[1]=d[1],h):d.slice(0,2)};a.Picture.prototype.makeShader=function(d,h,m,t,u){t=p(t);u=I(u);return this._makeShader(d,h,m,t,u)};a.Picture.prototype.cullRect=function(d){this._cullRect(W);var h=fa.toTypedArray();return d?(d.set(h),d):h.slice()};a.PictureRecorder.prototype.beginRecording=function(d,h){d=I(d);return this._beginRecording(d,!!h)};a.Surface.prototype.getCanvas=function(){var d=this._getCanvas();d.Zd=this.Zd;return d};a.Surface.prototype.makeImageSnapshot=
|
|
||||||
function(d){a.$d(this.Zd);d=n(d,"HEAP32",Na);return this._makeImageSnapshot(d)};a.Surface.prototype.makeSurface=function(d){a.$d(this.Zd);d=this._makeSurface(d);d.Zd=this.Zd;return d};a.Surface.prototype.Ze=function(d,h){this.te||(this.te=this.getCanvas());return requestAnimationFrame(function(){a.$d(this.Zd);d(this.te);this.flush(h)}.bind(this))};a.Surface.prototype.requestAnimationFrame||(a.Surface.prototype.requestAnimationFrame=a.Surface.prototype.Ze);a.Surface.prototype.We=function(d,h){this.te||
|
|
||||||
(this.te=this.getCanvas());requestAnimationFrame(function(){a.$d(this.Zd);d(this.te);this.flush(h);this.dispose()}.bind(this))};a.Surface.prototype.drawOnce||(a.Surface.prototype.drawOnce=a.Surface.prototype.We);a.PathEffect.MakeDash=function(d,h){h||=0;if(!d.length||1===d.length%2)throw"Intervals array must have even length";var m=n(d,"HEAPF32");h=a.PathEffect._MakeDash(m,d.length,h);k(m,d);return h};a.PathEffect.MakeLine2D=function(d,h){h=p(h);return a.PathEffect._MakeLine2D(d,h)};a.PathEffect.MakePath2D=
|
|
||||||
function(d,h){d=p(d);return a.PathEffect._MakePath2D(d,h)};a.Shader.MakeColor=function(d,h){h=h||null;d=w(d);return a.Shader._MakeColor(d,h)};a.Shader.Blend=a.Shader.MakeBlend;a.Shader.Color=a.Shader.MakeColor;a.Shader.MakeLinearGradient=function(d,h,m,t,u,x,C,G){G=G||null;var F=l(m),T=n(t,"HEAPF32");C=C||0;x=p(x);var U=fa.toTypedArray();U.set(d);U.set(h,2);d=a.Shader._MakeLinearGradient(W,F.he,F.colorType,T,F.count,u,C,x,G);k(F.he,m);t&&k(T,t);return d};a.Shader.MakeRadialGradient=function(d,h,m,
|
|
||||||
t,u,x,C,G){G=G||null;var F=l(m),T=n(t,"HEAPF32");C=C||0;x=p(x);d=a.Shader._MakeRadialGradient(d[0],d[1],h,F.he,F.colorType,T,F.count,u,C,x,G);k(F.he,m);t&&k(T,t);return d};a.Shader.MakeSweepGradient=function(d,h,m,t,u,x,C,G,F,T){T=T||null;var U=l(m),q=n(t,"HEAPF32");C=C||0;G=G||0;F=F||360;x=p(x);d=a.Shader._MakeSweepGradient(d,h,U.he,U.colorType,q,U.count,u,G,F,C,x,T);k(U.he,m);t&&k(q,t);return d};a.Shader.MakeTwoPointConicalGradient=function(d,h,m,t,u,x,C,G,F,T){T=T||null;var U=l(u),q=n(x,"HEAPF32");
|
|
||||||
F=F||0;G=p(G);var y=fa.toTypedArray();y.set(d);y.set(m,2);d=a.Shader._MakeTwoPointConicalGradient(W,h,t,U.he,U.colorType,q,U.count,C,F,G,T);k(U.he,u);x&&k(q,x);return d};a.Vertices.prototype.bounds=function(d){this._bounds(W);var h=fa.toTypedArray();return d?(d.set(h),d):h.slice()};a.ce&&a.ce.forEach(function(d){d()})};a.computeTonalColors=function(g){var d=n(g.ambient,"HEAPF32"),h=n(g.spot,"HEAPF32");this._computeTonalColors(d,h);var m={ambient:D(d),spot:D(h)};k(d,g.ambient);k(h,g.spot);return m};
|
|
||||||
a.LTRBRect=function(g,d,h,m){return Float32Array.of(g,d,h,m)};a.XYWHRect=function(g,d,h,m){return Float32Array.of(g,d,g+h,d+m)};a.LTRBiRect=function(g,d,h,m){return Int32Array.of(g,d,h,m)};a.XYWHiRect=function(g,d,h,m){return Int32Array.of(g,d,g+h,d+m)};a.RRectXY=function(g,d,h){return Float32Array.of(g[0],g[1],g[2],g[3],d,h,d,h,d,h,d,h)};a.MakeAnimatedImageFromEncoded=function(g){g=new Uint8Array(g);var d=a._malloc(g.byteLength);a.HEAPU8.set(g,d);return(g=a._decodeAnimatedImage(d,g.byteLength))?
|
|
||||||
g:null};a.MakeImageFromEncoded=function(g){g=new Uint8Array(g);var d=a._malloc(g.byteLength);a.HEAPU8.set(g,d);return(g=a._decodeImage(d,g.byteLength))?g:null};var ab=null;a.MakeImageFromCanvasImageSource=function(g){var d=g.width,h=g.height;ab||=document.createElement("canvas");ab.width=d;ab.height=h;var m=ab.getContext("2d",{willReadFrequently:!0});m.drawImage(g,0,0);g=m.getImageData(0,0,d,h);return a.MakeImage({width:d,height:h,alphaType:a.AlphaType.Unpremul,colorType:a.ColorType.RGBA_8888,colorSpace:a.ColorSpace.SRGB},
|
|
||||||
g.data,4*d)};a.MakeImage=function(g,d,h){var m=a._malloc(d.length);a.HEAPU8.set(d,m);return a._MakeImage(g,m,d.length,h)};a.MakeVertices=function(g,d,h,m,t,u){var x=t&&t.length||0,C=0;h&&h.length&&(C|=1);m&&m.length&&(C|=2);void 0===u||u||(C|=4);g=new a._VerticesBuilder(g,d.length/2,x,C);n(d,"HEAPF32",g.positions());g.texCoords()&&n(h,"HEAPF32",g.texCoords());g.colors()&&n(c(m),"HEAPU32",g.colors());g.indices()&&n(t,"HEAPU16",g.indices());return g.detach()};(function(g){g.ce=g.ce||[];g.ce.push(function(){function d(q){q&&
|
|
||||||
(q.dir=0===q.dir?g.TextDirection.RTL:g.TextDirection.LTR);return q}function h(q){if(!q||!q.length)return[];for(var y=[],N=0;N<q.length;N+=5){var X=g.LTRBRect(q[N],q[N+1],q[N+2],q[N+3]),xa=g.TextDirection.LTR;0===q[N+4]&&(xa=g.TextDirection.RTL);y.push({rect:X,dir:xa})}g._free(q.byteOffset);return y}function m(q){q=q||{};void 0===q.weight&&(q.weight=g.FontWeight.Normal);q.width=q.width||g.FontWidth.Normal;q.slant=q.slant||g.FontSlant.Upright;return q}function t(q){if(!q||!q.length)return K;for(var y=
|
|
||||||
[],N=0;N<q.length;N++){var X=u(q[N]);y.push(X)}return n(y,"HEAPU32")}function u(q){if(G[q])return G[q];var y=qa(q)+1,N=g._malloc(y);ra(q,N,y);return G[q]=N}function x(q){q._colorPtr=w(q.color);q._foregroundColorPtr=K;q._backgroundColorPtr=K;q._decorationColorPtr=K;q.foregroundColor&&(q._foregroundColorPtr=w(q.foregroundColor,F));q.backgroundColor&&(q._backgroundColorPtr=w(q.backgroundColor,T));q.decorationColor&&(q._decorationColorPtr=w(q.decorationColor,U));Array.isArray(q.fontFamilies)&&q.fontFamilies.length?
|
|
||||||
(q._fontFamiliesPtr=t(q.fontFamilies),q._fontFamiliesLen=q.fontFamilies.length):(q._fontFamiliesPtr=K,q._fontFamiliesLen=0);if(q.locale){var y=q.locale;q._localePtr=u(y);q._localeLen=qa(y)}else q._localePtr=K,q._localeLen=0;if(Array.isArray(q.shadows)&&q.shadows.length){y=q.shadows;var N=y.map(function(na){return na.color||g.BLACK}),X=y.map(function(na){return na.blurRadius||0});q._shadowLen=y.length;for(var xa=g._malloc(8*y.length),xb=xa/4,yb=0;yb<y.length;yb++){var $b=y[yb].offset||[0,0];g.HEAPF32[xb]=
|
|
||||||
$b[0];g.HEAPF32[xb+1]=$b[1];xb+=2}q._shadowColorsPtr=l(N).he;q._shadowOffsetsPtr=xa;q._shadowBlurRadiiPtr=n(X,"HEAPF32")}else q._shadowLen=0,q._shadowColorsPtr=K,q._shadowOffsetsPtr=K,q._shadowBlurRadiiPtr=K;Array.isArray(q.fontFeatures)&&q.fontFeatures.length?(y=q.fontFeatures,N=y.map(function(na){return na.name}),X=y.map(function(na){return na.value}),q._fontFeatureLen=y.length,q._fontFeatureNamesPtr=t(N),q._fontFeatureValuesPtr=n(X,"HEAPU32")):(q._fontFeatureLen=0,q._fontFeatureNamesPtr=K,q._fontFeatureValuesPtr=
|
|
||||||
K);Array.isArray(q.fontVariations)&&q.fontVariations.length?(y=q.fontVariations,N=y.map(function(na){return na.axis}),X=y.map(function(na){return na.value}),q._fontVariationLen=y.length,q._fontVariationAxesPtr=t(N),q._fontVariationValuesPtr=n(X,"HEAPF32")):(q._fontVariationLen=0,q._fontVariationAxesPtr=K,q._fontVariationValuesPtr=K)}function C(q){g._free(q._fontFamiliesPtr);g._free(q._shadowColorsPtr);g._free(q._shadowOffsetsPtr);g._free(q._shadowBlurRadiiPtr);g._free(q._fontFeatureNamesPtr);g._free(q._fontFeatureValuesPtr);
|
|
||||||
g._free(q._fontVariationAxesPtr);g._free(q._fontVariationValuesPtr)}g.Paragraph.prototype.getRectsForRange=function(q,y,N,X){q=this._getRectsForRange(q,y,N,X);return h(q)};g.Paragraph.prototype.getRectsForPlaceholders=function(){var q=this._getRectsForPlaceholders();return h(q)};g.Paragraph.prototype.getGlyphInfoAt=function(q){return d(this._getGlyphInfoAt(q))};g.Paragraph.prototype.getClosestGlyphInfoAtCoordinate=function(q,y){return d(this._getClosestGlyphInfoAtCoordinate(q,y))};g.TypefaceFontProvider.prototype.registerFont=
|
|
||||||
function(q,y){q=g.Typeface.MakeTypefaceFromData(q);if(!q)return null;y=u(y);this._registerFont(q,y)};g.ParagraphStyle=function(q){q.disableHinting=q.disableHinting||!1;if(q.ellipsis){var y=q.ellipsis;q._ellipsisPtr=u(y);q._ellipsisLen=qa(y)}else q._ellipsisPtr=K,q._ellipsisLen=0;null==q.heightMultiplier&&(q.heightMultiplier=-1);q.maxLines=q.maxLines||0;q.replaceTabCharacters=q.replaceTabCharacters||!1;y=(y=q.strutStyle)||{};y.strutEnabled=y.strutEnabled||!1;y.strutEnabled&&Array.isArray(y.fontFamilies)&&
|
|
||||||
y.fontFamilies.length?(y._fontFamiliesPtr=t(y.fontFamilies),y._fontFamiliesLen=y.fontFamilies.length):(y._fontFamiliesPtr=K,y._fontFamiliesLen=0);y.fontStyle=m(y.fontStyle);null==y.fontSize&&(y.fontSize=-1);null==y.heightMultiplier&&(y.heightMultiplier=-1);y.halfLeading=y.halfLeading||!1;y.leading=y.leading||0;y.forceStrutHeight=y.forceStrutHeight||!1;q.strutStyle=y;q.textAlign=q.textAlign||g.TextAlign.Start;q.textDirection=q.textDirection||g.TextDirection.LTR;q.textHeightBehavior=q.textHeightBehavior||
|
|
||||||
g.TextHeightBehavior.All;q.textStyle=g.TextStyle(q.textStyle);q.applyRoundingHack=!1!==q.applyRoundingHack;return q};g.TextStyle=function(q){q.color||(q.color=g.BLACK);q.decoration=q.decoration||0;q.decorationThickness=q.decorationThickness||0;q.decorationStyle=q.decorationStyle||g.DecorationStyle.Solid;q.textBaseline=q.textBaseline||g.TextBaseline.Alphabetic;null==q.fontSize&&(q.fontSize=-1);q.letterSpacing=q.letterSpacing||0;q.wordSpacing=q.wordSpacing||0;null==q.heightMultiplier&&(q.heightMultiplier=
|
|
||||||
-1);q.halfLeading=q.halfLeading||!1;q.fontStyle=m(q.fontStyle);return q};var G={},F=g._malloc(16),T=g._malloc(16),U=g._malloc(16);g.ParagraphBuilder.Make=function(q,y){x(q.textStyle);y=g.ParagraphBuilder._Make(q,y);C(q.textStyle);return y};g.ParagraphBuilder.MakeFromFontProvider=function(q,y){x(q.textStyle);y=g.ParagraphBuilder._MakeFromFontProvider(q,y);C(q.textStyle);return y};g.ParagraphBuilder.MakeFromFontCollection=function(q,y){x(q.textStyle);y=g.ParagraphBuilder._MakeFromFontCollection(q,y);
|
|
||||||
C(q.textStyle);return y};g.ParagraphBuilder.ShapeText=function(q,y,N){let X=0;for(const xa of y)X+=xa.length;if(X!==q.length)throw"Accumulated block lengths must equal text.length";return g.ParagraphBuilder._ShapeText(q,y,N)};g.ParagraphBuilder.prototype.pushStyle=function(q){x(q);this._pushStyle(q);C(q)};g.ParagraphBuilder.prototype.pushPaintStyle=function(q,y,N){x(q);this._pushPaintStyle(q,y,N);C(q)};g.ParagraphBuilder.prototype.addPlaceholder=function(q,y,N,X,xa){N=N||g.PlaceholderAlignment.Baseline;
|
|
||||||
X=X||g.TextBaseline.Alphabetic;this._addPlaceholder(q||0,y||0,N,X,xa||0)};g.ParagraphBuilder.prototype.setWordsUtf8=function(q){var y=n(q,"HEAPU32");this._setWordsUtf8(y,q&&q.length||0);k(y,q)};g.ParagraphBuilder.prototype.setWordsUtf16=function(q){var y=n(q,"HEAPU32");this._setWordsUtf16(y,q&&q.length||0);k(y,q)};g.ParagraphBuilder.prototype.setGraphemeBreaksUtf8=function(q){var y=n(q,"HEAPU32");this._setGraphemeBreaksUtf8(y,q&&q.length||0);k(y,q)};g.ParagraphBuilder.prototype.setGraphemeBreaksUtf16=
|
|
||||||
function(q){var y=n(q,"HEAPU32");this._setGraphemeBreaksUtf16(y,q&&q.length||0);k(y,q)};g.ParagraphBuilder.prototype.setLineBreaksUtf8=function(q){var y=n(q,"HEAPU32");this._setLineBreaksUtf8(y,q&&q.length||0);k(y,q)};g.ParagraphBuilder.prototype.setLineBreaksUtf16=function(q){var y=n(q,"HEAPU32");this._setLineBreaksUtf16(y,q&&q.length||0);k(y,q)}})})(r);a.ce=a.ce||[];a.ce.push(function(){a.Path.prototype.op=function(g,d){return this._op(g,d)?this:null};a.Path.prototype.simplify=function(){return this._simplify()?
|
|
||||||
this:null}});a.ce=a.ce||[];a.ce.push(function(){a.Canvas.prototype.drawText=function(g,d,h,m,t){var u=qa(g),x=a._malloc(u+1);ra(g,x,u+1);this._drawSimpleText(x,u,d,h,t,m);a._free(x)};a.Canvas.prototype.drawGlyphs=function(g,d,h,m,t,u){if(!(2*g.length<=d.length))throw"Not enough positions for the array of gyphs";a.$d(this.Zd);const x=n(g,"HEAPU16"),C=n(d,"HEAPF32");this._drawGlyphs(g.length,x,C,h,m,t,u);k(C,d);k(x,g)};a.Font.prototype.getGlyphBounds=function(g,d,h){var m=n(g,"HEAPU16"),t=a._malloc(16*
|
|
||||||
g.length);this._getGlyphWidthBounds(m,g.length,K,t,d||null);d=new Float32Array(a.HEAPU8.buffer,t,4*g.length);k(m,g);if(h)return h.set(d),a._free(t),h;g=Float32Array.from(d);a._free(t);return g};a.Font.prototype.getGlyphIDs=function(g,d,h){d||(d=g.length);var m=qa(g)+1,t=a._malloc(m);ra(g,t,m);g=a._malloc(2*d);d=this._getGlyphIDs(t,m-1,d,g);a._free(t);if(0>d)return a._free(g),null;t=new Uint16Array(a.HEAPU8.buffer,g,d);if(h)return h.set(t),a._free(g),h;h=Uint16Array.from(t);a._free(g);return h};a.Font.prototype.getGlyphIntercepts=
|
|
||||||
function(g,d,h,m){var t=n(g,"HEAPU16"),u=n(d,"HEAPF32");return this._getGlyphIntercepts(t,g.length,!(g&&g._ck),u,d.length,!(d&&d._ck),h,m)};a.Font.prototype.getGlyphWidths=function(g,d,h){var m=n(g,"HEAPU16"),t=a._malloc(4*g.length);this._getGlyphWidthBounds(m,g.length,t,K,d||null);d=new Float32Array(a.HEAPU8.buffer,t,g.length);k(m,g);if(h)return h.set(d),a._free(t),h;g=Float32Array.from(d);a._free(t);return g};a.FontMgr.FromData=function(){if(!arguments.length)return null;var g=arguments;1===g.length&&
|
|
||||||
Array.isArray(g[0])&&(g=arguments[0]);if(!g.length)return null;for(var d=[],h=[],m=0;m<g.length;m++){var t=new Uint8Array(g[m]),u=n(t,"HEAPU8");d.push(u);h.push(t.byteLength)}d=n(d,"HEAPU32");h=n(h,"HEAPU32");g=a.FontMgr._fromData(d,h,g.length);a._free(d);a._free(h);return g};a.Typeface.MakeTypefaceFromData=function(g){g=new Uint8Array(g);var d=n(g,"HEAPU8");return(g=a.Typeface._MakeTypefaceFromData(d,g.byteLength))?g:null};a.Typeface.MakeFreeTypeFaceFromData=a.Typeface.MakeTypefaceFromData;a.Typeface.prototype.getGlyphIDs=
|
|
||||||
function(g,d,h){d||(d=g.length);var m=qa(g)+1,t=a._malloc(m);ra(g,t,m);g=a._malloc(2*d);d=this._getGlyphIDs(t,m-1,d,g);a._free(t);if(0>d)return a._free(g),null;t=new Uint16Array(a.HEAPU8.buffer,g,d);if(h)return h.set(t),a._free(g),h;h=Uint16Array.from(t);a._free(g);return h};a.TextBlob.MakeOnPath=function(g,d,h,m){if(g&&g.length&&d&&d.countPoints()){if(1===d.countPoints())return this.MakeFromText(g,h);m||=0;var t=h.getGlyphIDs(g);t=h.getGlyphWidths(t);var u=[];d=new a.ContourMeasureIter(d,!1,1);for(var x=
|
|
||||||
d.next(),C=new Float32Array(4),G=0;G<g.length&&x;G++){var F=t[G];m+=F/2;if(m>x.length()){x.delete();x=d.next();if(!x){g=g.substring(0,G);break}m=F/2}x.getPosTan(m,C);var T=C[2],U=C[3];u.push(T,U,C[0]-F/2*T,C[1]-F/2*U);m+=F/2}g=this.MakeFromRSXform(g,u,h);x&&x.delete();d.delete();return g}};a.TextBlob.MakeFromRSXform=function(g,d,h){var m=qa(g)+1,t=a._malloc(m);ra(g,t,m);g=n(d,"HEAPF32");h=a.TextBlob._MakeFromRSXform(t,m-1,g,h);a._free(t);return h?h:null};a.TextBlob.MakeFromRSXformGlyphs=function(g,
|
|
||||||
d,h){var m=n(g,"HEAPU16");d=n(d,"HEAPF32");h=a.TextBlob._MakeFromRSXformGlyphs(m,2*g.length,d,h);k(m,g);return h?h:null};a.TextBlob.MakeFromGlyphs=function(g,d){var h=n(g,"HEAPU16");d=a.TextBlob._MakeFromGlyphs(h,2*g.length,d);k(h,g);return d?d:null};a.TextBlob.MakeFromText=function(g,d){var h=qa(g)+1,m=a._malloc(h);ra(g,m,h);g=a.TextBlob._MakeFromText(m,h-1,d);a._free(m);return g?g:null};a.MallocGlyphIDs=function(g){return a.Malloc(Uint16Array,g)}});a.ce=a.ce||[];a.ce.push(function(){a.MakePicture=
|
|
||||||
function(g){g=new Uint8Array(g);var d=a._malloc(g.byteLength);a.HEAPU8.set(g,d);return(g=a._MakePicture(d,g.byteLength))?g:null}});a.ce=a.ce||[];a.ce.push(function(){a.RuntimeEffect.Make=function(g,d){return a.RuntimeEffect._Make(g,{onError:d||function(h){console.log("RuntimeEffect error",h)}})};a.RuntimeEffect.MakeForBlender=function(g,d){return a.RuntimeEffect._MakeForBlender(g,{onError:d||function(h){console.log("RuntimeEffect error",h)}})};a.RuntimeEffect.prototype.makeShader=function(g,d){var h=
|
|
||||||
!g._ck,m=n(g,"HEAPF32");d=p(d);return this._makeShader(m,4*g.length,h,d)};a.RuntimeEffect.prototype.makeShaderWithChildren=function(g,d,h){var m=!g._ck,t=n(g,"HEAPF32");h=p(h);for(var u=[],x=0;x<d.length;x++)u.push(d[x].Yd.ae);d=n(u,"HEAPU32");return this._makeShaderWithChildren(t,4*g.length,m,d,u.length,h)};a.RuntimeEffect.prototype.makeBlender=function(g){var d=!g._ck,h=n(g,"HEAPF32");return this._makeBlender(h,4*g.length,d)}})})(r);var sa=Object.assign({},r),ta="",ua,va;
|
|
||||||
if(ea||ha)ha?ta=self.location.href:"undefined"!=typeof document&&document.currentScript&&(ta=document.currentScript.src),_scriptName&&(ta=_scriptName),ta.startsWith("blob:")?ta="":ta=ta.substr(0,ta.replace(/[?#].*/,"").lastIndexOf("/")+1),ha&&(va=a=>{var b=new XMLHttpRequest;b.open("GET",a,!1);b.responseType="arraybuffer";b.send(null);return new Uint8Array(b.response)}),ua=a=>fetch(a,{credentials:"same-origin"}).then(b=>b.ok?b.arrayBuffer():Promise.reject(Error(b.status+" : "+b.url)));
|
|
||||||
var wa=console.log.bind(console),ya=console.error.bind(console);Object.assign(r,sa);sa=null;var za,Aa=!1,Ca,B,Da,Fa,E,H,J,Ga;function Ha(){var a=za.buffer;r.HEAP8=Ca=new Int8Array(a);r.HEAP16=Da=new Int16Array(a);r.HEAPU8=B=new Uint8Array(a);r.HEAPU16=Fa=new Uint16Array(a);r.HEAP32=E=new Int32Array(a);r.HEAPU32=H=new Uint32Array(a);r.HEAPF32=J=new Float32Array(a);r.HEAPF64=Ga=new Float64Array(a)}var Ia=[],Ja=[],Ka=[],La=0,Ma=null,Oa=null;
|
|
||||||
function Pa(a){a="Aborted("+a+")";ya(a);Aa=!0;a=new WebAssembly.RuntimeError(a+". Build with -sASSERTIONS for more info.");ca(a);throw a;}var Qa=a=>a.startsWith("data:application/octet-stream;base64,"),Ra;function Sa(a){return ua(a).then(b=>new Uint8Array(b),()=>{if(va)var b=va(a);else throw"both async and sync fetching of the wasm failed";return b})}function Ta(a,b,c){return Sa(a).then(e=>WebAssembly.instantiate(e,b)).then(c,e=>{ya(`failed to asynchronously prepare wasm: ${e}`);Pa(e)})}
|
|
||||||
function Ua(a,b){var c=Ra;return"function"!=typeof WebAssembly.instantiateStreaming||Qa(c)||"function"!=typeof fetch?Ta(c,a,b):fetch(c,{credentials:"same-origin"}).then(e=>WebAssembly.instantiateStreaming(e,a).then(b,function(f){ya(`wasm streaming compile failed: ${f}`);ya("falling back to ArrayBuffer instantiation");return Ta(c,a,b)}))}function Va(a){this.name="ExitStatus";this.message=`Program terminated with exit(${a})`;this.status=a}var Wa=a=>{a.forEach(b=>b(r))};
|
|
||||||
class Xa{constructor(a){this.ae=a-24}}
|
|
||||||
var Ya=0,Za=0,bb="undefined"!=typeof TextDecoder?new TextDecoder:void 0,cb=(a,b=0,c=NaN)=>{var e=b+c;for(c=b;a[c]&&!(c>=e);)++c;if(16<c-b&&a.buffer&&bb)return bb.decode(a.subarray(b,c));for(e="";b<c;){var f=a[b++];if(f&128){var k=a[b++]&63;if(192==(f&224))e+=String.fromCharCode((f&31)<<6|k);else{var n=a[b++]&63;f=224==(f&240)?(f&15)<<12|k<<6|n:(f&7)<<18|k<<12|n<<6|a[b++]&63;65536>f?e+=String.fromCharCode(f):(f-=65536,e+=String.fromCharCode(55296|f>>10,56320|f&1023))}}else e+=String.fromCharCode(f)}return e},
|
|
||||||
db={},eb=a=>{for(;a.length;){var b=a.pop();a.pop()(b)}};function fb(a){return this.fromWireType(H[a>>2])}
|
|
||||||
var gb={},hb={},ib={},jb,lb=(a,b,c)=>{function e(l){l=c(l);if(l.length!==a.length)throw new jb("Mismatched type converter count");for(var p=0;p<a.length;++p)kb(a[p],l[p])}a.forEach(l=>ib[l]=b);var f=Array(b.length),k=[],n=0;b.forEach((l,p)=>{hb.hasOwnProperty(l)?f[p]=hb[l]:(k.push(l),gb.hasOwnProperty(l)||(gb[l]=[]),gb[l].push(()=>{f[p]=hb[l];++n;n===k.length&&e(f)}))});0===k.length&&e(f)},mb,L=a=>{for(var b="";B[a];)b+=mb[B[a++]];return b},M;
|
|
||||||
function nb(a,b,c={}){var e=b.name;if(!a)throw new M(`type "${e}" must have a positive integer typeid pointer`);if(hb.hasOwnProperty(a)){if(c.lf)return;throw new M(`Cannot register type '${e}' twice`);}hb[a]=b;delete ib[a];gb.hasOwnProperty(a)&&(b=gb[a],delete gb[a],b.forEach(f=>f()))}function kb(a,b,c={}){return nb(a,b,c)}
|
|
||||||
var ob=a=>{throw new M(a.Yd.de.be.name+" instance already deleted");},pb=!1,qb=()=>{},rb=(a,b,c)=>{if(b===c)return a;if(void 0===c.ge)return null;a=rb(a,b,c.ge);return null===a?null:c.cf(a)},sb={},tb={},zb=(a,b)=>{if(void 0===b)throw new M("ptr should not be undefined");for(;a.ge;)b=a.ye(b),a=a.ge;return tb[b]},Bb=(a,b)=>{if(!b.de||!b.ae)throw new jb("makeClassHandle requires ptr and ptrType");if(!!b.ie!==!!b.ee)throw new jb("Both smartPtrType and smartPtr must be specified");b.count={value:1};return Ab(Object.create(a,
|
|
||||||
{Yd:{value:b,writable:!0}}))},Ab=a=>{if("undefined"===typeof FinalizationRegistry)return Ab=b=>b,a;pb=new FinalizationRegistry(b=>{b=b.Yd;--b.count.value;0===b.count.value&&(b.ee?b.ie.ne(b.ee):b.de.be.ne(b.ae))});Ab=b=>{var c=b.Yd;c.ee&&pb.register(b,{Yd:c},b);return b};qb=b=>{pb.unregister(b)};return Ab(a)},Cb=[];function Db(){}
|
|
||||||
var Eb=(a,b)=>Object.defineProperty(b,"name",{value:a}),Fb=(a,b,c)=>{if(void 0===a[b].fe){var e=a[b];a[b]=function(...f){if(!a[b].fe.hasOwnProperty(f.length))throw new M(`Function '${c}' called with an invalid number of arguments (${f.length}) - expects one of (${a[b].fe})!`);return a[b].fe[f.length].apply(this,f)};a[b].fe=[];a[b].fe[e.oe]=e}},Gb=(a,b,c)=>{if(r.hasOwnProperty(a)){if(void 0===c||void 0!==r[a].fe&&void 0!==r[a].fe[c])throw new M(`Cannot register public name '${a}' twice`);Fb(r,a,a);
|
|
||||||
if(r[a].fe.hasOwnProperty(c))throw new M(`Cannot register multiple overloads of a function with the same number of arguments (${c})!`);r[a].fe[c]=b}else r[a]=b,r[a].oe=c},Hb=a=>{a=a.replace(/[^a-zA-Z0-9_]/g,"$");var b=a.charCodeAt(0);return 48<=b&&57>=b?`_${a}`:a};function Ib(a,b,c,e,f,k,n,l){this.name=a;this.constructor=b;this.se=c;this.ne=e;this.ge=f;this.ff=k;this.ye=n;this.cf=l;this.pf=[]}
|
|
||||||
var Jb=(a,b,c)=>{for(;b!==c;){if(!b.ye)throw new M(`Expected null or instance of ${c.name}, got an instance of ${b.name}`);a=b.ye(a);b=b.ge}return a};function Kb(a,b){if(null===b){if(this.Ke)throw new M(`null is not a valid ${this.name}`);return 0}if(!b.Yd)throw new M(`Cannot pass "${Lb(b)}" as a ${this.name}`);if(!b.Yd.ae)throw new M(`Cannot pass deleted object as a pointer of type ${this.name}`);return Jb(b.Yd.ae,b.Yd.de.be,this.be)}
|
|
||||||
function Mb(a,b){if(null===b){if(this.Ke)throw new M(`null is not a valid ${this.name}`);if(this.De){var c=this.Le();null!==a&&a.push(this.ne,c);return c}return 0}if(!b||!b.Yd)throw new M(`Cannot pass "${Lb(b)}" as a ${this.name}`);if(!b.Yd.ae)throw new M(`Cannot pass deleted object as a pointer of type ${this.name}`);if(!this.Ce&&b.Yd.de.Ce)throw new M(`Cannot convert argument of type ${b.Yd.ie?b.Yd.ie.name:b.Yd.de.name} to parameter type ${this.name}`);c=Jb(b.Yd.ae,b.Yd.de.be,this.be);if(this.De){if(void 0===
|
|
||||||
b.Yd.ee)throw new M("Passing raw pointer to smart pointer is illegal");switch(this.uf){case 0:if(b.Yd.ie===this)c=b.Yd.ee;else throw new M(`Cannot convert argument of type ${b.Yd.ie?b.Yd.ie.name:b.Yd.de.name} to parameter type ${this.name}`);break;case 1:c=b.Yd.ee;break;case 2:if(b.Yd.ie===this)c=b.Yd.ee;else{var e=b.clone();c=this.qf(c,Nb(()=>e["delete"]()));null!==a&&a.push(this.ne,c)}break;default:throw new M("Unsupporting sharing policy");}}return c}
|
|
||||||
function Ob(a,b){if(null===b){if(this.Ke)throw new M(`null is not a valid ${this.name}`);return 0}if(!b.Yd)throw new M(`Cannot pass "${Lb(b)}" as a ${this.name}`);if(!b.Yd.ae)throw new M(`Cannot pass deleted object as a pointer of type ${this.name}`);if(b.Yd.de.Ce)throw new M(`Cannot convert argument of type ${b.Yd.de.name} to parameter type ${this.name}`);return Jb(b.Yd.ae,b.Yd.de.be,this.be)}
|
|
||||||
function Pb(a,b,c,e,f,k,n,l,p,v,w){this.name=a;this.be=b;this.Ke=c;this.Ce=e;this.De=f;this.nf=k;this.uf=n;this.Se=l;this.Le=p;this.qf=v;this.ne=w;f||void 0!==b.ge?this.toWireType=Mb:(this.toWireType=e?Kb:Ob,this.ke=null)}
|
|
||||||
var Qb=(a,b,c)=>{if(!r.hasOwnProperty(a))throw new jb("Replacing nonexistent public symbol");void 0!==r[a].fe&&void 0!==c?r[a].fe[c]=b:(r[a]=b,r[a].oe=c)},O,Rb=(a,b,c=[])=>{a.includes("j")?(a=a.replace(/p/g,"i"),b=(0,r["dynCall_"+a])(b,...c)):b=O.get(b)(...c);return b},Sb=(a,b)=>(...c)=>Rb(a,b,c),Tb=(a,b)=>{a=L(a);var c=a.includes("j")?Sb(a,b):O.get(b);if("function"!=typeof c)throw new M(`unknown function pointer with signature ${a}: ${b}`);return c},ac,dc=a=>{a=bc(a);var b=L(a);cc(a);return b},ec=
|
|
||||||
(a,b)=>{function c(k){f[k]||hb[k]||(ib[k]?ib[k].forEach(c):(e.push(k),f[k]=!0))}var e=[],f={};b.forEach(c);throw new ac(`${a}: `+e.map(dc).join([", "]));};function fc(a){for(var b=1;b<a.length;++b)if(null!==a[b]&&void 0===a[b].ke)return!0;return!1}
|
|
||||||
function gc(a,b,c,e,f){var k=b.length;if(2>k)throw new M("argTypes array size mismatch! Must at least get return value and 'this' types!");var n=null!==b[1]&&null!==c,l=fc(b),p="void"!==b[0].name,v=k-2,w=Array(v),A=[],D=[];return Eb(a,function(...I){D.length=0;A.length=n?2:1;A[0]=f;if(n){var R=b[1].toWireType(D,this);A[1]=R}for(var P=0;P<v;++P)w[P]=b[P+2].toWireType(D,I[P]),A.push(w[P]);I=e(...A);if(l)eb(D);else for(P=n?1:2;P<b.length;P++){var ba=1===P?R:w[P-2];null!==b[P].ke&&b[P].ke(ba)}R=p?b[0].fromWireType(I):
|
|
||||||
void 0;return R})}
|
|
||||||
var hc=(a,b)=>{for(var c=[],e=0;e<a;e++)c.push(H[b+4*e>>2]);return c},ic=a=>{a=a.trim();const b=a.indexOf("(");return-1!==b?a.substr(0,b):a},jc=[],kc=[],lc=a=>{9<a&&0===--kc[a+1]&&(kc[a]=void 0,jc.push(a))},mc=a=>{if(!a)throw new M("Cannot use deleted val. handle = "+a);return kc[a]},Nb=a=>{switch(a){case void 0:return 2;case null:return 4;case !0:return 6;case !1:return 8;default:const b=jc.pop()||kc.length;kc[b]=a;kc[b+1]=1;return b}},nc={name:"emscripten::val",fromWireType:a=>{var b=mc(a);lc(a);
|
|
||||||
return b},toWireType:(a,b)=>Nb(b),je:8,readValueFromPointer:fb,ke:null},oc=(a,b,c)=>{switch(b){case 1:return c?function(e){return this.fromWireType(Ca[e])}:function(e){return this.fromWireType(B[e])};case 2:return c?function(e){return this.fromWireType(Da[e>>1])}:function(e){return this.fromWireType(Fa[e>>1])};case 4:return c?function(e){return this.fromWireType(E[e>>2])}:function(e){return this.fromWireType(H[e>>2])};default:throw new TypeError(`invalid integer width (${b}): ${a}`);}},pc=(a,b)=>
|
|
||||||
{var c=hb[a];if(void 0===c)throw a=`${b} has unknown type ${dc(a)}`,new M(a);return c},Lb=a=>{if(null===a)return"null";var b=typeof a;return"object"===b||"array"===b||"function"===b?a.toString():""+a},qc=(a,b)=>{switch(b){case 4:return function(c){return this.fromWireType(J[c>>2])};case 8:return function(c){return this.fromWireType(Ga[c>>3])};default:throw new TypeError(`invalid float width (${b}): ${a}`);}},rc=(a,b,c)=>{switch(b){case 1:return c?e=>Ca[e]:e=>B[e];case 2:return c?e=>Da[e>>1]:e=>Fa[e>>
|
|
||||||
1];case 4:return c?e=>E[e>>2]:e=>H[e>>2];default:throw new TypeError(`invalid integer width (${b}): ${a}`);}},ra=(a,b,c)=>{var e=B;if(!(0<c))return 0;var f=b;c=b+c-1;for(var k=0;k<a.length;++k){var n=a.charCodeAt(k);if(55296<=n&&57343>=n){var l=a.charCodeAt(++k);n=65536+((n&1023)<<10)|l&1023}if(127>=n){if(b>=c)break;e[b++]=n}else{if(2047>=n){if(b+1>=c)break;e[b++]=192|n>>6}else{if(65535>=n){if(b+2>=c)break;e[b++]=224|n>>12}else{if(b+3>=c)break;e[b++]=240|n>>18;e[b++]=128|n>>12&63}e[b++]=128|n>>6&
|
|
||||||
63}e[b++]=128|n&63}}e[b]=0;return b-f},qa=a=>{for(var b=0,c=0;c<a.length;++c){var e=a.charCodeAt(c);127>=e?b++:2047>=e?b+=2:55296<=e&&57343>=e?(b+=4,++c):b+=3}return b},sc="undefined"!=typeof TextDecoder?new TextDecoder("utf-16le"):void 0,tc=(a,b)=>{var c=a>>1;for(var e=c+b/2;!(c>=e)&&Fa[c];)++c;c<<=1;if(32<c-a&&sc)return sc.decode(B.subarray(a,c));c="";for(e=0;!(e>=b/2);++e){var f=Da[a+2*e>>1];if(0==f)break;c+=String.fromCharCode(f)}return c},uc=(a,b,c)=>{c??=2147483647;if(2>c)return 0;c-=2;var e=
|
|
||||||
b;c=c<2*a.length?c/2:a.length;for(var f=0;f<c;++f)Da[b>>1]=a.charCodeAt(f),b+=2;Da[b>>1]=0;return b-e},vc=a=>2*a.length,wc=(a,b)=>{for(var c=0,e="";!(c>=b/4);){var f=E[a+4*c>>2];if(0==f)break;++c;65536<=f?(f-=65536,e+=String.fromCharCode(55296|f>>10,56320|f&1023)):e+=String.fromCharCode(f)}return e},xc=(a,b,c)=>{c??=2147483647;if(4>c)return 0;var e=b;c=e+c-4;for(var f=0;f<a.length;++f){var k=a.charCodeAt(f);if(55296<=k&&57343>=k){var n=a.charCodeAt(++f);k=65536+((k&1023)<<10)|n&1023}E[b>>2]=k;b+=
|
|
||||||
4;if(b+4>c)break}E[b>>2]=0;return b-e},yc=a=>{for(var b=0,c=0;c<a.length;++c){var e=a.charCodeAt(c);55296<=e&&57343>=e&&++c;b+=4}return b},zc=(a,b,c)=>{var e=[];a=a.toWireType(e,c);e.length&&(H[b>>2]=Nb(e));return a},Ac=[],Bc={},Cc=a=>{var b=Bc[a];return void 0===b?L(a):b},Dc=()=>{function a(b){b.$$$embind_global$$$=b;var c="object"==typeof $$$embind_global$$$&&b.$$$embind_global$$$==b;c||delete b.$$$embind_global$$$;return c}if("object"==typeof globalThis)return globalThis;if("object"==typeof $$$embind_global$$$)return $$$embind_global$$$;
|
|
||||||
"object"==typeof global&&a(global)?$$$embind_global$$$=global:"object"==typeof self&&a(self)&&($$$embind_global$$$=self);if("object"==typeof $$$embind_global$$$)return $$$embind_global$$$;throw Error("unable to get global object.");},Ec=a=>{var b=Ac.length;Ac.push(a);return b},Fc=(a,b)=>{for(var c=Array(a),e=0;e<a;++e)c[e]=pc(H[b+4*e>>2],"parameter "+e);return c},Gc=Reflect.construct,Q,Hc=a=>{var b=a.getExtension("ANGLE_instanced_arrays");b&&(a.vertexAttribDivisor=(c,e)=>b.vertexAttribDivisorANGLE(c,
|
|
||||||
e),a.drawArraysInstanced=(c,e,f,k)=>b.drawArraysInstancedANGLE(c,e,f,k),a.drawElementsInstanced=(c,e,f,k,n)=>b.drawElementsInstancedANGLE(c,e,f,k,n))},Ic=a=>{var b=a.getExtension("OES_vertex_array_object");b&&(a.createVertexArray=()=>b.createVertexArrayOES(),a.deleteVertexArray=c=>b.deleteVertexArrayOES(c),a.bindVertexArray=c=>b.bindVertexArrayOES(c),a.isVertexArray=c=>b.isVertexArrayOES(c))},Jc=a=>{var b=a.getExtension("WEBGL_draw_buffers");b&&(a.drawBuffers=(c,e)=>b.drawBuffersWEBGL(c,e))},Kc=a=>
|
|
||||||
{var b="ANGLE_instanced_arrays EXT_blend_minmax EXT_disjoint_timer_query EXT_frag_depth EXT_shader_texture_lod EXT_sRGB OES_element_index_uint OES_fbo_render_mipmap OES_standard_derivatives OES_texture_float OES_texture_half_float OES_texture_half_float_linear OES_vertex_array_object WEBGL_color_buffer_float WEBGL_depth_texture WEBGL_draw_buffers EXT_color_buffer_float EXT_conservative_depth EXT_disjoint_timer_query_webgl2 EXT_texture_norm16 NV_shader_noperspective_interpolation WEBGL_clip_cull_distance EXT_clip_control EXT_color_buffer_half_float EXT_depth_clamp EXT_float_blend EXT_polygon_offset_clamp EXT_texture_compression_bptc EXT_texture_compression_rgtc EXT_texture_filter_anisotropic KHR_parallel_shader_compile OES_texture_float_linear WEBGL_blend_func_extended WEBGL_compressed_texture_astc WEBGL_compressed_texture_etc WEBGL_compressed_texture_etc1 WEBGL_compressed_texture_s3tc WEBGL_compressed_texture_s3tc_srgb WEBGL_debug_renderer_info WEBGL_debug_shaders WEBGL_lose_context WEBGL_multi_draw WEBGL_polygon_mode".split(" ");
|
|
||||||
return(a.getSupportedExtensions()||[]).filter(c=>b.includes(c))},Lc=1,Mc=[],Nc=[],Oc=[],Pc=[],ka=[],Qc=[],Rc=[],pa=[],Sc=[],Tc=[],Uc=[],Vc={},Xc={},Yc=4,Zc=0,ja=a=>{for(var b=Lc++,c=a.length;c<b;c++)a[c]=null;return b},$c=(a,b,c,e)=>{for(var f=0;f<a;f++){var k=Q[c](),n=k&&ja(e);k?(k.name=n,e[n]=k):S||=1282;E[b+4*f>>2]=n}},la=(a,b)=>{a.Ne||(a.Ne=a.getContext,a.getContext=function(e,f){f=a.Ne(e,f);return"webgl"==e==f instanceof WebGLRenderingContext?f:null});var c=1<b.majorVersion?a.getContext("webgl2",
|
|
||||||
b):a.getContext("webgl",b);return c?ad(c,b):0},ad=(a,b)=>{var c=ja(pa),e={handle:c,attributes:b,version:b.majorVersion,le:a};a.canvas&&(a.canvas.Ve=e);pa[c]=e;("undefined"==typeof b.df||b.df)&&bd(e);return c},oa=a=>{z=pa[a];r.vf=Q=z?.le;return!(a&&!Q)},bd=a=>{a||=z;if(!a.mf){a.mf=!0;var b=a.le;b.zf=b.getExtension("WEBGL_multi_draw");b.xf=b.getExtension("EXT_polygon_offset_clamp");b.wf=b.getExtension("EXT_clip_control");b.Bf=b.getExtension("WEBGL_polygon_mode");Hc(b);Ic(b);Jc(b);b.Pe=b.getExtension("WEBGL_draw_instanced_base_vertex_base_instance");
|
|
||||||
b.Re=b.getExtension("WEBGL_multi_draw_instanced_base_vertex_base_instance");2<=a.version&&(b.me=b.getExtension("EXT_disjoint_timer_query_webgl2"));if(2>a.version||!b.me)b.me=b.getExtension("EXT_disjoint_timer_query");Kc(b).forEach(c=>{c.includes("lose_context")||c.includes("debug")||b.getExtension(c)})}},z,S,cd=(a,b)=>{Q.bindFramebuffer(a,Oc[b])},dd=a=>{Q.bindVertexArray(Rc[a])},ed=a=>Q.clear(a),fd=(a,b,c,e)=>Q.clearColor(a,b,c,e),gd=a=>Q.clearStencil(a),hd=(a,b)=>{for(var c=0;c<a;c++){var e=E[b+
|
|
||||||
4*c>>2];Q.deleteVertexArray(Rc[e]);Rc[e]=null}},jd=[],kd=(a,b)=>{$c(a,b,"createVertexArray",Rc)};function ld(){var a=Kc(Q);return a=a.concat(a.map(b=>"GL_"+b))}
|
|
||||||
var md=(a,b,c)=>{if(b){var e=void 0;switch(a){case 36346:e=1;break;case 36344:0!=c&&1!=c&&(S||=1280);return;case 34814:case 36345:e=0;break;case 34466:var f=Q.getParameter(34467);e=f?f.length:0;break;case 33309:if(2>z.version){S||=1282;return}e=ld().length;break;case 33307:case 33308:if(2>z.version){S||=1280;return}e=33307==a?3:0}if(void 0===e)switch(f=Q.getParameter(a),typeof f){case "number":e=f;break;case "boolean":e=f?1:0;break;case "string":S||=1280;return;case "object":if(null===f)switch(a){case 34964:case 35725:case 34965:case 36006:case 36007:case 32873:case 34229:case 36662:case 36663:case 35053:case 35055:case 36010:case 35097:case 35869:case 32874:case 36389:case 35983:case 35368:case 34068:e=
|
|
||||||
0;break;default:S||=1280;return}else{if(f instanceof Float32Array||f instanceof Uint32Array||f instanceof Int32Array||f instanceof Array){for(a=0;a<f.length;++a)switch(c){case 0:E[b+4*a>>2]=f[a];break;case 2:J[b+4*a>>2]=f[a];break;case 4:Ca[b+a]=f[a]?1:0}return}try{e=f.name|0}catch(k){S||=1280;ya(`GL_INVALID_ENUM in glGet${c}v: Unknown object returned from WebGL getParameter(${a})! (error: ${k})`);return}}break;default:S||=1280;ya(`GL_INVALID_ENUM in glGet${c}v: Native code calling glGet${c}v(${a}) and it returns ${f} of type ${typeof f}!`);
|
|
||||||
return}switch(c){case 1:c=e;H[b>>2]=c;H[b+4>>2]=(c-H[b>>2])/4294967296;break;case 0:E[b>>2]=e;break;case 2:J[b>>2]=e;break;case 4:Ca[b]=e?1:0}}else S||=1281},nd=(a,b)=>md(a,b,0),od=(a,b,c)=>{if(c){a=Sc[a];b=2>z.version?Q.me.getQueryObjectEXT(a,b):Q.getQueryParameter(a,b);var e;"boolean"==typeof b?e=b?1:0:e=b;H[c>>2]=e;H[c+4>>2]=(e-H[c>>2])/4294967296}else S||=1281},qd=a=>{var b=qa(a)+1,c=pd(b);c&&ra(a,c,b);return c},rd=a=>{var b=Vc[a];if(!b){switch(a){case 7939:b=qd(ld().join(" "));break;case 7936:case 7937:case 37445:case 37446:(b=
|
|
||||||
Q.getParameter(a))||(S||=1280);b=b?qd(b):0;break;case 7938:b=Q.getParameter(7938);var c=`OpenGL ES 2.0 (${b})`;2<=z.version&&(c=`OpenGL ES 3.0 (${b})`);b=qd(c);break;case 35724:b=Q.getParameter(35724);c=b.match(/^WebGL GLSL ES ([0-9]\.[0-9][0-9]?)(?:$| .*)/);null!==c&&(3==c[1].length&&(c[1]+="0"),b=`OpenGL ES GLSL ES ${c[1]} (${b})`);b=qd(b);break;default:S||=1280}Vc[a]=b}return b},sd=(a,b)=>{if(2>z.version)return S||=1282,0;var c=Xc[a];if(c)return 0>b||b>=c.length?(S||=1281,0):c[b];switch(a){case 7939:return c=
|
|
||||||
ld().map(qd),c=Xc[a]=c,0>b||b>=c.length?(S||=1281,0):c[b];default:return S||=1280,0}},td=a=>"]"==a.slice(-1)&&a.lastIndexOf("["),ud=a=>{a-=5120;return 0==a?Ca:1==a?B:2==a?Da:4==a?E:6==a?J:5==a||28922==a||28520==a||30779==a||30782==a?H:Fa},vd=(a,b,c,e,f)=>{a=ud(a);b=e*((Zc||c)*({5:3,6:4,8:2,29502:3,29504:4,26917:2,26918:2,29846:3,29847:4}[b-6402]||1)*a.BYTES_PER_ELEMENT+Yc-1&-Yc);return a.subarray(f>>>31-Math.clz32(a.BYTES_PER_ELEMENT),f+b>>>31-Math.clz32(a.BYTES_PER_ELEMENT))},V=a=>{var b=Q.bf;if(b){var c=
|
|
||||||
b.xe[a];"number"==typeof c&&(b.xe[a]=c=Q.getUniformLocation(b,b.Te[a]+(0<c?`[${c}]`:"")));return c}S||=1282},wd=[],xd=[],yd={},Ad=()=>{if(!zd){var a={USER:"web_user",LOGNAME:"web_user",PATH:"/",PWD:"/",HOME:"/home/web_user",LANG:("object"==typeof navigator&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8",_:"./this.program"},b;for(b in yd)void 0===yd[b]?delete a[b]:a[b]=yd[b];var c=[];for(b in a)c.push(`${b}=${a[b]}`);zd=c}return zd},zd,Bd=[null,[],[]];
|
|
||||||
jb=r.InternalError=class extends Error{constructor(a){super(a);this.name="InternalError"}};for(var Cd=Array(256),Dd=0;256>Dd;++Dd)Cd[Dd]=String.fromCharCode(Dd);mb=Cd;M=r.BindingError=class extends Error{constructor(a){super(a);this.name="BindingError"}};
|
|
||||||
Object.assign(Db.prototype,{isAliasOf:function(a){if(!(this instanceof Db&&a instanceof Db))return!1;var b=this.Yd.de.be,c=this.Yd.ae;a.Yd=a.Yd;var e=a.Yd.de.be;for(a=a.Yd.ae;b.ge;)c=b.ye(c),b=b.ge;for(;e.ge;)a=e.ye(a),e=e.ge;return b===e&&c===a},clone:function(){this.Yd.ae||ob(this);if(this.Yd.we)return this.Yd.count.value+=1,this;var a=Ab,b=Object,c=b.create,e=Object.getPrototypeOf(this),f=this.Yd;a=a(c.call(b,e,{Yd:{value:{count:f.count,ve:f.ve,we:f.we,ae:f.ae,de:f.de,ee:f.ee,ie:f.ie}}}));a.Yd.count.value+=
|
|
||||||
1;a.Yd.ve=!1;return a},["delete"](){this.Yd.ae||ob(this);if(this.Yd.ve&&!this.Yd.we)throw new M("Object already scheduled for deletion");qb(this);var a=this.Yd;--a.count.value;0===a.count.value&&(a.ee?a.ie.ne(a.ee):a.de.be.ne(a.ae));this.Yd.we||(this.Yd.ee=void 0,this.Yd.ae=void 0)},isDeleted:function(){return!this.Yd.ae},deleteLater:function(){this.Yd.ae||ob(this);if(this.Yd.ve&&!this.Yd.we)throw new M("Object already scheduled for deletion");Cb.push(this);this.Yd.ve=!0;return this}});
|
|
||||||
Object.assign(Pb.prototype,{gf(a){this.Se&&(a=this.Se(a));return a},Oe(a){this.ne?.(a)},je:8,readValueFromPointer:fb,fromWireType:function(a){function b(){return this.De?Bb(this.be.se,{de:this.nf,ae:c,ie:this,ee:a}):Bb(this.be.se,{de:this,ae:a})}var c=this.gf(a);if(!c)return this.Oe(a),null;var e=zb(this.be,c);if(void 0!==e){if(0===e.Yd.count.value)return e.Yd.ae=c,e.Yd.ee=a,e.clone();e=e.clone();this.Oe(a);return e}e=this.be.ff(c);e=sb[e];if(!e)return b.call(this);e=this.Ce?e.af:e.pointerType;var f=
|
|
||||||
rb(c,this.be,e.be);return null===f?b.call(this):this.De?Bb(e.be.se,{de:e,ae:f,ie:this,ee:a}):Bb(e.be.se,{de:e,ae:f})}});ac=r.UnboundTypeError=((a,b)=>{var c=Eb(b,function(e){this.name=b;this.message=e;e=Error(e).stack;void 0!==e&&(this.stack=this.toString()+"\n"+e.replace(/^Error(:[^\n]*)?\n/,""))});c.prototype=Object.create(a.prototype);c.prototype.constructor=c;c.prototype.toString=function(){return void 0===this.message?this.name:`${this.name}: ${this.message}`};return c})(Error,"UnboundTypeError");
|
|
||||||
kc.push(0,1,void 0,1,null,1,!0,1,!1,1);r.count_emval_handles=()=>kc.length/2-5-jc.length;for(var Ed=0;32>Ed;++Ed)jd.push(Array(Ed));var Fd=new Float32Array(288);for(Ed=0;288>=Ed;++Ed)wd[Ed]=Fd.subarray(0,Ed);var Gd=new Int32Array(288);for(Ed=0;288>=Ed;++Ed)xd[Ed]=Gd.subarray(0,Ed);
|
|
||||||
var Vd={F:(a,b,c)=>{var e=new Xa(a);H[e.ae+16>>2]=0;H[e.ae+4>>2]=b;H[e.ae+8>>2]=c;Ya=a;Za++;throw Ya;},V:function(){return 0},vd:()=>{},ud:function(){return 0},td:()=>{},sd:()=>{},U:function(){},rd:()=>{},nd:()=>{Pa("")},B:a=>{var b=db[a];delete db[a];var c=b.Le,e=b.ne,f=b.Qe,k=f.map(n=>n.kf).concat(f.map(n=>n.sf));lb([a],k,n=>{var l={};f.forEach((p,v)=>{var w=n[v],A=p.hf,D=p.jf,I=n[v+f.length],R=p.rf,P=p.tf;l[p.ef]={read:ba=>w.fromWireType(A(D,ba)),write:(ba,ma)=>{var Y=[];R(P,ba,I.toWireType(Y,
|
|
||||||
ma));eb(Y)}}});return[{name:b.name,fromWireType:p=>{var v={},w;for(w in l)v[w]=l[w].read(p);e(p);return v},toWireType:(p,v)=>{for(var w in l)if(!(w in v))throw new TypeError(`Missing field: "${w}"`);var A=c();for(w in l)l[w].write(A,v[w]);null!==p&&p.push(e,A);return A},je:8,readValueFromPointer:fb,ke:e}]})},Y:()=>{},md:(a,b,c,e)=>{b=L(b);kb(a,{name:b,fromWireType:function(f){return!!f},toWireType:function(f,k){return k?c:e},je:8,readValueFromPointer:function(f){return this.fromWireType(B[f])},ke:null})},
|
|
||||||
l:(a,b,c,e,f,k,n,l,p,v,w,A,D)=>{w=L(w);k=Tb(f,k);l&&=Tb(n,l);v&&=Tb(p,v);D=Tb(A,D);var I=Hb(w);Gb(I,function(){ec(`Cannot construct ${w} due to unbound types`,[e])});lb([a,b,c],e?[e]:[],R=>{R=R[0];if(e){var P=R.be;var ba=P.se}else ba=Db.prototype;R=Eb(w,function(...Ea){if(Object.getPrototypeOf(this)!==ma)throw new M("Use 'new' to construct "+w);if(void 0===Y.pe)throw new M(w+" has no accessible constructor");var fa=Y.pe[Ea.length];if(void 0===fa)throw new M(`Tried to invoke ctor of ${w} with invalid number of parameters (${Ea.length}) - expected (${Object.keys(Y.pe).toString()}) parameters instead!`);
|
|
||||||
return fa.apply(this,Ea)});var ma=Object.create(ba,{constructor:{value:R}});R.prototype=ma;var Y=new Ib(w,R,ma,D,P,k,l,v);if(Y.ge){var ia;(ia=Y.ge).ze??(ia.ze=[]);Y.ge.ze.push(Y)}P=new Pb(w,Y,!0,!1,!1);ia=new Pb(w+"*",Y,!1,!1,!1);ba=new Pb(w+" const*",Y,!1,!0,!1);sb[a]={pointerType:ia,af:ba};Qb(I,R);return[P,ia,ba]})},e:(a,b,c,e,f,k,n)=>{var l=hc(c,e);b=L(b);b=ic(b);k=Tb(f,k);lb([],[a],p=>{function v(){ec(`Cannot call ${w} due to unbound types`,l)}p=p[0];var w=`${p.name}.${b}`;b.startsWith("@@")&&
|
|
||||||
(b=Symbol[b.substring(2)]);var A=p.be.constructor;void 0===A[b]?(v.oe=c-1,A[b]=v):(Fb(A,b,w),A[b].fe[c-1]=v);lb([],l,D=>{D=[D[0],null].concat(D.slice(1));D=gc(w,D,null,k,n);void 0===A[b].fe?(D.oe=c-1,A[b]=D):A[b].fe[c-1]=D;if(p.be.ze)for(const I of p.be.ze)I.constructor.hasOwnProperty(b)||(I.constructor[b]=D);return[]});return[]})},z:(a,b,c,e,f,k)=>{var n=hc(b,c);f=Tb(e,f);lb([],[a],l=>{l=l[0];var p=`constructor ${l.name}`;void 0===l.be.pe&&(l.be.pe=[]);if(void 0!==l.be.pe[b-1])throw new M(`Cannot register multiple constructors with identical number of parameters (${b-
|
|
||||||
1}) for class '${l.name}'! Overload resolution is currently only performed using the parameter count, not actual type info!`);l.be.pe[b-1]=()=>{ec(`Cannot construct ${l.name} due to unbound types`,n)};lb([],n,v=>{v.splice(1,0,null);l.be.pe[b-1]=gc(p,v,null,f,k);return[]});return[]})},a:(a,b,c,e,f,k,n,l)=>{var p=hc(c,e);b=L(b);b=ic(b);k=Tb(f,k);lb([],[a],v=>{function w(){ec(`Cannot call ${A} due to unbound types`,p)}v=v[0];var A=`${v.name}.${b}`;b.startsWith("@@")&&(b=Symbol[b.substring(2)]);l&&v.be.pf.push(b);
|
|
||||||
var D=v.be.se,I=D[b];void 0===I||void 0===I.fe&&I.className!==v.name&&I.oe===c-2?(w.oe=c-2,w.className=v.name,D[b]=w):(Fb(D,b,A),D[b].fe[c-2]=w);lb([],p,R=>{R=gc(A,R,v,k,n);void 0===D[b].fe?(R.oe=c-2,D[b]=R):D[b].fe[c-2]=R;return[]});return[]})},q:(a,b,c)=>{a=L(a);lb([],[b],e=>{e=e[0];r[a]=e.fromWireType(c);return[]})},ld:a=>kb(a,nc),j:(a,b,c,e)=>{function f(){}b=L(b);f.values={};kb(a,{name:b,constructor:f,fromWireType:function(k){return this.constructor.values[k]},toWireType:(k,n)=>n.value,je:8,
|
|
||||||
readValueFromPointer:oc(b,c,e),ke:null});Gb(b,f)},b:(a,b,c)=>{var e=pc(a,"enum");b=L(b);a=e.constructor;e=Object.create(e.constructor.prototype,{value:{value:c},constructor:{value:Eb(`${e.name}_${b}`,function(){})}});a.values[c]=e;a[b]=e},S:(a,b,c)=>{b=L(b);kb(a,{name:b,fromWireType:e=>e,toWireType:(e,f)=>f,je:8,readValueFromPointer:qc(b,c),ke:null})},w:(a,b,c,e,f,k)=>{var n=hc(b,c);a=L(a);a=ic(a);f=Tb(e,f);Gb(a,function(){ec(`Cannot call ${a} due to unbound types`,n)},b-1);lb([],n,l=>{l=[l[0],null].concat(l.slice(1));
|
|
||||||
Qb(a,gc(a,l,null,f,k),b-1);return[]})},C:(a,b,c,e,f)=>{b=L(b);-1===f&&(f=4294967295);f=l=>l;if(0===e){var k=32-8*c;f=l=>l<<k>>>k}var n=b.includes("unsigned")?function(l,p){return p>>>0}:function(l,p){return p};kb(a,{name:b,fromWireType:f,toWireType:n,je:8,readValueFromPointer:rc(b,c,0!==e),ke:null})},p:(a,b,c)=>{function e(k){return new f(Ca.buffer,H[k+4>>2],H[k>>2])}var f=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array][b];c=L(c);kb(a,{name:c,fromWireType:e,
|
|
||||||
je:8,readValueFromPointer:e},{lf:!0})},o:(a,b,c,e,f,k,n,l,p,v,w,A)=>{c=L(c);k=Tb(f,k);l=Tb(n,l);v=Tb(p,v);A=Tb(w,A);lb([a],[b],D=>{D=D[0];return[new Pb(c,D.be,!1,!1,!0,D,e,k,l,v,A)]})},R:(a,b)=>{b=L(b);var c="std::string"===b;kb(a,{name:b,fromWireType:function(e){var f=H[e>>2],k=e+4;if(c)for(var n=k,l=0;l<=f;++l){var p=k+l;if(l==f||0==B[p]){n=n?cb(B,n,p-n):"";if(void 0===v)var v=n;else v+=String.fromCharCode(0),v+=n;n=p+1}}else{v=Array(f);for(l=0;l<f;++l)v[l]=String.fromCharCode(B[k+l]);v=v.join("")}cc(e);
|
|
||||||
return v},toWireType:function(e,f){f instanceof ArrayBuffer&&(f=new Uint8Array(f));var k="string"==typeof f;if(!(k||f instanceof Uint8Array||f instanceof Uint8ClampedArray||f instanceof Int8Array))throw new M("Cannot pass non-string to std::string");var n=c&&k?qa(f):f.length;var l=pd(4+n+1),p=l+4;H[l>>2]=n;if(c&&k)ra(f,p,n+1);else if(k)for(k=0;k<n;++k){var v=f.charCodeAt(k);if(255<v)throw cc(p),new M("String has UTF-16 code units that do not fit in 8 bits");B[p+k]=v}else for(k=0;k<n;++k)B[p+k]=f[k];
|
|
||||||
null!==e&&e.push(cc,l);return l},je:8,readValueFromPointer:fb,ke(e){cc(e)}})},M:(a,b,c)=>{c=L(c);if(2===b){var e=tc;var f=uc;var k=vc;var n=l=>Fa[l>>1]}else 4===b&&(e=wc,f=xc,k=yc,n=l=>H[l>>2]);kb(a,{name:c,fromWireType:l=>{for(var p=H[l>>2],v,w=l+4,A=0;A<=p;++A){var D=l+4+A*b;if(A==p||0==n(D))w=e(w,D-w),void 0===v?v=w:(v+=String.fromCharCode(0),v+=w),w=D+b}cc(l);return v},toWireType:(l,p)=>{if("string"!=typeof p)throw new M(`Cannot pass non-string to C++ string type ${c}`);var v=k(p),w=pd(4+v+b);
|
|
||||||
H[w>>2]=v/b;f(p,w+4,v+b);null!==l&&l.push(cc,w);return w},je:8,readValueFromPointer:fb,ke(l){cc(l)}})},A:(a,b,c,e,f,k)=>{db[a]={name:L(b),Le:Tb(c,e),ne:Tb(f,k),Qe:[]}},d:(a,b,c,e,f,k,n,l,p,v)=>{db[a].Qe.push({ef:L(b),kf:c,hf:Tb(e,f),jf:k,sf:n,rf:Tb(l,p),tf:v})},kd:(a,b)=>{b=L(b);kb(a,{yf:!0,name:b,je:0,fromWireType:()=>{},toWireType:()=>{}})},jd:()=>1,id:()=>{throw Infinity;},E:(a,b,c)=>{a=mc(a);b=pc(b,"emval::as");return zc(b,c,a)},L:(a,b,c,e)=>{a=Ac[a];b=mc(b);return a(null,b,c,e)},t:(a,b,c,e,f)=>
|
|
||||||
{a=Ac[a];b=mc(b);c=Cc(c);return a(b,b[c],e,f)},c:lc,K:a=>{if(0===a)return Nb(Dc());a=Cc(a);return Nb(Dc()[a])},n:(a,b,c)=>{var e=Fc(a,b),f=e.shift();a--;var k=Array(a);b=`methodCaller<(${e.map(n=>n.name).join(", ")}) => ${f.name}>`;return Ec(Eb(b,(n,l,p,v)=>{for(var w=0,A=0;A<a;++A)k[A]=e[A].readValueFromPointer(v+w),w+=e[A].je;n=1===c?Gc(l,k):l.apply(n,k);return zc(f,p,n)}))},y:(a,b)=>{a=mc(a);b=mc(b);return Nb(a[b])},H:a=>{9<a&&(kc[a+1]+=1)},G:()=>Nb([]),f:a=>Nb(Cc(a)),D:()=>Nb({}),hd:a=>{a=mc(a);
|
|
||||||
return!a},m:a=>{var b=mc(a);eb(b);lc(a)},h:(a,b,c)=>{a=mc(a);b=mc(b);c=mc(c);a[b]=c},g:(a,b)=>{a=pc(a,"_emval_take_value");a=a.readValueFromPointer(b);return Nb(a)},X:function(){return-52},W:function(){},gd:(a,b,c,e)=>{var f=(new Date).getFullYear(),k=(new Date(f,0,1)).getTimezoneOffset();f=(new Date(f,6,1)).getTimezoneOffset();H[a>>2]=60*Math.max(k,f);E[b>>2]=Number(k!=f);b=n=>{var l=Math.abs(n);return`UTC${0<=n?"-":"+"}${String(Math.floor(l/60)).padStart(2,"0")}${String(l%60).padStart(2,"0")}`};
|
|
||||||
a=b(k);b=b(f);f<k?(ra(a,c,17),ra(b,e,17)):(ra(a,e,17),ra(b,c,17))},fd:()=>performance.now(),ed:a=>Q.activeTexture(a),dd:(a,b)=>{Q.attachShader(Nc[a],Qc[b])},cd:(a,b)=>{Q.beginQuery(a,Sc[b])},bd:(a,b)=>{Q.me.beginQueryEXT(a,Sc[b])},ad:(a,b,c)=>{Q.bindAttribLocation(Nc[a],b,c?cb(B,c):"")},$c:(a,b)=>{35051==a?Q.Ie=b:35052==a&&(Q.re=b);Q.bindBuffer(a,Mc[b])},_c:cd,Zc:(a,b)=>{Q.bindRenderbuffer(a,Pc[b])},Yc:(a,b)=>{Q.bindSampler(a,Tc[b])},Xc:(a,b)=>{Q.bindTexture(a,ka[b])},Wc:dd,Vc:dd,Uc:(a,b,c,e)=>Q.blendColor(a,
|
|
||||||
b,c,e),Tc:a=>Q.blendEquation(a),Sc:(a,b)=>Q.blendFunc(a,b),Rc:(a,b,c,e,f,k,n,l,p,v)=>Q.blitFramebuffer(a,b,c,e,f,k,n,l,p,v),Qc:(a,b,c,e)=>{2<=z.version?c&&b?Q.bufferData(a,B,e,c,b):Q.bufferData(a,b,e):Q.bufferData(a,c?B.subarray(c,c+b):b,e)},Pc:(a,b,c,e)=>{2<=z.version?c&&Q.bufferSubData(a,b,B,e,c):Q.bufferSubData(a,b,B.subarray(e,e+c))},Oc:a=>Q.checkFramebufferStatus(a),Nc:ed,Mc:fd,Lc:gd,Kc:(a,b,c,e)=>Q.clientWaitSync(Uc[a],b,(c>>>0)+4294967296*e),Jc:(a,b,c,e)=>{Q.colorMask(!!a,!!b,!!c,!!e)},Ic:a=>
|
|
||||||
{Q.compileShader(Qc[a])},Hc:(a,b,c,e,f,k,n,l)=>{2<=z.version?Q.re||!n?Q.compressedTexImage2D(a,b,c,e,f,k,n,l):Q.compressedTexImage2D(a,b,c,e,f,k,B,l,n):Q.compressedTexImage2D(a,b,c,e,f,k,B.subarray(l,l+n))},Gc:(a,b,c,e,f,k,n,l,p)=>{2<=z.version?Q.re||!l?Q.compressedTexSubImage2D(a,b,c,e,f,k,n,l,p):Q.compressedTexSubImage2D(a,b,c,e,f,k,n,B,p,l):Q.compressedTexSubImage2D(a,b,c,e,f,k,n,B.subarray(p,p+l))},Fc:(a,b,c,e,f)=>Q.copyBufferSubData(a,b,c,e,f),Ec:(a,b,c,e,f,k,n,l)=>Q.copyTexSubImage2D(a,b,c,
|
|
||||||
e,f,k,n,l),Dc:()=>{var a=ja(Nc),b=Q.createProgram();b.name=a;b.Ge=b.Ee=b.Fe=0;b.Me=1;Nc[a]=b;return a},Cc:a=>{var b=ja(Qc);Qc[b]=Q.createShader(a);return b},Bc:a=>Q.cullFace(a),Ac:(a,b)=>{for(var c=0;c<a;c++){var e=E[b+4*c>>2],f=Mc[e];f&&(Q.deleteBuffer(f),f.name=0,Mc[e]=null,e==Q.Ie&&(Q.Ie=0),e==Q.re&&(Q.re=0))}},zc:(a,b)=>{for(var c=0;c<a;++c){var e=E[b+4*c>>2],f=Oc[e];f&&(Q.deleteFramebuffer(f),f.name=0,Oc[e]=null)}},yc:a=>{if(a){var b=Nc[a];b?(Q.deleteProgram(b),b.name=0,Nc[a]=null):S||=1281}},
|
|
||||||
xc:(a,b)=>{for(var c=0;c<a;c++){var e=E[b+4*c>>2],f=Sc[e];f&&(Q.deleteQuery(f),Sc[e]=null)}},wc:(a,b)=>{for(var c=0;c<a;c++){var e=E[b+4*c>>2],f=Sc[e];f&&(Q.me.deleteQueryEXT(f),Sc[e]=null)}},vc:(a,b)=>{for(var c=0;c<a;c++){var e=E[b+4*c>>2],f=Pc[e];f&&(Q.deleteRenderbuffer(f),f.name=0,Pc[e]=null)}},uc:(a,b)=>{for(var c=0;c<a;c++){var e=E[b+4*c>>2],f=Tc[e];f&&(Q.deleteSampler(f),f.name=0,Tc[e]=null)}},tc:a=>{if(a){var b=Qc[a];b?(Q.deleteShader(b),Qc[a]=null):S||=1281}},sc:a=>{if(a){var b=Uc[a];b?
|
|
||||||
(Q.deleteSync(b),b.name=0,Uc[a]=null):S||=1281}},rc:(a,b)=>{for(var c=0;c<a;c++){var e=E[b+4*c>>2],f=ka[e];f&&(Q.deleteTexture(f),f.name=0,ka[e]=null)}},qc:hd,pc:hd,oc:a=>{Q.depthMask(!!a)},nc:a=>Q.disable(a),mc:a=>{Q.disableVertexAttribArray(a)},lc:(a,b,c)=>{Q.drawArrays(a,b,c)},kc:(a,b,c,e)=>{Q.drawArraysInstanced(a,b,c,e)},jc:(a,b,c,e,f)=>{Q.Pe.drawArraysInstancedBaseInstanceWEBGL(a,b,c,e,f)},ic:(a,b)=>{for(var c=jd[a],e=0;e<a;e++)c[e]=E[b+4*e>>2];Q.drawBuffers(c)},hc:(a,b,c,e)=>{Q.drawElements(a,
|
|
||||||
b,c,e)},gc:(a,b,c,e,f)=>{Q.drawElementsInstanced(a,b,c,e,f)},fc:(a,b,c,e,f,k,n)=>{Q.Pe.drawElementsInstancedBaseVertexBaseInstanceWEBGL(a,b,c,e,f,k,n)},ec:(a,b,c,e,f,k)=>{Q.drawElements(a,e,f,k)},dc:a=>Q.enable(a),cc:a=>{Q.enableVertexAttribArray(a)},bc:a=>Q.endQuery(a),ac:a=>{Q.me.endQueryEXT(a)},$b:(a,b)=>(a=Q.fenceSync(a,b))?(b=ja(Uc),a.name=b,Uc[b]=a,b):0,_b:()=>Q.finish(),Zb:()=>Q.flush(),Yb:(a,b,c,e)=>{Q.framebufferRenderbuffer(a,b,c,Pc[e])},Xb:(a,b,c,e,f)=>{Q.framebufferTexture2D(a,b,c,ka[e],
|
|
||||||
f)},Wb:a=>Q.frontFace(a),Vb:(a,b)=>{$c(a,b,"createBuffer",Mc)},Ub:(a,b)=>{$c(a,b,"createFramebuffer",Oc)},Tb:(a,b)=>{$c(a,b,"createQuery",Sc)},Sb:(a,b)=>{for(var c=0;c<a;c++){var e=Q.me.createQueryEXT();if(!e){for(S||=1282;c<a;)E[b+4*c++>>2]=0;break}var f=ja(Sc);e.name=f;Sc[f]=e;E[b+4*c>>2]=f}},Rb:(a,b)=>{$c(a,b,"createRenderbuffer",Pc)},Qb:(a,b)=>{$c(a,b,"createSampler",Tc)},Pb:(a,b)=>{$c(a,b,"createTexture",ka)},Ob:kd,Nb:kd,Mb:a=>Q.generateMipmap(a),Lb:(a,b,c)=>{c?E[c>>2]=Q.getBufferParameter(a,
|
|
||||||
b):S||=1281},Kb:()=>{var a=Q.getError()||S;S=0;return a},Jb:(a,b)=>md(a,b,2),Ib:(a,b,c,e)=>{a=Q.getFramebufferAttachmentParameter(a,b,c);if(a instanceof WebGLRenderbuffer||a instanceof WebGLTexture)a=a.name|0;E[e>>2]=a},Hb:nd,Gb:(a,b,c,e)=>{a=Q.getProgramInfoLog(Nc[a]);null===a&&(a="(unknown error)");b=0<b&&e?ra(a,e,b):0;c&&(E[c>>2]=b)},Fb:(a,b,c)=>{if(c)if(a>=Lc)S||=1281;else if(a=Nc[a],35716==b)a=Q.getProgramInfoLog(a),null===a&&(a="(unknown error)"),E[c>>2]=a.length+1;else if(35719==b){if(!a.Ge){var e=
|
|
||||||
Q.getProgramParameter(a,35718);for(b=0;b<e;++b)a.Ge=Math.max(a.Ge,Q.getActiveUniform(a,b).name.length+1)}E[c>>2]=a.Ge}else if(35722==b){if(!a.Ee)for(e=Q.getProgramParameter(a,35721),b=0;b<e;++b)a.Ee=Math.max(a.Ee,Q.getActiveAttrib(a,b).name.length+1);E[c>>2]=a.Ee}else if(35381==b){if(!a.Fe)for(e=Q.getProgramParameter(a,35382),b=0;b<e;++b)a.Fe=Math.max(a.Fe,Q.getActiveUniformBlockName(a,b).length+1);E[c>>2]=a.Fe}else E[c>>2]=Q.getProgramParameter(a,b);else S||=1281},Eb:od,Db:od,Cb:(a,b,c)=>{if(c){a=
|
|
||||||
Q.getQueryParameter(Sc[a],b);var e;"boolean"==typeof a?e=a?1:0:e=a;E[c>>2]=e}else S||=1281},Bb:(a,b,c)=>{if(c){a=Q.me.getQueryObjectEXT(Sc[a],b);var e;"boolean"==typeof a?e=a?1:0:e=a;E[c>>2]=e}else S||=1281},Ab:(a,b,c)=>{c?E[c>>2]=Q.getQuery(a,b):S||=1281},zb:(a,b,c)=>{c?E[c>>2]=Q.me.getQueryEXT(a,b):S||=1281},yb:(a,b,c)=>{c?E[c>>2]=Q.getRenderbufferParameter(a,b):S||=1281},xb:(a,b,c,e)=>{a=Q.getShaderInfoLog(Qc[a]);null===a&&(a="(unknown error)");b=0<b&&e?ra(a,e,b):0;c&&(E[c>>2]=b)},wb:(a,b,c,e)=>
|
|
||||||
{a=Q.getShaderPrecisionFormat(a,b);E[c>>2]=a.rangeMin;E[c+4>>2]=a.rangeMax;E[e>>2]=a.precision},vb:(a,b,c)=>{c?35716==b?(a=Q.getShaderInfoLog(Qc[a]),null===a&&(a="(unknown error)"),E[c>>2]=a?a.length+1:0):35720==b?(a=Q.getShaderSource(Qc[a]),E[c>>2]=a?a.length+1:0):E[c>>2]=Q.getShaderParameter(Qc[a],b):S||=1281},ub:rd,tb:sd,sb:(a,b)=>{b=b?cb(B,b):"";if(a=Nc[a]){var c=a,e=c.xe,f=c.Ue,k;if(!e){c.xe=e={};c.Te={};var n=Q.getProgramParameter(c,35718);for(k=0;k<n;++k){var l=Q.getActiveUniform(c,k);var p=
|
|
||||||
l.name;l=l.size;var v=td(p);v=0<v?p.slice(0,v):p;var w=c.Me;c.Me+=l;f[v]=[l,w];for(p=0;p<l;++p)e[w]=p,c.Te[w++]=v}}c=a.xe;e=0;f=b;k=td(b);0<k&&(e=parseInt(b.slice(k+1))>>>0,f=b.slice(0,k));if((f=a.Ue[f])&&e<f[0]&&(e+=f[1],c[e]=c[e]||Q.getUniformLocation(a,b)))return e}else S||=1281;return-1},rb:(a,b,c)=>{for(var e=jd[b],f=0;f<b;f++)e[f]=E[c+4*f>>2];Q.invalidateFramebuffer(a,e)},qb:(a,b,c,e,f,k,n)=>{for(var l=jd[b],p=0;p<b;p++)l[p]=E[c+4*p>>2];Q.invalidateSubFramebuffer(a,l,e,f,k,n)},pb:a=>Q.isSync(Uc[a]),
|
|
||||||
ob:a=>(a=ka[a])?Q.isTexture(a):0,nb:a=>Q.lineWidth(a),mb:a=>{a=Nc[a];Q.linkProgram(a);a.xe=0;a.Ue={}},lb:(a,b,c,e,f,k)=>{Q.Re.multiDrawArraysInstancedBaseInstanceWEBGL(a,E,b>>2,E,c>>2,E,e>>2,H,f>>2,k)},kb:(a,b,c,e,f,k,n,l)=>{Q.Re.multiDrawElementsInstancedBaseVertexBaseInstanceWEBGL(a,E,b>>2,c,E,e>>2,E,f>>2,E,k>>2,H,n>>2,l)},jb:(a,b)=>{3317==a?Yc=b:3314==a&&(Zc=b);Q.pixelStorei(a,b)},ib:(a,b)=>{Q.me.queryCounterEXT(Sc[a],b)},hb:a=>Q.readBuffer(a),gb:(a,b,c,e,f,k,n)=>{if(2<=z.version)if(Q.Ie)Q.readPixels(a,
|
|
||||||
b,c,e,f,k,n);else{var l=ud(k);n>>>=31-Math.clz32(l.BYTES_PER_ELEMENT);Q.readPixels(a,b,c,e,f,k,l,n)}else(l=vd(k,f,c,e,n))?Q.readPixels(a,b,c,e,f,k,l):S||=1280},fb:(a,b,c,e)=>Q.renderbufferStorage(a,b,c,e),eb:(a,b,c,e,f)=>Q.renderbufferStorageMultisample(a,b,c,e,f),db:(a,b,c)=>{Q.samplerParameterf(Tc[a],b,c)},cb:(a,b,c)=>{Q.samplerParameteri(Tc[a],b,c)},bb:(a,b,c)=>{Q.samplerParameteri(Tc[a],b,E[c>>2])},ab:(a,b,c,e)=>Q.scissor(a,b,c,e),$a:(a,b,c,e)=>{for(var f="",k=0;k<b;++k){var n=(n=H[c+4*k>>2])?
|
|
||||||
cb(B,n,e?H[e+4*k>>2]:void 0):"";f+=n}Q.shaderSource(Qc[a],f)},_a:(a,b,c)=>Q.stencilFunc(a,b,c),Za:(a,b,c,e)=>Q.stencilFuncSeparate(a,b,c,e),Ya:a=>Q.stencilMask(a),Xa:(a,b)=>Q.stencilMaskSeparate(a,b),Wa:(a,b,c)=>Q.stencilOp(a,b,c),Va:(a,b,c,e)=>Q.stencilOpSeparate(a,b,c,e),Ua:(a,b,c,e,f,k,n,l,p)=>{if(2<=z.version){if(Q.re){Q.texImage2D(a,b,c,e,f,k,n,l,p);return}if(p){var v=ud(l);p>>>=31-Math.clz32(v.BYTES_PER_ELEMENT);Q.texImage2D(a,b,c,e,f,k,n,l,v,p);return}}v=p?vd(l,n,e,f,p):null;Q.texImage2D(a,
|
|
||||||
b,c,e,f,k,n,l,v)},Ta:(a,b,c)=>Q.texParameterf(a,b,c),Sa:(a,b,c)=>{Q.texParameterf(a,b,J[c>>2])},Ra:(a,b,c)=>Q.texParameteri(a,b,c),Qa:(a,b,c)=>{Q.texParameteri(a,b,E[c>>2])},Pa:(a,b,c,e,f)=>Q.texStorage2D(a,b,c,e,f),Oa:(a,b,c,e,f,k,n,l,p)=>{if(2<=z.version){if(Q.re){Q.texSubImage2D(a,b,c,e,f,k,n,l,p);return}if(p){var v=ud(l);Q.texSubImage2D(a,b,c,e,f,k,n,l,v,p>>>31-Math.clz32(v.BYTES_PER_ELEMENT));return}}p=p?vd(l,n,f,k,p):null;Q.texSubImage2D(a,b,c,e,f,k,n,l,p)},Na:(a,b)=>{Q.uniform1f(V(a),b)},Ma:(a,
|
|
||||||
b,c)=>{if(2<=z.version)b&&Q.uniform1fv(V(a),J,c>>2,b);else{if(288>=b)for(var e=wd[b],f=0;f<b;++f)e[f]=J[c+4*f>>2];else e=J.subarray(c>>2,c+4*b>>2);Q.uniform1fv(V(a),e)}},La:(a,b)=>{Q.uniform1i(V(a),b)},Ka:(a,b,c)=>{if(2<=z.version)b&&Q.uniform1iv(V(a),E,c>>2,b);else{if(288>=b)for(var e=xd[b],f=0;f<b;++f)e[f]=E[c+4*f>>2];else e=E.subarray(c>>2,c+4*b>>2);Q.uniform1iv(V(a),e)}},Ja:(a,b,c)=>{Q.uniform2f(V(a),b,c)},Ia:(a,b,c)=>{if(2<=z.version)b&&Q.uniform2fv(V(a),J,c>>2,2*b);else{if(144>=b){b*=2;for(var e=
|
|
||||||
wd[b],f=0;f<b;f+=2)e[f]=J[c+4*f>>2],e[f+1]=J[c+(4*f+4)>>2]}else e=J.subarray(c>>2,c+8*b>>2);Q.uniform2fv(V(a),e)}},Ha:(a,b,c)=>{Q.uniform2i(V(a),b,c)},Ga:(a,b,c)=>{if(2<=z.version)b&&Q.uniform2iv(V(a),E,c>>2,2*b);else{if(144>=b){b*=2;for(var e=xd[b],f=0;f<b;f+=2)e[f]=E[c+4*f>>2],e[f+1]=E[c+(4*f+4)>>2]}else e=E.subarray(c>>2,c+8*b>>2);Q.uniform2iv(V(a),e)}},Fa:(a,b,c,e)=>{Q.uniform3f(V(a),b,c,e)},Ea:(a,b,c)=>{if(2<=z.version)b&&Q.uniform3fv(V(a),J,c>>2,3*b);else{if(96>=b){b*=3;for(var e=wd[b],f=0;f<
|
|
||||||
b;f+=3)e[f]=J[c+4*f>>2],e[f+1]=J[c+(4*f+4)>>2],e[f+2]=J[c+(4*f+8)>>2]}else e=J.subarray(c>>2,c+12*b>>2);Q.uniform3fv(V(a),e)}},Da:(a,b,c,e)=>{Q.uniform3i(V(a),b,c,e)},Ca:(a,b,c)=>{if(2<=z.version)b&&Q.uniform3iv(V(a),E,c>>2,3*b);else{if(96>=b){b*=3;for(var e=xd[b],f=0;f<b;f+=3)e[f]=E[c+4*f>>2],e[f+1]=E[c+(4*f+4)>>2],e[f+2]=E[c+(4*f+8)>>2]}else e=E.subarray(c>>2,c+12*b>>2);Q.uniform3iv(V(a),e)}},Ba:(a,b,c,e,f)=>{Q.uniform4f(V(a),b,c,e,f)},Aa:(a,b,c)=>{if(2<=z.version)b&&Q.uniform4fv(V(a),J,c>>2,4*
|
|
||||||
b);else{if(72>=b){var e=wd[4*b],f=J;c>>=2;b*=4;for(var k=0;k<b;k+=4){var n=c+k;e[k]=f[n];e[k+1]=f[n+1];e[k+2]=f[n+2];e[k+3]=f[n+3]}}else e=J.subarray(c>>2,c+16*b>>2);Q.uniform4fv(V(a),e)}},za:(a,b,c,e,f)=>{Q.uniform4i(V(a),b,c,e,f)},ya:(a,b,c)=>{if(2<=z.version)b&&Q.uniform4iv(V(a),E,c>>2,4*b);else{if(72>=b){b*=4;for(var e=xd[b],f=0;f<b;f+=4)e[f]=E[c+4*f>>2],e[f+1]=E[c+(4*f+4)>>2],e[f+2]=E[c+(4*f+8)>>2],e[f+3]=E[c+(4*f+12)>>2]}else e=E.subarray(c>>2,c+16*b>>2);Q.uniform4iv(V(a),e)}},xa:(a,b,c,e)=>
|
|
||||||
{if(2<=z.version)b&&Q.uniformMatrix2fv(V(a),!!c,J,e>>2,4*b);else{if(72>=b){b*=4;for(var f=wd[b],k=0;k<b;k+=4)f[k]=J[e+4*k>>2],f[k+1]=J[e+(4*k+4)>>2],f[k+2]=J[e+(4*k+8)>>2],f[k+3]=J[e+(4*k+12)>>2]}else f=J.subarray(e>>2,e+16*b>>2);Q.uniformMatrix2fv(V(a),!!c,f)}},wa:(a,b,c,e)=>{if(2<=z.version)b&&Q.uniformMatrix3fv(V(a),!!c,J,e>>2,9*b);else{if(32>=b){b*=9;for(var f=wd[b],k=0;k<b;k+=9)f[k]=J[e+4*k>>2],f[k+1]=J[e+(4*k+4)>>2],f[k+2]=J[e+(4*k+8)>>2],f[k+3]=J[e+(4*k+12)>>2],f[k+4]=J[e+(4*k+16)>>2],f[k+
|
|
||||||
5]=J[e+(4*k+20)>>2],f[k+6]=J[e+(4*k+24)>>2],f[k+7]=J[e+(4*k+28)>>2],f[k+8]=J[e+(4*k+32)>>2]}else f=J.subarray(e>>2,e+36*b>>2);Q.uniformMatrix3fv(V(a),!!c,f)}},va:(a,b,c,e)=>{if(2<=z.version)b&&Q.uniformMatrix4fv(V(a),!!c,J,e>>2,16*b);else{if(18>=b){var f=wd[16*b],k=J;e>>=2;b*=16;for(var n=0;n<b;n+=16){var l=e+n;f[n]=k[l];f[n+1]=k[l+1];f[n+2]=k[l+2];f[n+3]=k[l+3];f[n+4]=k[l+4];f[n+5]=k[l+5];f[n+6]=k[l+6];f[n+7]=k[l+7];f[n+8]=k[l+8];f[n+9]=k[l+9];f[n+10]=k[l+10];f[n+11]=k[l+11];f[n+12]=k[l+12];f[n+
|
|
||||||
13]=k[l+13];f[n+14]=k[l+14];f[n+15]=k[l+15]}}else f=J.subarray(e>>2,e+64*b>>2);Q.uniformMatrix4fv(V(a),!!c,f)}},ua:a=>{a=Nc[a];Q.useProgram(a);Q.bf=a},ta:(a,b)=>Q.vertexAttrib1f(a,b),sa:(a,b)=>{Q.vertexAttrib2f(a,J[b>>2],J[b+4>>2])},ra:(a,b)=>{Q.vertexAttrib3f(a,J[b>>2],J[b+4>>2],J[b+8>>2])},qa:(a,b)=>{Q.vertexAttrib4f(a,J[b>>2],J[b+4>>2],J[b+8>>2],J[b+12>>2])},pa:(a,b)=>{Q.vertexAttribDivisor(a,b)},oa:(a,b,c,e,f)=>{Q.vertexAttribIPointer(a,b,c,e,f)},na:(a,b,c,e,f,k)=>{Q.vertexAttribPointer(a,b,c,
|
|
||||||
!!e,f,k)},ma:(a,b,c,e)=>Q.viewport(a,b,c,e),la:(a,b,c,e)=>{Q.waitSync(Uc[a],b,(c>>>0)+4294967296*e)},ka:a=>{var b=B.length;a>>>=0;if(2147483648<a)return!1;for(var c=1;4>=c;c*=2){var e=b*(1+1/c);e=Math.min(e,a+100663296);a:{e=(Math.min(2147483648,65536*Math.ceil(Math.max(a,e)/65536))-za.buffer.byteLength+65535)/65536|0;try{za.grow(e);Ha();var f=1;break a}catch(k){}f=void 0}if(f)return!0}return!1},ja:()=>z?z.handle:0,qd:(a,b)=>{var c=0;Ad().forEach((e,f)=>{var k=b+c;f=H[a+4*f>>2]=k;for(k=0;k<e.length;++k)Ca[f++]=
|
|
||||||
e.charCodeAt(k);Ca[f]=0;c+=e.length+1});return 0},pd:(a,b)=>{var c=Ad();H[a>>2]=c.length;var e=0;c.forEach(f=>e+=f.length+1);H[b>>2]=e;return 0},ia:a=>{throw new Va(a);},N:()=>52,_:function(){return 52},od:()=>52,Z:function(){return 70},T:(a,b,c,e)=>{for(var f=0,k=0;k<c;k++){var n=H[b>>2],l=H[b+4>>2];b+=8;for(var p=0;p<l;p++){var v=B[n+p],w=Bd[a];0===v||10===v?((1===a?wa:ya)(cb(w)),w.length=0):w.push(v)}f+=l}H[e>>2]=f;return 0},ha:cd,ga:ed,fa:fd,ea:gd,J:nd,Q:rd,da:sd,k:Hd,u:Id,i:Jd,I:Kd,ca:Ld,P:Md,
|
|
||||||
O:Nd,s:Od,x:Pd,r:Qd,v:Rd,ba:Sd,aa:Td,$:Ud},Z=function(){var a={a:Vd};La++;Ra??=r.locateFile?Qa("canvaskit.wasm")?"canvaskit.wasm":ta+"canvaskit.wasm":(new URL("canvaskit.wasm",import.meta.url)).href;Ua(a,function(b){Z=b.instance.exports;za=Z.wd;Ha();O=Z.zd;Ja.unshift(Z.xd);La--;0==La&&(null!==Ma&&(clearInterval(Ma),Ma=null),Oa&&(b=Oa,Oa=null,b()))}).catch(ca);return{}}(),bc=a=>(bc=Z.yd)(a),pd=r._malloc=a=>(pd=r._malloc=Z.Ad)(a),cc=r._free=a=>(cc=r._free=Z.Bd)(a),Wd=(a,b)=>(Wd=Z.Cd)(a,b),
|
|
||||||
Xd=a=>(Xd=Z.Dd)(a),Yd=()=>(Yd=Z.Ed)();r.dynCall_viji=(a,b,c,e,f)=>(r.dynCall_viji=Z.Fd)(a,b,c,e,f);r.dynCall_vijiii=(a,b,c,e,f,k,n)=>(r.dynCall_vijiii=Z.Gd)(a,b,c,e,f,k,n);r.dynCall_viiiiij=(a,b,c,e,f,k,n,l)=>(r.dynCall_viiiiij=Z.Hd)(a,b,c,e,f,k,n,l);r.dynCall_iiiji=(a,b,c,e,f,k)=>(r.dynCall_iiiji=Z.Id)(a,b,c,e,f,k);r.dynCall_jii=(a,b,c)=>(r.dynCall_jii=Z.Jd)(a,b,c);r.dynCall_vij=(a,b,c,e)=>(r.dynCall_vij=Z.Kd)(a,b,c,e);r.dynCall_jiiiiii=(a,b,c,e,f,k,n)=>(r.dynCall_jiiiiii=Z.Ld)(a,b,c,e,f,k,n);
|
|
||||||
r.dynCall_jiiiiji=(a,b,c,e,f,k,n,l)=>(r.dynCall_jiiiiji=Z.Md)(a,b,c,e,f,k,n,l);r.dynCall_ji=(a,b)=>(r.dynCall_ji=Z.Nd)(a,b);r.dynCall_iijj=(a,b,c,e,f,k)=>(r.dynCall_iijj=Z.Od)(a,b,c,e,f,k);r.dynCall_iiji=(a,b,c,e,f)=>(r.dynCall_iiji=Z.Pd)(a,b,c,e,f);r.dynCall_iijjiii=(a,b,c,e,f,k,n,l,p)=>(r.dynCall_iijjiii=Z.Qd)(a,b,c,e,f,k,n,l,p);r.dynCall_iij=(a,b,c,e)=>(r.dynCall_iij=Z.Rd)(a,b,c,e);r.dynCall_vijjjii=(a,b,c,e,f,k,n,l,p,v)=>(r.dynCall_vijjjii=Z.Sd)(a,b,c,e,f,k,n,l,p,v);
|
|
||||||
r.dynCall_jiji=(a,b,c,e,f)=>(r.dynCall_jiji=Z.Td)(a,b,c,e,f);r.dynCall_viijii=(a,b,c,e,f,k,n)=>(r.dynCall_viijii=Z.Ud)(a,b,c,e,f,k,n);r.dynCall_iiiiij=(a,b,c,e,f,k,n)=>(r.dynCall_iiiiij=Z.Vd)(a,b,c,e,f,k,n);r.dynCall_iiiiijj=(a,b,c,e,f,k,n,l,p)=>(r.dynCall_iiiiijj=Z.Wd)(a,b,c,e,f,k,n,l,p);r.dynCall_iiiiiijj=(a,b,c,e,f,k,n,l,p,v)=>(r.dynCall_iiiiiijj=Z.Xd)(a,b,c,e,f,k,n,l,p,v);function Rd(a,b,c,e,f){var k=Yd();try{O.get(a)(b,c,e,f)}catch(n){Xd(k);if(n!==n+0)throw n;Wd(1,0)}}
|
|
||||||
function Id(a,b,c){var e=Yd();try{return O.get(a)(b,c)}catch(f){Xd(e);if(f!==f+0)throw f;Wd(1,0)}}function Pd(a,b,c){var e=Yd();try{O.get(a)(b,c)}catch(f){Xd(e);if(f!==f+0)throw f;Wd(1,0)}}function Hd(a,b){var c=Yd();try{return O.get(a)(b)}catch(e){Xd(c);if(e!==e+0)throw e;Wd(1,0)}}function Od(a,b){var c=Yd();try{O.get(a)(b)}catch(e){Xd(c);if(e!==e+0)throw e;Wd(1,0)}}function Jd(a,b,c,e){var f=Yd();try{return O.get(a)(b,c,e)}catch(k){Xd(f);if(k!==k+0)throw k;Wd(1,0)}}
|
|
||||||
function Ud(a,b,c,e,f,k,n,l,p,v){var w=Yd();try{O.get(a)(b,c,e,f,k,n,l,p,v)}catch(A){Xd(w);if(A!==A+0)throw A;Wd(1,0)}}function Qd(a,b,c,e){var f=Yd();try{O.get(a)(b,c,e)}catch(k){Xd(f);if(k!==k+0)throw k;Wd(1,0)}}function Td(a,b,c,e,f,k,n){var l=Yd();try{O.get(a)(b,c,e,f,k,n)}catch(p){Xd(l);if(p!==p+0)throw p;Wd(1,0)}}function Md(a,b,c,e,f,k,n,l){var p=Yd();try{return O.get(a)(b,c,e,f,k,n,l)}catch(v){Xd(p);if(v!==v+0)throw v;Wd(1,0)}}
|
|
||||||
function Sd(a,b,c,e,f,k){var n=Yd();try{O.get(a)(b,c,e,f,k)}catch(l){Xd(n);if(l!==l+0)throw l;Wd(1,0)}}function Kd(a,b,c,e,f){var k=Yd();try{return O.get(a)(b,c,e,f)}catch(n){Xd(k);if(n!==n+0)throw n;Wd(1,0)}}function Nd(a,b,c,e,f,k,n,l,p,v){var w=Yd();try{return O.get(a)(b,c,e,f,k,n,l,p,v)}catch(A){Xd(w);if(A!==A+0)throw A;Wd(1,0)}}function Ld(a,b,c,e,f,k,n){var l=Yd();try{return O.get(a)(b,c,e,f,k,n)}catch(p){Xd(l);if(p!==p+0)throw p;Wd(1,0)}}var Zd,$d;Oa=function ae(){Zd||be();Zd||(Oa=ae)};
|
|
||||||
function be(){if(!(0<La)){if(!$d&&($d=1,Wa(Ia),0<La))return;Zd||(Zd=1,r.calledRun=1,Aa||(Wa(Ja),aa(r),r.onRuntimeInitialized?.(),Wa(Ka)))}}be();moduleRtn=da;
|
|
||||||
|
|
||||||
|
|
||||||
return moduleRtn;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
})();
|
|
||||||
export default CanvasKitInit;
|
|
Binary file not shown.
@ -127,9 +127,29 @@
|
|||||||
<img class="center" aria-hidden="true" src="splash/img/light-1x.png" alt="">
|
<img class="center" aria-hidden="true" src="splash/img/light-1x.png" alt="">
|
||||||
</picture>
|
</picture>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
{{flutter_js}}
|
||||||
|
{{flutter_build_config}}
|
||||||
|
|
||||||
<script src="flutter_bootstrap.js" async=""></script>
|
const searchParams = new URLSearchParams(window.location.search);
|
||||||
|
const renderer = searchParams.get('renderer');
|
||||||
|
let cdn = searchParams.get('cdn');
|
||||||
|
|
||||||
|
if (cdn) {
|
||||||
|
localStorage.setItem('sn-web-canvaskit-cdn', cdn);
|
||||||
|
} else {
|
||||||
|
const storagedCdn = localStorage.getItem('sn-web-canvaskit-cdn');
|
||||||
|
cdn = storagedCdn ?? 'com';
|
||||||
|
}
|
||||||
|
|
||||||
|
_flutter.loader.load({
|
||||||
|
config: {
|
||||||
|
renderer: renderer ?? 'canvaskit',
|
||||||
|
canvasKitVariant: 'full',
|
||||||
|
canvasKitBaseUrl: `https://www.gstatic.${cdn}/flutter-canvaskit/f73bfc4522dd0bc87bbcdb4bb3088082755c5e87`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
Reference in New Issue
Block a user