🐛 Bug fixes and optimization

This commit is contained in:
LittleSheep 2024-05-12 20:59:33 +08:00
parent 98547708af
commit 6f7ae4467c
8 changed files with 109 additions and 68 deletions

View File

@ -13,6 +13,7 @@ import 'package:solian/utils/timeago.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:solian/utils/video_player.dart'; import 'package:solian/utils/video_player.dart';
import 'package:solian/widgets/chat/call/call_overlay.dart'; import 'package:solian/widgets/chat/call/call_overlay.dart';
import 'package:solian/widgets/provider_init.dart';
void main() { void main() {
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
@ -52,7 +53,9 @@ class SolianApp extends StatelessWidget {
OverlayEntry(builder: (context) { OverlayEntry(builder: (context) {
return ScaffoldMessenger( return ScaffoldMessenger(
child: Scaffold( child: Scaffold(
body: child ?? Container(), body: ProviderInitializer(
child: child ?? Container(),
),
), ),
); );
}), }),

View File

@ -31,6 +31,8 @@ class ChatProvider extends ChangeNotifier {
PagingController<int, Message>? historyPagingController; PagingController<int, Message>? historyPagingController;
WebSocketChannel? _channel;
Future<WebSocketChannel?> connect(AuthProvider auth) async { Future<WebSocketChannel?> connect(AuthProvider auth) async {
if (auth.client == null) await auth.loadClient(); if (auth.client == null) await auth.loadClient();
if (!await auth.isAuthorized()) return null; if (!await auth.isAuthorized()) return null;
@ -46,11 +48,12 @@ class ChatProvider extends ChangeNotifier {
queryParameters: {'tk': Uri.encodeComponent(auth.client!.currentToken!)}, queryParameters: {'tk': Uri.encodeComponent(auth.client!.currentToken!)},
); );
final channel = WebSocketChannel.connect(uri);
isOpened = true; isOpened = true;
channel.stream.listen( _channel = WebSocketChannel.connect(uri);
await _channel!.ready;
_channel!.stream.listen(
(event) { (event) {
final result = NetworkPackage.fromJson(jsonDecode(event)); final result = NetworkPackage.fromJson(jsonDecode(event));
if (focusChannel == null || historyPagingController == null) return; if (focusChannel == null || historyPagingController == null) return;
@ -90,11 +93,16 @@ class ChatProvider extends ChangeNotifier {
} }
notifyListeners(); notifyListeners();
}, },
onError: (_, __) => connect(auth), onError: (_, __) => Future.delayed(const Duration(seconds: 3), () => connect(auth)),
onDone: () => connect(auth), onDone: () => Future.delayed(const Duration(seconds: 1), () => connect(auth)),
); );
return channel; return _channel!;
}
void disconnect() {
_channel = null;
isOpened = false;
} }
Future<void> fetchMessages(int pageKey, BuildContext context) async { Future<void> fetchMessages(int pageKey, BuildContext context) async {

View File

@ -64,6 +64,8 @@ class NotifyProvider extends ChangeNotifier {
notifyListeners(); notifyListeners();
} }
WebSocketChannel? _channel;
Future<WebSocketChannel?> connect( Future<WebSocketChannel?> connect(
AuthProvider auth, { AuthProvider auth, {
Keypair? Function(String id)? onKexRequest, Keypair? Function(String id)? onKexRequest,
@ -83,10 +85,12 @@ class NotifyProvider extends ChangeNotifier {
queryParameters: {'tk': Uri.encodeComponent(auth.client!.currentToken!)}, queryParameters: {'tk': Uri.encodeComponent(auth.client!.currentToken!)},
); );
final channel = WebSocketChannel.connect(uri); isOpened = true;
await channel.ready;
channel.stream.listen( _channel = WebSocketChannel.connect(uri);
await _channel!.ready;
_channel!.stream.listen(
(event) { (event) {
final result = NetworkPackage.fromJson(jsonDecode(event)); final result = NetworkPackage.fromJson(jsonDecode(event));
switch (result.method) { switch (result.method) {
@ -101,7 +105,7 @@ class NotifyProvider extends ChangeNotifier {
if (onKexRequest == null || result.payload == null) break; if (onKexRequest == null || result.payload == null) break;
final resp = onKexRequest(result.payload!['keypair_id']); final resp = onKexRequest(result.payload!['keypair_id']);
if (resp == null) break; if (resp == null) break;
channel.sink.add(jsonEncode( _channel!.sink.add(jsonEncode(
NetworkPackage(method: 'kex.provide', payload: { NetworkPackage(method: 'kex.provide', payload: {
'request_id': result.payload!['request_id'], 'request_id': result.payload!['request_id'],
'keypair_id': resp.id, 'keypair_id': resp.id,
@ -121,11 +125,16 @@ class NotifyProvider extends ChangeNotifier {
break; break;
} }
}, },
onError: (_, __) => connect(auth), onError: (_, __) => Future.delayed(const Duration(seconds: 3), () => connect(auth)),
onDone: () => connect(auth), onDone: () => Future.delayed(const Duration(seconds: 1), () => connect(auth)),
); );
return channel; return _channel!;
}
void disconnect() {
_channel = null;
isOpened = false;
} }
void notifyMessage(String title, String body) { void notifyMessage(String title, String body) {

View File

@ -1,7 +1,9 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:solian/providers/auth.dart'; import 'package:solian/providers/auth.dart';
import 'package:solian/providers/chat.dart';
import 'package:solian/providers/keypair.dart'; import 'package:solian/providers/keypair.dart';
import 'package:solian/providers/notify.dart';
import 'package:solian/router.dart'; import 'package:solian/router.dart';
import 'package:solian/utils/theme.dart'; import 'package:solian/utils/theme.dart';
import 'package:solian/widgets/account/account_avatar.dart'; import 'package:solian/widgets/account/account_avatar.dart';
@ -82,6 +84,8 @@ class _AccountScreenWidgetState extends State<AccountScreenWidget> {
onTap: () { onTap: () {
auth.signoff(); auth.signoff();
keypair.clearKeys(); keypair.clearKeys();
context.read<NotifyProvider>().disconnect();
context.read<ChatProvider>().disconnect();
setState(() { setState(() {
_isAuthorized = false; _isAuthorized = false;
}); });

View File

@ -2,6 +2,8 @@ import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:solian/providers/auth.dart'; import 'package:solian/providers/auth.dart';
import 'package:solian/providers/chat.dart';
import 'package:solian/providers/notify.dart';
import 'package:solian/router.dart'; import 'package:solian/router.dart';
import 'package:solian/utils/services_url.dart'; import 'package:solian/utils/services_url.dart';
import 'package:solian/widgets/exts.dart'; import 'package:solian/widgets/exts.dart';
@ -21,6 +23,8 @@ class SignInScreen extends StatelessWidget {
final password = _passwordController.value.text; final password = _passwordController.value.text;
if (username.isEmpty || password.isEmpty) return; if (username.isEmpty || password.isEmpty) return;
auth.signin(context, username, password).then((_) { auth.signin(context, username, password).then((_) {
context.read<ChatProvider>().connect(auth);
context.read<NotifyProvider>().connect(auth);
SolianRouter.router.pop(true); SolianRouter.router.pop(true);
}).catchError((e) { }).catchError((e) {
List<String> messages = e.toString().split('\n'); List<String> messages = e.toString().split('\n');

View File

@ -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/pagination.dart'; import 'package:solian/models/pagination.dart';
import 'package:solian/models/post.dart'; import 'package:solian/models/post.dart';
@ -133,14 +134,12 @@ class _ExplorePostWidgetState extends State<ExplorePostWidget> {
return Container(); return Container();
} }
return Container( return Padding(
height: 120, padding: const EdgeInsets.only(bottom: 8),
decoration: BoxDecoration( child: const Material(
border: Border( elevation: 8,
bottom: BorderSide(width: 0.3, color: Theme.of(context).dividerColor), child: SizedBox(height: 120, child: RealmShortcuts()),
), ).animate().fade().slideY(begin: -1, end: 0, curve: Curves.fastEaseInToSlowEaseOut),
),
child: const RealmShortcuts(),
); );
}, },
), ),

View File

@ -1,57 +1,12 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:solian/providers/auth.dart';
import 'package:solian/providers/keypair.dart';
import 'package:solian/providers/notify.dart'; import 'package:solian/providers/notify.dart';
import 'package:solian/router.dart'; import 'package:solian/router.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:badges/badges.dart' as badge; import 'package:badges/badges.dart' as badge;
class NotificationButton extends StatefulWidget { class NotificationButton extends StatelessWidget {
const NotificationButton({super.key}); const NotificationButton({super.key});
@override
State<NotificationButton> createState() => _NotificationButtonState();
}
class _NotificationButtonState extends State<NotificationButton> {
void connect() async {
final auth = context.read<AuthProvider>();
final nty = context.read<NotifyProvider>();
final keypair = context.read<KeypairProvider>();
if (nty.isOpened) return;
final notify = ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(AppLocalizations.of(context)!.connectingServer),
duration: const Duration(minutes: 1),
),
);
if (await auth.isAuthorized()) {
if (auth.client == null) {
await auth.loadClient();
}
nty.fetch(auth);
keypair.channel = await nty.connect(
auth,
onKexRequest: keypair.provideKeypair,
onKexProvide: keypair.receiveKeypair,
);
}
notify.close();
}
@override
void initState() {
super.initState();
Future.delayed(Duration.zero, () => connect());
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final nty = context.watch<NotifyProvider>(); final nty = context.watch<NotifyProvider>();

View File

@ -0,0 +1,59 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:solian/providers/auth.dart';
import 'package:solian/providers/chat.dart';
import 'package:solian/providers/keypair.dart';
import 'package:solian/providers/notify.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
class ProviderInitializer extends StatefulWidget {
final Widget child;
const ProviderInitializer({super.key, required this.child});
@override
State<ProviderInitializer> createState() => _ProviderInitializerState();
}
class _ProviderInitializerState extends State<ProviderInitializer> {
void connect() async {
final auth = context.read<AuthProvider>();
final nty = context.read<NotifyProvider>();
final chat = context.read<ChatProvider>();
final keypair = context.read<KeypairProvider>();
final notify = ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(AppLocalizations.of(context)!.connectingServer),
duration: const Duration(minutes: 1),
),
);
if (await auth.isAuthorized()) {
if (auth.client == null) {
await auth.loadClient();
}
nty.fetch(auth);
chat.connect(auth);
keypair.channel = await nty.connect(
auth,
onKexRequest: keypair.provideKeypair,
onKexProvide: keypair.receiveKeypair,
);
}
notify.close();
}
@override
void initState() {
super.initState();
Future.delayed(Duration.zero, () => connect());
}
@override
Widget build(BuildContext context) {
return widget.child;
}
}