♻️ Refactored attachment loading system
This commit is contained in:
parent
619c90cdd9
commit
7656c08832
@ -15,6 +15,7 @@ analyzer:
|
|||||||
- "**/*.freezed.dart"
|
- "**/*.freezed.dart"
|
||||||
errors:
|
errors:
|
||||||
invalid_annotation_target: ignore # Due to freezed + json_serializable issue, ref https://github.com/rrousselGit/freezed/issues/488#issuecomment-894358980
|
invalid_annotation_target: ignore # Due to freezed + json_serializable issue, ref https://github.com/rrousselGit/freezed/issues/488#issuecomment-894358980
|
||||||
|
deprecated_member_use: ignore
|
||||||
|
|
||||||
linter:
|
linter:
|
||||||
# The lint rules applied to this project can be customized in the
|
# The lint rules applied to this project can be customized in the
|
||||||
|
@ -279,16 +279,22 @@
|
|||||||
"one": "{} 個附件",
|
"one": "{} 個附件",
|
||||||
"other": "{} 個附件"
|
"other": "{} 個附件"
|
||||||
},
|
},
|
||||||
|
"fieldAttachmentRandomId": "訪問 ID",
|
||||||
"addAttachmentFromAlbum": "從相冊中添加附件",
|
"addAttachmentFromAlbum": "從相冊中添加附件",
|
||||||
"addAttachmentFromClipboard": "粘貼附件",
|
"addAttachmentFromClipboard": "粘貼附件",
|
||||||
"addAttachmentFromCameraPhoto": "拍攝照片",
|
"addAttachmentFromCameraPhoto": "拍攝照片",
|
||||||
"addAttachmentFromCameraVideo": "拍攝視頻",
|
"addAttachmentFromCameraVideo": "拍攝視頻",
|
||||||
|
"addAttachmentFromRandomId": "通過訪問 ID 鏈接",
|
||||||
"attachmentPastedImage": "粘貼的圖片",
|
"attachmentPastedImage": "粘貼的圖片",
|
||||||
"attachmentInsertLink": "插入連接",
|
"attachmentInsertLink": "插入連接",
|
||||||
"attachmentSetAsPostThumbnail": "設置為帖子縮略圖",
|
"attachmentSetAsPostThumbnail": "設置為帖子縮略圖",
|
||||||
"attachmentUnsetAsPostThumbnail": "取消設置為帖子縮略圖",
|
"attachmentUnsetAsPostThumbnail": "取消設置為帖子縮略圖",
|
||||||
"attachmentSetThumbnail": "設置縮略圖",
|
"attachmentSetThumbnail": "設置縮略圖",
|
||||||
|
"attachmentCopyRandomId": "複製訪問 ID",
|
||||||
"attachmentUpload": "上傳",
|
"attachmentUpload": "上傳",
|
||||||
|
"attachmentInputDialog": "上傳附件",
|
||||||
|
"attachmentInputUseRandomId": "使用訪問 ID",
|
||||||
|
"attachmentInputNew": "新上傳附件",
|
||||||
"notification": "通知",
|
"notification": "通知",
|
||||||
"notificationUnreadCount": {
|
"notificationUnreadCount": {
|
||||||
"zero": "無未讀通知",
|
"zero": "無未讀通知",
|
||||||
@ -504,5 +510,6 @@
|
|||||||
"postCategoryKnowledge": "知識",
|
"postCategoryKnowledge": "知識",
|
||||||
"postCategoryLiterature": "文學",
|
"postCategoryLiterature": "文學",
|
||||||
"postCategoryFunny": "搞笑",
|
"postCategoryFunny": "搞笑",
|
||||||
"postCategoryUncategorized": "未分類"
|
"postCategoryUncategorized": "未分類",
|
||||||
|
"waitingForUpload": "等待上傳"
|
||||||
}
|
}
|
||||||
|
@ -7,15 +7,15 @@
|
|||||||
"screenAuthLogin": "登陸",
|
"screenAuthLogin": "登陸",
|
||||||
"screenAuthLoginSubtitle": "使用 Solarpass 登陸 Solar Network",
|
"screenAuthLoginSubtitle": "使用 Solarpass 登陸 Solar Network",
|
||||||
"screenAuthLoginGreeting": "歡迎回來",
|
"screenAuthLoginGreeting": "歡迎回來",
|
||||||
"screenAuthRegister": "建立賬號",
|
"screenAuthRegister": "創建賬號",
|
||||||
"screenAuthRegisterSubtitle": "建立一個 Solarpass 賬號",
|
"screenAuthRegisterSubtitle": "創建一個 Solarpass 賬號",
|
||||||
"screenAccountPublishers": "釋出者",
|
"screenAccountPublishers": "發佈者",
|
||||||
"screenAccountPublisherNew": "新建釋出者",
|
"screenAccountPublisherNew": "新建發佈者",
|
||||||
"screenAccountPublisherEdit": "編輯釋出者",
|
"screenAccountPublisherEdit": "編輯發佈者",
|
||||||
"screenAccountProfileEdit": "編輯資料",
|
"screenAccountProfileEdit": "編輯資料",
|
||||||
"screenAbuseReport": "濫用檢舉",
|
"screenAbuseReport": "濫用檢舉",
|
||||||
"screenSettings": "設定",
|
"screenSettings": "設置",
|
||||||
"screenAlbum": "相簿",
|
"screenAlbum": "相冊",
|
||||||
"screenChat": "聊天",
|
"screenChat": "聊天",
|
||||||
"screenChatManage": "編輯聊天頻道",
|
"screenChatManage": "編輯聊天頻道",
|
||||||
"screenChatNew": "新建聊天頻道",
|
"screenChatNew": "新建聊天頻道",
|
||||||
@ -23,37 +23,37 @@
|
|||||||
"screenRealmManage": "編輯領域",
|
"screenRealmManage": "編輯領域",
|
||||||
"screenRealmNew": "新建領域",
|
"screenRealmNew": "新建領域",
|
||||||
"screenNotification": "通知",
|
"screenNotification": "通知",
|
||||||
"screenPostSearch": "搜尋帖子",
|
"screenPostSearch": "搜索帖子",
|
||||||
"screenFriend": "好友",
|
"screenFriend": "好友",
|
||||||
"dialogOkay": "好的",
|
"dialogOkay": "好的",
|
||||||
"dialogCancel": "取消",
|
"dialogCancel": "取消",
|
||||||
"dialogConfirm": "確認",
|
"dialogConfirm": "確認",
|
||||||
"dialogDismiss": "忽略",
|
"dialogDismiss": "忽略",
|
||||||
"dialogError": "出了點問題",
|
"dialogError": "出了點問題",
|
||||||
"errorRequestBad": "伺服器拒絕了您的請求,請檢查您的輸入。",
|
"errorRequestBad": "服務器拒絕了您的請求,請檢查您的輸入。",
|
||||||
"errorRequestUnauthorized": "未授權的請求,請登入或者嘗試重新登陸。",
|
"errorRequestUnauthorized": "未授權的請求,請登錄或者嘗試重新登陸。",
|
||||||
"errorRequestForbidden": "被禁止的請求,您沒有足夠的許可權去做那件事。",
|
"errorRequestForbidden": "被禁止的請求,您沒有足夠的權限去做那件事。",
|
||||||
"errorRequestNotFound": "您正查詢的資源無法被找到。",
|
"errorRequestNotFound": "您正查找的資源無法被找到。",
|
||||||
"errorRequestConnection": "網路連線錯誤,請檢查您的網路狀態或者檢查我們的服務狀態。",
|
"errorRequestConnection": "網絡連接錯誤,請檢查您的網絡狀態或者檢查我們的服務狀態。",
|
||||||
"errorRequestUnknown": "未知請求錯誤,您可能想將此對話方塊截圖併發送給我們。",
|
"errorRequestUnknown": "未知請求錯誤,您可能想將此對話框截圖併發送給我們。",
|
||||||
"unknown": "未知",
|
"unknown": "未知",
|
||||||
"loading": "載入中…",
|
"loading": "加載中…",
|
||||||
"prev": "上一步",
|
"prev": "上一步",
|
||||||
"next": "下一步",
|
"next": "下一步",
|
||||||
"edit": "編輯",
|
"edit": "編輯",
|
||||||
"apply": "應用",
|
"apply": "應用",
|
||||||
"cancel": "取消",
|
"cancel": "取消",
|
||||||
"create": "建立",
|
"create": "創建",
|
||||||
"preview": "預覽",
|
"preview": "預覽",
|
||||||
"delete": "刪除",
|
"delete": "刪除",
|
||||||
"unlink": "解除連結",
|
"unlink": "解除鏈接",
|
||||||
"crop": "裁剪",
|
"crop": "裁剪",
|
||||||
"compress": "壓縮",
|
"compress": "壓縮",
|
||||||
"report": "檢舉",
|
"report": "檢舉",
|
||||||
"repost": "轉帖",
|
"repost": "轉帖",
|
||||||
"replyPost": "回貼",
|
"replyPost": "回貼",
|
||||||
"reply": "回覆",
|
"reply": "回覆",
|
||||||
"unset": "未設定",
|
"unset": "未設置",
|
||||||
"untitled": "無題",
|
"untitled": "無題",
|
||||||
"postDetail": "帖子詳情",
|
"postDetail": "帖子詳情",
|
||||||
"postNoun": "帖子",
|
"postNoun": "帖子",
|
||||||
@ -64,20 +64,20 @@
|
|||||||
"one": "總計 {} 字",
|
"one": "總計 {} 字",
|
||||||
"other": "總計 {} 字"
|
"other": "總計 {} 字"
|
||||||
},
|
},
|
||||||
"fieldUsername": "使用者名稱",
|
"fieldUsername": "用戶名",
|
||||||
"fieldNickname": "顯示名",
|
"fieldNickname": "顯示名",
|
||||||
"fieldEmail": "電子郵箱地址",
|
"fieldEmail": "電子郵箱地址",
|
||||||
"fieldPassword": "密碼",
|
"fieldPassword": "密碼",
|
||||||
"fieldUsernameAlphanumOnly": "使用者名稱只能包含英文大小寫字母和數字。",
|
"fieldUsernameAlphanumOnly": "用戶名只能包含英文大小寫字母和數字。",
|
||||||
"fieldUsernameLengthLimit": "使用者名稱必須在 {} 和 {} 之間。",
|
"fieldUsernameLengthLimit": "用戶名必須在 {} 和 {} 之間。",
|
||||||
"fieldUsernameCannotEditHint": "使用者名稱在建立後無法修改",
|
"fieldUsernameCannotEditHint": "用戶名在創建後無法修改",
|
||||||
"fieldUsernameLookupHint": "支援使用者名稱、電話號碼或郵箱地址",
|
"fieldUsernameLookupHint": "支持用戶名、電話號碼或郵箱地址",
|
||||||
"fieldNicknameLengthLimit": "暱稱必須在 {} 和 {} 之間。",
|
"fieldNicknameLengthLimit": "暱稱必須在 {} 和 {} 之間。",
|
||||||
"fieldEmailAddressMustBeValid": "電子郵箱地址必須是一個電子郵箱地址。",
|
"fieldEmailAddressMustBeValid": "電子郵箱地址必須是一個電子郵箱地址。",
|
||||||
"fieldFirstName": "名",
|
"fieldFirstName": "名",
|
||||||
"fieldLastName": "姓",
|
"fieldLastName": "姓",
|
||||||
"fieldBirthday": "生日",
|
"fieldBirthday": "生日",
|
||||||
"fieldImageHint": "你可以點選這些個人頭像來編輯它們。",
|
"fieldImageHint": "你可以點擊這些個人頭像來編輯它們。",
|
||||||
"fieldDescription": "簡介",
|
"fieldDescription": "簡介",
|
||||||
"forgotPassword": "忘記密碼",
|
"forgotPassword": "忘記密碼",
|
||||||
"loginPickFactor": "選擇方式驗證",
|
"loginPickFactor": "選擇方式驗證",
|
||||||
@ -85,24 +85,24 @@
|
|||||||
"one": "{} 步驗證",
|
"one": "{} 步驗證",
|
||||||
"other": "{} 步驗證"
|
"other": "{} 步驗證"
|
||||||
},
|
},
|
||||||
"loginEnterPassword": "驗證程式碼",
|
"loginEnterPassword": "驗證代碼",
|
||||||
"loginSuccess": "登入為 {}",
|
"loginSuccess": "登錄為 {}",
|
||||||
"authFactorPassword": "密碼",
|
"authFactorPassword": "密碼",
|
||||||
"authFactorEmail": "電郵一次性驗證碼",
|
"authFactorEmail": "電郵一次性驗證碼",
|
||||||
"accountIntroTitle": "喜歡您來!",
|
"accountIntroTitle": "喜歡您來!",
|
||||||
"accountIntroSubtitle": "登陸以探索更廣大的世界。",
|
"accountIntroSubtitle": "登陸以探索更廣大的世界。",
|
||||||
"accountLogout": "退出登入",
|
"accountLogout": "退出登錄",
|
||||||
"accountLogoutSubtitle": "登出當前賬戶的登陸狀態。",
|
"accountLogoutSubtitle": "註銷當前賬戶的登陸狀態。",
|
||||||
"accountLogoutConfirmTitle": "您確定要退出登入嗎?",
|
"accountLogoutConfirmTitle": "您確定要退出登錄嗎?",
|
||||||
"accountLogoutConfirm": "您需要重新輸入賬號密碼,甚至可能需要多步驗證來再次登陸。",
|
"accountLogoutConfirm": "您需要重新輸入賬號密碼,甚至可能需要多步驗證來再次登陸。",
|
||||||
"accountPublishers": "你的釋出者",
|
"accountPublishers": "你的發佈者",
|
||||||
"accountPublishersSubtitle": "管理你的公共形象。",
|
"accountPublishersSubtitle": "管理你的公共形象。",
|
||||||
"accountProfileEdit": "編輯資料",
|
"accountProfileEdit": "編輯資料",
|
||||||
"accountProfileEditSubtitle": "使你的 Solarpass 賬戶更像你。",
|
"accountProfileEditSubtitle": "使你的 Solarpass 賬戶更像你。",
|
||||||
"accountProfileEditApplied": "個人資料修改已被應用。",
|
"accountProfileEditApplied": "個人資料修改已被應用。",
|
||||||
"publishersNew": "新發布者",
|
"publishersNew": "新發布者",
|
||||||
"publisherNewSubtitle": "建立一個新的公共身份。",
|
"publisherNewSubtitle": "創建一個新的公共身份。",
|
||||||
"publisherSyncWithAccount": "同步賬戶資訊",
|
"publisherSyncWithAccount": "同步賬戶信息",
|
||||||
"publisherTotalUpvote": "總頂數",
|
"publisherTotalUpvote": "總頂數",
|
||||||
"publisherTotalDownvote": "總踩數",
|
"publisherTotalDownvote": "總踩數",
|
||||||
"publisherSocialPoint": "社會信用點",
|
"publisherSocialPoint": "社會信用點",
|
||||||
@ -115,10 +115,10 @@
|
|||||||
"publisherAffiliatedBy": "隸屬於 {}",
|
"publisherAffiliatedBy": "隸屬於 {}",
|
||||||
"publisherRunBy": "由 {} 管理",
|
"publisherRunBy": "由 {} 管理",
|
||||||
"fieldPublisherBelongToRealm": "所屬領域",
|
"fieldPublisherBelongToRealm": "所屬領域",
|
||||||
"fieldPublisherBelongToRealmUnset": "未設定釋出者所屬領域",
|
"fieldPublisherBelongToRealmUnset": "未設置發佈者所屬領域",
|
||||||
"writePostTypeStory": "發動態",
|
"writePostTypeStory": "發動態",
|
||||||
"writePostTypeArticle": "寫文章",
|
"writePostTypeArticle": "寫文章",
|
||||||
"fieldPostPublisher": "帖子釋出者",
|
"fieldPostPublisher": "帖子發佈者",
|
||||||
"fieldPostContent": "發生什麼事了?!",
|
"fieldPostContent": "發生什麼事了?!",
|
||||||
"fieldPostTitle": "標題",
|
"fieldPostTitle": "標題",
|
||||||
"fieldPostDescription": "描述",
|
"fieldPostDescription": "描述",
|
||||||
@ -126,26 +126,26 @@
|
|||||||
"fieldPostCategories": "分類",
|
"fieldPostCategories": "分類",
|
||||||
"fieldPostAlias": "別名",
|
"fieldPostAlias": "別名",
|
||||||
"fieldPostAliasHint": "可選項,用於在 URL 中表示該帖子,應遵循 URL-Safe 的原則。",
|
"fieldPostAliasHint": "可選項,用於在 URL 中表示該帖子,應遵循 URL-Safe 的原則。",
|
||||||
"postPublish": "釋出",
|
"postPublish": "發佈",
|
||||||
"postPublishedAt": "釋出於",
|
"postPublishedAt": "發佈於",
|
||||||
"postPublishedUntil": "取消釋出於",
|
"postPublishedUntil": "取消發佈於",
|
||||||
"postVisibility": "可見性",
|
"postVisibility": "可見性",
|
||||||
"postVisibilityDescription": "帖子可見性決定了誰能檢視該篇帖子。",
|
"postVisibilityDescription": "帖子可見性決定了誰能查看該篇帖子。",
|
||||||
"postVisibilityAll": "所有人可見",
|
"postVisibilityAll": "所有人可見",
|
||||||
"postVisibilityFriends": "僅限好友可見",
|
"postVisibilityFriends": "僅限好友可見",
|
||||||
"postVisibilitySelected": "選定的使用者可見",
|
"postVisibilitySelected": "選定的用戶可見",
|
||||||
"postVisibilityFiltered": "選定使用者不可見",
|
"postVisibilityFiltered": "選定用戶不可見",
|
||||||
"postVisibilityNone": "僅自己可見",
|
"postVisibilityNone": "僅自己可見",
|
||||||
"postVisibleUsers": "可見的使用者",
|
"postVisibleUsers": "可見的用戶",
|
||||||
"postInvisibleUsers": "不可見的使用者",
|
"postInvisibleUsers": "不可見的用戶",
|
||||||
"postSelectedUsers": {
|
"postSelectedUsers": {
|
||||||
"zero": "未選擇使用者",
|
"zero": "未選擇用戶",
|
||||||
"one": "選擇了 {} 個使用者",
|
"one": "選擇了 {} 個用戶",
|
||||||
"other": "選擇了 {} 個使用者"
|
"other": "選擇了 {} 個用戶"
|
||||||
},
|
},
|
||||||
"postEditingNotice": "你正在修改由 {} 釋出的帖子。",
|
"postEditingNotice": "你正在修改由 {} 發佈的帖子。",
|
||||||
"postReplyingNotice": "你正在回覆由 {} 釋出的帖子。",
|
"postReplyingNotice": "你正在回覆由 {} 發佈的帖子。",
|
||||||
"postRepostingNotice": "你正在轉發由 {} 釋出的帖子。",
|
"postRepostingNotice": "你正在轉發由 {} 發佈的帖子。",
|
||||||
"postReact": "反應",
|
"postReact": "反應",
|
||||||
"postPosted": "帖子已經發表。",
|
"postPosted": "帖子已經發表。",
|
||||||
"postReactions": "帖子的反應",
|
"postReactions": "帖子的反應",
|
||||||
@ -164,7 +164,7 @@
|
|||||||
"one": "{} 點社會信用點變更",
|
"one": "{} 點社會信用點變更",
|
||||||
"other": "{} 點社會信用點變更"
|
"other": "{} 點社會信用點變更"
|
||||||
},
|
},
|
||||||
"postReactCompleted": "反應已被新增。",
|
"postReactCompleted": "反應已被添加。",
|
||||||
"postReactUncompleted": "反應已被移除。",
|
"postReactUncompleted": "反應已被移除。",
|
||||||
"postComments": {
|
"postComments": {
|
||||||
"zero": "評論",
|
"zero": "評論",
|
||||||
@ -178,76 +178,76 @@
|
|||||||
},
|
},
|
||||||
"settingsAppearance": "外觀",
|
"settingsAppearance": "外觀",
|
||||||
"settingsBackgroundImage": "背景圖片",
|
"settingsBackgroundImage": "背景圖片",
|
||||||
"settingsBackgroundImageDescription": "設定應用全域性生效的的背景圖片。",
|
"settingsBackgroundImageDescription": "設置應用全局生效的的背景圖片。",
|
||||||
"settingsBackgroundImageClear": "清除現存背景圖",
|
"settingsBackgroundImageClear": "清除現存背景圖",
|
||||||
"settingsBackgroundImageClearDescription": "將應用背景圖重置為空白。",
|
"settingsBackgroundImageClearDescription": "將應用背景圖重置為空白。",
|
||||||
"settingsThemeMaterial3": "使用 Material You 設計正規化",
|
"settingsThemeMaterial3": "使用 Material You 設計範式",
|
||||||
"settingsThemeMaterial3Description": "將應用主題設定為 Material 3 設計正規化的主題。",
|
"settingsThemeMaterial3Description": "將應用主題設置為 Material 3 設計範式的主題。",
|
||||||
"settingsAppBarTransparent": "透明頂欄",
|
"settingsAppBarTransparent": "透明頂欄",
|
||||||
"settingsAppBarTransparentDescription": "為頂欄啟用透明效果。",
|
"settingsAppBarTransparentDescription": "為頂欄啟用透明效果。",
|
||||||
"settingsColorScheme": "主題色",
|
"settingsColorScheme": "主題色",
|
||||||
"settingsColorSchemeDescription": "設定應用主題色。",
|
"settingsColorSchemeDescription": "設置應用主題色。",
|
||||||
"settingsColorSeed": "預設色彩主題",
|
"settingsColorSeed": "預設色彩主題",
|
||||||
"settingsColorSeedDescription": "選擇一個預設色彩主題。",
|
"settingsColorSeedDescription": "選擇一個預設色彩主題。",
|
||||||
"settingsNetwork": "網路",
|
"settingsNetwork": "網絡",
|
||||||
"settingsNetworkServer": "HyperNet 伺服器",
|
"settingsNetworkServer": "HyperNet 服務器",
|
||||||
"settingsNetworkServerDescription": "設定 HyperNet 伺服器地址,選擇我們提供的,或者自己搭建。",
|
"settingsNetworkServerDescription": "設置 HyperNet 服務器地址,選擇我們提供的,或者自己搭建。",
|
||||||
"settingsNetworkServerReset": "重設為官方伺服器",
|
"settingsNetworkServerReset": "重設為官方服務器",
|
||||||
"settingsNetworkServerResetDescription": "重設為 Solar Network 的伺服器地址。",
|
"settingsNetworkServerResetDescription": "重設為 Solar Network 的服務器地址。",
|
||||||
"settingsNetworkServerPreset": "預設的 HyperNet 伺服器",
|
"settingsNetworkServerPreset": "預設的 HyperNet 服務器",
|
||||||
"settingsNetworkServerPresetDescription": "你可以在旁邊的列表中選擇我們提供的預設 HyperNet 伺服器地址。",
|
"settingsNetworkServerPresetDescription": "你可以在旁邊的列表中選擇我們提供的預設 HyperNet 服務器地址。",
|
||||||
"settingsNetworkServerSaved": "伺服器地址已儲存。",
|
"settingsNetworkServerSaved": "服務器地址已保存。",
|
||||||
"settingsPerformance": "效能",
|
"settingsPerformance": "性能",
|
||||||
"settingsImageQuality": "圖片預覽質量",
|
"settingsImageQuality": "圖片預覽質量",
|
||||||
"settingsImageQualityDescription": "設定圖片預覽質量,會影響圖片解碼速度。",
|
"settingsImageQualityDescription": "設置圖片預覽質量,會影響圖片解碼速度。",
|
||||||
"settingsImageQualityLowest": "極低",
|
"settingsImageQualityLowest": "極低",
|
||||||
"settingsImageQualityLow": "低",
|
"settingsImageQualityLow": "低",
|
||||||
"settingsImageQualityMedium": "中",
|
"settingsImageQualityMedium": "中",
|
||||||
"settingsImageQualityHigh": "高",
|
"settingsImageQualityHigh": "高",
|
||||||
"settingsMisc": "雜項",
|
"settingsMisc": "雜項",
|
||||||
"settingsMiscAbout": "關於",
|
"settingsMiscAbout": "關於",
|
||||||
"settingsMiscAboutDescription": "檢視 Solian 的版本資訊。",
|
"settingsMiscAboutDescription": "查看 Solian 的版本信息。",
|
||||||
"sensitiveContent": "敏感內容",
|
"sensitiveContent": "敏感內容",
|
||||||
"sensitiveContentCollapsed": "敏感內容已摺疊。",
|
"sensitiveContentCollapsed": "敏感內容已摺疊。",
|
||||||
"sensitiveContentDescription": "此內容已被標記,可能不適合所有人檢視。",
|
"sensitiveContentDescription": "此內容已被標記,可能不適合所有人查看。",
|
||||||
"sensitiveContentReveal": "顯示內容",
|
"sensitiveContentReveal": "顯示內容",
|
||||||
"serverConnecting": "正在連線伺服器…",
|
"serverConnecting": "正在連接服務器…",
|
||||||
"serverDisconnected": "已與伺服器斷開連線",
|
"serverDisconnected": "已與服務器斷開連接",
|
||||||
"fieldChatAlias": "頻道別名",
|
"fieldChatAlias": "頻道別名",
|
||||||
"fieldChatAliasHint": "全站範圍內唯一的頻道別名,用於在 URL 中表示該頻道,留空則自動生成。應遵循 URL-Safe 的原則。",
|
"fieldChatAliasHint": "全站範圍內唯一的頻道別名,用於在 URL 中表示該頻道,留空則自動生成。應遵循 URL-Safe 的原則。",
|
||||||
"fieldChatName": "名稱",
|
"fieldChatName": "名稱",
|
||||||
"fieldChatDescription": "描述",
|
"fieldChatDescription": "描述",
|
||||||
"fieldChatBelongToRealm": "所屬領域",
|
"fieldChatBelongToRealm": "所屬領域",
|
||||||
"fieldChatBelongToRealmUnset": "未設定頻道所屬領域",
|
"fieldChatBelongToRealmUnset": "未設置頻道所屬領域",
|
||||||
"channelEditingNotice": "您正在編輯頻道 {}",
|
"channelEditingNotice": "您正在編輯頻道 {}",
|
||||||
"channelDeleted": "聊天頻道 {} 已被刪除",
|
"channelDeleted": "聊天頻道 {} 已被刪除",
|
||||||
"channelDelete": "刪除聊天頻道 {}",
|
"channelDelete": "刪除聊天頻道 {}",
|
||||||
"channelDeleteDescription": "你確定要刪除這個聊天頻道嗎?該操作不可撤銷,其頻道內的所有訊息將被永久刪除。",
|
"channelDeleteDescription": "你確定要刪除這個聊天頻道嗎?該操作不可撤銷,其頻道內的所有消息將被永久刪除。",
|
||||||
"channelDetailPersonalRegion": "個人區域",
|
"channelDetailPersonalRegion": "個人區域",
|
||||||
"channelDetailMemberRegion": "成員管理",
|
"channelDetailMemberRegion": "成員管理",
|
||||||
"channelMemberManage": "管理成員",
|
"channelMemberManage": "管理成員",
|
||||||
"channelMemberManageDescription": "管理頻道內現有成員。",
|
"channelMemberManageDescription": "管理頻道內現有成員。",
|
||||||
"channelMemberAdd": "新增成員",
|
"channelMemberAdd": "添加成員",
|
||||||
"channelMemberAddDescription": "給當前頻道新增新成員。",
|
"channelMemberAddDescription": "給當前頻道添加新成員。",
|
||||||
"channelMemberAdded": "頻道成員已新增。",
|
"channelMemberAdded": "頻道成員已添加。",
|
||||||
"fieldMemberRelatedName": "成員名 / 賬戶 ID",
|
"fieldMemberRelatedName": "成員名 / 賬戶 ID",
|
||||||
"channelDetailAdminRegion": "管理區域",
|
"channelDetailAdminRegion": "管理區域",
|
||||||
"channelEditProfile": "更改頻道身份",
|
"channelEditProfile": "更改頻道身份",
|
||||||
"channelEdit": "編輯頻道",
|
"channelEdit": "編輯頻道",
|
||||||
"channelEditDescription": "更改頻道基本資訊,元資料等。",
|
"channelEditDescription": "更改頻道基本信息,元數據等。",
|
||||||
"channelProfileEdit": "編輯頻道身份",
|
"channelProfileEdit": "編輯頻道身份",
|
||||||
"channelActionDelete": "刪除頻道",
|
"channelActionDelete": "刪除頻道",
|
||||||
"channelActionDeleteDescription": "刪除整個頻道,並且刪除頻道里的所有資訊。",
|
"channelActionDeleteDescription": "刪除整個頻道,並且刪除頻道里的所有信息。",
|
||||||
"channelLeave": "退出頻道 {}",
|
"channelLeave": "退出頻道 {}",
|
||||||
"channelLeaveDescription": "退出該頻道,但是你頻道內的資訊不會被移除。",
|
"channelLeaveDescription": "退出該頻道,但是你頻道內的信息不會被移除。",
|
||||||
"channelActionLeave": "退出頻道",
|
"channelActionLeave": "退出頻道",
|
||||||
"channelActionLeaveDescription": "刪除你在這個頻道的身份。",
|
"channelActionLeaveDescription": "刪除你在這個頻道的身份。",
|
||||||
"channelNotifyLevel": "通知級別",
|
"channelNotifyLevel": "通知級別",
|
||||||
"channelNotifyLevelDescription": "有您決定要接受多少來自這個頻道的訊息。",
|
"channelNotifyLevelDescription": "有您決定要接受多少來自這個頻道的消息。",
|
||||||
"channelNotifyLevelAll": "全部通知",
|
"channelNotifyLevelAll": "全部通知",
|
||||||
"channelNotifyLevelMentioned": "僅提及",
|
"channelNotifyLevelMentioned": "僅提及",
|
||||||
"channelNotifyLevelNone": "全部靜音",
|
"channelNotifyLevelNone": "全部靜音",
|
||||||
"channelNotifyLevelApplied": "已經儲存並應用頻道通知級別配置。",
|
"channelNotifyLevelApplied": "已經保存並應用頻道通知級別配置。",
|
||||||
"fieldChannelProfileNick": "頻道內顯示名",
|
"fieldChannelProfileNick": "頻道內顯示名",
|
||||||
"fieldChannelProfileNickHint": "在頻道內顯示的暱稱,留空則使用賬號顯示名。",
|
"fieldChannelProfileNickHint": "在頻道內顯示的暱稱,留空則使用賬號顯示名。",
|
||||||
"fieldRealmAlias": "領域別名",
|
"fieldRealmAlias": "領域別名",
|
||||||
@ -257,38 +257,44 @@
|
|||||||
"realmEditingNotice": "您正在編輯領域 {}",
|
"realmEditingNotice": "您正在編輯領域 {}",
|
||||||
"realmDeleted": "領域 {} 已被刪除",
|
"realmDeleted": "領域 {} 已被刪除",
|
||||||
"realmDelete": "刪除領域 {}",
|
"realmDelete": "刪除領域 {}",
|
||||||
"realmDeleteDescription": "你確定要刪除這個領域嗎?該操作不可撤銷,其隸屬於該領域的所有資源(帖子、聊天頻道、釋出者、製品等)都將被永久刪除。三思而後行!",
|
"realmDeleteDescription": "你確定要刪除這個領域嗎?該操作不可撤銷,其隸屬於該領域的所有資源(帖子、聊天頻道、發佈者、製品等)都將被永久刪除。三思而後行!",
|
||||||
"realmActionDelete": "刪除領域",
|
"realmActionDelete": "刪除領域",
|
||||||
"realmActionDeleteDescription": "刪除整個領域及其附屬的資源。",
|
"realmActionDeleteDescription": "刪除整個領域及其附屬的資源。",
|
||||||
"realmEdit": "編輯領域",
|
"realmEdit": "編輯領域",
|
||||||
"realmEditDescription": "更改領域基本資訊,元資料等。",
|
"realmEditDescription": "更改領域基本信息,元數據等。",
|
||||||
"realmMemberAdd": "新增成員",
|
"realmMemberAdd": "添加成員",
|
||||||
"realmMemberAddDescription": "給當前領域新增新成員。",
|
"realmMemberAddDescription": "給當前領域添加新成員。",
|
||||||
"realmMemberAdded": "領域成員已新增。",
|
"realmMemberAdded": "領域成員已添加。",
|
||||||
"fieldChatMessage": "在 {} 中發訊息",
|
"fieldChatMessage": "在 {} 中發消息",
|
||||||
"fieldChatMessageDirect": "給 {} 發訊息",
|
"fieldChatMessageDirect": "給 {} 發消息",
|
||||||
"eventResourceTag": "訊息 {}",
|
"eventResourceTag": "消息 {}",
|
||||||
"messageDelete": "刪除訊息 {}",
|
"messageDelete": "刪除消息 {}",
|
||||||
"messageDeleteDescription": "你確定要刪除這個訊息嗎?該操作不可撤銷。同時您將留下一條刪除訊息的記錄。",
|
"messageDeleteDescription": "你確定要刪除這個消息嗎?該操作不可撤銷。同時您將留下一條刪除消息的記錄。",
|
||||||
"messageDeleted": "訊息 {} 已被刪除",
|
"messageDeleted": "消息 {} 已被刪除",
|
||||||
"messageEdited": "訊息 {} 已被編輯",
|
"messageEdited": "消息 {} 已被編輯",
|
||||||
"messageEditedHint": "已編輯",
|
"messageEditedHint": "已編輯",
|
||||||
"messageUnsupported": "不支援的訊息 {}",
|
"messageUnsupported": "不支持的消息 {}",
|
||||||
"messageFileHint": {
|
"messageFileHint": {
|
||||||
"zero": "沒有附件",
|
"zero": "沒有附件",
|
||||||
"one": "{} 個附件",
|
"one": "{} 個附件",
|
||||||
"other": "{} 個附件"
|
"other": "{} 個附件"
|
||||||
},
|
},
|
||||||
"addAttachmentFromAlbum": "從相簿中新增附件",
|
"fieldAttachmentRandomId": "訪問 ID",
|
||||||
"addAttachmentFromClipboard": "貼上附件",
|
"addAttachmentFromAlbum": "從相冊中添加附件",
|
||||||
|
"addAttachmentFromClipboard": "粘貼附件",
|
||||||
"addAttachmentFromCameraPhoto": "拍攝照片",
|
"addAttachmentFromCameraPhoto": "拍攝照片",
|
||||||
"addAttachmentFromCameraVideo": "拍攝影片",
|
"addAttachmentFromCameraVideo": "拍攝視頻",
|
||||||
"attachmentPastedImage": "貼上的圖片",
|
"addAttachmentFromRandomId": "通過訪問 ID 鏈接",
|
||||||
"attachmentInsertLink": "插入連線",
|
"attachmentPastedImage": "粘貼的圖片",
|
||||||
"attachmentSetAsPostThumbnail": "設定為帖子縮圖",
|
"attachmentInsertLink": "插入連接",
|
||||||
"attachmentUnsetAsPostThumbnail": "取消設定為帖子縮圖",
|
"attachmentSetAsPostThumbnail": "設置為帖子縮略圖",
|
||||||
"attachmentSetThumbnail": "設定縮圖",
|
"attachmentUnsetAsPostThumbnail": "取消設置為帖子縮略圖",
|
||||||
|
"attachmentSetThumbnail": "設置縮略圖",
|
||||||
|
"attachmentCopyRandomId": "複製訪問 ID",
|
||||||
"attachmentUpload": "上傳",
|
"attachmentUpload": "上傳",
|
||||||
|
"attachmentInputDialog": "上傳附件",
|
||||||
|
"attachmentInputUseRandomId": "使用訪問 ID",
|
||||||
|
"attachmentInputNew": "新上傳附件",
|
||||||
"notification": "通知",
|
"notification": "通知",
|
||||||
"notificationUnreadCount": {
|
"notificationUnreadCount": {
|
||||||
"zero": "無未讀通知",
|
"zero": "無未讀通知",
|
||||||
@ -298,18 +304,18 @@
|
|||||||
"notificationUnread": "未讀",
|
"notificationUnread": "未讀",
|
||||||
"notificationRead": "已讀",
|
"notificationRead": "已讀",
|
||||||
"notificationMarkAllRead": "已讀所有通知",
|
"notificationMarkAllRead": "已讀所有通知",
|
||||||
"notificationMarkAllReadDescription": "您確定要將所有通知設定為已讀嗎?該操作不可撤銷。",
|
"notificationMarkAllReadDescription": "您確定要將所有通知設置為已讀嗎?該操作不可撤銷。",
|
||||||
"notificationMarkAllReadPrompt": {
|
"notificationMarkAllReadPrompt": {
|
||||||
"zero": "已將 0 個通知標記為已讀。",
|
"zero": "已將 0 個通知標記為已讀。",
|
||||||
"one": "已將 {} 個通知標記為已讀。",
|
"one": "已將 {} 個通知標記為已讀。",
|
||||||
"other": "已將 {} 個通知標記為已讀。"
|
"other": "已將 {} 個通知標記為已讀。"
|
||||||
},
|
},
|
||||||
"notificationMarkOneReadPrompt": "已將通知 {} 標記為已讀。",
|
"notificationMarkOneReadPrompt": "已將通知 {} 標記為已讀。",
|
||||||
"search": "搜尋",
|
"search": "搜索",
|
||||||
"postSearchResult": {
|
"postSearchResult": {
|
||||||
"zero": "沒有搜尋到結果",
|
"zero": "沒有搜索到結果",
|
||||||
"one": "搜尋到 {} 個結果",
|
"one": "搜索到 {} 個結果",
|
||||||
"other": "搜尋到 {} 個結果"
|
"other": "搜索到 {} 個結果"
|
||||||
},
|
},
|
||||||
"postSearchTook": "耗時 {}",
|
"postSearchTook": "耗時 {}",
|
||||||
"postDelete": "刪除帖子 {}",
|
"postDelete": "刪除帖子 {}",
|
||||||
@ -321,26 +327,26 @@
|
|||||||
"callResume": "恢復",
|
"callResume": "恢復",
|
||||||
"callMicrophone": "麥克風",
|
"callMicrophone": "麥克風",
|
||||||
"callCamera": "攝像頭",
|
"callCamera": "攝像頭",
|
||||||
"callMicrophoneDisabled": "麥克風已停用",
|
"callMicrophoneDisabled": "麥克風已禁用",
|
||||||
"callMicrophoneSelect": "選擇麥克風",
|
"callMicrophoneSelect": "選擇麥克風",
|
||||||
"callCameraDisabled": "攝像頭已停用",
|
"callCameraDisabled": "攝像頭已禁用",
|
||||||
"callCameraSelect": "選擇攝像頭",
|
"callCameraSelect": "選擇攝像頭",
|
||||||
"callDisconnected": "通話已斷開",
|
"callDisconnected": "通話已斷開",
|
||||||
"callEnded": "通話已結束",
|
"callEnded": "通話已結束",
|
||||||
"callStatusConnected": "已連線",
|
"callStatusConnected": "已連接",
|
||||||
"callStatusDisconnected": "未連線",
|
"callStatusDisconnected": "未連接",
|
||||||
"callStatusConnecting": "正在連線",
|
"callStatusConnecting": "正在連接",
|
||||||
"callStatusReconnecting": "正在重連",
|
"callStatusReconnecting": "正在重連",
|
||||||
"callDisconnect": "斷開連線",
|
"callDisconnect": "斷開連接",
|
||||||
"callDisconnectDescription": "您確定要與通話斷開連線嗎?",
|
"callDisconnectDescription": "您確定要與通話斷開連接嗎?",
|
||||||
"callMicrophoneOff": "關閉麥克風",
|
"callMicrophoneOff": "關閉麥克風",
|
||||||
"callMicrophoneOn": "開啟麥克風",
|
"callMicrophoneOn": "打開麥克風",
|
||||||
"callCameraOff": "關閉攝像頭",
|
"callCameraOff": "關閉攝像頭",
|
||||||
"callCameraOn": "開啟攝像頭",
|
"callCameraOn": "打開攝像頭",
|
||||||
"callVideoFlip": "映象畫面",
|
"callVideoFlip": "鏡像畫面",
|
||||||
"callSpeakerphoneToggle": "切換揚聲器",
|
"callSpeakerphoneToggle": "切換揚聲器",
|
||||||
"callScreenOff": "關閉螢幕共享",
|
"callScreenOff": "關閉屏幕共享",
|
||||||
"callScreenOn": "開啟螢幕共享",
|
"callScreenOn": "開啟屏幕共享",
|
||||||
"callMessageEnded": "通話持續了 {}",
|
"callMessageEnded": "通話持續了 {}",
|
||||||
"callMessageStarted": "通話開始了",
|
"callMessageStarted": "通話開始了",
|
||||||
"dailyCheckIn": "每日簽到",
|
"dailyCheckIn": "每日簽到",
|
||||||
@ -396,27 +402,27 @@
|
|||||||
"pendingFatherDay": "{} 過父親節",
|
"pendingFatherDay": "{} 過父親節",
|
||||||
"pendingHalloween": "{} 過聖誕節",
|
"pendingHalloween": "{} 過聖誕節",
|
||||||
"pendingThanksgiving": "{} 過感恩節",
|
"pendingThanksgiving": "{} 過感恩節",
|
||||||
"friendNew": "新增好友",
|
"friendNew": "添加好友",
|
||||||
"friendRequests": "好友請求",
|
"friendRequests": "好友請求",
|
||||||
"friendRequestsDescription": {
|
"friendRequestsDescription": {
|
||||||
"zero": "你沒有好友請求",
|
"zero": "你沒有好友請求",
|
||||||
"one": "你有 {} 個好友請求",
|
"one": "你有 {} 個好友請求",
|
||||||
"other": "你有 {} 個好友請求"
|
"other": "你有 {} 個好友請求"
|
||||||
},
|
},
|
||||||
"friendBlocklist": "遮蔽列表",
|
"friendBlocklist": "屏蔽列表",
|
||||||
"friendBlocklistDescription": {
|
"friendBlocklistDescription": {
|
||||||
"zero": "你沒有遮蔽任何人",
|
"zero": "你沒有屏蔽任何人",
|
||||||
"one": "你遮蔽了 {} 個使用者",
|
"one": "你屏蔽了 {} 個用戶",
|
||||||
"other": "你遮蔽了 {} 個使用者"
|
"other": "你屏蔽了 {} 個用戶"
|
||||||
},
|
},
|
||||||
"friendStatusPending": "待處理",
|
"friendStatusPending": "待處理",
|
||||||
"friendStatusWaiting": "等待中",
|
"friendStatusWaiting": "等待中",
|
||||||
"friendStatusActive": "正活躍",
|
"friendStatusActive": "正活躍",
|
||||||
"friendStatusBlocked": "已遮蔽",
|
"friendStatusBlocked": "已屏蔽",
|
||||||
"friendRequestSent": "好友請求已傳送。",
|
"friendRequestSent": "好友請求已發送。",
|
||||||
"fieldFriendRelatedName": "好友名 / 賬戶 ID",
|
"fieldFriendRelatedName": "好友名 / 賬戶 ID",
|
||||||
"friendBlock": "遮蔽",
|
"friendBlock": "屏蔽",
|
||||||
"friendUnblock": "解除遮蔽",
|
"friendUnblock": "解除屏蔽",
|
||||||
"friendDeleteAction": "遺忘",
|
"friendDeleteAction": "遺忘",
|
||||||
"friendDelete": "遺忘跟 {} 的關係",
|
"friendDelete": "遺忘跟 {} 的關係",
|
||||||
"friendDeleteDescription": "你確定要遺忘跟 {} 的關係嗎?這個操作無法撤銷。",
|
"friendDeleteDescription": "你確定要遺忘跟 {} 的關係嗎?這個操作無法撤銷。",
|
||||||
@ -432,20 +438,20 @@
|
|||||||
"badgeCompanyStaff": "索爾辛茨士大夫 · 員工",
|
"badgeCompanyStaff": "索爾辛茨士大夫 · 員工",
|
||||||
"badgeSiteMigration": "Solar Network 原住民",
|
"badgeSiteMigration": "Solar Network 原住民",
|
||||||
"accountStatus": "狀態",
|
"accountStatus": "狀態",
|
||||||
"accountStatusOnline": "線上",
|
"accountStatusOnline": "在線",
|
||||||
"accountStatusOffline": "離線",
|
"accountStatusOffline": "離線",
|
||||||
"accountStatusLastSeen": "最後一次上線於 {}",
|
"accountStatusLastSeen": "最後一次上線於 {}",
|
||||||
"postArticle": "Solar Network 上的文章",
|
"postArticle": "Solar Network 上的文章",
|
||||||
"postStory": "Solar Network 上的故事",
|
"postStory": "Solar Network 上的故事",
|
||||||
"articleWrittenAt": "發表於 {}",
|
"articleWrittenAt": "發表於 {}",
|
||||||
"articleEditedAt": "編輯於 {}",
|
"articleEditedAt": "編輯於 {}",
|
||||||
"attachmentSaved": "已儲存到相簿",
|
"attachmentSaved": "已保存到相冊",
|
||||||
"attachmentSavedDesktop": "已儲存到下載目錄",
|
"attachmentSavedDesktop": "已保存到下載目錄",
|
||||||
"openInAlbum": "在相簿中開啟",
|
"openInAlbum": "在相冊中打開",
|
||||||
"postAbuseReport": "檢舉帖子",
|
"postAbuseReport": "檢舉帖子",
|
||||||
"postAbuseReportDescription": "檢舉不符合我們使用者協議以及社群準則的帖子,來幫助我們更好的維護 Solar Network 上的內容。請在下面描述該帖子如何違反我麼的相關規定。請勿填寫任何敏感資訊。我們將會在 24 小時內處理您的檢舉。",
|
"postAbuseReportDescription": "檢舉不符合我們用戶協議以及社區準則的帖子,來幫助我們更好的維護 Solar Network 上的內容。請在下面描述該帖子如何違反我麼的相關規定。請勿填寫任何敏感信息。我們將會在 24 小時內處理您的檢舉。",
|
||||||
"abuseReport": "檢舉",
|
"abuseReport": "檢舉",
|
||||||
"abuseReportDescription": "檢舉不符合我們使用者協議以及社群準則的任何資源,來幫助我們更好的維護 Solar Network 上的內容。請在下面描述資源的位置(提供資源 ID 為佳)以及如何違反我麼的相關規定。請勿填寫任何敏感資訊。我們將會在 24 小時內處理您的檢舉。",
|
"abuseReportDescription": "檢舉不符合我們用戶協議以及社區準則的任何資源,來幫助我們更好的維護 Solar Network 上的內容。請在下面描述資源的位置(提供資源 ID 為佳)以及如何違反我麼的相關規定。請勿填寫任何敏感信息。我們將會在 24 小時內處理您的檢舉。",
|
||||||
"abuseReportAction": "提交檢舉",
|
"abuseReportAction": "提交檢舉",
|
||||||
"abuseReportActionDescription": "檢舉不合規行為。",
|
"abuseReportActionDescription": "檢舉不合規行為。",
|
||||||
"abuseReportResource": "資源位置 / ID",
|
"abuseReportResource": "資源位置 / ID",
|
||||||
@ -453,35 +459,35 @@
|
|||||||
"abuseReportSubmitted": "檢舉已提交,感謝你的貢獻。",
|
"abuseReportSubmitted": "檢舉已提交,感謝你的貢獻。",
|
||||||
"submit": "提交",
|
"submit": "提交",
|
||||||
"accountDeletion": "刪除帳戶",
|
"accountDeletion": "刪除帳戶",
|
||||||
"accountDeletionDescription": "你確定要刪除這個帳戶嗎?該操作不可撤銷,其隸屬於該帳戶的所有資源(帖子、聊天頻道、釋出者、製品等)都將被永久刪除。三思而後行!",
|
"accountDeletionDescription": "你確定要刪除這個帳戶嗎?該操作不可撤銷,其隸屬於該帳戶的所有資源(帖子、聊天頻道、發佈者、製品等)都將被永久刪除。三思而後行!",
|
||||||
"accountDeletionActionDescription": "刪除你的 Solarpass 帳戶。",
|
"accountDeletionActionDescription": "刪除你的 Solarpass 帳戶。",
|
||||||
"accountDeletionSubmitted": "帳戶刪除申請已發出,你可以檢查你的收件箱並根據郵件內的指示完成刪除操作。",
|
"accountDeletionSubmitted": "帳戶刪除申請已發出,你可以檢查你的收件箱並根據郵件內的指示完成刪除操作。",
|
||||||
"channelNewChannel": "新建頻道",
|
"channelNewChannel": "新建頻道",
|
||||||
"channelNewDirectMessage": "發起私信",
|
"channelNewDirectMessage": "發起私信",
|
||||||
"channelDirectMessageDescription": "與 {} 的私聊",
|
"channelDirectMessageDescription": "與 {} 的私聊",
|
||||||
"fieldCannotBeEmpty": "此欄位不能為空。",
|
"fieldCannotBeEmpty": "此字段不能為空。",
|
||||||
"termAcceptLink": "瀏覽條款",
|
"termAcceptLink": "瀏覽條款",
|
||||||
"termAcceptNextWithAgree": "點選 “下一步”,即表示你同意我們的各項條款,包括其之後的更新。",
|
"termAcceptNextWithAgree": "點擊 “下一步”,即表示你同意我們的各項條款,包括其之後的更新。",
|
||||||
"unauthorized": "未登陸",
|
"unauthorized": "未登陸",
|
||||||
"unauthorizedDescription": "登陸以探索整個 Solar Network。",
|
"unauthorizedDescription": "登陸以探索整個 Solar Network。",
|
||||||
"serviceStatus": "服務狀態",
|
"serviceStatus": "服務狀態",
|
||||||
"termRelated": "相關條款",
|
"termRelated": "相關條款",
|
||||||
"appDetails": "應用程式詳情",
|
"appDetails": "應用程序詳情",
|
||||||
"postRecommendation": "推薦帖子",
|
"postRecommendation": "推薦帖子",
|
||||||
"publisherBlockHint": "遮蔽 {}",
|
"publisherBlockHint": "屏蔽 {}",
|
||||||
"publisherBlockHintDescription": "你正要遮蔽此釋出者的運營者,該操作也將遮蔽由同一使用者運營的釋出者。",
|
"publisherBlockHintDescription": "你正要屏蔽此發佈者的運營者,該操作也將屏蔽由同一用戶運營的發佈者。",
|
||||||
"userUnblocked": "已解除遮蔽使用者 {}",
|
"userUnblocked": "已解除屏蔽用戶 {}",
|
||||||
"userBlocked": "已遮蔽使用者 {}",
|
"userBlocked": "已屏蔽用戶 {}",
|
||||||
"postSharingViaPicture": "正在生成帖子截圖,請稍等片刻……",
|
"postSharingViaPicture": "正在生成帖子截圖,請稍等片刻……",
|
||||||
"postImageShareReadMore": "掃描右側 QRCode 檢視全文",
|
"postImageShareReadMore": "掃描右側 QRCode 查看全文",
|
||||||
"postImageShareAds": "來 Solar Network 探索更多有趣帖子",
|
"postImageShareAds": "來 Solar Network 探索更多有趣帖子",
|
||||||
"postShare": "分享",
|
"postShare": "分享",
|
||||||
"postShareImage": "分享帖圖",
|
"postShareImage": "分享帖圖",
|
||||||
"appInitializing": "正在初始化",
|
"appInitializing": "正在初始化",
|
||||||
"poweredBy": "由 {} 提供支援",
|
"poweredBy": "由 {} 提供支持",
|
||||||
"shareIntent": "分享",
|
"shareIntent": "分享",
|
||||||
"shareIntentDescription": "您想對您分享的內容做些什麼?",
|
"shareIntentDescription": "您想對您分享的內容做些什麼?",
|
||||||
"shareIntentPostStory": "釋出動態",
|
"shareIntentPostStory": "發佈動態",
|
||||||
"updateAvailable": "檢測到更新可用",
|
"updateAvailable": "檢測到更新可用",
|
||||||
"updateOngoing": "正在更新,請稍後……",
|
"updateOngoing": "正在更新,請稍後……",
|
||||||
"custom": "自定義",
|
"custom": "自定義",
|
||||||
@ -504,5 +510,6 @@
|
|||||||
"postCategoryKnowledge": "知識",
|
"postCategoryKnowledge": "知識",
|
||||||
"postCategoryLiterature": "文學",
|
"postCategoryLiterature": "文學",
|
||||||
"postCategoryFunny": "搞笑",
|
"postCategoryFunny": "搞笑",
|
||||||
"postCategoryUncategorized": "未分類"
|
"postCategoryUncategorized": "未分類",
|
||||||
|
"waitingForUpload": "等待上傳"
|
||||||
}
|
}
|
||||||
|
@ -15,16 +15,9 @@ import 'package:surface/types/post.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';
|
||||||
|
|
||||||
enum PostWriteMediaType {
|
|
||||||
image,
|
|
||||||
video,
|
|
||||||
audio,
|
|
||||||
file,
|
|
||||||
}
|
|
||||||
|
|
||||||
class PostWriteMedia {
|
class PostWriteMedia {
|
||||||
late String name;
|
late String name;
|
||||||
late PostWriteMediaType type;
|
late SnMediaType type;
|
||||||
final SnAttachment? attachment;
|
final SnAttachment? attachment;
|
||||||
final XFile? file;
|
final XFile? file;
|
||||||
final Uint8List? raw;
|
final Uint8List? raw;
|
||||||
@ -36,16 +29,16 @@ class PostWriteMedia {
|
|||||||
|
|
||||||
switch (attachment?.mimetype.split('/').firstOrNull) {
|
switch (attachment?.mimetype.split('/').firstOrNull) {
|
||||||
case 'image':
|
case 'image':
|
||||||
type = PostWriteMediaType.image;
|
type = SnMediaType.image;
|
||||||
break;
|
break;
|
||||||
case 'video':
|
case 'video':
|
||||||
type = PostWriteMediaType.video;
|
type = SnMediaType.video;
|
||||||
break;
|
break;
|
||||||
case 'audio':
|
case 'audio':
|
||||||
type = PostWriteMediaType.audio;
|
type = SnMediaType.audio;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
type = PostWriteMediaType.file;
|
type = SnMediaType.file;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,16 +50,16 @@ class PostWriteMedia {
|
|||||||
|
|
||||||
switch (mimetype?.split('/').firstOrNull) {
|
switch (mimetype?.split('/').firstOrNull) {
|
||||||
case 'image':
|
case 'image':
|
||||||
type = PostWriteMediaType.image;
|
type = SnMediaType.image;
|
||||||
break;
|
break;
|
||||||
case 'video':
|
case 'video':
|
||||||
type = PostWriteMediaType.video;
|
type = SnMediaType.video;
|
||||||
break;
|
break;
|
||||||
case 'audio':
|
case 'audio':
|
||||||
type = PostWriteMediaType.audio;
|
type = SnMediaType.audio;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
type = PostWriteMediaType.file;
|
type = SnMediaType.file;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,7 +237,7 @@ class PostWriteController extends ChangeNotifier {
|
|||||||
media.name,
|
media.name,
|
||||||
'interactive',
|
'interactive',
|
||||||
null,
|
null,
|
||||||
mimetype: media.raw != null && media.type == PostWriteMediaType.image ? 'image/png' : null,
|
mimetype: media.raw != null && media.type == SnMediaType.image ? 'image/png' : null,
|
||||||
);
|
);
|
||||||
|
|
||||||
final item = await attach.chunkedUploadParts(
|
final item = await attach.chunkedUploadParts(
|
||||||
@ -301,7 +294,7 @@ class PostWriteController extends ChangeNotifier {
|
|||||||
media.name,
|
media.name,
|
||||||
'interactive',
|
'interactive',
|
||||||
null,
|
null,
|
||||||
mimetype: media.raw != null && media.type == PostWriteMediaType.image ? 'image/png' : null,
|
mimetype: media.raw != null && media.type == SnMediaType.image ? 'image/png' : null,
|
||||||
);
|
);
|
||||||
|
|
||||||
final item = await attach.chunkedUploadParts(
|
final item = await attach.chunkedUploadParts(
|
||||||
|
@ -5,7 +5,6 @@ import 'package:provider/provider.dart';
|
|||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:surface/providers/config.dart';
|
import 'package:surface/providers/config.dart';
|
||||||
import 'package:surface/providers/sn_network.dart';
|
import 'package:surface/providers/sn_network.dart';
|
||||||
import 'package:surface/providers/widget.dart';
|
|
||||||
import 'package:surface/types/account.dart';
|
import 'package:surface/types/account.dart';
|
||||||
|
|
||||||
class UserProvider extends ChangeNotifier {
|
class UserProvider extends ChangeNotifier {
|
||||||
@ -13,12 +12,10 @@ class UserProvider extends ChangeNotifier {
|
|||||||
SnAccount? user;
|
SnAccount? user;
|
||||||
|
|
||||||
late final SnNetworkProvider _sn;
|
late final SnNetworkProvider _sn;
|
||||||
late final HomeWidgetProvider _home;
|
|
||||||
late final ConfigProvider _config;
|
late final ConfigProvider _config;
|
||||||
|
|
||||||
UserProvider(BuildContext context) {
|
UserProvider(BuildContext context) {
|
||||||
_sn = context.read<SnNetworkProvider>();
|
_sn = context.read<SnNetworkProvider>();
|
||||||
_home = context.read<HomeWidgetProvider>();
|
|
||||||
_config = context.read<ConfigProvider>();
|
_config = context.read<ConfigProvider>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,16 +1,11 @@
|
|||||||
import 'dart:io';
|
|
||||||
|
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:dropdown_button2/dropdown_button2.dart';
|
import 'package:dropdown_button2/dropdown_button2.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
|
||||||
import 'package:flutter/gestures.dart';
|
import 'package:flutter/gestures.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:image_picker/image_picker.dart';
|
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
import 'package:pasteboard/pasteboard.dart';
|
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
import 'package:surface/controllers/post_write_controller.dart';
|
import 'package:surface/controllers/post_write_controller.dart';
|
||||||
import 'package:surface/providers/config.dart';
|
import 'package:surface/providers/config.dart';
|
||||||
|
@ -33,7 +33,6 @@ Future<ThemeData> createAppTheme(
|
|||||||
brightness: brightness,
|
brightness: brightness,
|
||||||
);
|
);
|
||||||
|
|
||||||
final hasBackground = prefs.getBool(kAppBackgroundStoreKey) ?? false;
|
|
||||||
final hasAppBarBlurry = prefs.getBool(kAppbarTransparentStoreKey) ?? false;
|
final hasAppBarBlurry = prefs.getBool(kAppbarTransparentStoreKey) ?? false;
|
||||||
|
|
||||||
return ThemeData(
|
return ThemeData(
|
||||||
|
@ -1,10 +1,20 @@
|
|||||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
|
||||||
part 'attachment.freezed.dart';
|
part 'attachment.freezed.dart';
|
||||||
|
|
||||||
part 'attachment.g.dart';
|
part 'attachment.g.dart';
|
||||||
|
|
||||||
|
enum SnMediaType {
|
||||||
|
image,
|
||||||
|
video,
|
||||||
|
audio,
|
||||||
|
file,
|
||||||
|
}
|
||||||
|
|
||||||
@freezed
|
@freezed
|
||||||
class SnAttachment with _$SnAttachment {
|
class SnAttachment with _$SnAttachment {
|
||||||
|
const SnAttachment._();
|
||||||
|
|
||||||
const factory SnAttachment({
|
const factory SnAttachment({
|
||||||
required int id,
|
required int id,
|
||||||
required DateTime createdAt,
|
required DateTime createdAt,
|
||||||
@ -19,9 +29,10 @@ class SnAttachment with _$SnAttachment {
|
|||||||
required String hash,
|
required String hash,
|
||||||
required int destination,
|
required int destination,
|
||||||
required int refCount,
|
required int refCount,
|
||||||
|
@Default(0) int contentRating,
|
||||||
|
@Default(0) int qualityRating,
|
||||||
required dynamic fileChunks,
|
required dynamic fileChunks,
|
||||||
required dynamic cleanedAt,
|
required dynamic cleanedAt,
|
||||||
required bool isMature,
|
|
||||||
required bool isAnalyzed,
|
required bool isAnalyzed,
|
||||||
required bool isUploaded,
|
required bool isUploaded,
|
||||||
required bool isSelfRef,
|
required bool isSelfRef,
|
||||||
@ -30,11 +41,23 @@ class SnAttachment with _$SnAttachment {
|
|||||||
required SnAttachmentPool? pool,
|
required SnAttachmentPool? pool,
|
||||||
required int poolId,
|
required int poolId,
|
||||||
required int accountId,
|
required int accountId,
|
||||||
|
@Default({}) Map<String, dynamic> usermeta,
|
||||||
@Default({}) Map<String, dynamic> metadata,
|
@Default({}) Map<String, dynamic> metadata,
|
||||||
}) = _SnAttachment;
|
}) = _SnAttachment;
|
||||||
|
|
||||||
factory SnAttachment.fromJson(Map<String, Object?> json) =>
|
factory SnAttachment.fromJson(Map<String, Object?> json) => _$SnAttachmentFromJson(json);
|
||||||
_$SnAttachmentFromJson(json);
|
|
||||||
|
Map<String, dynamic> get data => {
|
||||||
|
...metadata,
|
||||||
|
...usermeta,
|
||||||
|
};
|
||||||
|
|
||||||
|
SnMediaType get mediaType => switch (mimetype.split('/').firstOrNull) {
|
||||||
|
'image' => SnMediaType.image,
|
||||||
|
'video' => SnMediaType.video,
|
||||||
|
'audio' => SnMediaType.audio,
|
||||||
|
_ => SnMediaType.file,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@freezed
|
@freezed
|
||||||
@ -51,6 +74,5 @@ class SnAttachmentPool with _$SnAttachmentPool {
|
|||||||
required int? accountId,
|
required int? accountId,
|
||||||
}) = _SnAttachmentPool;
|
}) = _SnAttachmentPool;
|
||||||
|
|
||||||
factory SnAttachmentPool.fromJson(Map<String, Object?> json) =>
|
factory SnAttachmentPool.fromJson(Map<String, Object?> json) => _$SnAttachmentPoolFromJson(json);
|
||||||
_$SnAttachmentPoolFromJson(json);
|
|
||||||
}
|
}
|
||||||
|
@ -33,9 +33,10 @@ mixin _$SnAttachment {
|
|||||||
String get hash => throw _privateConstructorUsedError;
|
String get hash => throw _privateConstructorUsedError;
|
||||||
int get destination => throw _privateConstructorUsedError;
|
int get destination => throw _privateConstructorUsedError;
|
||||||
int get refCount => throw _privateConstructorUsedError;
|
int get refCount => throw _privateConstructorUsedError;
|
||||||
|
int get contentRating => throw _privateConstructorUsedError;
|
||||||
|
int get qualityRating => throw _privateConstructorUsedError;
|
||||||
dynamic get fileChunks => throw _privateConstructorUsedError;
|
dynamic get fileChunks => throw _privateConstructorUsedError;
|
||||||
dynamic get cleanedAt => throw _privateConstructorUsedError;
|
dynamic get cleanedAt => throw _privateConstructorUsedError;
|
||||||
bool get isMature => throw _privateConstructorUsedError;
|
|
||||||
bool get isAnalyzed => throw _privateConstructorUsedError;
|
bool get isAnalyzed => throw _privateConstructorUsedError;
|
||||||
bool get isUploaded => throw _privateConstructorUsedError;
|
bool get isUploaded => throw _privateConstructorUsedError;
|
||||||
bool get isSelfRef => throw _privateConstructorUsedError;
|
bool get isSelfRef => throw _privateConstructorUsedError;
|
||||||
@ -44,6 +45,7 @@ mixin _$SnAttachment {
|
|||||||
SnAttachmentPool? get pool => throw _privateConstructorUsedError;
|
SnAttachmentPool? get pool => throw _privateConstructorUsedError;
|
||||||
int get poolId => throw _privateConstructorUsedError;
|
int get poolId => throw _privateConstructorUsedError;
|
||||||
int get accountId => throw _privateConstructorUsedError;
|
int get accountId => throw _privateConstructorUsedError;
|
||||||
|
Map<String, dynamic> get usermeta => throw _privateConstructorUsedError;
|
||||||
Map<String, dynamic> get metadata => throw _privateConstructorUsedError;
|
Map<String, dynamic> get metadata => throw _privateConstructorUsedError;
|
||||||
|
|
||||||
/// Serializes this SnAttachment to a JSON map.
|
/// Serializes this SnAttachment to a JSON map.
|
||||||
@ -76,9 +78,10 @@ abstract class $SnAttachmentCopyWith<$Res> {
|
|||||||
String hash,
|
String hash,
|
||||||
int destination,
|
int destination,
|
||||||
int refCount,
|
int refCount,
|
||||||
|
int contentRating,
|
||||||
|
int qualityRating,
|
||||||
dynamic fileChunks,
|
dynamic fileChunks,
|
||||||
dynamic cleanedAt,
|
dynamic cleanedAt,
|
||||||
bool isMature,
|
|
||||||
bool isAnalyzed,
|
bool isAnalyzed,
|
||||||
bool isUploaded,
|
bool isUploaded,
|
||||||
bool isSelfRef,
|
bool isSelfRef,
|
||||||
@ -87,6 +90,7 @@ abstract class $SnAttachmentCopyWith<$Res> {
|
|||||||
SnAttachmentPool? pool,
|
SnAttachmentPool? pool,
|
||||||
int poolId,
|
int poolId,
|
||||||
int accountId,
|
int accountId,
|
||||||
|
Map<String, dynamic> usermeta,
|
||||||
Map<String, dynamic> metadata});
|
Map<String, dynamic> metadata});
|
||||||
|
|
||||||
$SnAttachmentPoolCopyWith<$Res>? get pool;
|
$SnAttachmentPoolCopyWith<$Res>? get pool;
|
||||||
@ -120,9 +124,10 @@ class _$SnAttachmentCopyWithImpl<$Res, $Val extends SnAttachment>
|
|||||||
Object? hash = null,
|
Object? hash = null,
|
||||||
Object? destination = null,
|
Object? destination = null,
|
||||||
Object? refCount = null,
|
Object? refCount = null,
|
||||||
|
Object? contentRating = null,
|
||||||
|
Object? qualityRating = null,
|
||||||
Object? fileChunks = freezed,
|
Object? fileChunks = freezed,
|
||||||
Object? cleanedAt = freezed,
|
Object? cleanedAt = freezed,
|
||||||
Object? isMature = null,
|
|
||||||
Object? isAnalyzed = null,
|
Object? isAnalyzed = null,
|
||||||
Object? isUploaded = null,
|
Object? isUploaded = null,
|
||||||
Object? isSelfRef = null,
|
Object? isSelfRef = null,
|
||||||
@ -131,6 +136,7 @@ class _$SnAttachmentCopyWithImpl<$Res, $Val extends SnAttachment>
|
|||||||
Object? pool = freezed,
|
Object? pool = freezed,
|
||||||
Object? poolId = null,
|
Object? poolId = null,
|
||||||
Object? accountId = null,
|
Object? accountId = null,
|
||||||
|
Object? usermeta = null,
|
||||||
Object? metadata = null,
|
Object? metadata = null,
|
||||||
}) {
|
}) {
|
||||||
return _then(_value.copyWith(
|
return _then(_value.copyWith(
|
||||||
@ -186,6 +192,14 @@ class _$SnAttachmentCopyWithImpl<$Res, $Val extends SnAttachment>
|
|||||||
? _value.refCount
|
? _value.refCount
|
||||||
: refCount // ignore: cast_nullable_to_non_nullable
|
: refCount // ignore: cast_nullable_to_non_nullable
|
||||||
as int,
|
as int,
|
||||||
|
contentRating: null == contentRating
|
||||||
|
? _value.contentRating
|
||||||
|
: contentRating // ignore: cast_nullable_to_non_nullable
|
||||||
|
as int,
|
||||||
|
qualityRating: null == qualityRating
|
||||||
|
? _value.qualityRating
|
||||||
|
: qualityRating // ignore: cast_nullable_to_non_nullable
|
||||||
|
as int,
|
||||||
fileChunks: freezed == fileChunks
|
fileChunks: freezed == fileChunks
|
||||||
? _value.fileChunks
|
? _value.fileChunks
|
||||||
: fileChunks // ignore: cast_nullable_to_non_nullable
|
: fileChunks // ignore: cast_nullable_to_non_nullable
|
||||||
@ -194,10 +208,6 @@ class _$SnAttachmentCopyWithImpl<$Res, $Val extends SnAttachment>
|
|||||||
? _value.cleanedAt
|
? _value.cleanedAt
|
||||||
: cleanedAt // ignore: cast_nullable_to_non_nullable
|
: cleanedAt // ignore: cast_nullable_to_non_nullable
|
||||||
as dynamic,
|
as dynamic,
|
||||||
isMature: null == isMature
|
|
||||||
? _value.isMature
|
|
||||||
: isMature // ignore: cast_nullable_to_non_nullable
|
|
||||||
as bool,
|
|
||||||
isAnalyzed: null == isAnalyzed
|
isAnalyzed: null == isAnalyzed
|
||||||
? _value.isAnalyzed
|
? _value.isAnalyzed
|
||||||
: isAnalyzed // ignore: cast_nullable_to_non_nullable
|
: isAnalyzed // ignore: cast_nullable_to_non_nullable
|
||||||
@ -230,6 +240,10 @@ class _$SnAttachmentCopyWithImpl<$Res, $Val extends SnAttachment>
|
|||||||
? _value.accountId
|
? _value.accountId
|
||||||
: accountId // ignore: cast_nullable_to_non_nullable
|
: accountId // ignore: cast_nullable_to_non_nullable
|
||||||
as int,
|
as int,
|
||||||
|
usermeta: null == usermeta
|
||||||
|
? _value.usermeta
|
||||||
|
: usermeta // ignore: cast_nullable_to_non_nullable
|
||||||
|
as Map<String, dynamic>,
|
||||||
metadata: null == metadata
|
metadata: null == metadata
|
||||||
? _value.metadata
|
? _value.metadata
|
||||||
: metadata // ignore: cast_nullable_to_non_nullable
|
: metadata // ignore: cast_nullable_to_non_nullable
|
||||||
@ -274,9 +288,10 @@ abstract class _$$SnAttachmentImplCopyWith<$Res>
|
|||||||
String hash,
|
String hash,
|
||||||
int destination,
|
int destination,
|
||||||
int refCount,
|
int refCount,
|
||||||
|
int contentRating,
|
||||||
|
int qualityRating,
|
||||||
dynamic fileChunks,
|
dynamic fileChunks,
|
||||||
dynamic cleanedAt,
|
dynamic cleanedAt,
|
||||||
bool isMature,
|
|
||||||
bool isAnalyzed,
|
bool isAnalyzed,
|
||||||
bool isUploaded,
|
bool isUploaded,
|
||||||
bool isSelfRef,
|
bool isSelfRef,
|
||||||
@ -285,6 +300,7 @@ abstract class _$$SnAttachmentImplCopyWith<$Res>
|
|||||||
SnAttachmentPool? pool,
|
SnAttachmentPool? pool,
|
||||||
int poolId,
|
int poolId,
|
||||||
int accountId,
|
int accountId,
|
||||||
|
Map<String, dynamic> usermeta,
|
||||||
Map<String, dynamic> metadata});
|
Map<String, dynamic> metadata});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -317,9 +333,10 @@ class __$$SnAttachmentImplCopyWithImpl<$Res>
|
|||||||
Object? hash = null,
|
Object? hash = null,
|
||||||
Object? destination = null,
|
Object? destination = null,
|
||||||
Object? refCount = null,
|
Object? refCount = null,
|
||||||
|
Object? contentRating = null,
|
||||||
|
Object? qualityRating = null,
|
||||||
Object? fileChunks = freezed,
|
Object? fileChunks = freezed,
|
||||||
Object? cleanedAt = freezed,
|
Object? cleanedAt = freezed,
|
||||||
Object? isMature = null,
|
|
||||||
Object? isAnalyzed = null,
|
Object? isAnalyzed = null,
|
||||||
Object? isUploaded = null,
|
Object? isUploaded = null,
|
||||||
Object? isSelfRef = null,
|
Object? isSelfRef = null,
|
||||||
@ -328,6 +345,7 @@ class __$$SnAttachmentImplCopyWithImpl<$Res>
|
|||||||
Object? pool = freezed,
|
Object? pool = freezed,
|
||||||
Object? poolId = null,
|
Object? poolId = null,
|
||||||
Object? accountId = null,
|
Object? accountId = null,
|
||||||
|
Object? usermeta = null,
|
||||||
Object? metadata = null,
|
Object? metadata = null,
|
||||||
}) {
|
}) {
|
||||||
return _then(_$SnAttachmentImpl(
|
return _then(_$SnAttachmentImpl(
|
||||||
@ -383,6 +401,14 @@ class __$$SnAttachmentImplCopyWithImpl<$Res>
|
|||||||
? _value.refCount
|
? _value.refCount
|
||||||
: refCount // ignore: cast_nullable_to_non_nullable
|
: refCount // ignore: cast_nullable_to_non_nullable
|
||||||
as int,
|
as int,
|
||||||
|
contentRating: null == contentRating
|
||||||
|
? _value.contentRating
|
||||||
|
: contentRating // ignore: cast_nullable_to_non_nullable
|
||||||
|
as int,
|
||||||
|
qualityRating: null == qualityRating
|
||||||
|
? _value.qualityRating
|
||||||
|
: qualityRating // ignore: cast_nullable_to_non_nullable
|
||||||
|
as int,
|
||||||
fileChunks: freezed == fileChunks
|
fileChunks: freezed == fileChunks
|
||||||
? _value.fileChunks
|
? _value.fileChunks
|
||||||
: fileChunks // ignore: cast_nullable_to_non_nullable
|
: fileChunks // ignore: cast_nullable_to_non_nullable
|
||||||
@ -391,10 +417,6 @@ class __$$SnAttachmentImplCopyWithImpl<$Res>
|
|||||||
? _value.cleanedAt
|
? _value.cleanedAt
|
||||||
: cleanedAt // ignore: cast_nullable_to_non_nullable
|
: cleanedAt // ignore: cast_nullable_to_non_nullable
|
||||||
as dynamic,
|
as dynamic,
|
||||||
isMature: null == isMature
|
|
||||||
? _value.isMature
|
|
||||||
: isMature // ignore: cast_nullable_to_non_nullable
|
|
||||||
as bool,
|
|
||||||
isAnalyzed: null == isAnalyzed
|
isAnalyzed: null == isAnalyzed
|
||||||
? _value.isAnalyzed
|
? _value.isAnalyzed
|
||||||
: isAnalyzed // ignore: cast_nullable_to_non_nullable
|
: isAnalyzed // ignore: cast_nullable_to_non_nullable
|
||||||
@ -427,6 +449,10 @@ class __$$SnAttachmentImplCopyWithImpl<$Res>
|
|||||||
? _value.accountId
|
? _value.accountId
|
||||||
: accountId // ignore: cast_nullable_to_non_nullable
|
: accountId // ignore: cast_nullable_to_non_nullable
|
||||||
as int,
|
as int,
|
||||||
|
usermeta: null == usermeta
|
||||||
|
? _value._usermeta
|
||||||
|
: usermeta // ignore: cast_nullable_to_non_nullable
|
||||||
|
as Map<String, dynamic>,
|
||||||
metadata: null == metadata
|
metadata: null == metadata
|
||||||
? _value._metadata
|
? _value._metadata
|
||||||
: metadata // ignore: cast_nullable_to_non_nullable
|
: metadata // ignore: cast_nullable_to_non_nullable
|
||||||
@ -437,7 +463,7 @@ class __$$SnAttachmentImplCopyWithImpl<$Res>
|
|||||||
|
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
@JsonSerializable()
|
@JsonSerializable()
|
||||||
class _$SnAttachmentImpl implements _SnAttachment {
|
class _$SnAttachmentImpl extends _SnAttachment {
|
||||||
const _$SnAttachmentImpl(
|
const _$SnAttachmentImpl(
|
||||||
{required this.id,
|
{required this.id,
|
||||||
required this.createdAt,
|
required this.createdAt,
|
||||||
@ -452,9 +478,10 @@ class _$SnAttachmentImpl implements _SnAttachment {
|
|||||||
required this.hash,
|
required this.hash,
|
||||||
required this.destination,
|
required this.destination,
|
||||||
required this.refCount,
|
required this.refCount,
|
||||||
|
this.contentRating = 0,
|
||||||
|
this.qualityRating = 0,
|
||||||
required this.fileChunks,
|
required this.fileChunks,
|
||||||
required this.cleanedAt,
|
required this.cleanedAt,
|
||||||
required this.isMature,
|
|
||||||
required this.isAnalyzed,
|
required this.isAnalyzed,
|
||||||
required this.isUploaded,
|
required this.isUploaded,
|
||||||
required this.isSelfRef,
|
required this.isSelfRef,
|
||||||
@ -463,8 +490,11 @@ class _$SnAttachmentImpl implements _SnAttachment {
|
|||||||
required this.pool,
|
required this.pool,
|
||||||
required this.poolId,
|
required this.poolId,
|
||||||
required this.accountId,
|
required this.accountId,
|
||||||
|
final Map<String, dynamic> usermeta = const {},
|
||||||
final Map<String, dynamic> metadata = const {}})
|
final Map<String, dynamic> metadata = const {}})
|
||||||
: _metadata = metadata;
|
: _usermeta = usermeta,
|
||||||
|
_metadata = metadata,
|
||||||
|
super._();
|
||||||
|
|
||||||
factory _$SnAttachmentImpl.fromJson(Map<String, dynamic> json) =>
|
factory _$SnAttachmentImpl.fromJson(Map<String, dynamic> json) =>
|
||||||
_$$SnAttachmentImplFromJson(json);
|
_$$SnAttachmentImplFromJson(json);
|
||||||
@ -496,12 +526,16 @@ class _$SnAttachmentImpl implements _SnAttachment {
|
|||||||
@override
|
@override
|
||||||
final int refCount;
|
final int refCount;
|
||||||
@override
|
@override
|
||||||
|
@JsonKey()
|
||||||
|
final int contentRating;
|
||||||
|
@override
|
||||||
|
@JsonKey()
|
||||||
|
final int qualityRating;
|
||||||
|
@override
|
||||||
final dynamic fileChunks;
|
final dynamic fileChunks;
|
||||||
@override
|
@override
|
||||||
final dynamic cleanedAt;
|
final dynamic cleanedAt;
|
||||||
@override
|
@override
|
||||||
final bool isMature;
|
|
||||||
@override
|
|
||||||
final bool isAnalyzed;
|
final bool isAnalyzed;
|
||||||
@override
|
@override
|
||||||
final bool isUploaded;
|
final bool isUploaded;
|
||||||
@ -517,6 +551,15 @@ class _$SnAttachmentImpl implements _SnAttachment {
|
|||||||
final int poolId;
|
final int poolId;
|
||||||
@override
|
@override
|
||||||
final int accountId;
|
final int accountId;
|
||||||
|
final Map<String, dynamic> _usermeta;
|
||||||
|
@override
|
||||||
|
@JsonKey()
|
||||||
|
Map<String, dynamic> get usermeta {
|
||||||
|
if (_usermeta is EqualUnmodifiableMapView) return _usermeta;
|
||||||
|
// ignore: implicit_dynamic_type
|
||||||
|
return EqualUnmodifiableMapView(_usermeta);
|
||||||
|
}
|
||||||
|
|
||||||
final Map<String, dynamic> _metadata;
|
final Map<String, dynamic> _metadata;
|
||||||
@override
|
@override
|
||||||
@JsonKey()
|
@JsonKey()
|
||||||
@ -528,7 +571,7 @@ class _$SnAttachmentImpl implements _SnAttachment {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'SnAttachment(id: $id, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, rid: $rid, uuid: $uuid, size: $size, name: $name, alt: $alt, mimetype: $mimetype, hash: $hash, destination: $destination, refCount: $refCount, fileChunks: $fileChunks, cleanedAt: $cleanedAt, isMature: $isMature, isAnalyzed: $isAnalyzed, isUploaded: $isUploaded, isSelfRef: $isSelfRef, ref: $ref, refId: $refId, pool: $pool, poolId: $poolId, accountId: $accountId, metadata: $metadata)';
|
return 'SnAttachment(id: $id, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, rid: $rid, uuid: $uuid, size: $size, name: $name, alt: $alt, mimetype: $mimetype, hash: $hash, destination: $destination, refCount: $refCount, contentRating: $contentRating, qualityRating: $qualityRating, fileChunks: $fileChunks, cleanedAt: $cleanedAt, isAnalyzed: $isAnalyzed, isUploaded: $isUploaded, isSelfRef: $isSelfRef, ref: $ref, refId: $refId, pool: $pool, poolId: $poolId, accountId: $accountId, usermeta: $usermeta, metadata: $metadata)';
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -554,11 +597,13 @@ class _$SnAttachmentImpl implements _SnAttachment {
|
|||||||
other.destination == destination) &&
|
other.destination == destination) &&
|
||||||
(identical(other.refCount, refCount) ||
|
(identical(other.refCount, refCount) ||
|
||||||
other.refCount == refCount) &&
|
other.refCount == refCount) &&
|
||||||
|
(identical(other.contentRating, contentRating) ||
|
||||||
|
other.contentRating == contentRating) &&
|
||||||
|
(identical(other.qualityRating, qualityRating) ||
|
||||||
|
other.qualityRating == qualityRating) &&
|
||||||
const DeepCollectionEquality()
|
const DeepCollectionEquality()
|
||||||
.equals(other.fileChunks, fileChunks) &&
|
.equals(other.fileChunks, fileChunks) &&
|
||||||
const DeepCollectionEquality().equals(other.cleanedAt, cleanedAt) &&
|
const DeepCollectionEquality().equals(other.cleanedAt, cleanedAt) &&
|
||||||
(identical(other.isMature, isMature) ||
|
|
||||||
other.isMature == isMature) &&
|
|
||||||
(identical(other.isAnalyzed, isAnalyzed) ||
|
(identical(other.isAnalyzed, isAnalyzed) ||
|
||||||
other.isAnalyzed == isAnalyzed) &&
|
other.isAnalyzed == isAnalyzed) &&
|
||||||
(identical(other.isUploaded, isUploaded) ||
|
(identical(other.isUploaded, isUploaded) ||
|
||||||
@ -571,6 +616,7 @@ class _$SnAttachmentImpl implements _SnAttachment {
|
|||||||
(identical(other.poolId, poolId) || other.poolId == poolId) &&
|
(identical(other.poolId, poolId) || other.poolId == poolId) &&
|
||||||
(identical(other.accountId, accountId) ||
|
(identical(other.accountId, accountId) ||
|
||||||
other.accountId == accountId) &&
|
other.accountId == accountId) &&
|
||||||
|
const DeepCollectionEquality().equals(other._usermeta, _usermeta) &&
|
||||||
const DeepCollectionEquality().equals(other._metadata, _metadata));
|
const DeepCollectionEquality().equals(other._metadata, _metadata));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -591,9 +637,10 @@ class _$SnAttachmentImpl implements _SnAttachment {
|
|||||||
hash,
|
hash,
|
||||||
destination,
|
destination,
|
||||||
refCount,
|
refCount,
|
||||||
|
contentRating,
|
||||||
|
qualityRating,
|
||||||
const DeepCollectionEquality().hash(fileChunks),
|
const DeepCollectionEquality().hash(fileChunks),
|
||||||
const DeepCollectionEquality().hash(cleanedAt),
|
const DeepCollectionEquality().hash(cleanedAt),
|
||||||
isMature,
|
|
||||||
isAnalyzed,
|
isAnalyzed,
|
||||||
isUploaded,
|
isUploaded,
|
||||||
isSelfRef,
|
isSelfRef,
|
||||||
@ -602,6 +649,7 @@ class _$SnAttachmentImpl implements _SnAttachment {
|
|||||||
pool,
|
pool,
|
||||||
poolId,
|
poolId,
|
||||||
accountId,
|
accountId,
|
||||||
|
const DeepCollectionEquality().hash(_usermeta),
|
||||||
const DeepCollectionEquality().hash(_metadata)
|
const DeepCollectionEquality().hash(_metadata)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -621,7 +669,7 @@ class _$SnAttachmentImpl implements _SnAttachment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class _SnAttachment implements SnAttachment {
|
abstract class _SnAttachment extends SnAttachment {
|
||||||
const factory _SnAttachment(
|
const factory _SnAttachment(
|
||||||
{required final int id,
|
{required final int id,
|
||||||
required final DateTime createdAt,
|
required final DateTime createdAt,
|
||||||
@ -636,9 +684,10 @@ abstract class _SnAttachment implements SnAttachment {
|
|||||||
required final String hash,
|
required final String hash,
|
||||||
required final int destination,
|
required final int destination,
|
||||||
required final int refCount,
|
required final int refCount,
|
||||||
|
final int contentRating,
|
||||||
|
final int qualityRating,
|
||||||
required final dynamic fileChunks,
|
required final dynamic fileChunks,
|
||||||
required final dynamic cleanedAt,
|
required final dynamic cleanedAt,
|
||||||
required final bool isMature,
|
|
||||||
required final bool isAnalyzed,
|
required final bool isAnalyzed,
|
||||||
required final bool isUploaded,
|
required final bool isUploaded,
|
||||||
required final bool isSelfRef,
|
required final bool isSelfRef,
|
||||||
@ -647,7 +696,9 @@ abstract class _SnAttachment implements SnAttachment {
|
|||||||
required final SnAttachmentPool? pool,
|
required final SnAttachmentPool? pool,
|
||||||
required final int poolId,
|
required final int poolId,
|
||||||
required final int accountId,
|
required final int accountId,
|
||||||
|
final Map<String, dynamic> usermeta,
|
||||||
final Map<String, dynamic> metadata}) = _$SnAttachmentImpl;
|
final Map<String, dynamic> metadata}) = _$SnAttachmentImpl;
|
||||||
|
const _SnAttachment._() : super._();
|
||||||
|
|
||||||
factory _SnAttachment.fromJson(Map<String, dynamic> json) =
|
factory _SnAttachment.fromJson(Map<String, dynamic> json) =
|
||||||
_$SnAttachmentImpl.fromJson;
|
_$SnAttachmentImpl.fromJson;
|
||||||
@ -679,12 +730,14 @@ abstract class _SnAttachment implements SnAttachment {
|
|||||||
@override
|
@override
|
||||||
int get refCount;
|
int get refCount;
|
||||||
@override
|
@override
|
||||||
|
int get contentRating;
|
||||||
|
@override
|
||||||
|
int get qualityRating;
|
||||||
|
@override
|
||||||
dynamic get fileChunks;
|
dynamic get fileChunks;
|
||||||
@override
|
@override
|
||||||
dynamic get cleanedAt;
|
dynamic get cleanedAt;
|
||||||
@override
|
@override
|
||||||
bool get isMature;
|
|
||||||
@override
|
|
||||||
bool get isAnalyzed;
|
bool get isAnalyzed;
|
||||||
@override
|
@override
|
||||||
bool get isUploaded;
|
bool get isUploaded;
|
||||||
@ -701,6 +754,8 @@ abstract class _SnAttachment implements SnAttachment {
|
|||||||
@override
|
@override
|
||||||
int get accountId;
|
int get accountId;
|
||||||
@override
|
@override
|
||||||
|
Map<String, dynamic> get usermeta;
|
||||||
|
@override
|
||||||
Map<String, dynamic> get metadata;
|
Map<String, dynamic> get metadata;
|
||||||
|
|
||||||
/// Create a copy of SnAttachment
|
/// Create a copy of SnAttachment
|
||||||
|
@ -21,9 +21,10 @@ _$SnAttachmentImpl _$$SnAttachmentImplFromJson(Map<String, dynamic> json) =>
|
|||||||
hash: json['hash'] as String,
|
hash: json['hash'] as String,
|
||||||
destination: (json['destination'] as num).toInt(),
|
destination: (json['destination'] as num).toInt(),
|
||||||
refCount: (json['ref_count'] as num).toInt(),
|
refCount: (json['ref_count'] as num).toInt(),
|
||||||
|
contentRating: (json['content_rating'] as num?)?.toInt() ?? 0,
|
||||||
|
qualityRating: (json['quality_rating'] as num?)?.toInt() ?? 0,
|
||||||
fileChunks: json['file_chunks'],
|
fileChunks: json['file_chunks'],
|
||||||
cleanedAt: json['cleaned_at'],
|
cleanedAt: json['cleaned_at'],
|
||||||
isMature: json['is_mature'] as bool,
|
|
||||||
isAnalyzed: json['is_analyzed'] as bool,
|
isAnalyzed: json['is_analyzed'] as bool,
|
||||||
isUploaded: json['is_uploaded'] as bool,
|
isUploaded: json['is_uploaded'] as bool,
|
||||||
isSelfRef: json['is_self_ref'] as bool,
|
isSelfRef: json['is_self_ref'] as bool,
|
||||||
@ -34,6 +35,7 @@ _$SnAttachmentImpl _$$SnAttachmentImplFromJson(Map<String, dynamic> json) =>
|
|||||||
: SnAttachmentPool.fromJson(json['pool'] as Map<String, dynamic>),
|
: SnAttachmentPool.fromJson(json['pool'] as Map<String, dynamic>),
|
||||||
poolId: (json['pool_id'] as num).toInt(),
|
poolId: (json['pool_id'] as num).toInt(),
|
||||||
accountId: (json['account_id'] as num).toInt(),
|
accountId: (json['account_id'] as num).toInt(),
|
||||||
|
usermeta: json['usermeta'] as Map<String, dynamic>? ?? const {},
|
||||||
metadata: json['metadata'] as Map<String, dynamic>? ?? const {},
|
metadata: json['metadata'] as Map<String, dynamic>? ?? const {},
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -52,9 +54,10 @@ Map<String, dynamic> _$$SnAttachmentImplToJson(_$SnAttachmentImpl instance) =>
|
|||||||
'hash': instance.hash,
|
'hash': instance.hash,
|
||||||
'destination': instance.destination,
|
'destination': instance.destination,
|
||||||
'ref_count': instance.refCount,
|
'ref_count': instance.refCount,
|
||||||
|
'content_rating': instance.contentRating,
|
||||||
|
'quality_rating': instance.qualityRating,
|
||||||
'file_chunks': instance.fileChunks,
|
'file_chunks': instance.fileChunks,
|
||||||
'cleaned_at': instance.cleanedAt,
|
'cleaned_at': instance.cleanedAt,
|
||||||
'is_mature': instance.isMature,
|
|
||||||
'is_analyzed': instance.isAnalyzed,
|
'is_analyzed': instance.isAnalyzed,
|
||||||
'is_uploaded': instance.isUploaded,
|
'is_uploaded': instance.isUploaded,
|
||||||
'is_self_ref': instance.isSelfRef,
|
'is_self_ref': instance.isSelfRef,
|
||||||
@ -63,6 +66,7 @@ Map<String, dynamic> _$$SnAttachmentImplToJson(_$SnAttachmentImpl instance) =>
|
|||||||
'pool': instance.pool?.toJson(),
|
'pool': instance.pool?.toJson(),
|
||||||
'pool_id': instance.poolId,
|
'pool_id': instance.poolId,
|
||||||
'account_id': instance.accountId,
|
'account_id': instance.accountId,
|
||||||
|
'usermeta': instance.usermeta,
|
||||||
'metadata': instance.metadata,
|
'metadata': instance.metadata,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -99,10 +99,10 @@ class _AttachmentInputDialogState extends State<AttachmentInputDialog> {
|
|||||||
),
|
),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
child: Text('dialogDismiss').tr(),
|
|
||||||
onPressed: _isBusy ? null : () {
|
onPressed: _isBusy ? null : () {
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
},
|
},
|
||||||
|
child: Text('dialogDismiss').tr(),
|
||||||
),
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: _isBusy ? null : () => _finishUp(),
|
onPressed: _isBusy ? null : () => _finishUp(),
|
||||||
|
@ -18,6 +18,7 @@ import 'package:uuid/uuid.dart';
|
|||||||
class AttachmentItem extends StatelessWidget {
|
class AttachmentItem extends StatelessWidget {
|
||||||
final SnAttachment? data;
|
final SnAttachment? data;
|
||||||
final String? heroTag;
|
final String? heroTag;
|
||||||
|
|
||||||
const AttachmentItem({
|
const AttachmentItem({
|
||||||
super.key,
|
super.key,
|
||||||
required this.data,
|
required this.data,
|
||||||
@ -60,9 +61,14 @@ class AttachmentItem extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
if (data!.isMature) {
|
if (data!.contentRating > 0) {
|
||||||
return _AttachmentItemSensitiveBlur(
|
return LayoutBuilder(
|
||||||
child: _buildContent(context),
|
builder: (context, constraints) {
|
||||||
|
return _AttachmentItemSensitiveBlur(
|
||||||
|
isCompact: constraints.maxHeight < 360,
|
||||||
|
child: _buildContent(context),
|
||||||
|
);
|
||||||
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,15 +78,15 @@ class AttachmentItem extends StatelessWidget {
|
|||||||
|
|
||||||
class _AttachmentItemSensitiveBlur extends StatefulWidget {
|
class _AttachmentItemSensitiveBlur extends StatefulWidget {
|
||||||
final Widget child;
|
final Widget child;
|
||||||
const _AttachmentItemSensitiveBlur({super.key, required this.child});
|
final bool isCompact;
|
||||||
|
|
||||||
|
const _AttachmentItemSensitiveBlur({super.key, required this.child, this.isCompact = false});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<_AttachmentItemSensitiveBlur> createState() =>
|
State<_AttachmentItemSensitiveBlur> createState() => _AttachmentItemSensitiveBlurState();
|
||||||
_AttachmentItemSensitiveBlurState();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class _AttachmentItemSensitiveBlurState
|
class _AttachmentItemSensitiveBlurState extends State<_AttachmentItemSensitiveBlur> {
|
||||||
extends State<_AttachmentItemSensitiveBlur> {
|
|
||||||
bool _doesShow = false;
|
bool _doesShow = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -104,24 +110,21 @@ class _AttachmentItemSensitiveBlurState
|
|||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
size: 32,
|
size: 32,
|
||||||
),
|
),
|
||||||
const Gap(8),
|
if (!widget.isCompact) const Gap(8),
|
||||||
Text('sensitiveContent', textAlign: TextAlign.center)
|
if (!widget.isCompact)
|
||||||
.tr()
|
Text('sensitiveContent', textAlign: TextAlign.center)
|
||||||
.fontSize(20)
|
|
||||||
.textColor(Colors.white)
|
|
||||||
.bold(),
|
|
||||||
Text(
|
|
||||||
'sensitiveContentDescription',
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
)
|
|
||||||
.tr()
|
|
||||||
.fontSize(14)
|
|
||||||
.textColor(Colors.white.withOpacity(0.8)),
|
|
||||||
const Gap(16),
|
|
||||||
InkWell(
|
|
||||||
child: Text('sensitiveContentReveal')
|
|
||||||
.tr()
|
.tr()
|
||||||
.textColor(Colors.white),
|
.fontSize(20)
|
||||||
|
.textColor(Colors.white)
|
||||||
|
.bold(),
|
||||||
|
if (!widget.isCompact)
|
||||||
|
Text(
|
||||||
|
'sensitiveContentDescription',
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
).tr().fontSize(14).textColor(Colors.white.withOpacity(0.8)),
|
||||||
|
if (!widget.isCompact) const Gap(16),
|
||||||
|
InkWell(
|
||||||
|
child: Text('sensitiveContentReveal').tr().textColor(Colors.white),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
setState(() => _doesShow = !_doesShow);
|
setState(() => _doesShow = !_doesShow);
|
||||||
},
|
},
|
||||||
@ -131,9 +134,7 @@ class _AttachmentItemSensitiveBlurState
|
|||||||
).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,
|
||||||
@ -163,6 +164,7 @@ class _AttachmentItemSensitiveBlurState
|
|||||||
class _AttachmentItemContentVideo extends StatefulWidget {
|
class _AttachmentItemContentVideo extends StatefulWidget {
|
||||||
final SnAttachment data;
|
final SnAttachment data;
|
||||||
final bool isAutoload;
|
final bool isAutoload;
|
||||||
|
|
||||||
const _AttachmentItemContentVideo({
|
const _AttachmentItemContentVideo({
|
||||||
super.key,
|
super.key,
|
||||||
required this.data,
|
required this.data,
|
||||||
@ -170,12 +172,10 @@ class _AttachmentItemContentVideo extends StatefulWidget {
|
|||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<_AttachmentItemContentVideo> createState() =>
|
State<_AttachmentItemContentVideo> createState() => _AttachmentItemContentVideoState();
|
||||||
_AttachmentItemContentVideoState();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class _AttachmentItemContentVideoState
|
class _AttachmentItemContentVideoState extends State<_AttachmentItemContentVideo> {
|
||||||
extends State<_AttachmentItemContentVideo> {
|
|
||||||
bool _showContent = false;
|
bool _showContent = false;
|
||||||
|
|
||||||
Player? _videoPlayer;
|
Player? _videoPlayer;
|
||||||
@ -266,10 +266,7 @@ class _AttachmentItemContentVideoState
|
|||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
Duration(
|
Duration(
|
||||||
milliseconds:
|
milliseconds: (widget.data.metadata['duration'] ?? 0).toInt() * 1000,
|
||||||
(widget.data.metadata['duration'] ?? 0)
|
|
||||||
.toInt() *
|
|
||||||
1000,
|
|
||||||
).toString(),
|
).toString(),
|
||||||
style: GoogleFonts.robotoMono(
|
style: GoogleFonts.robotoMono(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
@ -317,6 +314,7 @@ class _AttachmentItemContentVideoState
|
|||||||
class _AttachmentItemContentAudio extends StatefulWidget {
|
class _AttachmentItemContentAudio extends StatefulWidget {
|
||||||
final SnAttachment data;
|
final SnAttachment data;
|
||||||
final bool isAutoload;
|
final bool isAutoload;
|
||||||
|
|
||||||
const _AttachmentItemContentAudio({
|
const _AttachmentItemContentAudio({
|
||||||
super.key,
|
super.key,
|
||||||
required this.data,
|
required this.data,
|
||||||
@ -324,12 +322,10 @@ class _AttachmentItemContentAudio extends StatefulWidget {
|
|||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<_AttachmentItemContentAudio> createState() =>
|
State<_AttachmentItemContentAudio> createState() => _AttachmentItemContentAudioState();
|
||||||
_AttachmentItemContentAudioState();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class _AttachmentItemContentAudioState
|
class _AttachmentItemContentAudioState extends State<_AttachmentItemContentAudio> {
|
||||||
extends State<_AttachmentItemContentAudio> {
|
|
||||||
bool _showContent = false;
|
bool _showContent = false;
|
||||||
|
|
||||||
double? _draggingValue;
|
double? _draggingValue;
|
||||||
@ -499,12 +495,8 @@ class _AttachmentItemContentAudioState
|
|||||||
overlayShape: SliderComponentShape.noOverlay,
|
overlayShape: SliderComponentShape.noOverlay,
|
||||||
),
|
),
|
||||||
child: Slider(
|
child: Slider(
|
||||||
secondaryTrackValue: _bufferedPosition
|
secondaryTrackValue: _bufferedPosition.inMilliseconds.abs().toDouble(),
|
||||||
.inMilliseconds
|
value: _draggingValue?.abs() ?? _position.inMilliseconds.toDouble().abs(),
|
||||||
.abs()
|
|
||||||
.toDouble(),
|
|
||||||
value: _draggingValue?.abs() ??
|
|
||||||
_position.inMilliseconds.toDouble().abs(),
|
|
||||||
min: 0,
|
min: 0,
|
||||||
max: math
|
max: math
|
||||||
.max(
|
.max(
|
||||||
@ -544,9 +536,7 @@ class _AttachmentItemContentAudioState
|
|||||||
),
|
),
|
||||||
const Gap(16),
|
const Gap(16),
|
||||||
IconButton.filled(
|
IconButton.filled(
|
||||||
icon: _isPlaying
|
icon: _isPlaying ? const Icon(Symbols.pause) : const Icon(Symbols.play_arrow),
|
||||||
? const Icon(Symbols.pause)
|
|
||||||
: const Icon(Symbols.play_arrow),
|
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
_audioPlayer!.playOrPause();
|
_audioPlayer!.playOrPause();
|
||||||
},
|
},
|
||||||
|
@ -58,7 +58,7 @@ 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 = widget.data[0]?.metadata['ratio']?.toDouble() ??
|
final singleAspectRatio = 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,
|
||||||
@ -114,6 +114,7 @@ class _AttachmentListState extends State<AttachmentList> {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
|
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(),
|
||||||
@ -136,7 +137,7 @@ class _AttachmentListState extends State<AttachmentList> {
|
|||||||
children: widget.data
|
children: widget.data
|
||||||
.mapIndexed(
|
.mapIndexed(
|
||||||
(idx, ele) => AspectRatio(
|
(idx, ele) => AspectRatio(
|
||||||
aspectRatio: (ele?.metadata['ratio'] ?? 1).toDouble(),
|
aspectRatio: (ele?.data['ratio'] ?? 1).toDouble(),
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: backgroundColor,
|
color: backgroundColor,
|
||||||
@ -161,7 +162,7 @@ class _AttachmentListState extends State<AttachmentList> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return AspectRatio(
|
return AspectRatio(
|
||||||
aspectRatio: (widget.data.firstOrNull?.metadata['ratio'] ?? 1).toDouble(),
|
aspectRatio: (widget.data.firstOrNull?.data['ratio'] ?? 1).toDouble(),
|
||||||
child: Container(
|
child: Container(
|
||||||
constraints: BoxConstraints(maxHeight: constraints.maxHeight),
|
constraints: BoxConstraints(maxHeight: constraints.maxHeight),
|
||||||
child: ScrollConfiguration(
|
child: ScrollConfiguration(
|
||||||
@ -173,12 +174,14 @@ class _AttachmentListState extends State<AttachmentList> {
|
|||||||
return Container(
|
return Container(
|
||||||
constraints: constraints,
|
constraints: constraints,
|
||||||
child: AspectRatio(
|
child: AspectRatio(
|
||||||
aspectRatio: (widget.data[idx]?.metadata['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;
|
||||||
context.pushTransparentRoute(
|
context.pushTransparentRoute(
|
||||||
AttachmentZoomView(
|
AttachmentZoomView(
|
||||||
data: widget.data.where((ele) => ele != null).cast(),
|
data:
|
||||||
|
widget.data.where((ele) => ele != null && ele.mediaType == SnMediaType.image).cast(),
|
||||||
initialIndex: idx,
|
initialIndex: idx,
|
||||||
heroTags: heroTags,
|
heroTags: heroTags,
|
||||||
),
|
),
|
||||||
|
@ -1,18 +1,14 @@
|
|||||||
import 'dart:io';
|
|
||||||
|
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:image_picker/image_picker.dart';
|
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
import 'package:pasteboard/pasteboard.dart';
|
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
import 'package:surface/controllers/chat_message_controller.dart';
|
import 'package:surface/controllers/chat_message_controller.dart';
|
||||||
import 'package:surface/controllers/post_write_controller.dart';
|
import 'package:surface/controllers/post_write_controller.dart';
|
||||||
import 'package:surface/providers/sn_attachment.dart';
|
import 'package:surface/providers/sn_attachment.dart';
|
||||||
import 'package:surface/providers/user_directory.dart';
|
import 'package:surface/providers/user_directory.dart';
|
||||||
|
import 'package:surface/types/attachment.dart';
|
||||||
import 'package:surface/types/chat.dart';
|
import 'package:surface/types/chat.dart';
|
||||||
import 'package:surface/widgets/dialog.dart';
|
import 'package:surface/widgets/dialog.dart';
|
||||||
import 'package:surface/widgets/markdown_content.dart';
|
import 'package:surface/widgets/markdown_content.dart';
|
||||||
@ -80,7 +76,7 @@ class ChatMessageInputState extends State<ChatMessageInput> {
|
|||||||
media.name,
|
media.name,
|
||||||
'messaging',
|
'messaging',
|
||||||
null,
|
null,
|
||||||
mimetype: media.raw != null && media.type == PostWriteMediaType.image ? 'image/png' : null,
|
mimetype: media.raw != null && media.type == SnMediaType.image ? 'image/png' : null,
|
||||||
);
|
);
|
||||||
|
|
||||||
final item = await attach.chunkedUploadParts(
|
final item = await attach.chunkedUploadParts(
|
||||||
|
@ -124,7 +124,7 @@ class PostMediaPendingList extends StatelessWidget {
|
|||||||
ContextMenu _createContextMenu(BuildContext context, int idx, PostWriteMedia media) {
|
ContextMenu _createContextMenu(BuildContext context, int idx, PostWriteMedia media) {
|
||||||
return ContextMenu(
|
return ContextMenu(
|
||||||
entries: [
|
entries: [
|
||||||
if (media.attachment != null && media.type == PostWriteMediaType.video)
|
if (media.attachment != null && media.type == SnMediaType.video)
|
||||||
MenuItem(
|
MenuItem(
|
||||||
label: 'attachmentSetThumbnail'.tr(),
|
label: 'attachmentSetThumbnail'.tr(),
|
||||||
icon: Symbols.image,
|
icon: Symbols.image,
|
||||||
@ -140,7 +140,7 @@ class PostMediaPendingList extends StatelessWidget {
|
|||||||
onUpload!(idx);
|
onUpload!(idx);
|
||||||
}),
|
}),
|
||||||
if (media.attachment != null &&
|
if (media.attachment != null &&
|
||||||
media.type == PostWriteMediaType.image &&
|
media.type == SnMediaType.image &&
|
||||||
onPostSetThumbnail != null &&
|
onPostSetThumbnail != null &&
|
||||||
idx != -1)
|
idx != -1)
|
||||||
MenuItem(
|
MenuItem(
|
||||||
@ -150,7 +150,7 @@ class PostMediaPendingList extends StatelessWidget {
|
|||||||
onPostSetThumbnail!(idx);
|
onPostSetThumbnail!(idx);
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
else if (media.attachment != null && media.type == PostWriteMediaType.image && onPostSetThumbnail != null)
|
else if (media.attachment != null && media.type == SnMediaType.image && onPostSetThumbnail != null)
|
||||||
MenuItem(
|
MenuItem(
|
||||||
label: 'attachmentUnsetAsPostThumbnail'.tr(),
|
label: 'attachmentUnsetAsPostThumbnail'.tr(),
|
||||||
icon: Symbols.cancel,
|
icon: Symbols.cancel,
|
||||||
@ -166,7 +166,7 @@ class PostMediaPendingList extends StatelessWidget {
|
|||||||
onInsertLink!(idx);
|
onInsertLink!(idx);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
if (media.type == PostWriteMediaType.image && media.attachment != null)
|
if (media.type == SnMediaType.image && media.attachment != null)
|
||||||
MenuItem(
|
MenuItem(
|
||||||
label: 'preview'.tr(),
|
label: 'preview'.tr(),
|
||||||
icon: Symbols.preview,
|
icon: Symbols.preview,
|
||||||
@ -177,7 +177,7 @@ class PostMediaPendingList extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
if (media.type == PostWriteMediaType.image && media.attachment == null)
|
if (media.type == SnMediaType.image && media.attachment == null)
|
||||||
MenuItem(
|
MenuItem(
|
||||||
label: 'crop'.tr(),
|
label: 'crop'.tr(),
|
||||||
icon: Symbols.crop,
|
icon: Symbols.crop,
|
||||||
@ -219,10 +219,6 @@ class PostMediaPendingList extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final devicePixelRatio = MediaQuery.of(context).devicePixelRatio;
|
|
||||||
|
|
||||||
final sn = context.read<SnNetworkProvider>();
|
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
constraints: const BoxConstraints(maxHeight: 120),
|
constraints: const BoxConstraints(maxHeight: 120),
|
||||||
child: Row(
|
child: Row(
|
||||||
@ -285,7 +281,7 @@ class _PostMediaPendingItem extends StatelessWidget {
|
|||||||
child: AspectRatio(
|
child: AspectRatio(
|
||||||
aspectRatio: 1,
|
aspectRatio: 1,
|
||||||
child: switch (media.type) {
|
child: switch (media.type) {
|
||||||
PostWriteMediaType.image => Container(
|
SnMediaType.image => Container(
|
||||||
color: Theme.of(context).colorScheme.surfaceContainer,
|
color: Theme.of(context).colorScheme.surfaceContainer,
|
||||||
child: LayoutBuilder(builder: (context, constraints) {
|
child: LayoutBuilder(builder: (context, constraints) {
|
||||||
return Image(
|
return Image(
|
||||||
@ -298,7 +294,7 @@ class _PostMediaPendingItem extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
PostWriteMediaType.video => Container(
|
SnMediaType.video => Container(
|
||||||
color: Theme.of(context).colorScheme.surfaceContainer,
|
color: Theme.of(context).colorScheme.surfaceContainer,
|
||||||
child: media.attachment?.metadata['thumbnail'] != null
|
child: media.attachment?.metadata['thumbnail'] != null
|
||||||
? AutoResizeUniversalImage(sn.getAttachmentUrl(media.attachment?.metadata['thumbnail']))
|
? AutoResizeUniversalImage(sn.getAttachmentUrl(media.attachment?.metadata['thumbnail']))
|
||||||
@ -345,7 +341,7 @@ class AddPostMediaButton extends StatelessWidget {
|
|||||||
PostWriteMedia.fromBytes(
|
PostWriteMedia.fromBytes(
|
||||||
imageBytes,
|
imageBytes,
|
||||||
'attachmentPastedImage'.tr(),
|
'attachmentPastedImage'.tr(),
|
||||||
PostWriteMediaType.image,
|
SnMediaType.image,
|
||||||
),
|
),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user