✨ Notify level in channel
This commit is contained in:
parent
6acbd1ee9e
commit
0f24ac03f7
@ -31,8 +31,6 @@ class ChatCallProvider extends GetxController {
|
|||||||
Rx<MediaDevice?> videoDevice = Rx(null);
|
Rx<MediaDevice?> videoDevice = Rx(null);
|
||||||
Rx<MediaDevice?> audioDevice = Rx(null);
|
Rx<MediaDevice?> audioDevice = Rx(null);
|
||||||
|
|
||||||
final VideoParameters videoParameters = VideoParametersPresets.h720_169;
|
|
||||||
|
|
||||||
late Room room;
|
late Room room;
|
||||||
late EventsListener<RoomEvent> listener;
|
late EventsListener<RoomEvent> listener;
|
||||||
|
|
||||||
@ -105,29 +103,27 @@ class ChatCallProvider extends GetxController {
|
|||||||
await room.connect(
|
await room.connect(
|
||||||
url,
|
url,
|
||||||
token,
|
token,
|
||||||
roomOptions: RoomOptions(
|
roomOptions: const RoomOptions(
|
||||||
dynacast: true,
|
dynacast: true,
|
||||||
adaptiveStream: true,
|
adaptiveStream: true,
|
||||||
defaultAudioPublishOptions: const AudioPublishOptions(
|
defaultAudioPublishOptions: AudioPublishOptions(
|
||||||
name: 'call_voice',
|
name: 'call_voice',
|
||||||
stream: 'call_stream',
|
stream: 'call_stream',
|
||||||
),
|
),
|
||||||
defaultVideoPublishOptions: const VideoPublishOptions(
|
defaultVideoPublishOptions: VideoPublishOptions(
|
||||||
name: 'call_video',
|
name: 'call_video',
|
||||||
stream: 'call_stream',
|
stream: 'call_stream',
|
||||||
simulcast: true,
|
simulcast: true,
|
||||||
backupVideoCodec: BackupVideoCodec(enabled: true),
|
backupVideoCodec: BackupVideoCodec(enabled: true),
|
||||||
),
|
),
|
||||||
defaultScreenShareCaptureOptions: const ScreenShareCaptureOptions(
|
defaultScreenShareCaptureOptions: ScreenShareCaptureOptions(
|
||||||
useiOSBroadcastExtension: true,
|
useiOSBroadcastExtension: true,
|
||||||
params: VideoParameters(
|
params: VideoParametersPresets.screenShareH1080FPS30,
|
||||||
dimensions: VideoDimensionsPresets.h1080_169,
|
|
||||||
encoding:
|
|
||||||
VideoEncoding(maxBitrate: 3 * 1000 * 1000, maxFramerate: 30),
|
|
||||||
),
|
),
|
||||||
|
defaultCameraCaptureOptions: CameraCaptureOptions(
|
||||||
|
maxFrameRate: 30,
|
||||||
|
params: VideoParametersPresets.h1080_169,
|
||||||
),
|
),
|
||||||
defaultCameraCaptureOptions:
|
|
||||||
CameraCaptureOptions(maxFrameRate: 30, params: videoParameters),
|
|
||||||
),
|
),
|
||||||
fastConnectOptions: FastConnectOptions(
|
fastConnectOptions: FastConnectOptions(
|
||||||
microphone: TrackOption(track: audioTrack.value),
|
microphone: TrackOption(track: audioTrack.value),
|
||||||
@ -334,7 +330,7 @@ class ChatCallProvider extends GetxController {
|
|||||||
videoTrack.value = await LocalVideoTrack.createCameraTrack(
|
videoTrack.value = await LocalVideoTrack.createCameraTrack(
|
||||||
CameraCaptureOptions(
|
CameraCaptureOptions(
|
||||||
deviceId: videoDevice.value!.deviceId,
|
deviceId: videoDevice.value!.deviceId,
|
||||||
params: videoParameters,
|
params: VideoParametersPresets.h1080_169,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
await videoTrack.value!.start();
|
await videoTrack.value!.start();
|
||||||
|
@ -19,6 +19,20 @@ class ChannelProvider extends GetxController {
|
|||||||
return resp;
|
return resp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<Response> getMyChannelProfile(String alias, {String realm = 'global'}) async {
|
||||||
|
final AuthProvider auth = Get.find();
|
||||||
|
if (!await auth.isAuthorized) throw Exception('unauthorized');
|
||||||
|
|
||||||
|
final client = auth.configureClient(service: 'messaging');
|
||||||
|
|
||||||
|
final resp = await client.get('/api/channels/$realm/$alias/me');
|
||||||
|
if (resp.statusCode != 200) {
|
||||||
|
throw Exception(resp.bodyString);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
Future<Response?> getChannelOngoingCall(String alias,
|
Future<Response?> getChannelOngoingCall(String alias,
|
||||||
{String realm = 'global'}) async {
|
{String realm = 'global'}) async {
|
||||||
final AuthProvider auth = Get.find();
|
final AuthProvider auth = Get.find();
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:solian/models/channel.dart';
|
|
||||||
import 'package:solian/models/realm.dart';
|
import 'package:solian/models/realm.dart';
|
||||||
import 'package:solian/screens/about.dart';
|
import 'package:solian/screens/about.dart';
|
||||||
import 'package:solian/screens/account.dart';
|
import 'package:solian/screens/account.dart';
|
||||||
@ -102,10 +101,14 @@ abstract class AppRouter {
|
|||||||
GoRoute(
|
GoRoute(
|
||||||
path: '/chat/:alias/detail',
|
path: '/chat/:alias/detail',
|
||||||
name: 'channelDetail',
|
name: 'channelDetail',
|
||||||
builder: (context, state) => ChannelDetailScreen(
|
builder: (context, state) {
|
||||||
channel: state.extra as Channel,
|
final arguments = state.extra as ChannelDetailArguments;
|
||||||
|
return ChannelDetailScreen(
|
||||||
|
channel: arguments.channel,
|
||||||
|
profile: arguments.profile,
|
||||||
realm: state.uri.queryParameters['realm'] ?? 'global',
|
realm: state.uri.queryParameters['realm'] ?? 'global',
|
||||||
),
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -33,7 +33,6 @@ class _NotificationScreenState extends State<NotificationScreen> {
|
|||||||
|
|
||||||
if (markList.isNotEmpty) {
|
if (markList.isNotEmpty) {
|
||||||
final client = auth.configureClient(service: 'passport');
|
final client = auth.configureClient(service: 'passport');
|
||||||
|
|
||||||
await client.put('/api/notifications/batch/read', {'messages': markList});
|
await client.put('/api/notifications/batch/read', {'messages': markList});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,6 +128,7 @@ class _NotificationScreenState extends State<NotificationScreen> {
|
|||||||
),
|
),
|
||||||
title: Text(element.subject),
|
title: Text(element.subject),
|
||||||
subtitle: Column(
|
subtitle: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(element.content),
|
Text(element.content),
|
||||||
if (element.links != null)
|
if (element.links != null)
|
||||||
|
@ -25,6 +25,7 @@ class _SignInPopupState extends State<SignInPopup> {
|
|||||||
if (username.isEmpty || password.isEmpty) return;
|
if (username.isEmpty || password.isEmpty) return;
|
||||||
provider.signin(context, username, password).then((_) async {
|
provider.signin(context, username, password).then((_) async {
|
||||||
await showDialog(
|
await showDialog(
|
||||||
|
useRootNavigator: true,
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) => const PushNotifyRegisterDialog(),
|
builder: (context) => const PushNotifyRegisterDialog(),
|
||||||
);
|
);
|
||||||
|
@ -55,6 +55,7 @@ class _CallScreenState extends State<CallScreen> {
|
|||||||
color: Theme.of(context).colorScheme.surface,
|
color: Theme.of(context).colorScheme.surface,
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
|
centerTitle: true,
|
||||||
title: RichText(
|
title: RichText(
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
text: TextSpan(children: [
|
text: TextSpan(children: [
|
||||||
|
@ -15,6 +15,7 @@ import 'package:solian/providers/chat.dart';
|
|||||||
import 'package:solian/providers/content/call.dart';
|
import 'package:solian/providers/content/call.dart';
|
||||||
import 'package:solian/providers/content/channel.dart';
|
import 'package:solian/providers/content/channel.dart';
|
||||||
import 'package:solian/router.dart';
|
import 'package:solian/router.dart';
|
||||||
|
import 'package:solian/screens/channel/channel_detail.dart';
|
||||||
import 'package:solian/theme.dart';
|
import 'package:solian/theme.dart';
|
||||||
import 'package:solian/widgets/chat/call/call_prejoin.dart';
|
import 'package:solian/widgets/chat/call/call_prejoin.dart';
|
||||||
import 'package:solian/widgets/chat/call/chat_call_action.dart';
|
import 'package:solian/widgets/chat/call/chat_call_action.dart';
|
||||||
@ -44,6 +45,7 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
|
|||||||
String? _overrideAlias;
|
String? _overrideAlias;
|
||||||
|
|
||||||
Channel? _channel;
|
Channel? _channel;
|
||||||
|
ChannelMember? _channelProfile;
|
||||||
Call? _ongoingCall;
|
Call? _ongoingCall;
|
||||||
StreamSubscription<NetworkPackage>? _subscription;
|
StreamSubscription<NetworkPackage>? _subscription;
|
||||||
|
|
||||||
@ -61,16 +63,21 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
|
|||||||
|
|
||||||
setState(() => _isBusy = true);
|
setState(() => _isBusy = true);
|
||||||
|
|
||||||
if (overrideAlias != null) {
|
if (overrideAlias != null) _overrideAlias = overrideAlias;
|
||||||
_overrideAlias = overrideAlias;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final resp = await provider.getChannel(
|
final resp = await provider.getChannel(
|
||||||
_overrideAlias ?? widget.alias,
|
_overrideAlias ?? widget.alias,
|
||||||
realm: widget.realm,
|
realm: widget.realm,
|
||||||
);
|
);
|
||||||
setState(() => _channel = Channel.fromJson(resp.body));
|
final respProfile = await provider.getMyChannelProfile(
|
||||||
|
_overrideAlias ?? widget.alias,
|
||||||
|
realm: widget.realm,
|
||||||
|
);
|
||||||
|
setState(() {
|
||||||
|
_channel = Channel.fromJson(resp.body);
|
||||||
|
_channelProfile = ChannelMember.fromJson(respProfile.body);
|
||||||
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
context.showErrorDialog(e);
|
context.showErrorDialog(e);
|
||||||
}
|
}
|
||||||
@ -192,7 +199,7 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
|
|||||||
Message? _messageToReplying;
|
Message? _messageToReplying;
|
||||||
Message? _messageToEditing;
|
Message? _messageToEditing;
|
||||||
|
|
||||||
Widget buildHistory(context, item, index) {
|
Widget buildHistory(context, Message item, index) {
|
||||||
bool isMerged = false, hasMerged = false;
|
bool isMerged = false, hasMerged = false;
|
||||||
if (index > 0) {
|
if (index > 0) {
|
||||||
hasMerged = checkMessageMergeable(
|
hasMerged = checkMessageMergeable(
|
||||||
@ -212,8 +219,8 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
|
|||||||
content = Column(
|
content = Column(
|
||||||
children: [
|
children: [
|
||||||
ChatMessage(
|
ChatMessage(
|
||||||
key: Key('m${item.replyTo.uuid}'),
|
key: Key('m${item.replyTo!.uuid}'),
|
||||||
item: item.replyTo,
|
item: item.replyTo!,
|
||||||
isReply: true,
|
isReply: true,
|
||||||
).paddingOnly(left: 24, right: 4, bottom: 2),
|
).paddingOnly(left: 24, right: 4, bottom: 2),
|
||||||
ChatMessage(
|
ChatMessage(
|
||||||
@ -273,8 +280,11 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
if (_isBusy || _channel == null) {
|
if (_isBusy || _channel == null) {
|
||||||
return const Center(
|
return Material(
|
||||||
|
color: Theme.of(context).colorScheme.surface,
|
||||||
|
child: const Center(
|
||||||
child: CircularProgressIndicator(),
|
child: CircularProgressIndicator(),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -315,7 +325,10 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
|
|||||||
'channelDetail',
|
'channelDetail',
|
||||||
pathParameters: {'alias': widget.alias},
|
pathParameters: {'alias': widget.alias},
|
||||||
queryParameters: {'realm': widget.realm},
|
queryParameters: {'realm': widget.realm},
|
||||||
extra: _channel,
|
extra: ChannelDetailArguments(
|
||||||
|
profile: _channelProfile!,
|
||||||
|
channel: _channel!,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
.then((value) {
|
.then((value) {
|
||||||
if (value == false) AppRouter.instance.pop();
|
if (value == false) AppRouter.instance.pop();
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
|
import 'package:dropdown_button2/dropdown_button2.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:solian/exts.dart';
|
||||||
import 'package:solian/models/channel.dart';
|
import 'package:solian/models/channel.dart';
|
||||||
import 'package:solian/providers/auth.dart';
|
import 'package:solian/providers/auth.dart';
|
||||||
import 'package:solian/router.dart';
|
import 'package:solian/router.dart';
|
||||||
@ -8,14 +10,23 @@ import 'package:solian/screens/channel/channel_organize.dart';
|
|||||||
import 'package:solian/widgets/channel/channel_deletion.dart';
|
import 'package:solian/widgets/channel/channel_deletion.dart';
|
||||||
import 'package:solian/widgets/channel/channel_member.dart';
|
import 'package:solian/widgets/channel/channel_member.dart';
|
||||||
|
|
||||||
|
class ChannelDetailArguments {
|
||||||
|
final Channel channel;
|
||||||
|
final ChannelMember profile;
|
||||||
|
|
||||||
|
ChannelDetailArguments({required this.channel, required this.profile});
|
||||||
|
}
|
||||||
|
|
||||||
class ChannelDetailScreen extends StatefulWidget {
|
class ChannelDetailScreen extends StatefulWidget {
|
||||||
final String realm;
|
final String realm;
|
||||||
final Channel channel;
|
final Channel channel;
|
||||||
|
final ChannelMember profile;
|
||||||
|
|
||||||
const ChannelDetailScreen({
|
const ChannelDetailScreen({
|
||||||
super.key,
|
super.key,
|
||||||
required this.channel,
|
required this.channel,
|
||||||
required this.realm,
|
required this.realm,
|
||||||
|
required this.profile,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -23,7 +34,10 @@ class ChannelDetailScreen extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _ChannelDetailScreenState extends State<ChannelDetailScreen> {
|
class _ChannelDetailScreenState extends State<ChannelDetailScreen> {
|
||||||
|
bool _isBusy = false;
|
||||||
|
|
||||||
bool _isOwned = false;
|
bool _isOwned = false;
|
||||||
|
int _notifyLevel = 0;
|
||||||
|
|
||||||
void checkOwner() async {
|
void checkOwner() async {
|
||||||
final AuthProvider auth = Get.find();
|
final AuthProvider auth = Get.find();
|
||||||
@ -59,15 +73,43 @@ class _ChannelDetailScreenState extends State<ChannelDetailScreen> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void applyProfileChanges() async {
|
||||||
|
final AuthProvider auth = Get.find();
|
||||||
|
if (!await auth.isAuthorized) return;
|
||||||
|
|
||||||
|
setState(() => _isBusy = true);
|
||||||
|
|
||||||
|
final client = auth.configureClient(service: 'messaging');
|
||||||
|
|
||||||
|
final resp = await client
|
||||||
|
.put('/api/channels/${widget.realm}/${widget.channel.alias}/members/me', {
|
||||||
|
'nick': null,
|
||||||
|
'notify_level': _notifyLevel,
|
||||||
|
});
|
||||||
|
if (resp.statusCode != 200) {
|
||||||
|
context.showErrorDialog(resp.bodyString);
|
||||||
|
} else {
|
||||||
|
context.showSnackbar('channelNotifyLevelApplied'.tr);
|
||||||
|
}
|
||||||
|
|
||||||
|
setState(() => _isBusy = false);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
_notifyLevel = widget.profile.notify;
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
checkOwner();
|
checkOwner();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final notifyTypes = {
|
||||||
|
0: 'channelNotifyLevelAll'.tr,
|
||||||
|
1: 'channelNotifyLevelMentioned'.tr,
|
||||||
|
2: 'channelNotifyLevelNone'.tr,
|
||||||
|
};
|
||||||
|
|
||||||
final ownerActions = [
|
final ownerActions = [
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: const Icon(Icons.edit),
|
leading: const Icon(Icons.edit),
|
||||||
@ -127,9 +169,38 @@ class _ChannelDetailScreenState extends State<ChannelDetailScreen> {
|
|||||||
child: ListView(
|
child: ListView(
|
||||||
children: [
|
children: [
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: const Icon(Icons.settings),
|
leading: const Icon(Icons.notifications_active),
|
||||||
trailing: const Icon(Icons.chevron_right),
|
title: Text('channelNotifyLevel'.tr.capitalize!),
|
||||||
title: Text('channelSettings'.tr.capitalize!),
|
trailing: DropdownButtonHideUnderline(
|
||||||
|
child: DropdownButton2<int>(
|
||||||
|
isExpanded: true,
|
||||||
|
items: notifyTypes.entries
|
||||||
|
.map((item) => DropdownMenuItem<int>(
|
||||||
|
enabled: !_isBusy,
|
||||||
|
value: item.key,
|
||||||
|
child: Text(
|
||||||
|
item.value,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
))
|
||||||
|
.toList(),
|
||||||
|
value: _notifyLevel,
|
||||||
|
onChanged: (int? value) {
|
||||||
|
setState(() => _notifyLevel = value ?? 0);
|
||||||
|
applyProfileChanges();
|
||||||
|
},
|
||||||
|
buttonStyleData: const ButtonStyleData(
|
||||||
|
padding: EdgeInsets.only(left: 16, right: 1),
|
||||||
|
height: 40,
|
||||||
|
width: 140,
|
||||||
|
),
|
||||||
|
menuItemStyleData: const MenuItemStyleData(
|
||||||
|
height: 40,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: const Icon(Icons.supervisor_account),
|
leading: const Icon(Icons.supervisor_account),
|
||||||
|
@ -119,6 +119,9 @@ class SolianMessages extends Translations {
|
|||||||
'realmAdjust': 'Realm adjustment',
|
'realmAdjust': 'Realm adjustment',
|
||||||
'realmSettings': 'Realm settings',
|
'realmSettings': 'Realm settings',
|
||||||
'realmEditingNotify': 'You\'re editing realm @realm',
|
'realmEditingNotify': 'You\'re editing realm @realm',
|
||||||
|
'realmLeaveConfirm': 'Confirm realm quit',
|
||||||
|
'realmLeaveConfirmCaption':
|
||||||
|
'Are you sure you want leave realm @realm? Your content published in this realm will not be deleted.',
|
||||||
'realmDeletionConfirm': 'Confirm realm deletion',
|
'realmDeletionConfirm': 'Confirm realm deletion',
|
||||||
'realmDeletionConfirmCaption':
|
'realmDeletionConfirmCaption':
|
||||||
'Are you sure to delete realm @realm? This action cannot be undone!',
|
'Are you sure to delete realm @realm? This action cannot be undone!',
|
||||||
@ -145,11 +148,19 @@ class SolianMessages extends Translations {
|
|||||||
'channelAdjust': 'Channel adjustment',
|
'channelAdjust': 'Channel adjustment',
|
||||||
'channelDetail': 'Channel detail',
|
'channelDetail': 'Channel detail',
|
||||||
'channelSettings': 'Channel settings',
|
'channelSettings': 'Channel settings',
|
||||||
|
'channelLeaveConfirm': 'Confirm channel quit',
|
||||||
|
'channelLeaveConfirmCaption':
|
||||||
|
'Are you sure to leave channel @channel? All your messages will be deleted!',
|
||||||
'channelDeletionConfirm': 'Confirm channel deletion',
|
'channelDeletionConfirm': 'Confirm channel deletion',
|
||||||
'channelDeletionConfirmCaption':
|
'channelDeletionConfirmCaption':
|
||||||
'Are you sure to delete channel @channel? This action cannot be undone!',
|
'Are you sure to delete channel @channel? This action cannot be undone!',
|
||||||
'channelCategoryDirect': 'DM',
|
'channelCategoryDirect': 'DM',
|
||||||
'channelCategoryDirectHint': 'Your direct messages',
|
'channelCategoryDirectHint': 'Your direct messages',
|
||||||
|
'channelNotifyLevel': 'Notify level',
|
||||||
|
'channelNotifyLevelAll': 'All',
|
||||||
|
'channelNotifyLevelMentioned': 'Only mentioned',
|
||||||
|
'channelNotifyLevelNone': 'Ignore all',
|
||||||
|
'channelNotifyLevelApplied': 'Your notification settings has been applied.',
|
||||||
'messageDecoding': 'Decoding...',
|
'messageDecoding': 'Decoding...',
|
||||||
'messageDecodeFailed': 'Unable to decode: @message',
|
'messageDecodeFailed': 'Unable to decode: @message',
|
||||||
'messageInputPlaceholder': 'Message @channel',
|
'messageInputPlaceholder': 'Message @channel',
|
||||||
@ -309,6 +320,8 @@ class SolianMessages extends Translations {
|
|||||||
'realmAdjust': '调整领域',
|
'realmAdjust': '调整领域',
|
||||||
'realmSettings': '领域设置',
|
'realmSettings': '领域设置',
|
||||||
'realmEditingNotify': '你正在编辑领域 @realm',
|
'realmEditingNotify': '你正在编辑领域 @realm',
|
||||||
|
'realmLeaveConfirm': '确认离开领域',
|
||||||
|
'realmLeaveConfirmCaption': '你确认要离开领域 @realm 吗?你在该领域发表的内容不会被删除。',
|
||||||
'realmDeletionConfirm': '确认删除领域',
|
'realmDeletionConfirm': '确认删除领域',
|
||||||
'realmDeletionConfirmCaption': '你确定要删除领域 @realm 嘛?该操作不可撤销。',
|
'realmDeletionConfirmCaption': '你确定要删除领域 @realm 嘛?该操作不可撤销。',
|
||||||
'channelNew': '创建新频道',
|
'channelNew': '创建新频道',
|
||||||
@ -334,10 +347,17 @@ class SolianMessages extends Translations {
|
|||||||
'channelAdjust': '调整频道',
|
'channelAdjust': '调整频道',
|
||||||
'channelDetail': '频道详情',
|
'channelDetail': '频道详情',
|
||||||
'channelSettings': '频道设置',
|
'channelSettings': '频道设置',
|
||||||
|
'channelLeaveConfirm': '确认离开频道',
|
||||||
|
'channelLeaveConfirmCaption': '你确认要离开频道 @channel 吗?你在这个频道的消息将被删除。',
|
||||||
'channelDeletionConfirm': '确认删除频道',
|
'channelDeletionConfirm': '确认删除频道',
|
||||||
'channelDeletionConfirmCaption': '你确认要删除频道 @channel 吗?该操作不可撤销。',
|
'channelDeletionConfirmCaption': '你确认要删除频道 @channel 吗?该操作不可撤销。',
|
||||||
'channelCategoryDirect': '私聊频道',
|
'channelCategoryDirect': '私聊频道',
|
||||||
'channelCategoryDirectHint': '你的所有私聊频道',
|
'channelCategoryDirectHint': '你的所有私聊频道',
|
||||||
|
'channelNotifyLevel': '通知等级',
|
||||||
|
'channelNotifyLevelAll': '全部通知',
|
||||||
|
'channelNotifyLevelMentioned': '仅提及',
|
||||||
|
'channelNotifyLevelNone': '忽略一切',
|
||||||
|
'channelNotifyLevelApplied': '你的通知设置已经应用。',
|
||||||
'messageDecoding': '解码信息中…',
|
'messageDecoding': '解码信息中…',
|
||||||
'messageDecodeFailed': '解码信息失败:@message',
|
'messageDecodeFailed': '解码信息失败:@message',
|
||||||
'messageInputPlaceholder': '在 @channel 发信息',
|
'messageInputPlaceholder': '在 @channel 发信息',
|
||||||
|
@ -65,9 +65,14 @@ class _ChannelDeletionDialogState extends State<ChannelDeletionDialog> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
title: Text('channelDeletionConfirm'.tr),
|
title: Text(widget.isOwned
|
||||||
|
? 'channelDeletionConfirm'.tr
|
||||||
|
: 'channelLeaveConfirm'.tr),
|
||||||
content: Text(
|
content: Text(
|
||||||
|
widget.isOwned ?
|
||||||
'channelDeletionConfirmCaption'
|
'channelDeletionConfirmCaption'
|
||||||
|
.trParams({'channel': '#${widget.channel.alias}'}) :
|
||||||
|
'channelLeaveConfirmCaption'
|
||||||
.trParams({'channel': '#${widget.channel.alias}'}),
|
.trParams({'channel': '#${widget.channel.alias}'}),
|
||||||
),
|
),
|
||||||
actions: <Widget>[
|
actions: <Widget>[
|
||||||
|
@ -113,7 +113,7 @@ class _ChatMessageInputState extends State<ChatMessageInput> {
|
|||||||
Response resp;
|
Response resp;
|
||||||
if (_editTo != null) {
|
if (_editTo != null) {
|
||||||
resp = await client.put(
|
resp = await client.put(
|
||||||
'/api/channels/${widget.realm}/${widget.channel.alias}/messages/${widget.edit!.id}',
|
'/api/channels/${widget.realm}/${widget.channel.alias}/messages/${_editTo!.id}',
|
||||||
payload,
|
payload,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@ -171,6 +171,11 @@ class _ChatMessageInputState extends State<ChatMessageInput> {
|
|||||||
MaterialBanner(
|
MaterialBanner(
|
||||||
leading: const FaIcon(FontAwesomeIcons.reply, size: 18),
|
leading: const FaIcon(FontAwesomeIcons.reply, size: 18),
|
||||||
dividerColor: Colors.transparent,
|
dividerColor: Colors.transparent,
|
||||||
|
padding: const EdgeInsets.only(left: 20),
|
||||||
|
backgroundColor: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.surfaceContainerHighest
|
||||||
|
.withOpacity(0.5),
|
||||||
content: ChatMessage(
|
content: ChatMessage(
|
||||||
item: _replyTo!,
|
item: _replyTo!,
|
||||||
isContentPreviewing: true,
|
isContentPreviewing: true,
|
||||||
@ -181,6 +186,11 @@ class _ChatMessageInputState extends State<ChatMessageInput> {
|
|||||||
MaterialBanner(
|
MaterialBanner(
|
||||||
leading: const Icon(Icons.edit),
|
leading: const Icon(Icons.edit),
|
||||||
dividerColor: Colors.transparent,
|
dividerColor: Colors.transparent,
|
||||||
|
padding: const EdgeInsets.only(left: 20),
|
||||||
|
backgroundColor: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.surfaceContainerHighest
|
||||||
|
.withOpacity(0.5),
|
||||||
content: ChatMessage(
|
content: ChatMessage(
|
||||||
item: _editTo!,
|
item: _editTo!,
|
||||||
isContentPreviewing: true,
|
isContentPreviewing: true,
|
||||||
|
@ -61,9 +61,14 @@ class _RealmDeletionDialogState extends State<RealmDeletionDialog> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
title: Text('realmDeletionConfirm'.tr),
|
title: Text(widget.isOwned
|
||||||
|
? 'realmDeletionConfirm'.tr
|
||||||
|
: 'channelLeaveConfirm'.tr),
|
||||||
content: Text(
|
content: Text(
|
||||||
'realmDeletionConfirmCaption'
|
widget.isOwned
|
||||||
|
? 'realmDeletionConfirmCaption'
|
||||||
|
.trParams({'realm': '#${widget.realm.alias}'})
|
||||||
|
: 'realmLeaveConfirmCaption'
|
||||||
.trParams({'realm': '#${widget.realm.alias}'}),
|
.trParams({'realm': '#${widget.realm.alias}'}),
|
||||||
),
|
),
|
||||||
actions: <Widget>[
|
actions: <Widget>[
|
||||||
|
Loading…
Reference in New Issue
Block a user