Compare commits

...

13 Commits

Author SHA1 Message Date
LittleSheep
4e4bd99598 🚀 Launch 3.1.0+123 2025-08-11 02:06:29 +08:00
LittleSheep
d1fbe5f15e 🐛 Dozens of bug fixes 2025-08-11 01:56:19 +08:00
LittleSheep
c061ef2132 🐛 Bug fixes 2025-08-11 01:44:18 +08:00
LittleSheep
c378309bdd 📝 Update localization 2025-08-11 01:44:12 +08:00
LittleSheep
b2c5d64fc5 Keyboard navigation basis 2025-08-10 16:57:11 +08:00
LittleSheep
5371637b16 🔀 Merge pull request #161 from Texas0295/v3
🐛 linux: guard FirebaseMessaging on unsupported platforms
2025-08-10 14:05:48 +08:00
LittleSheep
c5cbf0af37 ⬆️ Upgrade android native project 2025-08-10 13:51:19 +08:00
LittleSheep
1a31e22450 🐛 Fix stickers pack unable to create 2025-08-10 13:23:15 +08:00
Texas0295
49db54529d 🐛 linux: guard FirebaseMessaging on unsupported platforms 2025-08-10 13:17:48 +08:00
LittleSheep
8e0c0c6054 🚀 Launch 3.1.0+122 2025-08-10 04:16:58 +08:00
LittleSheep
f3d1183076 🐛 Fix android update 2025-08-10 04:16:53 +08:00
LittleSheep
a9f7f0cce0 🐛 Fix bugs, ah bugs ha ha, bugs 2025-08-10 04:04:31 +08:00
LittleSheep
f2943f8411 🐛 Fix iOS notify delegate wrong path 2025-08-10 03:30:57 +08:00
23 changed files with 438 additions and 74 deletions

View File

