💄 Improve UX
This commit is contained in:
parent
3a2894b533
commit
0230ea5c79
@ -53,6 +53,9 @@
|
|||||||
"chatNew": "New Chat",
|
"chatNew": "New Chat",
|
||||||
"chatNewCreate": "Create a channel",
|
"chatNewCreate": "Create a channel",
|
||||||
"chatNewJoin": "Join a exists channel",
|
"chatNewJoin": "Join a exists channel",
|
||||||
|
"chatManage": "Manage Chat",
|
||||||
|
"chatMember": "Member",
|
||||||
|
"chatNotifySetting": "Notify Settings",
|
||||||
"chatChannelUsage": "Channel",
|
"chatChannelUsage": "Channel",
|
||||||
"chatChannelUsageCaption": "Channel is place to talk with people, one or a lot.",
|
"chatChannelUsageCaption": "Channel is place to talk with people, one or a lot.",
|
||||||
"chatChannelOrganize": "Organize a channel",
|
"chatChannelOrganize": "Organize a channel",
|
||||||
|
@ -51,6 +51,9 @@
|
|||||||
"reactionAdded": "你的反应已被添加。",
|
"reactionAdded": "你的反应已被添加。",
|
||||||
"reactionRemoved": "你的反应已被移除。",
|
"reactionRemoved": "你的反应已被移除。",
|
||||||
"chatNew": "新聊天",
|
"chatNew": "新聊天",
|
||||||
|
"chatManage": "管理聊天",
|
||||||
|
"chatMember": "成员",
|
||||||
|
"chatNotifySetting": "通知设定",
|
||||||
"chatNewCreate": "新建频道",
|
"chatNewCreate": "新建频道",
|
||||||
"chatNewJoin": "加入已有频道",
|
"chatNewJoin": "加入已有频道",
|
||||||
"chatChannelUsage": "频道",
|
"chatChannelUsage": "频道",
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import 'package:solian/models/account.dart';
|
||||||
|
|
||||||
class Channel {
|
class Channel {
|
||||||
int id;
|
int id;
|
||||||
DateTime createdAt;
|
DateTime createdAt;
|
||||||
@ -7,9 +9,9 @@ class Channel {
|
|||||||
String name;
|
String name;
|
||||||
String description;
|
String description;
|
||||||
dynamic members;
|
dynamic members;
|
||||||
dynamic messages;
|
|
||||||
dynamic calls;
|
dynamic calls;
|
||||||
int type;
|
int type;
|
||||||
|
Account account;
|
||||||
int accountId;
|
int accountId;
|
||||||
int realmId;
|
int realmId;
|
||||||
|
|
||||||
@ -22,9 +24,9 @@ class Channel {
|
|||||||
required this.name,
|
required this.name,
|
||||||
required this.description,
|
required this.description,
|
||||||
this.members,
|
this.members,
|
||||||
this.messages,
|
|
||||||
this.calls,
|
this.calls,
|
||||||
required this.type,
|
required this.type,
|
||||||
|
required this.account,
|
||||||
required this.accountId,
|
required this.accountId,
|
||||||
required this.realmId,
|
required this.realmId,
|
||||||
});
|
});
|
||||||
@ -38,9 +40,9 @@ class Channel {
|
|||||||
name: json["name"],
|
name: json["name"],
|
||||||
description: json["description"],
|
description: json["description"],
|
||||||
members: json["members"],
|
members: json["members"],
|
||||||
messages: json["messages"],
|
|
||||||
calls: json["calls"],
|
calls: json["calls"],
|
||||||
type: json["type"],
|
type: json["type"],
|
||||||
|
account: Account.fromJson(json["account"]),
|
||||||
accountId: json["account_id"],
|
accountId: json["account_id"],
|
||||||
realmId: json["realm_id"],
|
realmId: json["realm_id"],
|
||||||
);
|
);
|
||||||
@ -54,9 +56,9 @@ class Channel {
|
|||||||
"name": name,
|
"name": name,
|
||||||
"description": description,
|
"description": description,
|
||||||
"members": members,
|
"members": members,
|
||||||
"messages": messages,
|
|
||||||
"calls": calls,
|
"calls": calls,
|
||||||
"type": type,
|
"type": type,
|
||||||
|
"account": account,
|
||||||
"account_id": accountId,
|
"account_id": accountId,
|
||||||
"realm_id": realmId,
|
"realm_id": realmId,
|
||||||
};
|
};
|
||||||
|
@ -13,7 +13,7 @@ class ChatProvider {
|
|||||||
|
|
||||||
await auth.refreshToken();
|
await auth.refreshToken();
|
||||||
|
|
||||||
var ori = getRequestUri('messaging', '/api/unified');
|
var ori = getRequestUri('messaging', '/api/ws');
|
||||||
var uri = Uri(
|
var uri = Uri(
|
||||||
scheme: ori.scheme.replaceFirst('http', 'ws'),
|
scheme: ori.scheme.replaceFirst('http', 'ws'),
|
||||||
host: ori.host,
|
host: ori.host,
|
||||||
|
@ -4,13 +4,14 @@ import 'package:solian/models/post.dart';
|
|||||||
import 'package:solian/screens/account.dart';
|
import 'package:solian/screens/account.dart';
|
||||||
import 'package:solian/screens/chat/chat.dart';
|
import 'package:solian/screens/chat/chat.dart';
|
||||||
import 'package:solian/screens/chat/index.dart';
|
import 'package:solian/screens/chat/index.dart';
|
||||||
|
import 'package:solian/screens/chat/manage.dart';
|
||||||
|
import 'package:solian/screens/chat/channel/channel_editor.dart';
|
||||||
import 'package:solian/screens/explore.dart';
|
import 'package:solian/screens/explore.dart';
|
||||||
import 'package:solian/screens/notification.dart';
|
import 'package:solian/screens/notification.dart';
|
||||||
import 'package:solian/screens/posts/comment_editor.dart';
|
import 'package:solian/screens/posts/comment_editor.dart';
|
||||||
import 'package:solian/screens/posts/moment_editor.dart';
|
import 'package:solian/screens/posts/moment_editor.dart';
|
||||||
import 'package:solian/screens/posts/screen.dart';
|
import 'package:solian/screens/posts/screen.dart';
|
||||||
import 'package:solian/screens/signin.dart';
|
import 'package:solian/screens/signin.dart';
|
||||||
import 'package:solian/widgets/chat/channel_editor.dart';
|
|
||||||
|
|
||||||
final router = GoRouter(
|
final router = GoRouter(
|
||||||
routes: [
|
routes: [
|
||||||
@ -27,13 +28,18 @@ final router = GoRouter(
|
|||||||
GoRoute(
|
GoRoute(
|
||||||
path: '/chat/create',
|
path: '/chat/create',
|
||||||
name: 'chat.channel.editor',
|
name: 'chat.channel.editor',
|
||||||
builder: (context, state) => ChannelEditor(editing: state.extra as Channel?),
|
builder: (context, state) => ChannelEditorScreen(editing: state.extra as Channel?),
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: '/chat/c/:channel',
|
path: '/chat/c/:channel',
|
||||||
name: 'chat.channel',
|
name: 'chat.channel',
|
||||||
builder: (context, state) => ChatScreen(alias: state.pathParameters['channel'] as String),
|
builder: (context, state) => ChatScreen(alias: state.pathParameters['channel'] as String),
|
||||||
),
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: '/chat/c/:channel/manage',
|
||||||
|
name: 'chat.channel.manage',
|
||||||
|
builder: (context, state) => ChatManageScreen(channel: state.extra as Channel),
|
||||||
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: '/account',
|
path: '/account',
|
||||||
name: 'account',
|
name: 'account',
|
||||||
|
@ -12,16 +12,16 @@ import 'package:solian/widgets/indent_wrapper.dart';
|
|||||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
import 'package:uuid/uuid.dart';
|
import 'package:uuid/uuid.dart';
|
||||||
|
|
||||||
class ChannelEditor extends StatefulWidget {
|
class ChannelEditorScreen extends StatefulWidget {
|
||||||
final Channel? editing;
|
final Channel? editing;
|
||||||
|
|
||||||
const ChannelEditor({super.key, this.editing});
|
const ChannelEditorScreen({super.key, this.editing});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<ChannelEditor> createState() => _ChannelEditorState();
|
State<ChannelEditorScreen> createState() => _ChannelEditorScreenState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ChannelEditorState extends State<ChannelEditor> {
|
class _ChannelEditorScreenState extends State<ChannelEditorScreen> {
|
||||||
final _aliasController = TextEditingController();
|
final _aliasController = TextEditingController();
|
||||||
final _nameController = TextEditingController();
|
final _nameController = TextEditingController();
|
||||||
final _descriptionController = TextEditingController();
|
final _descriptionController = TextEditingController();
|
@ -9,6 +9,7 @@ import 'package:solian/utils/service_url.dart';
|
|||||||
import 'package:solian/widgets/chat/chat_new.dart';
|
import 'package:solian/widgets/chat/chat_new.dart';
|
||||||
import 'package:solian/widgets/indent_wrapper.dart';
|
import 'package:solian/widgets/indent_wrapper.dart';
|
||||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
|
import 'package:solian/widgets/notification_notifier.dart';
|
||||||
import 'package:solian/widgets/signin_required.dart';
|
import 'package:solian/widgets/signin_required.dart';
|
||||||
|
|
||||||
class ChatIndexScreen extends StatefulWidget {
|
class ChatIndexScreen extends StatefulWidget {
|
||||||
@ -63,6 +64,7 @@ class _ChatIndexScreenState extends State<ChatIndexScreen> {
|
|||||||
|
|
||||||
return IndentWrapper(
|
return IndentWrapper(
|
||||||
title: AppLocalizations.of(context)!.chat,
|
title: AppLocalizations.of(context)!.chat,
|
||||||
|
appBarActions: const [NotificationButton()],
|
||||||
floatingActionButton: FutureBuilder(
|
floatingActionButton: FutureBuilder(
|
||||||
future: auth.isAuthorized(),
|
future: auth.isAuthorized(),
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
|
96
lib/screens/chat/manage.dart
Normal file
96
lib/screens/chat/manage.dart
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:solian/models/channel.dart';
|
||||||
|
import 'package:solian/providers/auth.dart';
|
||||||
|
import 'package:solian/router.dart';
|
||||||
|
import 'package:solian/widgets/indent_wrapper.dart';
|
||||||
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
|
|
||||||
|
class ChatManageScreen extends StatefulWidget {
|
||||||
|
final Channel channel;
|
||||||
|
|
||||||
|
const ChatManageScreen({super.key, required this.channel});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<ChatManageScreen> createState() => _ChatManageScreenState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ChatManageScreenState extends State<ChatManageScreen> {
|
||||||
|
bool isOwned = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
|
||||||
|
Future.delayed(Duration.zero, () async {
|
||||||
|
final auth = context.read<AuthProvider>();
|
||||||
|
final prof = await auth.getProfiles();
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
isOwned = prof['id'] == widget.channel.account.externalId;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final authorizedItems = [
|
||||||
|
ListTile(
|
||||||
|
leading: const Icon(Icons.settings),
|
||||||
|
title: Text(AppLocalizations.of(context)!.settings),
|
||||||
|
onTap: () async {
|
||||||
|
router.pushNamed('chat.channel.editor', extra: widget.channel).then((did) {
|
||||||
|
if (did == true) {
|
||||||
|
if (router.canPop()) router.pop(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
return IndentWrapper(
|
||||||
|
title: AppLocalizations.of(context)!.chatManage,
|
||||||
|
hideDrawer: true,
|
||||||
|
noSafeArea: true,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
const CircleAvatar(
|
||||||
|
radius: 24,
|
||||||
|
backgroundColor: Colors.teal,
|
||||||
|
child: Icon(Icons.tag, color: Colors.white),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 16),
|
||||||
|
Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||||||
|
Text(widget.channel.name, style: Theme.of(context).textTheme.bodyLarge),
|
||||||
|
Text(widget.channel.description, style: Theme.of(context).textTheme.bodySmall),
|
||||||
|
])
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Divider(thickness: 0.3),
|
||||||
|
Expanded(
|
||||||
|
child: ListView(
|
||||||
|
children: [
|
||||||
|
ListTile(
|
||||||
|
leading: const Icon(Icons.edit_notifications),
|
||||||
|
title: Text(AppLocalizations.of(context)!.chatNotifySetting),
|
||||||
|
onTap: () {},
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
leading: const Icon(Icons.supervisor_account),
|
||||||
|
title: Text(AppLocalizations.of(context)!.chatMember),
|
||||||
|
onTap: () {},
|
||||||
|
),
|
||||||
|
...(isOwned ? authorizedItems : List.empty()),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -23,6 +23,7 @@ class _NotificationScreenState extends State<NotificationScreen> {
|
|||||||
|
|
||||||
return IndentWrapper(
|
return IndentWrapper(
|
||||||
noSafeArea: true,
|
noSafeArea: true,
|
||||||
|
hideDrawer: true,
|
||||||
title: AppLocalizations.of(context)!.notification,
|
title: AppLocalizations.of(context)!.notification,
|
||||||
child: RefreshIndicator(
|
child: RefreshIndicator(
|
||||||
onRefresh: () => nty.fetch(auth),
|
onRefresh: () => nty.fetch(auth),
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
|
||||||
import 'package:solian/models/channel.dart';
|
import 'package:solian/models/channel.dart';
|
||||||
import 'package:solian/router.dart';
|
import 'package:solian/router.dart';
|
||||||
|
|
||||||
@ -13,41 +12,17 @@ class ChannelAction extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Column(
|
return IconButton(
|
||||||
children: [
|
onPressed: () {
|
||||||
MenuAnchor(
|
router.pushNamed(
|
||||||
menuChildren: [
|
'chat.channel.manage',
|
||||||
MenuItemButton(
|
extra: channel,
|
||||||
child: Row(
|
pathParameters: {'channel': channel.alias},
|
||||||
children: [
|
);
|
||||||
const Icon(Icons.settings),
|
},
|
||||||
const SizedBox(width: 12),
|
focusNode: _focusNode,
|
||||||
Text(AppLocalizations.of(context)!.settings),
|
style: TextButton.styleFrom(shape: const CircleBorder()),
|
||||||
],
|
icon: const Icon(Icons.more_horiz),
|
||||||
),
|
|
||||||
onPressed: () {
|
|
||||||
router.pushNamed('chat.channel.editor', extra: channel).then((did) {
|
|
||||||
if(did == true) onUpdate();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
builder: (BuildContext context, MenuController controller, Widget? child) {
|
|
||||||
return IconButton(
|
|
||||||
onPressed: () {
|
|
||||||
if (controller.isOpen) {
|
|
||||||
controller.close();
|
|
||||||
} else {
|
|
||||||
controller.open();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
focusNode: _focusNode,
|
|
||||||
style: TextButton.styleFrom(shape: const CircleBorder()),
|
|
||||||
icon: const Icon(Icons.more_horiz),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,8 @@ class ChatMaintainer extends StatefulWidget {
|
|||||||
|
|
||||||
class _ChatMaintainerState extends State<ChatMaintainer> {
|
class _ChatMaintainerState extends State<ChatMaintainer> {
|
||||||
void connect() {
|
void connect() {
|
||||||
|
ScaffoldMessenger.of(context).clearSnackBars();
|
||||||
|
|
||||||
final notify = ScaffoldMessenger.of(context).showSnackBar(
|
final notify = ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(
|
SnackBar(
|
||||||
content: Text(AppLocalizations.of(context)!.connectingServer),
|
content: Text(AppLocalizations.of(context)!.connectingServer),
|
||||||
@ -73,8 +75,6 @@ class _ChatMaintainerState extends State<ChatMaintainer> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
ScaffoldMessenger.of(context).clearSnackBars();
|
|
||||||
|
|
||||||
return widget.child;
|
return widget.child;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_animate/flutter_animate.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:solian/models/reaction.dart';
|
import 'package:solian/models/reaction.dart';
|
||||||
import 'package:solian/providers/auth.dart';
|
import 'package:solian/providers/auth.dart';
|
||||||
@ -106,7 +107,7 @@ class _ReactionActionPopupState extends State<ReactionActionPopup> {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
padding: const EdgeInsets.only(left: 8, right: 8, top: 20),
|
padding: const EdgeInsets.only(left: 8, right: 8, top: 20, bottom: 12),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
horizontal: 8,
|
horizontal: 8,
|
||||||
@ -118,7 +119,7 @@ class _ReactionActionPopupState extends State<ReactionActionPopup> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
_isSubmitting ? const LinearProgressIndicator() : Container(),
|
_isSubmitting ? const LinearProgressIndicator().animate().scaleX() : Container(),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ListView.builder(
|
child: ListView.builder(
|
||||||
itemCount: reactions.length,
|
itemCount: reactions.length,
|
||||||
|
Loading…
Reference in New Issue
Block a user