♻️ 使用 Drift 作为本地数据库 #3
@ -51,6 +51,14 @@
|
|||||||
to determine the Window background behind the Flutter UI. -->
|
to determine the Window background behind the Flutter UI. -->
|
||||||
<meta-data android:name="flutter_deeplinking_enabled" android:value="true" />
|
<meta-data android:name="flutter_deeplinking_enabled" android:value="true" />
|
||||||
|
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
<data android:scheme="solink" />
|
||||||
|
</intent-filter>
|
||||||
|
|
||||||
<intent-filter android:autoVerify="true">
|
<intent-filter android:autoVerify="true">
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
@ -61,14 +69,6 @@
|
|||||||
<data android:scheme="https" />
|
<data android:scheme="https" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.intent.action.VIEW" />
|
|
||||||
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
|
||||||
<data android:scheme="solink" />
|
|
||||||
</intent-filter>
|
|
||||||
|
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="io.flutter.embedding.android.NormalTheme"
|
android:name="io.flutter.embedding.android.NormalTheme"
|
||||||
android:resource="@style/NormalTheme"
|
android:resource="@style/NormalTheme"
|
||||||
|
@ -12,7 +12,7 @@ class ChatEventController {
|
|||||||
RxList.empty(growable: true);
|
RxList.empty(growable: true);
|
||||||
final RxInt totalEvents = 0.obs;
|
final RxInt totalEvents = 0.obs;
|
||||||
|
|
||||||
final RxBool isLoading = false.obs;
|
final RxBool isLoading = true.obs;
|
||||||
|
|
||||||
Channel? channel;
|
Channel? channel;
|
||||||
String? scope;
|
String? scope;
|
||||||
@ -27,7 +27,7 @@ class ChatEventController {
|
|||||||
return await src.getEvent(id, channel!, scope: scope!);
|
return await src.getEvent(id, channel!, scope: scope!);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> getEvents(Channel channel, String scope) async {
|
Future<void> getInitialEvents(Channel channel, String scope) async {
|
||||||
this.channel = channel;
|
this.channel = channel;
|
||||||
this.scope = scope;
|
this.scope = scope;
|
||||||
|
|
||||||
@ -38,7 +38,7 @@ class ChatEventController {
|
|||||||
final result = await src.fetchRemoteEvents(
|
final result = await src.fetchRemoteEvents(
|
||||||
channel,
|
channel,
|
||||||
scope,
|
scope,
|
||||||
remainDepth: 3,
|
depth: 1,
|
||||||
offset: 0,
|
offset: 0,
|
||||||
);
|
);
|
||||||
totalEvents.value = result?.$2 ?? 0;
|
totalEvents.value = result?.$2 ?? 0;
|
||||||
@ -58,6 +58,7 @@ class ChatEventController {
|
|||||||
final result = await src.pullRemoteEvents(
|
final result = await src.pullRemoteEvents(
|
||||||
channel,
|
channel,
|
||||||
scope: scope,
|
scope: scope,
|
||||||
|
depth: 1,
|
||||||
);
|
);
|
||||||
totalEvents.value = result?.$2 ?? 0;
|
totalEvents.value = result?.$2 ?? 0;
|
||||||
await syncLocal(channel);
|
await syncLocal(channel);
|
||||||
@ -71,7 +72,7 @@ class ChatEventController {
|
|||||||
final result = await src.fetchRemoteEvents(
|
final result = await src.fetchRemoteEvents(
|
||||||
channel,
|
channel,
|
||||||
scope,
|
scope,
|
||||||
remainDepth: 3,
|
depth: 3,
|
||||||
offset: currentEvents.length,
|
offset: currentEvents.length,
|
||||||
);
|
);
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
@ -123,6 +124,7 @@ class ChatEventController {
|
|||||||
entry = await src.receiveEvent(remote);
|
entry = await src.receiveEvent(remote);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
totalEvents.value++;
|
||||||
insertEvent(entry);
|
insertEvent(entry);
|
||||||
applyEvent(entry);
|
applyEvent(entry);
|
||||||
}
|
}
|
||||||
|
@ -51,12 +51,12 @@ class MessagesFetchingProvider extends GetxController {
|
|||||||
Future<(List<Event>, int)?> fetchRemoteEvents(
|
Future<(List<Event>, int)?> fetchRemoteEvents(
|
||||||
Channel channel,
|
Channel channel,
|
||||||
String scope, {
|
String scope, {
|
||||||
required int remainDepth,
|
required int depth,
|
||||||
bool Function(List<Event> items)? onBrake,
|
bool Function(List<Event> items)? onBrake,
|
||||||
take = 10,
|
take = 10,
|
||||||
offset = 0,
|
offset = 0,
|
||||||
}) async {
|
}) async {
|
||||||
if (remainDepth <= 0) {
|
if (depth <= 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,7 +84,7 @@ class MessagesFetchingProvider extends GetxController {
|
|||||||
final expandResult = (await fetchRemoteEvents(
|
final expandResult = (await fetchRemoteEvents(
|
||||||
channel,
|
channel,
|
||||||
scope,
|
scope,
|
||||||
remainDepth: remainDepth - 1,
|
depth: depth - 1,
|
||||||
take: take,
|
take: take,
|
||||||
offset: offset + result.length,
|
offset: offset + result.length,
|
||||||
))
|
))
|
||||||
@ -162,7 +162,7 @@ class MessagesFetchingProvider extends GetxController {
|
|||||||
final data = await fetchRemoteEvents(
|
final data = await fetchRemoteEvents(
|
||||||
channel,
|
channel,
|
||||||
scope,
|
scope,
|
||||||
remainDepth: depth,
|
depth: depth,
|
||||||
offset: offset,
|
offset: offset,
|
||||||
onBrake: (items) {
|
onBrake: (items) {
|
||||||
return items.any((x) => x.id == lastOne?.id);
|
return items.any((x) => x.id == lastOne?.id);
|
||||||
|
@ -2,7 +2,6 @@ import 'dart:async';
|
|||||||
import 'dart:ui';
|
import 'dart:ui';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_animate/flutter_animate.dart';
|
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:solian/controllers/chat_events_controller.dart';
|
import 'package:solian/controllers/chat_events_controller.dart';
|
||||||
import 'package:solian/exts.dart';
|
import 'package:solian/exts.dart';
|
||||||
@ -156,7 +155,7 @@ class _ChannelChatScreenState extends State<ChannelChatScreen>
|
|||||||
|
|
||||||
void _keepUpdateWithServer() {
|
void _keepUpdateWithServer() {
|
||||||
_getOngoingCall();
|
_getOngoingCall();
|
||||||
_chatController.getEvents(_channel!, widget.realm);
|
_chatController.getInitialEvents(_channel!, widget.realm);
|
||||||
setState(() => _isOutOfSyncSince = null);
|
setState(() => _isOutOfSyncSince = null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,7 +192,7 @@ class _ChannelChatScreenState extends State<ChannelChatScreen>
|
|||||||
|
|
||||||
_getOngoingCall();
|
_getOngoingCall();
|
||||||
_getChannel().then((_) {
|
_getChannel().then((_) {
|
||||||
_chatController.getEvents(_channel!, widget.realm);
|
_chatController.getInitialEvents(_channel!, widget.realm);
|
||||||
_listenMessages();
|
_listenMessages();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -295,13 +294,6 @@ class _ChannelChatScreenState extends State<ChannelChatScreen>
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Obx(() {
|
|
||||||
if (_chatController.isLoading.isTrue) {
|
|
||||||
return const LinearProgressIndicator().animate().slideY();
|
|
||||||
} else {
|
|
||||||
return const SizedBox.shrink();
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
ClipRect(
|
ClipRect(
|
||||||
child: BackdropFilter(
|
child: BackdropFilter(
|
||||||
filter: ImageFilter.blur(sigmaX: 50, sigmaY: 50),
|
filter: ImageFilter.blur(sigmaX: 50, sigmaY: 50),
|
||||||
|
@ -6,6 +6,7 @@ import 'package:solian/models/event.dart';
|
|||||||
import 'package:solian/providers/last_read.dart';
|
import 'package:solian/providers/last_read.dart';
|
||||||
import 'package:solian/widgets/chat/chat_event.dart';
|
import 'package:solian/widgets/chat/chat_event.dart';
|
||||||
import 'package:solian/widgets/chat/chat_event_action.dart';
|
import 'package:solian/widgets/chat/chat_event_action.dart';
|
||||||
|
import 'package:very_good_infinite_list/very_good_infinite_list.dart';
|
||||||
|
|
||||||
class ChatEventList extends StatelessWidget {
|
class ChatEventList extends StatelessWidget {
|
||||||
final String scope;
|
final String scope;
|
||||||
@ -36,8 +37,9 @@ class ChatEventList extends StatelessWidget {
|
|||||||
reverse: true,
|
reverse: true,
|
||||||
slivers: [
|
slivers: [
|
||||||
Obx(() {
|
Obx(() {
|
||||||
return SliverList.builder(
|
return SliverInfiniteList(
|
||||||
key: Key('chat-history#${channel.id}'),
|
key: Key('chat-history#${channel.id}'),
|
||||||
|
isLoading: chatController.isLoading.value,
|
||||||
itemCount: chatController.currentEvents.length,
|
itemCount: chatController.currentEvents.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
Get.find<LastReadProvider>().messagesLastReadAt =
|
Get.find<LastReadProvider>().messagesLastReadAt =
|
||||||
@ -89,28 +91,12 @@ class ChatEventList extends StatelessWidget {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
onFetchData: () {
|
||||||
}),
|
chatController.loadEvents(
|
||||||
Obx(() {
|
chatController.channel!,
|
||||||
final amount =
|
chatController.scope!,
|
||||||
chatController.totalEvents - chatController.currentEvents.length;
|
);
|
||||||
|
},
|
||||||
if (amount.value <= 0 || chatController.isLoading.isTrue) {
|
|
||||||
return const SliverToBoxAdapter(child: SizedBox.shrink());
|
|
||||||
}
|
|
||||||
|
|
||||||
return SliverToBoxAdapter(
|
|
||||||
child: ListTile(
|
|
||||||
tileColor: Theme.of(context).colorScheme.surfaceContainerLow,
|
|
||||||
leading: const Icon(Icons.sync_disabled),
|
|
||||||
title: Text('messageUnSync'.tr),
|
|
||||||
subtitle: Text('messageUnSyncCaption'.trParams({
|
|
||||||
'count': amount.string,
|
|
||||||
})),
|
|
||||||
onTap: () {
|
|
||||||
chatController.loadEvents(channel, scope);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
|
Loading…
Reference in New Issue
Block a user