@@ -51,6 +51,12 @@ android {
buildTypes {
release {
signingConfig = signingConfigs.getByName("release")
isMinifyEnabled = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
}
@@ -58,7 +64,7 @@ android {
dependencies {
implementation("com.google.android.material:material:1.12.0")
implementation("com.github.bumptech.glide:glide:4.16.0")
implementation("com.squareup.okhttp3:okhttp:4.12.0")
implementation("com.squareup.okhttp3:okhttp:5.1.0")
}
flutter {

5
android/app/proguard-rules.pro vendored Normal file
View File

@@ -0,0 +1,5 @@
# JNI Zero initialization (required for WebRTC native method registration)
-keep class livekit.org.jni_zero.JniInit {
# Keep the init method un-obfuscated for native code callback
private static java.lang.Object[] init();
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

View File

@@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-all.zip

View File

@@ -18,11 +18,11 @@ pluginManagement {
plugins {
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
id("com.android.application") version "8.10.1" apply false
id("com.android.application") version "8.12.0" apply false
// START: FlutterFire Configuration
id("com.google.gms.google-services") version("4.3.15") apply false
// END: FlutterFire Configuration
id("org.jetbrains.kotlin.android") version "1.8.22" apply false
id("org.jetbrains.kotlin.android") version("2.2.0") apply false
}
include(":app")

View File

@@ -789,5 +789,8 @@
"linkKey": "Link Name",
"linkValue": "URL",
"debugOptions": "Debug Options",
"joinedAt": "Joined at {}"
"joinedAt": "Joined at {}",
"searchAccounts": "Search accounts...",
"webFeeds": "Web Feeds",
"polls": "Polls"
}

View File

@@ -46,7 +46,7 @@
"delete": "删除",
"deletePublisher": "删除发布者",
"deletePublisherHint": "确定要删除此发布者吗?这也会删除此发布者下的所有帖子和收藏。",
"somethingWentWrong": "发生了一些错误",
"somethingWentWrong": "发生了一些错误……",
"deletePost": "删除帖子",
"deletePostHint": "确定要删除这篇帖子吗?",
"copyLink": "复制链接",
@@ -120,14 +120,9 @@
"other": "{}个附件"
},
"edited": "已编辑",
"editedAt": "编辑于 {}",
"addVideo": "添加视频",
"addPhoto": "添加照片",
"addFile": "添加文件",
"addAttachmentById": "通过 ID 添加附件",
"enterFileId": "输入文件 ID",
"fileIdCannotBeEmpty": "文件 ID 不能为空",
"failedToFetchFile": "获取文件失败: {}",
"createDirectMessage": "创建新私人消息",
"gotoDirectMessage": "前往私信",
"react": "反应",
@@ -350,7 +345,7 @@
"accountSettingsHelpContent": "此页面允许您管理您的帐户安全性、隐私和其他设置。如果您需要帮助,请联系管理员。",
"unauthorized": "未授权",
"unauthorizedHint": "您未登录或会话已过期,请重新登录。",
"publisherBelongsTo": "属于 {}",
"publisherBelongsTo": "属于",
"postContent": "内容",
"postSettings": "设置",
"postPublisherUnselected": "未指定发布者",
@@ -478,7 +473,7 @@
"description": "描述",
"pinCode": "PIN 码",
"biometric": "生物识别",
"enterPinToConfirm": "请输入您的 6 位数字 PIN 以确认付款",
"enterPinToConfirm": "请输入您的6位数字 PIN 以确认付款",
"clearPin": "清除 PIN 码",
"useBiometricToConfirm": "使用生物特征认证来确认付款",
"touchSensorToAuthenticate": "触摸传感器进行身份验证",
@@ -495,20 +490,29 @@
"paymentError": "付款失败: {error}",
"usePinInstead": "使用 PIN 码",
"levelProgress": "等级进度",
"unlockedFeatures": "已解锁的功能",
"unlockedFeaturesDescription": "在您当前级别上解锁的功能将显示在这里。",
"stellarMembership": "恒星计划",
"upgradeYourPlan": "升级您的计划",
"chooseYourPlan": "选择你的方案",
"currentMembership": "当前:{}",
"currentMembershipMember": "恒星计划「{}」级会员",
"membershipExpires": "过期于:{}",
"membershipTierStellar": "恒星",
"membershipTierNova": "新星",
"membershipTierSupernova": "超新星",
"membershipTierUnknown": "未知",
"membershipPriceStellar": "每月 1200 源点,至少需要 3 级",
"membershipPriceNova": "每月 2400 源点,至少需要 6 级",
"membershipPriceSupernova": "每月 3600 源点,至少需要 9 级",
"membershipPriceStellar": "每月 10 金点",
"membershipPriceNova": "每月 20 金点",
"membershipPriceSupernova": "每月 30 金点",
"membershipFeatureBasic": "基础功能",
"membershipFeaturePrioritySupport": "优先支持",
"membershipFeatureAdFree": "无广告",
"membershipFeatureAllPrimary": "所有主要功能",
"membershipFeatureAdvancedCustomization": "高级自定义",
"membershipFeatureEarlyAccess": "抢先体验",
"membershipFeatureAllNova": "所有「新星」功能",
"membershipFeatureExclusiveContent": "限定内容",
"membershipFeatureVipSupport": "VIP 支持",
"membershipCurrentBadge": "当前",
"restorePurchase": "恢复购买",
"restorePurchaseDescription": "输入您付款的提供商和订单 ID 以恢复您的购买。",
@@ -518,11 +522,167 @@
"enterOrderId": "输入您的订单 ID",
"restore": "恢复",
"keyboardShortcuts": "键盘快捷键",
"safetyReport": "举报",
"safetyReportTitle": "举报",
"safetyReportDescription": "通过举报不合适的内容和行为来维护我们社区的稳定。",
"safetyReportType": "举报类型",
"safetyReportReason": "更多证据",
"safetyReportReasonHint": "请提供更多证据……",
"safetyReportSubmit": "提交举报",
"safetyReportSubmitting": "提交中……",
"safetyReportSuccess": "举报成功,感谢您参与维护社区健康发展。",
"safetyReportError": "举报失败,请稍后重试。",
"safetyReportReasonRequired": "请提供举报证据",
"safetyReportTypeSpam": "垃圾或导向错误",
"safetyReportTypeHarassment": "骚扰或暴力行为",
"safetyReportTypeHateSpeech": "歧视言论",
"safetyReportTypeViolence": "威胁或暴力内容",
"safetyReportTypeAdultContent": "成人内容",
"safetyReportTypeIntellectualProperty": "抄袭",
"safetyReportTypeOther": "其它",
"safetyReportTypeInappropriate": "不良内容",
"safetyReportTypeCopyright": "版权侵害",
"safetyReportSuccessTitle": "举报成功",
"safetyReportErrorTitle": "错误",
"discover": "发现",
"joinRealm": "加入领域",
"removePublisherMember": "移除发布者",
"removePublisherMemberHint": "你确定要将这个成员从发布者中移除?",
"drafts": "草稿箱",
"noDrafts": "无草稿",
"articleDrafts": "文章草稿",
"postDrafts": "帖子草稿",
"saveDraft": "保存草稿",
"draftSaved": "草稿已保存",
"draftSaveFailed": "保存草稿失败",
"clearAllDrafts": "清除全部草稿",
"clearAllDraftsConfirm": "你确定要清除全部草稿?这一操作无法撤销。",
"clearAll": "清除所有",
"untitled": "未命名",
"noContent": "内容为空",
"justNow": "刚刚",
"minutesAgo": "{} 分钟以前",
"hoursAgo": "{} 小时以前",
"daysAgo": "{} 天以前",
"public": "公开的",
"unlisted": "不列出",
"friends": "朋友",
"selected": "选择的",
"private": "私密的",
"postContentEmpty": "发布的内容不能为空",
"share": "分享",
"sharePost": "分享帖子",
"quickActions": "快捷操作",
"post": "帖子",
"copy": "复制",
"sendToChat": "发送到聊天",
"failedToShareToPost": "分享到帖子失败:{}",
"shareToChatComingSoon": "分享到聊天的功能即将到来",
"failedToShareToChat": "分享到聊天失败:{}",
"shareToSpecificChatComingSoon": "分享到 {} 的功能即将到来",
"directChat": "私信",
"systemShareComingSoon": "系统分享功能即将到来",
"failedToShareToSystem": "分享到系统失败:{}",
"failedToCopy": "复制失败:{}",
"noChatRoomsAvailable": "没有聊天室可用",
"failedToLoadChats": "加载聊天室失败",
"contentToShare": "要分享的内容:",
"unknownChat": "未知聊天室",
"addAdditionalMessage": "添加额外消息……",
"uploadingFiles": "上传文件中……",
"sharedSuccessfully": "分享成功!",
"shareSuccess": "分享成功!",
"shareToSpecificChatSuccess": "分享到 {} 成功!",
"wouldYouLikeToGoToChat": "你想要前往聊天页面吗?",
"no": "是",
"yes": "否",
"navigateToChat": "前往聊天室",
"wouldYouLikeToNavigateToChat": "你想要前往聊天页面吗?",
"abuseReport": "举报",
"abuseReportTitle": "举报内容",
"abuseReportDescription": "通过举报不合适的内容和行为来帮助我们维护社区的健康稳定发展。",
"abuseReportType": "举报类型",
"abuseReportReason": "额外细节",
"abuseReportReasonHint": "请提供更多关于此的细节……",
"abuseReportSubmit": "提交举报",
"abuseReportSuccess": "举报提交成功,感谢你为社区维护作出贡献。",
"abuseReportError": "无法提交举报,请稍后再试。",
"abuseReportReasonRequired": "请提供关于此事件的细节",
"abuseReportSuccessTitle": "举报已提交",
"abuseReportErrorTitle": "错误",
"abuseReportTypeSpam": "垃圾或错误信息",
"abuseReportTypeHarassment": "骚扰或滥用",
"abuseReportTypeInappropriate": "不合适的内容",
"abuseReportTypeViolence": "暴力或人身威胁",
"abuseReportTypeCopyright": "版权侵犯",
"abuseReportTypeImpersonation": "冒充",
"abuseReportTypeOffensiveContent": "冒犯性内容",
"abuseReportTypePrivacyViolation": "隐私侵犯",
"abuseReportTypeIllegalContent": "违法内容",
"abuseReportTypeOther": "其他",
"tags": "标签",
"tagsHint": "输入标签,用英文逗号分隔",
"categories": "分类",
"categoriesHint": "输入分类,由逗号隔开",
"chatNotJoined": "你还没有加入这个聊天。",
"chatUnableJoin": "由于该聊天的访问设置使你无法加入。",
"chatJoin": "加入聊天",
"realmJoin": "加入领域",
"realmJoinSuccess": "成功加入领域。",
"discoverRealms": "发现领域",
"discoverPublishers": "发现发布者",
"search": "搜索",
"publisherMembers": "合作者",
"developerHub": "开发者中心",
"developerHubUnselectedHint": "选择一名开发者查看总结数据或成为一名。",
"enrollDeveloper": "成为一名开发者",
"enrollDeveloperHint": "让你的一个发布者成为开发者。",
"noPublishersToEnroll": "你没有可以成为开发者的发布者。",
"totalCustomApps": "所有应用套件",
"customApps": "应用套件",
"noCustomApps": "还没有应用套件。",
"createCustomApp": "创建应用套件",
"editCustomApp": "编辑应用套件",
"deleteCustomApp": "删除应用套件",
"deleteCustomAppHint": "你确定要删除这个应用套件吗?这一步无法撤销。",
"publicRealm": "公开领域",
"publicRealmDescription": "所有人都可以预览这个领域的内容。",
"communityRealm": "领域",
"communityRealmDescription": "所有人都可以加入该领域并参与讨论,并将在发现和反馈页面显示。",
"publicChat": "公开聊天",
"publicChatDescription": "任何人都可以预览此聊天的内容。包括未加入的机器人。",
"communityChat": "社区聊天",
"communityChatDescription": "所有人都可以加入该聊天并参与参与讨论。",
"appLinks": "应用链接",
"homePageUrl": "主页链接",
"privacyPolicyUrl": "隐私政策链接",
"termsOfServiceUrl": "用户协议链接",
"oauthConfig": "OAuth 配置",
"clientUri": "客户端 URI",
"redirectUris": "重定向 URIs",
"addRedirectUri": "添加重定向 URI",
"allowedScopes": "允许的范围",
"requirePkce": "需要 PKCE",
"allowOfflineAccess": "允许离线访问",
"redirectUri": "重定向 URI",
"redirectUriHint": "重定向 URI 用于 OAuth 认证,但您的项目状态转为线上时我们会验证请求中的重定向 URI 是否符合此配置。",
"uriRequired": "这个 URI 是必须填写的。",
"uriInvalid": "无效 URI。",
"add": "添加",
"addScope": "添加范围",
"scope": "范围",
"publisherFeatures": "功能",
"publisherFeatureDevelop": "开发者计划",
"publisherFeatureDevelopDescription": "为你的开发者解锁包括应用套件API 及更多开发功能。",
"publisherFeatureDevelopHint": "目前该功能还在开发中,你需要邀请才可解锁。",
"learnMore": "了解更多",
"discoverWebArticles": "来自站外的文章",
"webArticlesStand": "文章亭",
"about": "关于",
"membershipCancel": "取消会员订阅",
"membershipCancelConfirm": "确定要取消您的会员订阅",
"membershipCancelHint": "确定要取消您的会员订阅吗?将不会再被收费。的会员资格将在当前计费周期结束前保持有效。并且您在当前订阅结束之前无法重新订阅。",
"membershipCancelSuccess": "的会员订阅已成功取消。",
"membershipCancel": "取消会员资格",
"membershipCancelConfirm": "确定要取消会员资格吗",
"membershipCancelHint": "确定要取消会员资格吗?将不会再次被扣费。的会员资格将在当前计费周期结束前保持有效。并且你将无法重新订阅,直到当前订阅结束。",
"membershipCancelSuccess": "的会员资格已成功取消。",
"aboutScreenTitle": "关于",
"aboutScreenVersionInfo": "版本 {} ({})",
"aboutScreenAppInfoSectionTitle": "应用信息",
@@ -532,18 +692,103 @@
"aboutScreenLinksSectionTitle": "链接",
"aboutScreenPrivacyPolicyTitle": "隐私政策",
"aboutScreenTermsOfServiceTitle": "服务条款",
"aboutScreenOpenSourceLicensesTitle": "开源许可",
"aboutScreenOpenSourceLicensesTitle": "开源许可",
"aboutScreenDeveloperSectionTitle": "开发者",
"aboutScreenContactUsTitle": "联系我们",
"aboutScreenLicenseTitle": "许可",
"aboutScreenLicenseTitle": "许可",
"aboutScreenLicenseContent": "GNU Affero General Public License v3.0",
"aboutScreenCopyright": "版权所有 © 索尔辛茨 {}",
"aboutScreenMadeWith": "由 Solar Network Team 用 ❤︎️ 制作",
"aboutScreenFailedToLoadPackageInfo": "加载包信息失败{error}",
"aboutScreenCopyright": "版权所有 © Solsynth {}",
"aboutScreenMadeWith": "由 Solar Network 团队用 ❤︎️ 制作",
"aboutScreenFailedToLoadPackageInfo": "无法加载包信息:{error}",
"copiedToClipboard": "已复制到剪贴板",
"copyToClipboardTooltip": "复制到剪贴板",
"postForwardingTo": "转发",
"postReplyingTo": "回复",
"postEditing": "您正在编辑现有帖子",
"postArticle": "文章"
"postForwardingTo": "正在转发",
"postReplyingTo": "正在回复",
"postReplyPlaceholder": "发表你的回复",
"postEditing": "你正在编辑一个现有的帖子",
"postArticle": "文章",
"aboutDeviceName": "设备名称",
"aboutDeviceIdentifier": "设备标识符",
"donate": "捐赠",
"donateDescription": "支持我们继续开发 Solar Network并保持服务器运行。",
"fileId": "文件ID",
"fileIdHint": "文件ID是你通过 Solar Network Drive 上传文件后获得的ID。",
"translate": "翻译",
"translating": "正在翻译",
"translated": "已翻译",
"reactionThumbUp": "点赞",
"reactionThumbDown": "踩",
"reactionJustOkay": "还行",
"reactionCry": "哭",
"reactionConfuse": "困惑",
"reactionClap": "鼓掌",
"reactionLaugh": "笑",
"reactionAngry": "生气",
"reactionParty": "派对",
"reactionPray": "祈祷",
"reactionHeart": "心",
"selectMicrophone": "选择麦克风",
"selectCamera": "选择摄像头",
"switchedTo": "已切换到 {}",
"connecting": "正在连接",
"reconnecting": "正在重新连接",
"disconnected": "已断开连接",
"connected": "已连接",
"repliesLoadMore": "加载更多回复",
"attachmentsRecentUploads": "最近上传",
"attachmentsManualInput": "手动输入",
"crop": "裁剪",
"rename": "重命名",
"markAsSensitive": "标记为敏感",
"fileName": "文件名",
"sensitiveCategories.language": "语言",
"sensitiveCategories.sexualContent": "色情内容",
"sensitiveCategories.violence": "暴力",
"sensitiveCategories.profanity": "亵渎",
"sensitiveCategories.hateSpeech": "仇恨言论",
"sensitiveCategories.racism": "种族主义",
"sensitiveCategories.adultContent": "成人内容",
"sensitiveCategories.drugAbuse": "药物滥用",
"sensitiveCategories.alcoholAbuse": "酗酒",
"sensitiveCategories.gambling": "赌博",
"sensitiveCategories.selfHarm": "自残",
"sensitiveCategories.childAbuse": "虐待儿童",
"sensitiveCategories.other": "其他",
"poll": "投票",
"pollsRecent": "最近投票",
"pollCreateNew": "创建新投票",
"pollCreateNewHint": "为你的帖子创建一个新投票。选择一个发布者然后继续。",
"publisher": "发布者",
"publisherHint": "输入发布者名称",
"publisherCannotBeEmpty": "发布者不能为空",
"operationFailed": "操作失败:{}",
"stickerMarketplace": "贴纸市场",
"stickerPackAdded": "贴纸包已添加到你的收藏",
"stickerPackRemoved": "贴纸包已从你的收藏中移除",
"addPack": "添加贴纸包",
"removePack": "移除贴纸包",
"browseAndAddStickers": "浏览并添加贴纸包",
"stickerPack": "贴纸包",
"postCategoryTechnology": "科技",
"postCategoryTravel": "旅行",
"postCategoryFood": "美食",
"postCategoryHealth": "健康",
"postCategoryScience": "科学",
"postCategorySports": "体育",
"postCategoryFinance": "金融",
"postCategoryLife": "生活",
"postCategoryArt": "艺术",
"postCategoryStudy": "学习",
"postCategoryGaming": "游戏",
"postCategoryProgramming": "编程",
"postCategoryMusic": "音乐",
"links": "链接",
"addLink": "添加链接",
"linkKey": "链接名称",
"linkValue": "URL",
"debugOptions": "调试选项",
"joinedAt": "加入于 {}",
"searchAccounts": "搜索帐号……",
"webFeeds": "订阅源",
"polls": "投票"
}

View File

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

View File

@@ -28,6 +28,7 @@ import 'package:relative_time/relative_time.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:image_picker_platform_interface/image_picker_platform_interface.dart';
import 'package:flutter_native_splash/flutter_native_splash.dart';
import 'package:island/widgets/keyboard_navigation.dart';
import 'package:url_launcher/url_launcher_string.dart';
import 'package:flutter_langdetect/flutter_langdetect.dart' as langdetect;
@@ -244,7 +245,8 @@ class IslandApp extends HookConsumerWidget {
final router = ref.watch(routerProvider);
return MaterialApp.router(
return KeyboardNavigation(
child: MaterialApp.router(
theme: theme?.light,
darkTheme: theme?.dark,
themeMode: ThemeMode.system,
@@ -268,6 +270,7 @@ class IslandApp extends HookConsumerWidget {
],
);
},
),
);
}
}

View File

@@ -236,7 +236,7 @@ class AccountScreen extends HookConsumerWidget {
),
ListTile(
minTileHeight: 48,
title: Text('abuseReports').tr(),
title: Text('abuseReport').tr(),
contentPadding: const EdgeInsets.symmetric(horizontal: 24),
leading: const Icon(Symbols.gavel),
trailing: const Icon(Symbols.chevron_right),

View File

@@ -216,6 +216,7 @@ class RelationshipScreen extends HookConsumerWidget {
final result = await showModalBottomSheet(
context: context,
useRootNavigator: true,
isScrollControlled: true,
builder: (context) => AccountPickerSheet(),
);
if (result == null) return;

View File

@@ -227,6 +227,7 @@ class ChatListScreen extends HookConsumerWidget {
final result = await showModalBottomSheet(
context: context,
useRootNavigator: true,
isScrollControlled: true,
builder: (context) => const AccountPickerSheet(),
);
if (result == null) return;

View File

@@ -339,7 +339,7 @@ class ChatRoomScreen extends HookConsumerWidget {
}
await apiClient.post(
'/chat/${chatRoom.value!.id}/members/me',
'/sphere/chat/${chatRoom.value!.id}/members/me',
);
ref.invalidate(chatroomIdentityProvider(id));
} catch (err) {
@@ -929,7 +929,7 @@ class ChatRoomScreen extends HookConsumerWidget {
if (attachment.isOnCloud) {
final client = ref.watch(apiClientProvider);
await client.delete(
'/files/${attachment.data.id}',
'/drive/files/${attachment.data.id}',
);
}
final clone = List.of(attachments.value);

View File

@@ -589,6 +589,7 @@ class _ChatMemberListSheet extends HookConsumerWidget {
final result = await showModalBottomSheet(
context: context,
useRootNavigator: true,
isScrollControlled: true,
builder: (context) => const AccountPickerSheet(),
);
if (result == null) return;
@@ -727,7 +728,7 @@ class _ChatMemberListSheet extends HookConsumerWidget {
apiClientProvider,
);
await apiClient.delete(
'/chat/$roomId/members/${member.accountId}',
'/sphere/chat/$roomId/members/${member.accountId}',
);
// Refresh both providers
memberNotifier.reset();

View File

@@ -382,7 +382,7 @@ class CreatorHubScreen extends HookConsumerWidget {
),
ListTile(
minTileHeight: 48,
title: const Text('Polls'),
title: Text('polls').tr(),
trailing: const Icon(Symbols.chevron_right),
leading: const Icon(Symbols.poll),
contentPadding: const EdgeInsets.symmetric(
@@ -419,7 +419,7 @@ class CreatorHubScreen extends HookConsumerWidget {
),
ListTile(
minTileHeight: 48,
title: const Text('Web Feeds').tr(),
title: const Text('webFeeds').tr(),
trailing: const Icon(Symbols.chevron_right),
leading: const Icon(Symbols.rss_feed),
contentPadding: const EdgeInsets.symmetric(
@@ -659,7 +659,7 @@ class PublisherMemberNotifier extends StateNotifier<PublisherMemberState> {
try {
final response = await _apiClient.get(
'/publishers/$publisherUname/members',
'/sphere/publishers/$publisherUname/members',
queryParameters: {'offset': offset, 'take': take},
);
@@ -708,6 +708,7 @@ class _PublisherMemberListSheet extends HookConsumerWidget {
Future<void> invitePerson() async {
final result = await showModalBottomSheet(
useRootNavigator: true,
isScrollControlled: true,
context: context,
builder: (context) => const AccountPickerSheet(),
@@ -719,6 +720,9 @@ class _PublisherMemberListSheet extends HookConsumerWidget {
'/publishers/$publisherUname/invites',
data: {'related_user_id': result.id, 'role': 0},
);
// Refresh both providers
memberNotifier.reset();
await memberNotifier.loadMore();
ref.invalidate(memberListProvider);
} catch (err) {
showErrorAlert(err);
@@ -822,6 +826,9 @@ class _PublisherMemberListSheet extends HookConsumerWidget {
),
).then((value) {
if (value != null) {
// Refresh both providers
memberNotifier.reset();
memberNotifier.loadMore();
ref.invalidate(memberListProvider);
}
});
@@ -843,6 +850,9 @@ class _PublisherMemberListSheet extends HookConsumerWidget {
await apiClient.delete(
'/publishers/$publisherUname/members/${member.accountId}',
);
// Refresh both providers
memberNotifier.reset();
memberNotifier.loadMore();
ref.invalidate(memberListProvider);
} catch (err) {
showErrorAlert(err);

View File

@@ -180,6 +180,7 @@ class StickerPackDetailScreen extends HookConsumerWidget {
.pushNamed(
'creatorStickerEdit',
pathParameters: {
'name': pubName,
'packId': id,
'id': sticker.id,
},

View File

@@ -31,7 +31,7 @@ class StickersScreen extends HookConsumerWidget {
context
.pushNamed(
'creatorStickerPackNew',
queryParameters: {'name': pubName},
pathParameters: {'name': pubName},
)
.then((value) {
if (value != null) {
@@ -187,10 +187,8 @@ class EditStickerPacksScreen extends HookConsumerWidget {
'description': descriptionController.text,
'prefix': prefixController.text,
},
options: Options(
method: packId == null ? 'POST' : 'PATCH',
headers: {'X-Pub': pubName},
),
queryParameters: {'pub': pubName},
options: Options(method: packId == null ? 'POST' : 'PATCH'),
);
if (!context.mounted) return;
context.pop(SnStickerPack.fromJson(resp.data));

View File

@@ -488,6 +488,7 @@ class _RealmMemberListSheet extends HookConsumerWidget {
Future<void> invitePerson() async {
final result = await showModalBottomSheet(
isScrollControlled: true,
useRootNavigator: true,
context: context,
builder: (context) => const AccountPickerSheet(),
);

View File

@@ -67,6 +67,9 @@ Future<void> subscribePushNotification(
Dio apiClient, {
bool detailedErrors = false,
}) async {
if (Platform.isLinux){
return;
}
await FirebaseMessaging.instance.requestPermission(
alert: true,
badge: true,

View File

@@ -305,7 +305,7 @@ class _UpdateSheetState extends State<_UpdateSheet> {
UpdateModel model = UpdateModel(
downloadUrl,
"solian-update-${widget.release.tagName}.apk",
"ic_launcher",
"launcher_icon",
'https://apps.apple.com/us/app/solian/id6499032345',
);
AzhonAppUpdate.update(model);

View File

@@ -1,5 +1,6 @@
import 'dart:async';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
@@ -44,9 +45,8 @@ class AccountPickerSheet extends HookConsumerWidget {
}
return Container(
constraints: BoxConstraints(
maxHeight: MediaQuery.of(context).size.height * 0.4,
),
padding: MediaQuery.of(context).viewInsets,
height: MediaQuery.of(context).size.height * 0.6,
child: Column(
children: [
Padding(
@@ -54,8 +54,8 @@ class AccountPickerSheet extends HookConsumerWidget {
child: TextField(
controller: searchController,
onChanged: onSearchChanged,
decoration: const InputDecoration(
hintText: 'Search accounts...',
decoration: InputDecoration(
hintText: 'searchAccounts'.tr(),
contentPadding: EdgeInsets.symmetric(
horizontal: 18,
vertical: 16,

View File

@@ -0,0 +1,86 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
enum VimMode { normal, insert }
class KeyboardNavigation extends StatefulWidget {
const KeyboardNavigation({super.key, required this.child});
final Widget child;
@override
State<KeyboardNavigation> createState() => _KeyboardNavigationState();
}
class _KeyboardNavigationState extends State<KeyboardNavigation> {
VimMode _mode = VimMode.normal;
final FocusScopeNode _focusScopeNode = FocusScopeNode();
@override
void dispose() {
_focusScopeNode.dispose();
super.dispose();
}
KeyEventResult _handleKeyEvent(FocusNode node, KeyEvent event) {
if (event is! KeyDownEvent && event is! KeyRepeatEvent) {
return KeyEventResult.ignored;
}
if (_mode == VimMode.normal) {
if (event.logicalKey == LogicalKeyboardKey.keyJ) {
node.focusInDirection(TraversalDirection.down);
return KeyEventResult.handled;
} else if (event.logicalKey == LogicalKeyboardKey.keyK) {
node.focusInDirection(TraversalDirection.up);
return KeyEventResult.handled;
} else if (event.logicalKey == LogicalKeyboardKey.keyH) {
final focusNode = FocusManager.instance.primaryFocus;
if (focusNode != null) {
final scrollable = Scrollable.of(focusNode.context!);
if (scrollable.position.axis == Axis.horizontal) {
scrollable.position.moveTo(scrollable.position.pixels - 50);
return KeyEventResult.handled;
}
}
node.focusInDirection(TraversalDirection.left);
return KeyEventResult.handled;
} else if (event.logicalKey == LogicalKeyboardKey.keyL) {
final focusNode = FocusManager.instance.primaryFocus;
if (focusNode != null) {
final scrollable = Scrollable.of(focusNode.context!);
if (scrollable.position.axis == Axis.horizontal) {
scrollable.position.moveTo(scrollable.position.pixels + 50);
return KeyEventResult.handled;
}
}
node.focusInDirection(TraversalDirection.right);
return KeyEventResult.handled;
} else if (event.logicalKey == LogicalKeyboardKey.keyI) {
setState(() {
_mode = VimMode.insert;
});
return KeyEventResult.handled;
}
} else if (_mode == VimMode.insert) {
if (event.logicalKey == LogicalKeyboardKey.escape) {
setState(() {
_mode = VimMode.normal;
});
// Unfocus the current widget to prevent typing
node.unfocus();
return KeyEventResult.handled;
}
}
return KeyEventResult.ignored;
}
@override
Widget build(BuildContext context) {
return Focus(
focusNode: _focusScopeNode,
onKeyEvent: _handleKeyEvent,
child: widget.child,
);
}
}

View File

@@ -16,7 +16,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# 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.
version: 3.1.0+121
version: 3.1.0+123
environment:
sdk: ^3.7.2