Compare commits
7 Commits
Author | SHA1 | Date | |
---|---|---|---|
efcfd3f57d | |||
84759715a4 | |||
fda09382dd | |||
2c5dd0563a | |||
5bdd8e94fa | |||
2a53031c9a | |||
e8bc7261f3 |
@ -718,5 +718,8 @@
|
|||||||
"stickersNew": "New Sticker",
|
"stickersNew": "New Sticker",
|
||||||
"stickersNewDescription": "Create a new sticker belongs to this pack.",
|
"stickersNewDescription": "Create a new sticker belongs to this pack.",
|
||||||
"stickersPackNew": "New Sticker Pack",
|
"stickersPackNew": "New Sticker Pack",
|
||||||
"trayMenuShow": "Show"
|
"trayMenuShow": "Show",
|
||||||
|
"update": "Update",
|
||||||
|
"forceUpdate": "Force Update",
|
||||||
|
"forceUpdateDescription": "Force to show the application update popup, even the new version is not available."
|
||||||
}
|
}
|
||||||
|
@ -716,5 +716,8 @@
|
|||||||
"stickersNew": "新建贴图",
|
"stickersNew": "新建贴图",
|
||||||
"stickersNewDescription": "创建一个新的贴图。",
|
"stickersNewDescription": "创建一个新的贴图。",
|
||||||
"stickersPackNew": "新建贴图包",
|
"stickersPackNew": "新建贴图包",
|
||||||
"trayMenuShow": "显示"
|
"trayMenuShow": "显示",
|
||||||
|
"update": "更新",
|
||||||
|
"forceUpdate": "强制更新",
|
||||||
|
"forceUpdateDescription": "强制更新应用程序,即使有更新的版本可能不可用。"
|
||||||
}
|
}
|
||||||
|
@ -715,5 +715,9 @@
|
|||||||
"fieldStickerAttachment": "附件",
|
"fieldStickerAttachment": "附件",
|
||||||
"stickersNew": "新建貼圖",
|
"stickersNew": "新建貼圖",
|
||||||
"stickersNewDescription": "創建一個新的貼圖。",
|
"stickersNewDescription": "創建一個新的貼圖。",
|
||||||
"stickersPackNew": "新建貼圖包"
|
"stickersPackNew": "新建貼圖包",
|
||||||
|
"trayMenuShow": "顯示",
|
||||||
|
"update": "更新",
|
||||||
|
"forceUpdate": "強制更新",
|
||||||
|
"forceUpdateDescription": "強制更新應用程序,即使有更新的版本可能不可用。"
|
||||||
}
|
}
|
||||||
|
@ -715,5 +715,9 @@
|
|||||||
"fieldStickerAttachment": "附件",
|
"fieldStickerAttachment": "附件",
|
||||||
"stickersNew": "新建貼圖",
|
"stickersNew": "新建貼圖",
|
||||||
"stickersNewDescription": "創建一個新的貼圖。",
|
"stickersNewDescription": "創建一個新的貼圖。",
|
||||||
"stickersPackNew": "新建貼圖包"
|
"stickersPackNew": "新建貼圖包",
|
||||||
|
"trayMenuShow": "顯示",
|
||||||
|
"update": "更新",
|
||||||
|
"forceUpdate": "強制更新",
|
||||||
|
"forceUpdateDescription": "強制更新應用程序,即使有更新的版本可能不可用。"
|
||||||
}
|
}
|
||||||
|
@ -179,7 +179,7 @@ PODS:
|
|||||||
- in_app_review (2.0.0):
|
- in_app_review (2.0.0):
|
||||||
- Flutter
|
- Flutter
|
||||||
- Kingfisher (8.2.0)
|
- Kingfisher (8.2.0)
|
||||||
- livekit_client (2.3.6):
|
- livekit_client (2.4.0):
|
||||||
- Flutter
|
- Flutter
|
||||||
- flutter_webrtc
|
- flutter_webrtc
|
||||||
- WebRTC-SDK (= 125.6422.06)
|
- WebRTC-SDK (= 125.6422.06)
|
||||||
@ -426,7 +426,7 @@ SPEC CHECKSUMS:
|
|||||||
image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1
|
image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1
|
||||||
in_app_review: a31b5257259646ea78e0e35fc914979b0031d011
|
in_app_review: a31b5257259646ea78e0e35fc914979b0031d011
|
||||||
Kingfisher: 323e5c4ec7983aaace12af655a7b51a7f88a599d
|
Kingfisher: 323e5c4ec7983aaace12af655a7b51a7f88a599d
|
||||||
livekit_client: 148b2cf67a09aaf475ba8e5bf1667fe10dc35f81
|
livekit_client: 9819ebc8be8ef00ed0fae7d806bf8938ec689573
|
||||||
media_kit_libs_ios_video: a5fe24bc7875ccd6378a0978c13185e1344651c1
|
media_kit_libs_ios_video: a5fe24bc7875ccd6378a0978c13185e1344651c1
|
||||||
media_kit_native_event_loop: e6b2ab20cf0746eb1c33be961fcf79667304fa2a
|
media_kit_native_event_loop: e6b2ab20cf0746eb1c33be961fcf79667304fa2a
|
||||||
media_kit_video: 5da63f157170e5bf303bf85453b7ef6971218a2e
|
media_kit_video: 5da63f157170e5bf303bf85453b7ef6971218a2e
|
||||||
|
@ -322,6 +322,7 @@ class ChatMessageController extends ChangeNotifier {
|
|||||||
notifyListeners();
|
notifyListeners();
|
||||||
|
|
||||||
final mostRecentMessage = await (_dt.db.snLocalChatMessage.select()
|
final mostRecentMessage = await (_dt.db.snLocalChatMessage.select()
|
||||||
|
..where((e) => e.channelId.equals(channel!.id))
|
||||||
..limit(1)
|
..limit(1)
|
||||||
..orderBy([
|
..orderBy([
|
||||||
(e) =>
|
(e) =>
|
||||||
|
@ -254,10 +254,9 @@ class _AppSplashScreenState extends State<_AppSplashScreen> with TrayListener {
|
|||||||
receiveTimeout: const Duration(seconds: 60),
|
receiveTimeout: const Duration(seconds: 60),
|
||||||
),
|
),
|
||||||
).get(
|
).get(
|
||||||
'https://git.solsynth.dev/api/v1/repos/HyperNet/Surface/tags?page=1&limit=1',
|
'https://api.github.com/repos/Solsynth/HyperNet.Surface/releases/latest',
|
||||||
);
|
);
|
||||||
final remoteVersionString =
|
final remoteVersionString = resp.data?['tag_name'] ?? '0.0.0+0';
|
||||||
(resp.data as List).firstOrNull?['name'] ?? '0.0.0+0';
|
|
||||||
final remoteVersion = Version.parse(remoteVersionString.split('+').first);
|
final remoteVersion = Version.parse(remoteVersionString.split('+').first);
|
||||||
final localVersion = Version.parse(localVersionString.split('+').first);
|
final localVersion = Version.parse(localVersionString.split('+').first);
|
||||||
final remoteBuildNumber =
|
final remoteBuildNumber =
|
||||||
@ -269,10 +268,12 @@ class _AppSplashScreenState extends State<_AppSplashScreen> with TrayListener {
|
|||||||
remoteBuildNumber > localBuildNumber) &&
|
remoteBuildNumber > localBuildNumber) &&
|
||||||
mounted) {
|
mounted) {
|
||||||
final config = context.read<ConfigProvider>();
|
final config = context.read<ConfigProvider>();
|
||||||
config.setUpdate(remoteVersionString);
|
config.setUpdate(
|
||||||
|
remoteVersionString, resp.data?['body'] ?? 'No changelog');
|
||||||
log("[Update] Update available: $remoteVersionString");
|
log("[Update] Update available: $remoteVersionString");
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
log('[Error] Unable to check update: $e');
|
||||||
if (mounted) context.showErrorDialog('Unable to check update: $e');
|
if (mounted) context.showErrorDialog('Unable to check update: $e');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,7 +65,11 @@ class ChatChannelProvider extends ChangeNotifier {
|
|||||||
.getSingleOrNull();
|
.getSingleOrNull();
|
||||||
if (local != null) {
|
if (local != null) {
|
||||||
final out = local.content;
|
final out = local.content;
|
||||||
return out.copyWith(realm: await _rels.getRealm(out.realmId!));
|
if (out.realmId != null) {
|
||||||
|
return out.copyWith(realm: await _rels.getRealm(out.realmId!));
|
||||||
|
} else {
|
||||||
|
return out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var resp =
|
var resp =
|
||||||
|
@ -58,7 +58,8 @@ class ConfigProvider extends ChangeNotifier {
|
|||||||
: false;
|
: false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newDrawerIsExpanded != drawerIsExpanded || newDrawerIsCollapsed != drawerIsCollapsed) {
|
if (newDrawerIsExpanded != drawerIsExpanded ||
|
||||||
|
newDrawerIsCollapsed != drawerIsCollapsed) {
|
||||||
drawerIsExpanded = newDrawerIsExpanded;
|
drawerIsExpanded = newDrawerIsExpanded;
|
||||||
drawerIsCollapsed = newDrawerIsCollapsed;
|
drawerIsCollapsed = newDrawerIsCollapsed;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
@ -66,7 +67,9 @@ class ConfigProvider extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FilterQuality get imageQuality {
|
FilterQuality get imageQuality {
|
||||||
return kImageQualityLevel.values.elementAtOrNull(prefs.getInt('app_image_quality') ?? 3) ?? FilterQuality.high;
|
return kImageQualityLevel.values
|
||||||
|
.elementAtOrNull(prefs.getInt('app_image_quality') ?? 3) ??
|
||||||
|
FilterQuality.high;
|
||||||
}
|
}
|
||||||
|
|
||||||
String get serverUrl {
|
String get serverUrl {
|
||||||
@ -76,6 +79,7 @@ class ConfigProvider extends ChangeNotifier {
|
|||||||
bool get realmCompactView {
|
bool get realmCompactView {
|
||||||
return prefs.getBool(kAppRealmCompactView) ?? false;
|
return prefs.getBool(kAppRealmCompactView) ?? false;
|
||||||
}
|
}
|
||||||
|
|
||||||
set realmCompactView(bool value) {
|
set realmCompactView(bool value) {
|
||||||
prefs.setBool(kAppRealmCompactView, value);
|
prefs.setBool(kAppRealmCompactView, value);
|
||||||
}
|
}
|
||||||
@ -86,9 +90,11 @@ class ConfigProvider extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String? updatableVersion;
|
String? updatableVersion;
|
||||||
|
String? updatableChangelog;
|
||||||
|
|
||||||
void setUpdate(String newVersion) {
|
void setUpdate(String newVersion, String newChangelog) {
|
||||||
updatableVersion = newVersion;
|
updatableVersion = newVersion;
|
||||||
|
updatableChangelog = newChangelog;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -78,10 +78,23 @@ class NotificationProvider extends ChangeNotifier {
|
|||||||
int showingTrayCount = 0;
|
int showingTrayCount = 0;
|
||||||
List<SnNotification> notifications = List.empty(growable: true);
|
List<SnNotification> notifications = List.empty(growable: true);
|
||||||
|
|
||||||
|
int? skippableNotifyChannel;
|
||||||
|
|
||||||
void listen() {
|
void listen() {
|
||||||
_ws.pk.stream.listen((event) {
|
_ws.pk.stream.listen((event) {
|
||||||
if (event.method == 'notifications.new') {
|
if (event.method == 'notifications.new') {
|
||||||
final notification = SnNotification.fromJson(event.payload!);
|
final notification = SnNotification.fromJson(event.payload!);
|
||||||
|
|
||||||
|
final doHaptic = _cfg.prefs.getBool(kAppNotifyWithHaptic) ?? true;
|
||||||
|
if (doHaptic) HapticFeedback.mediumImpact();
|
||||||
|
|
||||||
|
if (notification.topic == 'messaging.message') {
|
||||||
|
if (notification.metadata['channel_id'] != null &&
|
||||||
|
notification.metadata['channel_id'] == skippableNotifyChannel) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (showingCount < 0) showingCount = 0;
|
if (showingCount < 0) showingCount = 0;
|
||||||
showingCount++;
|
showingCount++;
|
||||||
showingTrayCount++;
|
showingTrayCount++;
|
||||||
@ -92,8 +105,6 @@ class NotificationProvider extends ChangeNotifier {
|
|||||||
});
|
});
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
updateTray();
|
updateTray();
|
||||||
final doHaptic = _cfg.prefs.getBool(kAppNotifyWithHaptic) ?? true;
|
|
||||||
if (doHaptic) HapticFeedback.mediumImpact();
|
|
||||||
|
|
||||||
if (!kIsWeb) {
|
if (!kIsWeb) {
|
||||||
if (Platform.isWindows || Platform.isLinux || Platform.isMacOS) {
|
if (Platform.isWindows || Platform.isLinux || Platform.isMacOS) {
|
||||||
|
@ -258,7 +258,8 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||||||
channel.name),
|
channel.name),
|
||||||
),
|
),
|
||||||
const Gap(8),
|
const Gap(8),
|
||||||
if (_unreadCounts?[channel.id] != null)
|
if (_unreadCounts?[channel.id] != null &&
|
||||||
|
_unreadCounts![channel.id]! > 0)
|
||||||
Badge(
|
Badge(
|
||||||
label: Text('${_unreadCounts![channel.id]}'),
|
label: Text('${_unreadCounts![channel.id]}'),
|
||||||
),
|
),
|
||||||
@ -294,7 +295,11 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||||||
'alias': channel.alias,
|
'alias': channel.alias,
|
||||||
},
|
},
|
||||||
).then((value) {
|
).then((value) {
|
||||||
if (mounted) _refreshChannels(noRemote: true);
|
if (mounted) {
|
||||||
|
_unreadCounts?[channel.id] = 0;
|
||||||
|
setState(() => _unreadCounts?[channel.id] = 0);
|
||||||
|
_refreshChannels(noRemote: true);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -305,7 +310,8 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||||||
children: [
|
children: [
|
||||||
Expanded(child: Text(channel.name)),
|
Expanded(child: Text(channel.name)),
|
||||||
const Gap(8),
|
const Gap(8),
|
||||||
if (_unreadCounts?[channel.id] != null)
|
if (_unreadCounts?[channel.id] != null &&
|
||||||
|
_unreadCounts![channel.id]! > 0)
|
||||||
Badge(
|
Badge(
|
||||||
label: Text('${_unreadCounts![channel.id]}'),
|
label: Text('${_unreadCounts![channel.id]}'),
|
||||||
),
|
),
|
||||||
@ -330,6 +336,7 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (doExpand) {
|
if (doExpand) {
|
||||||
|
_unreadCounts?[channel.id] = 0;
|
||||||
setState(() => _focusChannel = channel);
|
setState(() => _focusChannel = channel);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -340,7 +347,10 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||||||
'alias': channel.alias,
|
'alias': channel.alias,
|
||||||
},
|
},
|
||||||
).then((value) {
|
).then((value) {
|
||||||
if (value == true) _refreshChannels(noRemote: true);
|
if (mounted) {
|
||||||
|
setState(() => _unreadCounts?[channel.id] = 0);
|
||||||
|
_refreshChannels(noRemote: true);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -58,7 +58,8 @@ class _ChannelDetailScreenState extends State<ChannelDetailScreen> {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
final sn = context.read<SnNetworkProvider>();
|
final sn = context.read<SnNetworkProvider>();
|
||||||
final resp = await sn.client.get('/cgi/im/channels/${_channel!.keyPath}/members/me');
|
final resp =
|
||||||
|
await sn.client.get('/cgi/im/channels/${_channel!.keyPath}/me');
|
||||||
_profile = SnChannelMember.fromJson(resp.data);
|
_profile = SnChannelMember.fromJson(resp.data);
|
||||||
_notifyLevel = _profile!.notify;
|
_notifyLevel = _profile!.notify;
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
@ -245,7 +246,11 @@ class _ChannelDetailScreenState extends State<ChannelDetailScreen> {
|
|||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text('channelDetailPersonalRegion').bold().fontSize(17).tr().padding(horizontal: 20, bottom: 4),
|
Text('channelDetailPersonalRegion')
|
||||||
|
.bold()
|
||||||
|
.fontSize(17)
|
||||||
|
.tr()
|
||||||
|
.padding(horizontal: 20, bottom: 4),
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: const Icon(Symbols.notifications),
|
leading: const Icon(Symbols.notifications),
|
||||||
trailing: DropdownButtonHideUnderline(
|
trailing: DropdownButtonHideUnderline(
|
||||||
@ -284,7 +289,8 @@ class _ChannelDetailScreenState extends State<ChannelDetailScreen> {
|
|||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: AccountImage(
|
leading: AccountImage(
|
||||||
content: ud.getAccountFromCache(_profile!.accountId)?.avatar,
|
content:
|
||||||
|
ud.getAccountFromCache(_profile!.accountId)?.avatar,
|
||||||
radius: 18,
|
radius: 18,
|
||||||
),
|
),
|
||||||
trailing: const Icon(Symbols.chevron_right),
|
trailing: const Icon(Symbols.chevron_right),
|
||||||
@ -303,7 +309,8 @@ class _ChannelDetailScreenState extends State<ChannelDetailScreen> {
|
|||||||
trailing: const Icon(Symbols.chevron_right),
|
trailing: const Icon(Symbols.chevron_right),
|
||||||
title: Text('channelActionLeave').tr(),
|
title: Text('channelActionLeave').tr(),
|
||||||
subtitle: Text('channelActionLeaveDescription').tr(),
|
subtitle: Text('channelActionLeaveDescription').tr(),
|
||||||
contentPadding: const EdgeInsets.symmetric(horizontal: 24),
|
contentPadding:
|
||||||
|
const EdgeInsets.symmetric(horizontal: 24),
|
||||||
onTap: _leaveChannel,
|
onTap: _leaveChannel,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -311,7 +318,11 @@ class _ChannelDetailScreenState extends State<ChannelDetailScreen> {
|
|||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text('channelDetailMemberRegion').bold().fontSize(17).tr().padding(horizontal: 20, bottom: 4),
|
Text('channelDetailMemberRegion')
|
||||||
|
.bold()
|
||||||
|
.fontSize(17)
|
||||||
|
.tr()
|
||||||
|
.padding(horizontal: 20, bottom: 4),
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: const Icon(Symbols.group),
|
leading: const Icon(Symbols.group),
|
||||||
trailing: const Icon(Symbols.chevron_right),
|
trailing: const Icon(Symbols.chevron_right),
|
||||||
@ -333,7 +344,11 @@ class _ChannelDetailScreenState extends State<ChannelDetailScreen> {
|
|||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text('channelDetailAdminRegion').bold().fontSize(17).tr().padding(horizontal: 20, bottom: 4),
|
Text('channelDetailAdminRegion')
|
||||||
|
.bold()
|
||||||
|
.fontSize(17)
|
||||||
|
.tr()
|
||||||
|
.padding(horizontal: 20, bottom: 4),
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: const Icon(Symbols.edit),
|
leading: const Icon(Symbols.edit),
|
||||||
trailing: const Icon(Symbols.chevron_right),
|
trailing: const Icon(Symbols.chevron_right),
|
||||||
@ -379,10 +394,12 @@ class _ChannelProfileDetailDialog extends StatefulWidget {
|
|||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<_ChannelProfileDetailDialog> createState() => _ChannelProfileDetailDialogState();
|
State<_ChannelProfileDetailDialog> createState() =>
|
||||||
|
_ChannelProfileDetailDialogState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ChannelProfileDetailDialogState extends State<_ChannelProfileDetailDialog> {
|
class _ChannelProfileDetailDialogState
|
||||||
|
extends State<_ChannelProfileDetailDialog> {
|
||||||
bool _isBusy = false;
|
bool _isBusy = false;
|
||||||
|
|
||||||
final TextEditingController _nickController = TextEditingController();
|
final TextEditingController _nickController = TextEditingController();
|
||||||
@ -457,7 +474,8 @@ class _ChannelMemberListWidget extends StatefulWidget {
|
|||||||
const _ChannelMemberListWidget({required this.channel});
|
const _ChannelMemberListWidget({required this.channel});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<_ChannelMemberListWidget> createState() => _ChannelMemberListWidgetState();
|
State<_ChannelMemberListWidget> createState() =>
|
||||||
|
_ChannelMemberListWidgetState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ChannelMemberListWidgetState extends State<_ChannelMemberListWidget> {
|
class _ChannelMemberListWidgetState extends State<_ChannelMemberListWidget> {
|
||||||
@ -472,10 +490,12 @@ class _ChannelMemberListWidgetState extends State<_ChannelMemberListWidget> {
|
|||||||
try {
|
try {
|
||||||
final ud = context.read<UserDirectoryProvider>();
|
final ud = context.read<UserDirectoryProvider>();
|
||||||
final sn = context.read<SnNetworkProvider>();
|
final sn = context.read<SnNetworkProvider>();
|
||||||
final resp = await sn.client.get('/cgi/im/channels/${widget.channel.keyPath}/members', queryParameters: {
|
final resp = await sn.client.get(
|
||||||
'take': 10,
|
'/cgi/im/channels/${widget.channel.keyPath}/members',
|
||||||
'offset': _members.length,
|
queryParameters: {
|
||||||
});
|
'take': 10,
|
||||||
|
'offset': _members.length,
|
||||||
|
});
|
||||||
final out = List<SnChannelMember>.from(
|
final out = List<SnChannelMember>.from(
|
||||||
resp.data['data']?.map((e) => SnChannelMember.fromJson(e)) ?? [],
|
resp.data['data']?.map((e) => SnChannelMember.fromJson(e)) ?? [],
|
||||||
);
|
);
|
||||||
@ -533,7 +553,9 @@ class _ChannelMemberListWidgetState extends State<_ChannelMemberListWidget> {
|
|||||||
children: [
|
children: [
|
||||||
const Icon(Symbols.group, size: 24),
|
const Icon(Symbols.group, size: 24),
|
||||||
const Gap(16),
|
const Gap(16),
|
||||||
Text('channelMemberManage').tr().textStyle(Theme.of(context).textTheme.titleLarge!),
|
Text('channelMemberManage')
|
||||||
|
.tr()
|
||||||
|
.textStyle(Theme.of(context).textTheme.titleLarge!),
|
||||||
],
|
],
|
||||||
).padding(horizontal: 20, top: 16, bottom: 12),
|
).padding(horizontal: 20, top: 16, bottom: 12),
|
||||||
Expanded(
|
Expanded(
|
||||||
@ -544,7 +566,8 @@ class _ChannelMemberListWidgetState extends State<_ChannelMemberListWidget> {
|
|||||||
},
|
},
|
||||||
child: InfiniteList(
|
child: InfiniteList(
|
||||||
itemCount: _members.length,
|
itemCount: _members.length,
|
||||||
hasReachedMax: _totalCount != null && _members.length >= _totalCount!,
|
hasReachedMax:
|
||||||
|
_totalCount != null && _members.length >= _totalCount!,
|
||||||
isLoading: _isBusy,
|
isLoading: _isBusy,
|
||||||
onFetchData: _fetchMembers,
|
onFetchData: _fetchMembers,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
@ -555,7 +578,8 @@ class _ChannelMemberListWidgetState extends State<_ChannelMemberListWidget> {
|
|||||||
content: ud.getAccountFromCache(member.accountId)?.avatar,
|
content: ud.getAccountFromCache(member.accountId)?.avatar,
|
||||||
),
|
),
|
||||||
title: Text(
|
title: Text(
|
||||||
ud.getAccountFromCache(member.accountId)?.name ?? 'unknown'.tr(),
|
ud.getAccountFromCache(member.accountId)?.name ??
|
||||||
|
'unknown'.tr(),
|
||||||
),
|
),
|
||||||
subtitle: Text(member.nick ?? 'unknown'.tr()),
|
subtitle: Text(member.nick ?? 'unknown'.tr()),
|
||||||
trailing: SizedBox(
|
trailing: SizedBox(
|
||||||
@ -565,7 +589,8 @@ class _ChannelMemberListWidgetState extends State<_ChannelMemberListWidget> {
|
|||||||
mainAxisAlignment: MainAxisAlignment.end,
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
children: [
|
children: [
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: _isUpdating ? null : () => _deleteMember(member),
|
onPressed:
|
||||||
|
_isUpdating ? null : () => _deleteMember(member),
|
||||||
icon: const Icon(Symbols.person_remove),
|
icon: const Icon(Symbols.person_remove),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
import 'dart:io';
|
|
||||||
import 'dart:math' as math;
|
import 'dart:math' as math;
|
||||||
import 'dart:ui';
|
import 'dart:ui';
|
||||||
|
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter_app_update/flutter_app_update.dart';
|
|
||||||
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
|
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.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';
|
||||||
@ -29,6 +27,7 @@ import 'package:surface/widgets/app_bar_leading.dart';
|
|||||||
import 'package:surface/widgets/dialog.dart';
|
import 'package:surface/widgets/dialog.dart';
|
||||||
import 'package:surface/widgets/navigation/app_scaffold.dart';
|
import 'package:surface/widgets/navigation/app_scaffold.dart';
|
||||||
import 'package:surface/widgets/post/post_item.dart';
|
import 'package:surface/widgets/post/post_item.dart';
|
||||||
|
import 'package:surface/widgets/updater.dart';
|
||||||
|
|
||||||
class HomeScreenDashEntry {
|
class HomeScreenDashEntry {
|
||||||
final String name;
|
final String name;
|
||||||
@ -83,14 +82,20 @@ class _HomeScreenState extends State<HomeScreen> {
|
|||||||
body: LayoutBuilder(
|
body: LayoutBuilder(
|
||||||
builder: (context, constraints) {
|
builder: (context, constraints) {
|
||||||
return Align(
|
return Align(
|
||||||
alignment: constraints.maxWidth > 640 ? Alignment.center : Alignment.topCenter,
|
alignment: constraints.maxWidth > 640
|
||||||
|
? Alignment.center
|
||||||
|
: Alignment.topCenter,
|
||||||
child: Container(
|
child: Container(
|
||||||
constraints: const BoxConstraints(maxWidth: 640),
|
constraints: const BoxConstraints(maxWidth: 640),
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: constraints.maxWidth > 640 ? MainAxisAlignment.center : MainAxisAlignment.start,
|
mainAxisAlignment: constraints.maxWidth > 640
|
||||||
|
? MainAxisAlignment.center
|
||||||
|
: MainAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
_HomeDashUpdateWidget(padding: const EdgeInsets.only(bottom: 8, left: 8, right: 8)),
|
_HomeDashUpdateWidget(
|
||||||
|
padding: const EdgeInsets.only(
|
||||||
|
bottom: 8, left: 8, right: 8)),
|
||||||
_HomeDashSpecialDayWidget().padding(horizontal: 8),
|
_HomeDashSpecialDayWidget().padding(horizontal: 8),
|
||||||
StaggeredGrid.extent(
|
StaggeredGrid.extent(
|
||||||
maxCrossAxisExtent: 280,
|
maxCrossAxisExtent: 280,
|
||||||
@ -136,21 +141,15 @@ class _HomeDashUpdateWidget extends StatelessWidget {
|
|||||||
leading: Icon(Symbols.update),
|
leading: Icon(Symbols.update),
|
||||||
title: Text('updateAvailable').tr(),
|
title: Text('updateAvailable').tr(),
|
||||||
subtitle: Text(config.updatableVersion!),
|
subtitle: Text(config.updatableVersion!),
|
||||||
trailing: (kIsWeb || Platform.isWindows || Platform.isLinux)
|
trailing: IconButton(
|
||||||
? null
|
icon: const Icon(Symbols.arrow_right_alt),
|
||||||
: IconButton(
|
onPressed: () {
|
||||||
icon: const Icon(Symbols.arrow_right_alt),
|
showModalBottomSheet(
|
||||||
onPressed: () {
|
context: context,
|
||||||
final model = UpdateModel(
|
builder: (context) => VersionUpdatePopup(),
|
||||||
'https://files.solsynth.dev/d/production01/solian/app-arm64-v8a-release.apk',
|
);
|
||||||
'solian-app-release-${config.updatableVersion!}.apk',
|
},
|
||||||
'ic_launcher',
|
),
|
||||||
'https://apps.apple.com/us/app/solian/id6499032345',
|
|
||||||
);
|
|
||||||
AzhonAppUpdate.update(model);
|
|
||||||
context.showSnackbar('updateOngoing'.tr());
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -166,7 +165,8 @@ class _HomeDashSpecialDayWidget extends StatefulWidget {
|
|||||||
const _HomeDashSpecialDayWidget();
|
const _HomeDashSpecialDayWidget();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<_HomeDashSpecialDayWidget> createState() => _HomeDashSpecialDayWidgetState();
|
State<_HomeDashSpecialDayWidget> createState() =>
|
||||||
|
_HomeDashSpecialDayWidgetState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _HomeDashSpecialDayWidgetState extends State<_HomeDashSpecialDayWidget> {
|
class _HomeDashSpecialDayWidgetState extends State<_HomeDashSpecialDayWidget> {
|
||||||
@ -208,7 +208,9 @@ class _HomeDashSpecialDayWidgetState extends State<_HomeDashSpecialDayWidget> {
|
|||||||
margin: EdgeInsets.zero,
|
margin: EdgeInsets.zero,
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
leading: Text(kSpecialDaysSymbol[name] ?? '🎉').fontSize(24),
|
leading: Text(kSpecialDaysSymbol[name] ?? '🎉').fontSize(24),
|
||||||
title: Text('pending$name').tr(args: [RelativeTime(context).format(date).replaceFirst('in', '').trim()]),
|
title: Text('pending$name').tr(args: [
|
||||||
|
RelativeTime(context).format(date).replaceFirst('in', '').trim()
|
||||||
|
]),
|
||||||
subtitle: Row(
|
subtitle: Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
@ -297,12 +299,19 @@ class _HomeDashTodayNewsState extends State<_HomeDashTodayNews> {
|
|||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
_article!.title,
|
_article!.title,
|
||||||
style: Theme.of(context).textTheme.titleMedium!.copyWith(fontSize: 18),
|
style: Theme.of(context)
|
||||||
maxLines: MediaQuery.of(context).size.width >= 640 ? 2 : 1,
|
.textTheme
|
||||||
|
.titleMedium!
|
||||||
|
.copyWith(fontSize: 18),
|
||||||
|
maxLines:
|
||||||
|
MediaQuery.of(context).size.width >= 640 ? 2 : 1,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
parse(_article!.description).children.map((e) => e.text.trim()).join(),
|
parse(_article!.description)
|
||||||
|
.children
|
||||||
|
.map((e) => e.text.trim())
|
||||||
|
.join(),
|
||||||
maxLines: 3,
|
maxLines: 3,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
style: Theme.of(context).textTheme.bodyMedium,
|
style: Theme.of(context).textTheme.bodyMedium,
|
||||||
@ -313,9 +322,13 @@ class _HomeDashTodayNewsState extends State<_HomeDashTodayNews> {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
spacing: 2,
|
spacing: 2,
|
||||||
children: [
|
children: [
|
||||||
Text(DateFormat().format(date)).textStyle(Theme.of(context).textTheme.bodySmall!),
|
Text(DateFormat().format(date)).textStyle(
|
||||||
Text(' · ').textStyle(Theme.of(context).textTheme.bodySmall!).bold(),
|
Theme.of(context).textTheme.bodySmall!),
|
||||||
Text(RelativeTime(context).format(date)).textStyle(Theme.of(context).textTheme.bodySmall!),
|
Text(' · ')
|
||||||
|
.textStyle(Theme.of(context).textTheme.bodySmall!)
|
||||||
|
.bold(),
|
||||||
|
Text(RelativeTime(context).format(date)).textStyle(
|
||||||
|
Theme.of(context).textTheme.bodySmall!),
|
||||||
],
|
],
|
||||||
).opacity(0.75);
|
).opacity(0.75);
|
||||||
}),
|
}),
|
||||||
@ -386,15 +399,20 @@ class _HomeDashCheckInWidgetState extends State<_HomeDashCheckInWidget> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildDetailChunk(int index, bool positive) {
|
Widget _buildDetailChunk(int index, bool positive) {
|
||||||
final prefix = positive ? 'dailyCheckPositiveHint' : 'dailyCheckNegativeHint';
|
final prefix =
|
||||||
final mod = positive ? kSuggestionPositiveHintCount : kSuggestionNegativeHintCount;
|
positive ? 'dailyCheckPositiveHint' : 'dailyCheckNegativeHint';
|
||||||
|
final mod =
|
||||||
|
positive ? kSuggestionPositiveHintCount : kSuggestionNegativeHintCount;
|
||||||
final pos = math.max(1, _todayRecord!.resultModifiers[index] % mod);
|
final pos = math.max(1, _todayRecord!.resultModifiers[index] % mod);
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
prefix.tr(args: ['$prefix$pos'.tr()]),
|
prefix.tr(args: ['$prefix$pos'.tr()]),
|
||||||
style: Theme.of(context).textTheme.titleMedium!.copyWith(fontWeight: FontWeight.bold),
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.titleMedium!
|
||||||
|
.copyWith(fontWeight: FontWeight.bold),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
'$prefix${pos}Description',
|
'$prefix${pos}Description',
|
||||||
@ -429,7 +447,10 @@ class _HomeDashCheckInWidgetState extends State<_HomeDashCheckInWidget> {
|
|||||||
else
|
else
|
||||||
Text(
|
Text(
|
||||||
'dailyCheckEverythingIsNegative',
|
'dailyCheckEverythingIsNegative',
|
||||||
style: Theme.of(context).textTheme.titleMedium!.copyWith(fontWeight: FontWeight.bold),
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.titleMedium!
|
||||||
|
.copyWith(fontWeight: FontWeight.bold),
|
||||||
).tr(),
|
).tr(),
|
||||||
const Gap(8),
|
const Gap(8),
|
||||||
if (_todayRecord?.resultTier != 4)
|
if (_todayRecord?.resultTier != 4)
|
||||||
@ -445,7 +466,10 @@ class _HomeDashCheckInWidgetState extends State<_HomeDashCheckInWidget> {
|
|||||||
else
|
else
|
||||||
Text(
|
Text(
|
||||||
'dailyCheckEverythingIsPositive',
|
'dailyCheckEverythingIsPositive',
|
||||||
style: Theme.of(context).textTheme.titleMedium!.copyWith(fontWeight: FontWeight.bold),
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.titleMedium!
|
||||||
|
.copyWith(fontWeight: FontWeight.bold),
|
||||||
).tr(),
|
).tr(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -571,10 +595,12 @@ class _HomeDashNotificationWidget extends StatefulWidget {
|
|||||||
const _HomeDashNotificationWidget();
|
const _HomeDashNotificationWidget();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<_HomeDashNotificationWidget> createState() => _HomeDashNotificationWidgetState();
|
State<_HomeDashNotificationWidget> createState() =>
|
||||||
|
_HomeDashNotificationWidgetState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _HomeDashNotificationWidgetState extends State<_HomeDashNotificationWidget> {
|
class _HomeDashNotificationWidgetState
|
||||||
|
extends State<_HomeDashNotificationWidget> {
|
||||||
int? _count;
|
int? _count;
|
||||||
|
|
||||||
Future<void> _fetchNotificationCount() async {
|
Future<void> _fetchNotificationCount() async {
|
||||||
@ -612,7 +638,9 @@ class _HomeDashNotificationWidgetState extends State<_HomeDashNotificationWidget
|
|||||||
style: Theme.of(context).textTheme.titleLarge,
|
style: Theme.of(context).textTheme.titleLarge,
|
||||||
).tr(),
|
).tr(),
|
||||||
Text(
|
Text(
|
||||||
_count == null ? 'loading'.tr() : 'notificationUnreadCount'.plural(_count ?? 0),
|
_count == null
|
||||||
|
? 'loading'.tr()
|
||||||
|
: 'notificationUnreadCount'.plural(_count ?? 0),
|
||||||
style: Theme.of(context).textTheme.bodyLarge,
|
style: Theme.of(context).textTheme.bodyLarge,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -643,10 +671,12 @@ class _HomeDashRecommendationPostWidget extends StatefulWidget {
|
|||||||
const _HomeDashRecommendationPostWidget();
|
const _HomeDashRecommendationPostWidget();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<_HomeDashRecommendationPostWidget> createState() => _HomeDashRecommendationPostWidgetState();
|
State<_HomeDashRecommendationPostWidget> createState() =>
|
||||||
|
_HomeDashRecommendationPostWidgetState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _HomeDashRecommendationPostWidgetState extends State<_HomeDashRecommendationPostWidget> {
|
class _HomeDashRecommendationPostWidgetState
|
||||||
|
extends State<_HomeDashRecommendationPostWidget> {
|
||||||
bool _isBusy = false;
|
bool _isBusy = false;
|
||||||
List<SnPost>? _posts;
|
List<SnPost>? _posts;
|
||||||
|
|
||||||
@ -710,13 +740,15 @@ class _HomeDashRecommendationPostWidgetState extends State<_HomeDashRecommendati
|
|||||||
).tr(),
|
).tr(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Text('${_currentPage + 1}/${_posts?.length ?? 0}', style: GoogleFonts.robotoMono())
|
Text('${_currentPage + 1}/${_posts?.length ?? 0}',
|
||||||
|
style: GoogleFonts.robotoMono())
|
||||||
],
|
],
|
||||||
).padding(horizontal: 18, top: 12, bottom: 8),
|
).padding(horizontal: 18, top: 12, bottom: 8),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: PageView.builder(
|
child: PageView.builder(
|
||||||
controller: _pageController,
|
controller: _pageController,
|
||||||
scrollBehavior: ScrollConfiguration.of(context).copyWith(dragDevices: {
|
scrollBehavior:
|
||||||
|
ScrollConfiguration.of(context).copyWith(dragDevices: {
|
||||||
PointerDeviceKind.mouse,
|
PointerDeviceKind.mouse,
|
||||||
PointerDeviceKind.touch,
|
PointerDeviceKind.touch,
|
||||||
}),
|
}),
|
||||||
@ -729,7 +761,8 @@ class _HomeDashRecommendationPostWidgetState extends State<_HomeDashRecommendati
|
|||||||
showMenu: false,
|
showMenu: false,
|
||||||
).padding(bottom: 8),
|
).padding(bottom: 8),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
GoRouter.of(context).pushNamed('postDetail', pathParameters: {
|
GoRouter.of(context)
|
||||||
|
.pushNamed('postDetail', pathParameters: {
|
||||||
'slug': _posts![index].id.toString(),
|
'slug': _posts![index].id.toString(),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -24,6 +24,7 @@ import 'package:surface/providers/theme.dart';
|
|||||||
import 'package:surface/theme.dart';
|
import 'package:surface/theme.dart';
|
||||||
import 'package:surface/widgets/dialog.dart';
|
import 'package:surface/widgets/dialog.dart';
|
||||||
import 'package:surface/widgets/navigation/app_scaffold.dart';
|
import 'package:surface/widgets/navigation/app_scaffold.dart';
|
||||||
|
import 'package:surface/widgets/updater.dart';
|
||||||
|
|
||||||
const Map<String, Color> kColorSchemes = {
|
const Map<String, Color> kColorSchemes = {
|
||||||
'colorSchemeIndigo': Colors.indigo,
|
'colorSchemeIndigo': Colors.indigo,
|
||||||
@ -604,6 +605,19 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
ListTile(
|
||||||
|
title: Text('forceUpdate').tr(),
|
||||||
|
subtitle: Text('forceUpdateDescription').tr(),
|
||||||
|
contentPadding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
|
leading: const Icon(Symbols.update),
|
||||||
|
trailing: const Icon(Symbols.chevron_right),
|
||||||
|
onTap: () async {
|
||||||
|
showModalBottomSheet(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => VersionUpdatePopup(),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
title: Text('settingsMiscAbout').tr(),
|
title: Text('settingsMiscAbout').tr(),
|
||||||
subtitle: Text('settingsMiscAboutDescription').tr(),
|
subtitle: Text('settingsMiscAboutDescription').tr(),
|
||||||
|
96
lib/widgets/updater.dart
Normal file
96
lib/widgets/updater.dart
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:dio/dio.dart';
|
||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_app_update/azhon_app_update.dart';
|
||||||
|
import 'package:flutter_app_update/update_model.dart';
|
||||||
|
import 'package:gap/gap.dart';
|
||||||
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
|
import 'package:surface/providers/config.dart';
|
||||||
|
import 'package:surface/widgets/dialog.dart';
|
||||||
|
import 'package:surface/widgets/markdown_content.dart';
|
||||||
|
import 'package:url_launcher/url_launcher_string.dart';
|
||||||
|
|
||||||
|
class VersionUpdatePopup extends StatelessWidget {
|
||||||
|
const VersionUpdatePopup({super.key});
|
||||||
|
|
||||||
|
void _update(BuildContext context) async {
|
||||||
|
if (kIsWeb) return;
|
||||||
|
|
||||||
|
final config = context.read<ConfigProvider>();
|
||||||
|
|
||||||
|
if (Platform.isAndroid) {
|
||||||
|
final model = UpdateModel(
|
||||||
|
'https://files.solsynth.dev/d/production01/solian/app-arm64-v8a-release.apk',
|
||||||
|
'solian-app-release-${config.updatableVersion!}.apk',
|
||||||
|
'ic_launcher',
|
||||||
|
'https://apps.apple.com/us/app/solian/id6499032345',
|
||||||
|
);
|
||||||
|
AzhonAppUpdate.update(model);
|
||||||
|
context.showSnackbar('updateOngoing'.tr());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final resp = await Dio(
|
||||||
|
BaseOptions(
|
||||||
|
sendTimeout: const Duration(seconds: 60),
|
||||||
|
receiveTimeout: const Duration(seconds: 60),
|
||||||
|
),
|
||||||
|
).get(
|
||||||
|
'https://api.github.com/repos/Solsynth/HyperNet.Surface/releases/latest',
|
||||||
|
);
|
||||||
|
|
||||||
|
launchUrlString(resp.data?['html_url']);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final config = context.watch<ConfigProvider>();
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
const Icon(Icons.update),
|
||||||
|
const Gap(16),
|
||||||
|
Text('update')
|
||||||
|
.tr()
|
||||||
|
.textStyle(Theme.of(context).textTheme.titleLarge!),
|
||||||
|
],
|
||||||
|
).padding(horizontal: 20, top: 16, bottom: 12),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
config.updatableVersion ?? 'unknown'.tr(),
|
||||||
|
style: GoogleFonts.robotoMono(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
ElevatedButton(
|
||||||
|
style: ButtonStyle(
|
||||||
|
visualDensity: const VisualDensity(
|
||||||
|
horizontal: -4,
|
||||||
|
vertical: -3,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onPressed: () => _update(context),
|
||||||
|
child: Text('update').tr(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
).padding(horizontal: 20),
|
||||||
|
const Divider(height: 1).padding(vertical: 8),
|
||||||
|
Expanded(
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: MarkdownTextContent(
|
||||||
|
content: config.updatableChangelog ?? 'No changelog',
|
||||||
|
).padding(horizontal: 20),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -142,10 +142,12 @@ PODS:
|
|||||||
- HotKey
|
- HotKey
|
||||||
- in_app_review (2.0.0):
|
- in_app_review (2.0.0):
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
- livekit_client (2.3.6):
|
- livekit_client (2.4.0):
|
||||||
- flutter_webrtc
|
- flutter_webrtc
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
- WebRTC-SDK (= 125.6422.06)
|
- WebRTC-SDK (= 125.6422.06)
|
||||||
|
- local_notifier (0.1.0):
|
||||||
|
- FlutterMacOS
|
||||||
- media_kit_libs_macos_video (1.0.4):
|
- media_kit_libs_macos_video (1.0.4):
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
- media_kit_native_event_loop (1.0.0):
|
- media_kit_native_event_loop (1.0.0):
|
||||||
@ -225,6 +227,7 @@ DEPENDENCIES:
|
|||||||
- hotkey_manager_macos (from `Flutter/ephemeral/.symlinks/plugins/hotkey_manager_macos/macos`)
|
- hotkey_manager_macos (from `Flutter/ephemeral/.symlinks/plugins/hotkey_manager_macos/macos`)
|
||||||
- in_app_review (from `Flutter/ephemeral/.symlinks/plugins/in_app_review/macos`)
|
- in_app_review (from `Flutter/ephemeral/.symlinks/plugins/in_app_review/macos`)
|
||||||
- livekit_client (from `Flutter/ephemeral/.symlinks/plugins/livekit_client/macos`)
|
- livekit_client (from `Flutter/ephemeral/.symlinks/plugins/livekit_client/macos`)
|
||||||
|
- local_notifier (from `Flutter/ephemeral/.symlinks/plugins/local_notifier/macos`)
|
||||||
- media_kit_libs_macos_video (from `Flutter/ephemeral/.symlinks/plugins/media_kit_libs_macos_video/macos`)
|
- media_kit_libs_macos_video (from `Flutter/ephemeral/.symlinks/plugins/media_kit_libs_macos_video/macos`)
|
||||||
- media_kit_native_event_loop (from `Flutter/ephemeral/.symlinks/plugins/media_kit_native_event_loop/macos`)
|
- media_kit_native_event_loop (from `Flutter/ephemeral/.symlinks/plugins/media_kit_native_event_loop/macos`)
|
||||||
- media_kit_video (from `Flutter/ephemeral/.symlinks/plugins/media_kit_video/macos`)
|
- media_kit_video (from `Flutter/ephemeral/.symlinks/plugins/media_kit_video/macos`)
|
||||||
@ -297,6 +300,8 @@ EXTERNAL SOURCES:
|
|||||||
:path: Flutter/ephemeral/.symlinks/plugins/in_app_review/macos
|
:path: Flutter/ephemeral/.symlinks/plugins/in_app_review/macos
|
||||||
livekit_client:
|
livekit_client:
|
||||||
:path: Flutter/ephemeral/.symlinks/plugins/livekit_client/macos
|
:path: Flutter/ephemeral/.symlinks/plugins/livekit_client/macos
|
||||||
|
local_notifier:
|
||||||
|
:path: Flutter/ephemeral/.symlinks/plugins/local_notifier/macos
|
||||||
media_kit_libs_macos_video:
|
media_kit_libs_macos_video:
|
||||||
:path: Flutter/ephemeral/.symlinks/plugins/media_kit_libs_macos_video/macos
|
:path: Flutter/ephemeral/.symlinks/plugins/media_kit_libs_macos_video/macos
|
||||||
media_kit_native_event_loop:
|
media_kit_native_event_loop:
|
||||||
@ -356,7 +361,8 @@ SPEC CHECKSUMS:
|
|||||||
HotKey: 400beb7caa29054ea8d864c96f5ba7e5b4852277
|
HotKey: 400beb7caa29054ea8d864c96f5ba7e5b4852277
|
||||||
hotkey_manager_macos: 1e2edb0c7ae4fe67108af44a9d3445de41404160
|
hotkey_manager_macos: 1e2edb0c7ae4fe67108af44a9d3445de41404160
|
||||||
in_app_review: a6a031b9acd03c7d103e341aa334adf2c493fb93
|
in_app_review: a6a031b9acd03c7d103e341aa334adf2c493fb93
|
||||||
livekit_client: 0ad107154753a5a76802d2222c040223ad049499
|
livekit_client: 2e766be2c3ee6274a8e2633b356b98b5eb842987
|
||||||
|
local_notifier: e9506bc66fc70311e8bc7291fb70f743c081e4ff
|
||||||
media_kit_libs_macos_video: b3e2bbec2eef97c285f2b1baa7963c67c753fb82
|
media_kit_libs_macos_video: b3e2bbec2eef97c285f2b1baa7963c67c753fb82
|
||||||
media_kit_native_event_loop: 81fd5b45192b72f8b5b69eaf5b540f45777eb8d5
|
media_kit_native_event_loop: 81fd5b45192b72f8b5b69eaf5b540f45777eb8d5
|
||||||
media_kit_video: c75b07f14d59706c775778e4dd47dd027de8d1e5
|
media_kit_video: c75b07f14d59706c775778e4dd47dd027de8d1e5
|
||||||
|
@ -2309,10 +2309,11 @@ packages:
|
|||||||
workmanager:
|
workmanager:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: workmanager
|
path: workmanager
|
||||||
sha256: ed13530cccd28c5c9959ad42d657cd0666274ca74c56dea0ca183ddd527d3a00
|
ref: main
|
||||||
url: "https://pub.dev"
|
resolved-ref: "4ce065135dc1b91fee918f81596b42a56850391d"
|
||||||
source: hosted
|
url: "https://github.com/fluttercommunity/flutter_workmanager.git"
|
||||||
|
source: git
|
||||||
version: "0.5.2"
|
version: "0.5.2"
|
||||||
xdg_directories:
|
xdg_directories:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
|
@ -16,7 +16,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev
|
|||||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||||
# In Windows, build-name is used as the major, minor, and patch parts
|
# In Windows, build-name is used as the major, minor, and patch parts
|
||||||
# of the product and file versions while build-number is used as the build suffix.
|
# of the product and file versions while build-number is used as the build suffix.
|
||||||
version: 2.3.2+71
|
version: 2.3.2+73
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ^3.5.4
|
sdk: ^3.5.4
|
||||||
@ -103,7 +103,11 @@ dependencies:
|
|||||||
flutter_svg: ^2.0.16
|
flutter_svg: ^2.0.16
|
||||||
home_widget: ^0.7.0
|
home_widget: ^0.7.0
|
||||||
receive_sharing_intent: ^1.8.1
|
receive_sharing_intent: ^1.8.1
|
||||||
workmanager: ^0.5.2
|
workmanager:
|
||||||
|
git:
|
||||||
|
url: https://github.com/fluttercommunity/flutter_workmanager.git
|
||||||
|
path: workmanager
|
||||||
|
ref: main
|
||||||
flutter_app_update: ^3.2.2
|
flutter_app_update: ^3.2.2
|
||||||
in_app_review: ^2.0.10
|
in_app_review: ^2.0.10
|
||||||
version: ^3.0.2
|
version: ^3.0.2
|
||||||
|
Reference in New Issue
Block a user