💄 Improve UX

This commit is contained in:
LittleSheep 2024-04-25 21:33:53 +08:00
parent 3a2894b533
commit 0230ea5c79
12 changed files with 140 additions and 51 deletions

View File

@ -53,6 +53,9 @@
"chatNew": "New Chat",
"chatNewCreate": "Create a channel",
"chatNewJoin": "Join a exists channel",
"chatManage": "Manage Chat",
"chatMember": "Member",
"chatNotifySetting": "Notify Settings",
"chatChannelUsage": "Channel",
"chatChannelUsageCaption": "Channel is place to talk with people, one or a lot.",
"chatChannelOrganize": "Organize a channel",

View File

@ -51,6 +51,9 @@
"reactionAdded": "你的反应已被添加。",
"reactionRemoved": "你的反应已被移除。",
"chatNew": "新聊天",
"chatManage": "管理聊天",
"chatMember": "成员",
"chatNotifySetting": "通知设定",
"chatNewCreate": "新建频道",
"chatNewJoin": "加入已有频道",
"chatChannelUsage": "频道",

View File

@ -1,3 +1,5 @@
import 'package:solian/models/account.dart';
class Channel {
int id;
DateTime createdAt;
@ -7,9 +9,9 @@ class Channel {
String name;
String description;
dynamic members;
dynamic messages;
dynamic calls;
int type;
Account account;
int accountId;
int realmId;
@ -22,9 +24,9 @@ class Channel {
required this.name,
required this.description,
this.members,
this.messages,
this.calls,
required this.type,
required this.account,
required this.accountId,
required this.realmId,
});
@ -38,9 +40,9 @@ class Channel {
name: json["name"],
description: json["description"],
members: json["members"],
messages: json["messages"],
calls: json["calls"],
type: json["type"],
account: Account.fromJson(json["account"]),
accountId: json["account_id"],
realmId: json["realm_id"],
);
@ -54,9 +56,9 @@ class Channel {
"name": name,
"description": description,
"members": members,
"messages": messages,
"calls": calls,
"type": type,
"account": account,
"account_id": accountId,
"realm_id": realmId,
};

View File

@ -13,7 +13,7 @@ class ChatProvider {
await auth.refreshToken();
var ori = getRequestUri('messaging', '/api/unified');
var ori = getRequestUri('messaging', '/api/ws');
var uri = Uri(
scheme: ori.scheme.replaceFirst('http', 'ws'),
host: ori.host,

View File

@ -4,13 +4,14 @@ import 'package:solian/models/post.dart';
import 'package:solian/screens/account.dart';
import 'package:solian/screens/chat/chat.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/notification.dart';
import 'package:solian/screens/posts/comment_editor.dart';
import 'package:solian/screens/posts/moment_editor.dart';
import 'package:solian/screens/posts/screen.dart';
import 'package:solian/screens/signin.dart';
import 'package:solian/widgets/chat/channel_editor.dart';
final router = GoRouter(
routes: [
@ -27,13 +28,18 @@ final router = GoRouter(
GoRoute(
path: '/chat/create',
name: 'chat.channel.editor',
builder: (context, state) => ChannelEditor(editing: state.extra as Channel?),
builder: (context, state) => ChannelEditorScreen(editing: state.extra as Channel?),
),
GoRoute(
path: '/chat/c/:channel',
name: 'chat.channel',
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(
path: '/account',
name: 'account',

View File

@ -12,16 +12,16 @@ import 'package:solian/widgets/indent_wrapper.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:uuid/uuid.dart';
class ChannelEditor extends StatefulWidget {
class ChannelEditorScreen extends StatefulWidget {
final Channel? editing;
const ChannelEditor({super.key, this.editing});
const ChannelEditorScreen({super.key, this.editing});
@override
State<ChannelEditor> createState() => _ChannelEditorState();
State<ChannelEditorScreen> createState() => _ChannelEditorScreenState();
}
class _ChannelEditorState extends State<ChannelEditor> {
class _ChannelEditorScreenState extends State<ChannelEditorScreen> {
final _aliasController = TextEditingController();
final _nameController = TextEditingController();
final _descriptionController = TextEditingController();

View File

@ -9,6 +9,7 @@ import 'package:solian/utils/service_url.dart';
import 'package:solian/widgets/chat/chat_new.dart';
import 'package:solian/widgets/indent_wrapper.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:solian/widgets/notification_notifier.dart';
import 'package:solian/widgets/signin_required.dart';
class ChatIndexScreen extends StatefulWidget {
@ -63,6 +64,7 @@ class _ChatIndexScreenState extends State<ChatIndexScreen> {
return IndentWrapper(
title: AppLocalizations.of(context)!.chat,
appBarActions: const [NotificationButton()],
floatingActionButton: FutureBuilder(
future: auth.isAuthorized(),
builder: (context, snapshot) {

View 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()),
],
),
),
],
),
);
}
}

View File

@ -23,6 +23,7 @@ class _NotificationScreenState extends State<NotificationScreen> {
return IndentWrapper(
noSafeArea: true,
hideDrawer: true,
title: AppLocalizations.of(context)!.notification,
child: RefreshIndicator(
onRefresh: () => nty.fetch(auth),

View File

@ -1,5 +1,4 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:solian/models/channel.dart';
import 'package:solian/router.dart';
@ -13,41 +12,17 @@ class ChannelAction extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Column(
children: [
MenuAnchor(
menuChildren: [
MenuItemButton(
child: Row(
children: [
const Icon(Icons.settings),
const SizedBox(width: 12),
Text(AppLocalizations.of(context)!.settings),
],
),
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();
}
router.pushNamed(
'chat.channel.manage',
extra: channel,
pathParameters: {'channel': channel.alias},
);
},
focusNode: _focusNode,
style: TextButton.styleFrom(shape: const CircleBorder()),
icon: const Icon(Icons.more_horiz),
);
},
),
],
);
}
}

View File

@ -28,6 +28,8 @@ class ChatMaintainer extends StatefulWidget {
class _ChatMaintainerState extends State<ChatMaintainer> {
void connect() {
ScaffoldMessenger.of(context).clearSnackBars();
final notify = ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(AppLocalizations.of(context)!.connectingServer),
@ -73,8 +75,6 @@ class _ChatMaintainerState extends State<ChatMaintainer> {
@override
Widget build(BuildContext context) {
ScaffoldMessenger.of(context).clearSnackBars();
return widget.child;
}
}

View File

@ -1,6 +1,7 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_animate/flutter_animate.dart';
import 'package:provider/provider.dart';
import 'package:solian/models/reaction.dart';
import 'package:solian/providers/auth.dart';
@ -106,7 +107,7 @@ class _ReactionActionPopupState extends State<ReactionActionPopup> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
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(
padding: const EdgeInsets.symmetric(
horizontal: 8,
@ -118,7 +119,7 @@ class _ReactionActionPopupState extends State<ReactionActionPopup> {
),
),
),
_isSubmitting ? const LinearProgressIndicator() : Container(),
_isSubmitting ? const LinearProgressIndicator().animate().scaleX() : Container(),
Expanded(
child: ListView.builder(
itemCount: reactions.length,