Basic message sending and listing

This commit is contained in:
2024-11-17 01:16:54 +08:00
parent e9fbd0c65f
commit 285bb42b09
19 changed files with 2220 additions and 378 deletions

View File

@ -28,8 +28,11 @@ class ChatChannelProvider extends ChangeNotifier {
});
}
Future<List<SnChannel>> _fetchChannelsFromServer(
{scope = 'global', direct = false}) async {
Future<List<SnChannel>> _fetchChannelsFromServer({
String scope = 'global',
bool direct = false,
bool doNotSave = false,
}) async {
final resp = await _sn.client.get(
'/cgi/im/channels/$scope/me/available',
queryParameters: {
@ -39,15 +42,37 @@ class ChatChannelProvider extends ChangeNotifier {
final out = List<SnChannel>.from(
resp.data?.map((e) => SnChannel.fromJson(e)) ?? [],
);
_saveChannelToLocal(out);
if (!doNotSave) _saveChannelToLocal(out);
return out;
}
// The fetch channel method return a stream, which will emit twice.
// The first time is when the data was fetched from the local storage.
// And the second time is when the data was fetched from the server.
// But there is some exception that will only cause one of them to be emitted.
// Like the local storage is broken or the server is down.
/// The get channel method will return the channel with the given alias.
/// It will use the local storage as much as possible.
/// The alias should include the scope, formatted as `scope:alias`.
Future<SnChannel> getChannel(String key) async {
if (_channelBox != null) {
final local = _channelBox!.get(key);
if (local != null) return local;
}
var resp = await _sn.client.get('/cgi/im/channels/$key');
var out = SnChannel.fromJson(resp.data);
// Preload realm of the channel
if (out.realmId != null) {
resp = await _sn.client.get('/cgi/id/realms/${out.realmId}');
out = out.copyWith(realm: SnRealm.fromJson(resp.data));
}
_saveChannelToLocal([out]);
return out;
}
/// The fetch channel method return a stream, which will emit twice.
/// The first time is when the data was fetched from the local storage.
/// And the second time is when the data was fetched from the server.
/// But there is some exception that will only cause one of them to be emitted.
/// Like the local storage is broken or the server is down.
Stream<List<SnChannel>> fetchChannels() async* {
if (_channelBox != null) yield _channelBox!.values.toList();
@ -55,18 +80,34 @@ class ChatChannelProvider extends ChangeNotifier {
final realms = List<SnRealm>.from(
resp.data?.map((e) => SnRealm.fromJson(e)) ?? [],
);
final realmMap = {
for (final realm in realms) realm.alias: realm,
};
final scopeToFetch = {'global', ...realms.map((e) => e.alias)};
final List<SnChannel> result = List.empty(growable: true);
final dm =
await _fetchChannelsFromServer(scope: scopeToFetch.first, direct: true);
result.addAll(dm);
final directMessages = await _fetchChannelsFromServer(
scope: scopeToFetch.first,
direct: true,
);
result.addAll(directMessages);
for (final scope in scopeToFetch) {
final channel =
await _fetchChannelsFromServer(scope: scope, direct: false);
result.addAll(channel);
final nonBelongsChannels = await _fetchChannelsFromServer(
scope: scopeToFetch.first,
direct: false,
);
result.addAll(nonBelongsChannels);
for (final scope in scopeToFetch.skip(1)) {
final channel = await _fetchChannelsFromServer(
scope: scope,
direct: false,
doNotSave: true,
);
final out = channel.map((ele) => ele.copyWith(realm: realmMap[scope]));
_saveChannelToLocal(out);
result.addAll(out);
}
yield result;