✨ Channel content auto refresh after long time background activity
This commit is contained in:
parent
2356eac118
commit
9910fc7a92
@ -20,7 +20,6 @@ import 'package:solian/widgets/app_bar_leading.dart';
|
|||||||
import 'package:solian/widgets/app_bar_title.dart';
|
import 'package:solian/widgets/app_bar_title.dart';
|
||||||
import 'package:solian/widgets/channel/channel_call_indicator.dart';
|
import 'package:solian/widgets/channel/channel_call_indicator.dart';
|
||||||
import 'package:solian/widgets/chat/call/chat_call_action.dart';
|
import 'package:solian/widgets/chat/call/chat_call_action.dart';
|
||||||
import 'package:solian/widgets/chat/chat_event.dart';
|
|
||||||
import 'package:solian/widgets/chat/chat_event_list.dart';
|
import 'package:solian/widgets/chat/chat_event_list.dart';
|
||||||
import 'package:solian/widgets/chat/chat_message_input.dart';
|
import 'package:solian/widgets/chat/chat_message_input.dart';
|
||||||
import 'package:solian/widgets/current_state_action.dart';
|
import 'package:solian/widgets/current_state_action.dart';
|
||||||
@ -39,7 +38,10 @@ class ChannelChatScreen extends StatefulWidget {
|
|||||||
State<ChannelChatScreen> createState() => _ChannelChatScreenState();
|
State<ChannelChatScreen> createState() => _ChannelChatScreenState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ChannelChatScreenState extends State<ChannelChatScreen> {
|
class _ChannelChatScreenState extends State<ChannelChatScreen>
|
||||||
|
with WidgetsBindingObserver {
|
||||||
|
DateTime? _isOutOfSyncSince;
|
||||||
|
|
||||||
bool _isBusy = false;
|
bool _isBusy = false;
|
||||||
int? _accountId;
|
int? _accountId;
|
||||||
|
|
||||||
@ -123,20 +125,38 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _keepUpdateWithServer() {
|
||||||
|
_getOngoingCall();
|
||||||
|
_chatController.getEvents(_channel!, widget.realm);
|
||||||
|
setState(() => _isOutOfSyncSince = null);
|
||||||
|
}
|
||||||
|
|
||||||
Event? _messageToReplying;
|
Event? _messageToReplying;
|
||||||
Event? _messageToEditing;
|
Event? _messageToEditing;
|
||||||
|
|
||||||
Widget buildHistoryBody(Event item, {bool isMerged = false}) {
|
@override
|
||||||
return ChatEvent(
|
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||||
key: Key('m${item.uuid}'),
|
switch (state) {
|
||||||
item: item,
|
case AppLifecycleState.resumed:
|
||||||
isMerged: isMerged,
|
if (_isOutOfSyncSince == null) break;
|
||||||
chatController: _chatController,
|
if (DateTime.now().difference(_isOutOfSyncSince!).inSeconds < 60) break;
|
||||||
);
|
_keepUpdateWithServer();
|
||||||
|
break;
|
||||||
|
case AppLifecycleState.paused:
|
||||||
|
if (mounted) {
|
||||||
|
setState(() => _isOutOfSyncSince = DateTime.now());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
WidgetsBinding.instance.addObserver(this);
|
||||||
|
|
||||||
_accountId = Get.find<AuthProvider>().userProfile.value!['id'];
|
_accountId = Get.find<AuthProvider>().userProfile.value!['id'];
|
||||||
|
|
||||||
_chatController = ChatEventController();
|
_chatController = ChatEventController();
|
||||||
@ -147,21 +167,10 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
|
|||||||
_chatController.getEvents(_channel!, widget.realm);
|
_chatController.getEvents(_channel!, widget.realm);
|
||||||
_listenMessages();
|
_listenMessages();
|
||||||
});
|
});
|
||||||
|
|
||||||
super.initState();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
if (_isBusy || _channel == null) {
|
|
||||||
return Material(
|
|
||||||
color: Theme.of(context).colorScheme.surface,
|
|
||||||
child: const Center(
|
|
||||||
child: CircularProgressIndicator(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
String title = _channel?.name ?? 'loading'.tr;
|
String title = _channel?.name ?? 'loading'.tr;
|
||||||
String? placeholder;
|
String? placeholder;
|
||||||
|
|
||||||
@ -185,7 +194,8 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
|
|||||||
actions: [
|
actions: [
|
||||||
const BackgroundStateWidget(),
|
const BackgroundStateWidget(),
|
||||||
Builder(builder: (context) {
|
Builder(builder: (context) {
|
||||||
if (_isBusy) return const SizedBox();
|
if (_isBusy || _channel == null) return const SizedBox();
|
||||||
|
|
||||||
return ChatCallButton(
|
return ChatCallButton(
|
||||||
realm: _channel!.realm,
|
realm: _channel!.realm,
|
||||||
channel: _channel!,
|
channel: _channel!,
|
||||||
@ -195,6 +205,8 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
|
|||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Icons.more_vert),
|
icon: const Icon(Icons.more_vert),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
|
if (_channel == null) return;
|
||||||
|
|
||||||
AppRouter.instance
|
AppRouter.instance
|
||||||
.pushNamed(
|
.pushNamed(
|
||||||
'channelDetail',
|
'channelDetail',
|
||||||
@ -219,66 +231,87 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
body: Column(
|
body: Builder(builder: (context) {
|
||||||
children: [
|
if (_isBusy || _channel == null) {
|
||||||
if (_ongoingCall != null)
|
return const Center(
|
||||||
ChannelCallIndicator(
|
child: CircularProgressIndicator(),
|
||||||
channel: _channel!,
|
);
|
||||||
ongoingCall: _ongoingCall!,
|
}
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
if (_ongoingCall != null)
|
||||||
|
ChannelCallIndicator(
|
||||||
|
channel: _channel!,
|
||||||
|
ongoingCall: _ongoingCall!,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: ChatEventList(
|
||||||
|
scope: widget.realm,
|
||||||
|
channel: _channel!,
|
||||||
|
chatController: _chatController,
|
||||||
|
onEdit: (item) {
|
||||||
|
setState(() => _messageToEditing = item);
|
||||||
|
},
|
||||||
|
onReply: (item) {
|
||||||
|
setState(() => _messageToReplying = item);
|
||||||
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
if (_isOutOfSyncSince != null)
|
||||||
child: ChatEventList(
|
ListTile(
|
||||||
scope: widget.realm,
|
tileColor: Theme.of(context).colorScheme.surfaceContainerLow,
|
||||||
channel: _channel!,
|
leading: const Icon(Icons.history_toggle_off),
|
||||||
chatController: _chatController,
|
title: Text('messageOutOfSync'.tr),
|
||||||
onEdit: (item) {
|
subtitle: Text('messageOutOfSyncCaption'.tr),
|
||||||
setState(() => _messageToEditing = item);
|
onTap: _isBusy
|
||||||
},
|
? null
|
||||||
onReply: (item) {
|
: () {
|
||||||
setState(() => _messageToReplying = item);
|
_keepUpdateWithServer();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
Obx(() {
|
||||||
Obx(() {
|
if (_chatController.isLoading.isTrue) {
|
||||||
if (_chatController.isLoading.isTrue) {
|
return const LinearProgressIndicator().animate().slideY();
|
||||||
return const LinearProgressIndicator().animate().slideY();
|
} else {
|
||||||
} else {
|
return const SizedBox();
|
||||||
return const SizedBox();
|
}
|
||||||
}
|
}),
|
||||||
}),
|
ClipRect(
|
||||||
ClipRect(
|
child: BackdropFilter(
|
||||||
child: BackdropFilter(
|
filter: ImageFilter.blur(sigmaX: 50, sigmaY: 50),
|
||||||
filter: ImageFilter.blur(sigmaX: 50, sigmaY: 50),
|
child: SafeArea(
|
||||||
child: SafeArea(
|
child: ChatMessageInput(
|
||||||
child: ChatMessageInput(
|
edit: _messageToEditing,
|
||||||
edit: _messageToEditing,
|
reply: _messageToReplying,
|
||||||
reply: _messageToReplying,
|
realm: widget.realm,
|
||||||
realm: widget.realm,
|
placeholder: placeholder,
|
||||||
placeholder: placeholder,
|
channel: _channel!,
|
||||||
channel: _channel!,
|
onSent: (Event item) {
|
||||||
onSent: (Event item) {
|
setState(() {
|
||||||
setState(() {
|
_chatController.addPendingEvent(item);
|
||||||
_chatController.addPendingEvent(item);
|
});
|
||||||
});
|
},
|
||||||
},
|
onReset: () {
|
||||||
onReset: () {
|
setState(() {
|
||||||
setState(() {
|
_messageToReplying = null;
|
||||||
_messageToReplying = null;
|
_messageToEditing = null;
|
||||||
_messageToEditing = null;
|
});
|
||||||
});
|
},
|
||||||
},
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
],
|
);
|
||||||
),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_subscription?.cancel();
|
_subscription?.cancel();
|
||||||
|
WidgetsBinding.instance.removeObserver(this);
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -370,4 +370,7 @@ const i18nEnglish = {
|
|||||||
'callStatusDisconnected': 'Disconnected',
|
'callStatusDisconnected': 'Disconnected',
|
||||||
'callStatusConnecting': 'Connecting',
|
'callStatusConnecting': 'Connecting',
|
||||||
'callStatusReconnected': 'Reconnecting',
|
'callStatusReconnected': 'Reconnecting',
|
||||||
|
'messageOutOfSync': 'May Out of Sync with Server',
|
||||||
|
'messageOutOfSyncCaption':
|
||||||
|
'Since the App has entered the background, there may be a time difference between the message list and the server. Click to Refresh.',
|
||||||
};
|
};
|
||||||
|
@ -337,4 +337,6 @@ const i18nSimplifiedChinese = {
|
|||||||
'callStatusDisconnected': '已断开',
|
'callStatusDisconnected': '已断开',
|
||||||
'callStatusConnecting': '连接中',
|
'callStatusConnecting': '连接中',
|
||||||
'callStatusReconnected': '重连中',
|
'callStatusReconnected': '重连中',
|
||||||
|
'messageOutOfSync': '消息可能与服务器脱节',
|
||||||
|
'messageOutOfSyncCaption': '由于 App 进入后台,消息列表可能与服务器存在时差,点击刷新。',
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user