Compare commits

..

No commits in common. "9910fc7a92b7acc0ab1177848b36989a76c969d5" and "8ec33ccbf468139c3d859e5b71c81df865eb60c8" have entirely different histories.

6 changed files with 79 additions and 119 deletions

View File

@ -20,6 +20,7 @@ import 'package:solian/widgets/app_bar_leading.dart';
import 'package:solian/widgets/app_bar_title.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/chat_event.dart';
import 'package:solian/widgets/chat/chat_event_list.dart';
import 'package:solian/widgets/chat/chat_message_input.dart';
import 'package:solian/widgets/current_state_action.dart';
@ -38,10 +39,7 @@ class ChannelChatScreen extends StatefulWidget {
State<ChannelChatScreen> createState() => _ChannelChatScreenState();
}
class _ChannelChatScreenState extends State<ChannelChatScreen>
with WidgetsBindingObserver {
DateTime? _isOutOfSyncSince;
class _ChannelChatScreenState extends State<ChannelChatScreen> {
bool _isBusy = false;
int? _accountId;
@ -125,38 +123,20 @@ class _ChannelChatScreenState extends State<ChannelChatScreen>
});
}
void _keepUpdateWithServer() {
_getOngoingCall();
_chatController.getEvents(_channel!, widget.realm);
setState(() => _isOutOfSyncSince = null);
}
Event? _messageToReplying;
Event? _messageToEditing;
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
switch (state) {
case AppLifecycleState.resumed:
if (_isOutOfSyncSince == null) break;
if (DateTime.now().difference(_isOutOfSyncSince!).inSeconds < 60) break;
_keepUpdateWithServer();
break;
case AppLifecycleState.paused:
if (mounted) {
setState(() => _isOutOfSyncSince = DateTime.now());
}
break;
default:
break;
}
Widget buildHistoryBody(Event item, {bool isMerged = false}) {
return ChatEvent(
key: Key('m${item.uuid}'),
item: item,
isMerged: isMerged,
chatController: _chatController,
);
}
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
_accountId = Get.find<AuthProvider>().userProfile.value!['id'];
_chatController = ChatEventController();
@ -167,10 +147,21 @@ class _ChannelChatScreenState extends State<ChannelChatScreen>
_chatController.getEvents(_channel!, widget.realm);
_listenMessages();
});
super.initState();
}
@override
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? placeholder;
@ -194,8 +185,7 @@ class _ChannelChatScreenState extends State<ChannelChatScreen>
actions: [
const BackgroundStateWidget(),
Builder(builder: (context) {
if (_isBusy || _channel == null) return const SizedBox();
if (_isBusy) return const SizedBox();
return ChatCallButton(
realm: _channel!.realm,
channel: _channel!,
@ -205,8 +195,6 @@ class _ChannelChatScreenState extends State<ChannelChatScreen>
IconButton(
icon: const Icon(Icons.more_vert),
onPressed: () {
if (_channel == null) return;
AppRouter.instance
.pushNamed(
'channelDetail',
@ -231,87 +219,66 @@ class _ChannelChatScreenState extends State<ChannelChatScreen>
),
],
),
body: Builder(builder: (context) {
if (_isBusy || _channel == null) {
return const Center(
child: CircularProgressIndicator(),
);
}
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);
},
),
body: Column(
children: [
if (_ongoingCall != null)
ChannelCallIndicator(
channel: _channel!,
ongoingCall: _ongoingCall!,
),
if (_isOutOfSyncSince != null)
ListTile(
tileColor: Theme.of(context).colorScheme.surfaceContainerLow,
leading: const Icon(Icons.history_toggle_off),
title: Text('messageOutOfSync'.tr),
subtitle: Text('messageOutOfSyncCaption'.tr),
onTap: _isBusy
? null
: () {
_keepUpdateWithServer();
},
),
Obx(() {
if (_chatController.isLoading.isTrue) {
return const LinearProgressIndicator().animate().slideY();
} else {
return const SizedBox();
}
}),
ClipRect(
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 50, sigmaY: 50),
child: SafeArea(
child: ChatMessageInput(
edit: _messageToEditing,
reply: _messageToReplying,
realm: widget.realm,
placeholder: placeholder,
channel: _channel!,
onSent: (Event item) {
setState(() {
_chatController.addPendingEvent(item);
});
},
onReset: () {
setState(() {
_messageToReplying = null;
_messageToEditing = null;
});
},
),
Expanded(
child: ChatEventList(
scope: widget.realm,
channel: _channel!,
chatController: _chatController,
onEdit: (item) {
setState(() => _messageToEditing = item);
},
onReply: (item) {
setState(() => _messageToReplying = item);
},
),
),
Obx(() {
if (_chatController.isLoading.isTrue) {
return const LinearProgressIndicator().animate().slideY();
} else {
return const SizedBox();
}
}),
ClipRect(
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 50, sigmaY: 50),
child: SafeArea(
child: ChatMessageInput(
edit: _messageToEditing,
reply: _messageToReplying,
realm: widget.realm,
placeholder: placeholder,
channel: _channel!,
onSent: (Event item) {
setState(() {
_chatController.addPendingEvent(item);
});
},
onReset: () {
setState(() {
_messageToReplying = null;
_messageToEditing = null;
});
},
),
),
),
],
);
}),
),
],
),
);
}
@override
void dispose() {
_subscription?.cancel();
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
}

