✨ Basic message sending and listing
This commit is contained in:
@ -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;
|
||||
|
50
lib/providers/user_directory.dart
Normal file
50
lib/providers/user_directory.dart
Normal file
@ -0,0 +1,50 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:surface/providers/sn_network.dart';
|
||||
import 'package:surface/types/account.dart';
|
||||
|
||||
class UserDirectoryProvider {
|
||||
late final SnNetworkProvider _sn;
|
||||
|
||||
UserDirectoryProvider(BuildContext context) {
|
||||
_sn = context.read<SnNetworkProvider>();
|
||||
}
|
||||
|
||||
final Map<String, int> _idCache = {};
|
||||
final Map<int, SnAccount> _cache = {};
|
||||
|
||||
Future<List<SnAccount?>> listAccount(Iterable<dynamic> id) async {
|
||||
final out = await Future.wait(
|
||||
id.map((e) => getAccount(e)),
|
||||
);
|
||||
return out;
|
||||
}
|
||||
|
||||
Future<SnAccount?> getAccount(dynamic id) async {
|
||||
if (id is String && _idCache.containsKey(id)) {
|
||||
id = _idCache[id];
|
||||
}
|
||||
if (_cache.containsKey(id)) {
|
||||
return _cache[id];
|
||||
}
|
||||
|
||||
try {
|
||||
final resp = await _sn.client.get('/cgi/id/users/$id');
|
||||
final account = SnAccount.fromJson(
|
||||
resp.data as Map<String, dynamic>,
|
||||
);
|
||||
_cache[account.id] = account;
|
||||
if (id is String) _idCache[id] = account.id;
|
||||
return account;
|
||||
} catch (err) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
SnAccount? getAccountFromCache(dynamic id) {
|
||||
if (id is String && _idCache.containsKey(id)) {
|
||||
id = _idCache[id];
|
||||
}
|
||||
return _cache[id];
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user