View File

@ -370,7 +370,4 @@ const i18nEnglish = {
'callStatusDisconnected': 'Disconnected',
'callStatusConnecting': 'Connecting',
'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.',
};

View File

@ -337,6 +337,4 @@ const i18nSimplifiedChinese = {
'callStatusDisconnected': '已断开',
'callStatusConnecting': '连接中',
'callStatusReconnected': '重连中',
'messageOutOfSync': '消息可能与服务器脱节',
'messageOutOfSyncCaption': '由于 App 进入后台,消息列表可能与服务器存在时差,点击刷新。',
};

View File

@ -159,9 +159,8 @@ class _ControlsWidgetState extends State<ControlsWidget> {
}
var track = await LocalVideoTrack.createScreenShareTrack(
ScreenShareCaptureOptions(
captureScreenAudio: true,
sourceId: source.id,
maxFrameRate: 30.0,
maxFrameRate: 15.0,
),
);
await _participant.publishVideoTrack(track);
@ -175,7 +174,6 @@ class _ControlsWidgetState extends State<ControlsWidget> {
var track = await LocalVideoTrack.createScreenShareTrack(
const ScreenShareCaptureOptions(
useiOSBroadcastExtension: true,
captureScreenAudio: true,
maxFrameRate: 30.0,
),
);

View File

@ -4,17 +4,17 @@ import 'package:get/utils.dart';
abstract class AppNavigation {
static List<AppNavigationDestination> destinations = [
AppNavigationDestination(
icon: Icons.home,
icon: const Icon(Icons.home),
label: 'home'.tr,
page: 'home',
),
AppNavigationDestination(
icon: Icons.workspaces,
icon: const Icon(Icons.workspaces),
label: 'realms'.tr,
page: 'realms',
),
AppNavigationDestination(
icon: Icons.forum,
icon: const Icon(Icons.forum),
label: 'channelTypeDirect'.tr,
page: 'chat',
),
@ -25,7 +25,7 @@ abstract class AppNavigation {
}
class AppNavigationDestination {
final IconData icon;
final Widget icon;
final String label;
final String page;

View File

@ -81,7 +81,7 @@ class _AppNavigationDrawerState extends State<AppNavigationDrawer> {
}
return ListTile(
contentPadding: const EdgeInsets.only(left: 20, right: 20),
contentPadding: const EdgeInsets.symmetric(horizontal: 24),
title: Text(
auth.userProfile.value!['nick'],
maxLines: 1,
@ -154,7 +154,7 @@ class _AppNavigationDrawerState extends State<AppNavigationDrawer> {
});
},
);
}).paddingSymmetric(vertical: 8),
}).paddingOnly(top: 8),
const Divider(thickness: 0.3, height: 1),
Column(
children: AppNavigation.destinations
@ -163,7 +163,7 @@ class _AppNavigationDrawerState extends State<AppNavigationDrawer> {
contentPadding: const EdgeInsets.symmetric(
horizontal: 20,
),
leading: Icon(e.icon, size: 20).paddingAll(2),
leading: e.icon,
title: Text(e.label),
enabled: true,
onTap: () {