✨ Basic message sending and listing
This commit is contained in:
parent
e9fbd0c65f
commit
285bb42b09
183
lib/controllers/chat_message_controller.dart
Normal file
183
lib/controllers/chat_message_controller.dart
Normal file
@ -0,0 +1,183 @@
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:surface/providers/sn_network.dart';
|
||||
import 'package:surface/providers/user_directory.dart';
|
||||
import 'package:surface/types/chat.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
class ChatMessageController extends ChangeNotifier {
|
||||
static const kChatMessageBoxPrefix = 'nex_chat_messages_';
|
||||
static const kSingleBatchLoadLimit = 100;
|
||||
|
||||
late final SnNetworkProvider _sn;
|
||||
late final UserDirectoryProvider _ud;
|
||||
|
||||
ChatMessageController(BuildContext context) {
|
||||
_sn = context.read<SnNetworkProvider>();
|
||||
_ud = context.read<UserDirectoryProvider>();
|
||||
}
|
||||
|
||||
bool isPending = true;
|
||||
bool isLoading = false;
|
||||
|
||||
int? messageTotal;
|
||||
|
||||
bool get isAllLoaded =>
|
||||
messageTotal != null && messages.length >= messageTotal!;
|
||||
|
||||
String? _boxKey;
|
||||
SnChannel? _channel;
|
||||
|
||||
List<SnChatMessage> messages = List.empty(growable: true);
|
||||
|
||||
Box<SnChatMessage>? get _box =>
|
||||
(_boxKey == null || isPending) ? null : Hive.box<SnChatMessage>(_boxKey!);
|
||||
|
||||
Future<void> initialize(SnChannel channel) async {
|
||||
_channel = channel;
|
||||
_boxKey = '$kChatMessageBoxPrefix${channel.id}';
|
||||
await Hive.openBox<SnChatMessage>(_boxKey!);
|
||||
isPending = false;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> _saveMessageToLocal(Iterable<SnChatMessage> messages) async {
|
||||
if (_box == null) return;
|
||||
await _box!.putAll({
|
||||
for (final message in messages) message.id: message,
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _addMessage(SnChatMessage message) async {
|
||||
messages.add(message);
|
||||
notifyListeners();
|
||||
|
||||
if (_box == null) return;
|
||||
await _box!.put(message.id, message);
|
||||
}
|
||||
|
||||
Future<void> sendMessage(
|
||||
String type,
|
||||
String content, {
|
||||
int? quoteId,
|
||||
int? relatedId,
|
||||
List<String>? attachments,
|
||||
}) async {
|
||||
if (_channel == null) return;
|
||||
const uuid = Uuid();
|
||||
final nonce = uuid.v4();
|
||||
final resp = await _sn.client.post(
|
||||
'/cgi/im/channels/${_channel!.keyPath}/messages',
|
||||
data: {
|
||||
'type': type,
|
||||
'uuid': nonce,
|
||||
'body': {
|
||||
'text': content,
|
||||
'algorithm': 'plain',
|
||||
if (quoteId != null) 'quote_id': quoteId,
|
||||
if (relatedId != null) 'related_id': relatedId,
|
||||
if (attachments != null) 'attachments': attachments,
|
||||
},
|
||||
},
|
||||
);
|
||||
final out = SnChatMessage.fromJson(
|
||||
resp.data['data'] as Map<String, dynamic>,
|
||||
);
|
||||
await _addMessage(out);
|
||||
}
|
||||
|
||||
/// Check the local storage is up to date with the server.
|
||||
/// If the local storage is not up to date, it will be updated.
|
||||
Future<void> checkUpdate() async {
|
||||
if (_box == null) return;
|
||||
if (_box!.isEmpty) return;
|
||||
|
||||
isLoading = true;
|
||||
notifyListeners();
|
||||
|
||||
try {
|
||||
final resp = await _sn.client.get(
|
||||
'/cgi/im/channels/${_channel!.keyPath}/events/update',
|
||||
queryParameters: {
|
||||
'pivot': _box!.values.last.id,
|
||||
},
|
||||
);
|
||||
if (resp.data['up_to_date'] == true) {
|
||||
await loadMessages();
|
||||
return;
|
||||
}
|
||||
// Only preload the first 100 messages to prevent first time check update cause load to server and waste local storage.
|
||||
// FIXME If the local is missing more than 100 messages, it won't be fetched, this is a problem, we need to fix it.
|
||||
final countToFetch = math.min(resp.data['count'] as int, 100);
|
||||
|
||||
for (int idx = 0; idx < countToFetch; idx += kSingleBatchLoadLimit) {
|
||||
await getMessages(kSingleBatchLoadLimit, idx);
|
||||
}
|
||||
} catch (err) {
|
||||
rethrow;
|
||||
} finally {
|
||||
isLoading = false;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
/// Get message from local storage first, then from the server.
|
||||
/// Will not check local storage is up to date with the server.
|
||||
/// If you need to do the sync, do the `checkUpdate` instead.
|
||||
Future<List<SnChatMessage>> getMessages(
|
||||
int take,
|
||||
int offset, {
|
||||
bool forceLocal = false,
|
||||
}) async {
|
||||
if (_box != null) {
|
||||
// Try retrieve these messages from the local storage
|
||||
if (_box!.length >= take + offset || forceLocal) {
|
||||
return _box!.values.skip(offset).take(take).toList();
|
||||
}
|
||||
}
|
||||
|
||||
final resp = await _sn.client.get(
|
||||
'/cgi/im/channels/${_channel!.keyPath}/events',
|
||||
queryParameters: {
|
||||
'take': take,
|
||||
'offset': offset,
|
||||
},
|
||||
);
|
||||
messageTotal = resp.data['count'] as int?;
|
||||
final out = List<SnChatMessage>.from(
|
||||
resp.data['data']?.map((e) => SnChatMessage.fromJson(e)) ?? [],
|
||||
);
|
||||
_saveMessageToLocal(out);
|
||||
|
||||
// Preload sender accounts
|
||||
await _ud.listAccount(out.map((ele) => ele.sender.accountId).toSet());
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/// The load messages method work as same as the `getMessages` method.
|
||||
/// But it won't return the messages instead append them to the value that controller has.
|
||||
/// At the same time, this method provide the `isLoading` state.
|
||||
/// The `skip` parameter is no longer required since it will skip the messages count that already loaded.
|
||||
Future<void> loadMessages({int take = 20}) async {
|
||||
isLoading = true;
|
||||
notifyListeners();
|
||||
|
||||
try {
|
||||
final out = await getMessages(take, messages.length);
|
||||
messages.addAll(out);
|
||||
} catch (err) {
|
||||
rethrow;
|
||||
} finally {
|
||||
isLoading = false;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
close() {
|
||||
_box?.close();
|
||||
}
|
||||
}
|
@ -12,10 +12,12 @@ import 'package:surface/providers/navigation.dart';
|
||||
import 'package:surface/providers/sn_attachment.dart';
|
||||
import 'package:surface/providers/sn_network.dart';
|
||||
import 'package:surface/providers/theme.dart';
|
||||
import 'package:surface/providers/user_directory.dart';
|
||||
import 'package:surface/providers/userinfo.dart';
|
||||
import 'package:surface/providers/websocket.dart';
|
||||
import 'package:surface/router.dart';
|
||||
import 'package:surface/types/chat.dart';
|
||||
import 'package:surface/types/realm.dart';
|
||||
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
@ -23,6 +25,9 @@ void main() async {
|
||||
|
||||
await Hive.initFlutter();
|
||||
Hive.registerAdapter(SnChannelImplAdapter());
|
||||
Hive.registerAdapter(SnRealmImplAdapter());
|
||||
Hive.registerAdapter(SnChannelMemberImplAdapter());
|
||||
Hive.registerAdapter(SnChatMessageImplAdapter());
|
||||
|
||||
if (!kReleaseMode) {
|
||||
debugInvertOversizedImages = true;
|
||||
@ -53,6 +58,7 @@ class SolianApp extends StatelessWidget {
|
||||
// Data layer
|
||||
Provider(create: (_) => SnNetworkProvider()),
|
||||
Provider(create: (ctx) => SnAttachmentProvider(ctx)),
|
||||
Provider(create: (ctx) => UserDirectoryProvider(ctx)),
|
||||
ChangeNotifierProvider(create: (ctx) => UserProvider(ctx)),
|
||||
ChangeNotifierProvider(create: (ctx) => WebSocketProvider(ctx)),
|
||||
ChangeNotifierProvider(create: (ctx) => ChatChannelProvider(ctx)),
|
||||
|
@ -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];
|
||||
}
|
||||
}
|
@ -10,6 +10,7 @@ import 'package:surface/screens/auth/login.dart';
|
||||
import 'package:surface/screens/auth/register.dart';
|
||||
import 'package:surface/screens/chat.dart';
|
||||
import 'package:surface/screens/chat/manage.dart';
|
||||
import 'package:surface/screens/chat/room.dart';
|
||||
import 'package:surface/screens/explore.dart';
|
||||
import 'package:surface/screens/home.dart';
|
||||
import 'package:surface/screens/post/post_detail.dart';
|
||||
@ -102,6 +103,16 @@ final _appRoutes = [
|
||||
child: const ChatScreen(),
|
||||
),
|
||||
routes: [
|
||||
GoRoute(
|
||||
path: '/chat/:scope/:alias',
|
||||
name: 'chatRoom',
|
||||
builder: (context, state) => AppBackground(
|
||||
child: ChatRoomScreen(
|
||||
scope: state.pathParameters['scope']!,
|
||||
alias: state.pathParameters['alias']!,
|
||||
),
|
||||
),
|
||||
),
|
||||
GoRoute(
|
||||
path: '/chat/manage',
|
||||
name: 'chatManage',
|
||||
|
@ -6,6 +6,7 @@ import 'package:provider/provider.dart';
|
||||
import 'package:surface/providers/channel.dart';
|
||||
import 'package:surface/types/chat.dart';
|
||||
import 'package:surface/widgets/account/account_image.dart';
|
||||
import 'package:surface/widgets/dialog.dart';
|
||||
import 'package:surface/widgets/loading_indicator.dart';
|
||||
|
||||
class ChatScreen extends StatefulWidget {
|
||||
@ -27,10 +28,13 @@ class _ChatScreenState extends State<ChatScreen> {
|
||||
chan.fetchChannels().listen((channels) {
|
||||
if (mounted) setState(() => _channels = channels);
|
||||
})
|
||||
..onError((_) {
|
||||
..onError((err) {
|
||||
if (!mounted) return;
|
||||
context.showErrorDialog(err);
|
||||
setState(() => _isBusy = false);
|
||||
})
|
||||
..onDone(() {
|
||||
if (!mounted) return;
|
||||
setState(() => _isBusy = false);
|
||||
});
|
||||
}
|
||||
@ -67,6 +71,15 @@ class _ChatScreenState extends State<ChatScreen> {
|
||||
content: null,
|
||||
fallbackWidget: const Icon(Symbols.chat, size: 20),
|
||||
),
|
||||
onTap: () {
|
||||
GoRouter.of(context).pushNamed(
|
||||
'chatRoom',
|
||||
pathParameters: {
|
||||
'scope': channel.realm?.alias ?? 'global',
|
||||
'alias': channel.alias,
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
|
102
lib/screens/chat/room.dart
Normal file
102
lib/screens/chat/room.dart
Normal file
@ -0,0 +1,102 @@
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
import 'package:surface/controllers/chat_message_controller.dart';
|
||||
import 'package:surface/providers/channel.dart';
|
||||
import 'package:surface/types/chat.dart';
|
||||
import 'package:surface/widgets/chat/chat_message.dart';
|
||||
import 'package:surface/widgets/chat/chat_message_input.dart';
|
||||
import 'package:surface/widgets/dialog.dart';
|
||||
import 'package:surface/widgets/loading_indicator.dart';
|
||||
import 'package:very_good_infinite_list/very_good_infinite_list.dart';
|
||||
|
||||
class ChatRoomScreen extends StatefulWidget {
|
||||
final String scope;
|
||||
final String alias;
|
||||
const ChatRoomScreen({super.key, required this.scope, required this.alias});
|
||||
|
||||
@override
|
||||
State<ChatRoomScreen> createState() => _ChatRoomScreenState();
|
||||
}
|
||||
|
||||
class _ChatRoomScreenState extends State<ChatRoomScreen> {
|
||||
bool _isBusy = false;
|
||||
|
||||
SnChannel? _channel;
|
||||
|
||||
late final ChatMessageController _messageController;
|
||||
|
||||
Future<void> _fetchChannel() async {
|
||||
setState(() => _isBusy = true);
|
||||
|
||||
try {
|
||||
final chan = context.read<ChatChannelProvider>();
|
||||
_channel = await chan.getChannel('${widget.scope}:${widget.alias}');
|
||||
} catch (err) {
|
||||
if (!mounted) return;
|
||||
context.showErrorDialog(err);
|
||||
} finally {
|
||||
setState(() => _isBusy = false);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_messageController = ChatMessageController(context);
|
||||
_fetchChannel().then((_) async {
|
||||
await _messageController.initialize(_channel!);
|
||||
await _messageController.checkUpdate();
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(_channel?.name ?? 'loading'.tr()),
|
||||
),
|
||||
body: ListenableBuilder(
|
||||
listenable: _messageController,
|
||||
builder: (context, _) {
|
||||
return Column(
|
||||
children: [
|
||||
LoadingIndicator(isActive: _isBusy),
|
||||
if (_messageController.isPending)
|
||||
Expanded(
|
||||
child: const CircularProgressIndicator().center(),
|
||||
),
|
||||
if (!_messageController.isPending)
|
||||
Expanded(
|
||||
child: InfiniteList(
|
||||
hasReachedMax: _messageController.isAllLoaded,
|
||||
itemCount: _messageController.messages.length,
|
||||
isLoading: _messageController.isLoading,
|
||||
onFetchData: () {
|
||||
_messageController.loadMessages();
|
||||
},
|
||||
itemBuilder: (context, idx) {
|
||||
final message = _messageController.messages[idx];
|
||||
return ChatMessage(data: message);
|
||||
},
|
||||
),
|
||||
),
|
||||
if (!_messageController.isPending)
|
||||
Material(
|
||||
elevation: 2,
|
||||
child: ChatMessageInput(controller: _messageController)
|
||||
.padding(bottom: MediaQuery.of(context).padding.bottom),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,29 +1,32 @@
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:hive_flutter/hive_flutter.dart';
|
||||
|
||||
part 'account.freezed.dart';
|
||||
part 'account.g.dart';
|
||||
|
||||
@freezed
|
||||
class SnAccount with _$SnAccount {
|
||||
const SnAccount._();
|
||||
|
||||
const factory SnAccount({
|
||||
required int id,
|
||||
required int? affiliatedId,
|
||||
required int? affiliatedTo,
|
||||
required int? automatedBy,
|
||||
required int? automatedId,
|
||||
@HiveField(0) required int id,
|
||||
required DateTime createdAt,
|
||||
required DateTime updatedAt,
|
||||
required DateTime? deletedAt,
|
||||
required DateTime? confirmedAt,
|
||||
required List<SnAccountContact>? contacts,
|
||||
required String avatar,
|
||||
required String banner,
|
||||
required DateTime? confirmedAt,
|
||||
required List<SnAccountContact> contacts,
|
||||
required DateTime createdAt,
|
||||
required DateTime? deletedAt,
|
||||
required String description,
|
||||
required String name,
|
||||
required String nick,
|
||||
required Map<String, dynamic> permNodes,
|
||||
required SnAccountProfile? profile,
|
||||
required DateTime? suspendedAt,
|
||||
required DateTime updatedAt,
|
||||
required int? affiliatedId,
|
||||
required int? affiliatedTo,
|
||||
required int? automatedBy,
|
||||
required int? automatedId,
|
||||
}) = _SnAccount;
|
||||
|
||||
factory SnAccount.fromJson(Map<String, Object?> json) =>
|
||||
|
@ -20,24 +20,25 @@ SnAccount _$SnAccountFromJson(Map<String, dynamic> json) {
|
||||
|
||||
/// @nodoc
|
||||
mixin _$SnAccount {
|
||||
@HiveField(0)
|
||||
int get id => throw _privateConstructorUsedError;
|
||||
int? get affiliatedId => throw _privateConstructorUsedError;
|
||||
int? get affiliatedTo => throw _privateConstructorUsedError;
|
||||
int? get automatedBy => throw _privateConstructorUsedError;
|
||||
int? get automatedId => throw _privateConstructorUsedError;
|
||||
DateTime get createdAt => throw _privateConstructorUsedError;
|
||||
DateTime get updatedAt => throw _privateConstructorUsedError;
|
||||
DateTime? get deletedAt => throw _privateConstructorUsedError;
|
||||
DateTime? get confirmedAt => throw _privateConstructorUsedError;
|
||||
List<SnAccountContact>? get contacts => throw _privateConstructorUsedError;
|
||||
String get avatar => throw _privateConstructorUsedError;
|
||||
String get banner => throw _privateConstructorUsedError;
|
||||
DateTime? get confirmedAt => throw _privateConstructorUsedError;
|
||||
List<SnAccountContact> get contacts => throw _privateConstructorUsedError;
|
||||
DateTime get createdAt => throw _privateConstructorUsedError;
|
||||
DateTime? get deletedAt => throw _privateConstructorUsedError;
|
||||
String get description => throw _privateConstructorUsedError;
|
||||
String get name => throw _privateConstructorUsedError;
|
||||
String get nick => throw _privateConstructorUsedError;
|
||||
Map<String, dynamic> get permNodes => throw _privateConstructorUsedError;
|
||||
SnAccountProfile? get profile => throw _privateConstructorUsedError;
|
||||
DateTime? get suspendedAt => throw _privateConstructorUsedError;
|
||||
DateTime get updatedAt => throw _privateConstructorUsedError;
|
||||
int? get affiliatedId => throw _privateConstructorUsedError;
|
||||
int? get affiliatedTo => throw _privateConstructorUsedError;
|
||||
int? get automatedBy => throw _privateConstructorUsedError;
|
||||
int? get automatedId => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this SnAccount to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@ -55,24 +56,24 @@ abstract class $SnAccountCopyWith<$Res> {
|
||||
_$SnAccountCopyWithImpl<$Res, SnAccount>;
|
||||
@useResult
|
||||
$Res call(
|
||||
{int id,
|
||||
int? affiliatedId,
|
||||
int? affiliatedTo,
|
||||
int? automatedBy,
|
||||
int? automatedId,
|
||||
{@HiveField(0) int id,
|
||||
DateTime createdAt,
|
||||
DateTime updatedAt,
|
||||
DateTime? deletedAt,
|
||||
DateTime? confirmedAt,
|
||||
List<SnAccountContact>? contacts,
|
||||
String avatar,
|
||||
String banner,
|
||||
DateTime? confirmedAt,
|
||||
List<SnAccountContact> contacts,
|
||||
DateTime createdAt,
|
||||
DateTime? deletedAt,
|
||||
String description,
|
||||
String name,
|
||||
String nick,
|
||||
Map<String, dynamic> permNodes,
|
||||
SnAccountProfile? profile,
|
||||
DateTime? suspendedAt,
|
||||
DateTime updatedAt});
|
||||
int? affiliatedId,
|
||||
int? affiliatedTo,
|
||||
int? automatedBy,
|
||||
int? automatedId});
|
||||
|
||||
$SnAccountProfileCopyWith<$Res>? get profile;
|
||||
}
|
||||
@ -93,45 +94,49 @@ class _$SnAccountCopyWithImpl<$Res, $Val extends SnAccount>
|
||||
@override
|
||||
$Res call({
|
||||
Object? id = null,
|
||||
Object? affiliatedId = freezed,
|
||||
Object? affiliatedTo = freezed,
|
||||
Object? automatedBy = freezed,
|
||||
Object? automatedId = freezed,
|
||||
Object? createdAt = null,
|
||||
Object? updatedAt = null,
|
||||
Object? deletedAt = freezed,
|
||||
Object? confirmedAt = freezed,
|
||||
Object? contacts = freezed,
|
||||
Object? avatar = null,
|
||||
Object? banner = null,
|
||||
Object? confirmedAt = freezed,
|
||||
Object? contacts = null,
|
||||
Object? createdAt = null,
|
||||
Object? deletedAt = freezed,
|
||||
Object? description = null,
|
||||
Object? name = null,
|
||||
Object? nick = null,
|
||||
Object? permNodes = null,
|
||||
Object? profile = freezed,
|
||||
Object? suspendedAt = freezed,
|
||||
Object? updatedAt = null,
|
||||
Object? affiliatedId = freezed,
|
||||
Object? affiliatedTo = freezed,
|
||||
Object? automatedBy = freezed,
|
||||
Object? automatedId = freezed,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
id: null == id
|
||||
? _value.id
|
||||
: id // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
affiliatedId: freezed == affiliatedId
|
||||
? _value.affiliatedId
|
||||
: affiliatedId // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
affiliatedTo: freezed == affiliatedTo
|
||||
? _value.affiliatedTo
|
||||
: affiliatedTo // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
automatedBy: freezed == automatedBy
|
||||
? _value.automatedBy
|
||||
: automatedBy // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
automatedId: freezed == automatedId
|
||||
? _value.automatedId
|
||||
: automatedId // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
createdAt: null == createdAt
|
||||
? _value.createdAt
|
||||
: createdAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,
|
||||
updatedAt: null == updatedAt
|
||||
? _value.updatedAt
|
||||
: updatedAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,
|
||||
deletedAt: freezed == deletedAt
|
||||
? _value.deletedAt
|
||||
: deletedAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime?,
|
||||
confirmedAt: freezed == confirmedAt
|
||||
? _value.confirmedAt
|
||||
: confirmedAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime?,
|
||||
contacts: freezed == contacts
|
||||
? _value.contacts
|
||||
: contacts // ignore: cast_nullable_to_non_nullable
|
||||
as List<SnAccountContact>?,
|
||||
avatar: null == avatar
|
||||
? _value.avatar
|
||||
: avatar // ignore: cast_nullable_to_non_nullable
|
||||
@ -140,22 +145,6 @@ class _$SnAccountCopyWithImpl<$Res, $Val extends SnAccount>
|
||||
? _value.banner
|
||||
: banner // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
confirmedAt: freezed == confirmedAt
|
||||
? _value.confirmedAt
|
||||
: confirmedAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime?,
|
||||
contacts: null == contacts
|
||||
? _value.contacts
|
||||
: contacts // ignore: cast_nullable_to_non_nullable
|
||||
as List<SnAccountContact>,
|
||||
createdAt: null == createdAt
|
||||
? _value.createdAt
|
||||
: createdAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,
|
||||
deletedAt: freezed == deletedAt
|
||||
? _value.deletedAt
|
||||
: deletedAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime?,
|
||||
description: null == description
|
||||
? _value.description
|
||||
: description // ignore: cast_nullable_to_non_nullable
|
||||
@ -180,10 +169,22 @@ class _$SnAccountCopyWithImpl<$Res, $Val extends SnAccount>
|
||||
? _value.suspendedAt
|
||||
: suspendedAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime?,
|
||||
updatedAt: null == updatedAt
|
||||
? _value.updatedAt
|
||||
: updatedAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,
|
||||
affiliatedId: freezed == affiliatedId
|
||||
? _value.affiliatedId
|
||||
: affiliatedId // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
affiliatedTo: freezed == affiliatedTo
|
||||
? _value.affiliatedTo
|
||||
: affiliatedTo // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
automatedBy: freezed == automatedBy
|
||||
? _value.automatedBy
|
||||
: automatedBy // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
automatedId: freezed == automatedId
|
||||
? _value.automatedId
|
||||
: automatedId // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
) as $Val);
|
||||
}
|
||||
|
||||
@ -211,24 +212,24 @@ abstract class _$$SnAccountImplCopyWith<$Res>
|
||||
@override
|
||||
@useResult
|
||||
$Res call(
|
||||
{int id,
|
||||
int? affiliatedId,
|
||||
int? affiliatedTo,
|
||||
int? automatedBy,
|
||||
int? automatedId,
|
||||
{@HiveField(0) int id,
|
||||
DateTime createdAt,
|
||||
DateTime updatedAt,
|
||||
DateTime? deletedAt,
|
||||
DateTime? confirmedAt,
|
||||
List<SnAccountContact>? contacts,
|
||||
String avatar,
|
||||
String banner,
|
||||
DateTime? confirmedAt,
|
||||
List<SnAccountContact> contacts,
|
||||
DateTime createdAt,
|
||||
DateTime? deletedAt,
|
||||
String description,
|
||||
String name,
|
||||
String nick,
|
||||
Map<String, dynamic> permNodes,
|
||||
SnAccountProfile? profile,
|
||||
DateTime? suspendedAt,
|
||||
DateTime updatedAt});
|
||||
int? affiliatedId,
|
||||
int? affiliatedTo,
|
||||
int? automatedBy,
|
||||
int? automatedId});
|
||||
|
||||
@override
|
||||
$SnAccountProfileCopyWith<$Res>? get profile;
|
||||
@ -248,45 +249,49 @@ class __$$SnAccountImplCopyWithImpl<$Res>
|
||||
@override
|
||||
$Res call({
|
||||
Object? id = null,
|
||||
Object? affiliatedId = freezed,
|
||||
Object? affiliatedTo = freezed,
|
||||
Object? automatedBy = freezed,
|
||||
Object? automatedId = freezed,
|
||||
Object? createdAt = null,
|
||||
Object? updatedAt = null,
|
||||
Object? deletedAt = freezed,
|
||||
Object? confirmedAt = freezed,
|
||||
Object? contacts = freezed,
|
||||
Object? avatar = null,
|
||||
Object? banner = null,
|
||||
Object? confirmedAt = freezed,
|
||||
Object? contacts = null,
|
||||
Object? createdAt = null,
|
||||
Object? deletedAt = freezed,
|
||||
Object? description = null,
|
||||
Object? name = null,
|
||||
Object? nick = null,
|
||||
Object? permNodes = null,
|
||||
Object? profile = freezed,
|
||||
Object? suspendedAt = freezed,
|
||||
Object? updatedAt = null,
|
||||
Object? affiliatedId = freezed,
|
||||
Object? affiliatedTo = freezed,
|
||||
Object? automatedBy = freezed,
|
||||
Object? automatedId = freezed,
|
||||
}) {
|
||||
return _then(_$SnAccountImpl(
|
||||
id: null == id
|
||||
? _value.id
|
||||
: id // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
affiliatedId: freezed == affiliatedId
|
||||
? _value.affiliatedId
|
||||
: affiliatedId // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
affiliatedTo: freezed == affiliatedTo
|
||||
? _value.affiliatedTo
|
||||
: affiliatedTo // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
automatedBy: freezed == automatedBy
|
||||
? _value.automatedBy
|
||||
: automatedBy // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
automatedId: freezed == automatedId
|
||||
? _value.automatedId
|
||||
: automatedId // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
createdAt: null == createdAt
|
||||
? _value.createdAt
|
||||
: createdAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,
|
||||
updatedAt: null == updatedAt
|
||||
? _value.updatedAt
|
||||
: updatedAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,
|
||||
deletedAt: freezed == deletedAt
|
||||
? _value.deletedAt
|
||||
: deletedAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime?,
|
||||
confirmedAt: freezed == confirmedAt
|
||||
? _value.confirmedAt
|
||||
: confirmedAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime?,
|
||||
contacts: freezed == contacts
|
||||
? _value._contacts
|
||||
: contacts // ignore: cast_nullable_to_non_nullable
|
||||
as List<SnAccountContact>?,
|
||||
avatar: null == avatar
|
||||
? _value.avatar
|
||||
: avatar // ignore: cast_nullable_to_non_nullable
|
||||
@ -295,22 +300,6 @@ class __$$SnAccountImplCopyWithImpl<$Res>
|
||||
? _value.banner
|
||||
: banner // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
confirmedAt: freezed == confirmedAt
|
||||
? _value.confirmedAt
|
||||
: confirmedAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime?,
|
||||
contacts: null == contacts
|
||||
? _value._contacts
|
||||
: contacts // ignore: cast_nullable_to_non_nullable
|
||||
as List<SnAccountContact>,
|
||||
createdAt: null == createdAt
|
||||
? _value.createdAt
|
||||
: createdAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,
|
||||
deletedAt: freezed == deletedAt
|
||||
? _value.deletedAt
|
||||
: deletedAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime?,
|
||||
description: null == description
|
||||
? _value.description
|
||||
: description // ignore: cast_nullable_to_non_nullable
|
||||
@ -335,71 +324,81 @@ class __$$SnAccountImplCopyWithImpl<$Res>
|
||||
? _value.suspendedAt
|
||||
: suspendedAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime?,
|
||||
updatedAt: null == updatedAt
|
||||
? _value.updatedAt
|
||||
: updatedAt // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,
|
||||
affiliatedId: freezed == affiliatedId
|
||||
? _value.affiliatedId
|
||||
: affiliatedId // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
affiliatedTo: freezed == affiliatedTo
|
||||
? _value.affiliatedTo
|
||||
: affiliatedTo // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
automatedBy: freezed == automatedBy
|
||||
? _value.automatedBy
|
||||
: automatedBy // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
automatedId: freezed == automatedId
|
||||
? _value.automatedId
|
||||
: automatedId // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _$SnAccountImpl implements _SnAccount {
|
||||
class _$SnAccountImpl extends _SnAccount {
|
||||
const _$SnAccountImpl(
|
||||
{required this.id,
|
||||
required this.affiliatedId,
|
||||
required this.affiliatedTo,
|
||||
required this.automatedBy,
|
||||
required this.automatedId,
|
||||
{@HiveField(0) required this.id,
|
||||
required this.createdAt,
|
||||
required this.updatedAt,
|
||||
required this.deletedAt,
|
||||
required this.confirmedAt,
|
||||
required final List<SnAccountContact>? contacts,
|
||||
required this.avatar,
|
||||
required this.banner,
|
||||
required this.confirmedAt,
|
||||
required final List<SnAccountContact> contacts,
|
||||
required this.createdAt,
|
||||
required this.deletedAt,
|
||||
required this.description,
|
||||
required this.name,
|
||||
required this.nick,
|
||||
required final Map<String, dynamic> permNodes,
|
||||
required this.profile,
|
||||
required this.suspendedAt,
|
||||
required this.updatedAt})
|
||||
required this.affiliatedId,
|
||||
required this.affiliatedTo,
|
||||
required this.automatedBy,
|
||||
required this.automatedId})
|
||||
: _contacts = contacts,
|
||||
_permNodes = permNodes;
|
||||
_permNodes = permNodes,
|
||||
super._();
|
||||
|
||||
factory _$SnAccountImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$SnAccountImplFromJson(json);
|
||||
|
||||
@override
|
||||
@HiveField(0)
|
||||
final int id;
|
||||
@override
|
||||
final int? affiliatedId;
|
||||
final DateTime createdAt;
|
||||
@override
|
||||
final int? affiliatedTo;
|
||||
final DateTime updatedAt;
|
||||
@override
|
||||
final int? automatedBy;
|
||||
final DateTime? deletedAt;
|
||||
@override
|
||||
final int? automatedId;
|
||||
final DateTime? confirmedAt;
|
||||
final List<SnAccountContact>? _contacts;
|
||||
@override
|
||||
List<SnAccountContact>? get contacts {
|
||||
final value = _contacts;
|
||||
if (value == null) return null;
|
||||
if (_contacts is EqualUnmodifiableListView) return _contacts;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(value);
|
||||
}
|
||||
|
||||
@override
|
||||
final String avatar;
|
||||
@override
|
||||
final String banner;
|
||||
@override
|
||||
final DateTime? confirmedAt;
|
||||
final List<SnAccountContact> _contacts;
|
||||
@override
|
||||
List<SnAccountContact> get contacts {
|
||||
if (_contacts is EqualUnmodifiableListView) return _contacts;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(_contacts);
|
||||
}
|
||||
|
||||
@override
|
||||
final DateTime createdAt;
|
||||
@override
|
||||
final DateTime? deletedAt;
|
||||
@override
|
||||
final String description;
|
||||
@override
|
||||
final String name;
|
||||
@ -418,11 +417,17 @@ class _$SnAccountImpl implements _SnAccount {
|
||||
@override
|
||||
final DateTime? suspendedAt;
|
||||
@override
|
||||
final DateTime updatedAt;
|
||||
final int? affiliatedId;
|
||||
@override
|
||||
final int? affiliatedTo;
|
||||
@override
|
||||
final int? automatedBy;
|
||||
@override
|
||||
final int? automatedId;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'SnAccount(id: $id, affiliatedId: $affiliatedId, affiliatedTo: $affiliatedTo, automatedBy: $automatedBy, automatedId: $automatedId, avatar: $avatar, banner: $banner, confirmedAt: $confirmedAt, contacts: $contacts, createdAt: $createdAt, deletedAt: $deletedAt, description: $description, name: $name, nick: $nick, permNodes: $permNodes, profile: $profile, suspendedAt: $suspendedAt, updatedAt: $updatedAt)';
|
||||
return 'SnAccount(id: $id, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, confirmedAt: $confirmedAt, contacts: $contacts, avatar: $avatar, banner: $banner, description: $description, name: $name, nick: $nick, permNodes: $permNodes, profile: $profile, suspendedAt: $suspendedAt, affiliatedId: $affiliatedId, affiliatedTo: $affiliatedTo, automatedBy: $automatedBy, automatedId: $automatedId)';
|
||||
}
|
||||
|
||||
@override
|
||||
@ -431,23 +436,17 @@ class _$SnAccountImpl implements _SnAccount {
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$SnAccountImpl &&
|
||||
(identical(other.id, id) || other.id == id) &&
|
||||
(identical(other.affiliatedId, affiliatedId) ||
|
||||
other.affiliatedId == affiliatedId) &&
|
||||
(identical(other.affiliatedTo, affiliatedTo) ||
|
||||
other.affiliatedTo == affiliatedTo) &&
|
||||
(identical(other.automatedBy, automatedBy) ||
|
||||
other.automatedBy == automatedBy) &&
|
||||
(identical(other.automatedId, automatedId) ||
|
||||
other.automatedId == automatedId) &&
|
||||
(identical(other.avatar, avatar) || other.avatar == avatar) &&
|
||||
(identical(other.banner, banner) || other.banner == banner) &&
|
||||
(identical(other.createdAt, createdAt) ||
|
||||
other.createdAt == createdAt) &&
|
||||
(identical(other.updatedAt, updatedAt) ||
|
||||
other.updatedAt == updatedAt) &&
|
||||
(identical(other.deletedAt, deletedAt) ||
|
||||
other.deletedAt == deletedAt) &&
|
||||
(identical(other.confirmedAt, confirmedAt) ||
|
||||
other.confirmedAt == confirmedAt) &&
|
||||
const DeepCollectionEquality().equals(other._contacts, _contacts) &&
|
||||
(identical(other.createdAt, createdAt) ||
|
||||
other.createdAt == createdAt) &&
|
||||
(identical(other.deletedAt, deletedAt) ||
|
||||
other.deletedAt == deletedAt) &&
|
||||
(identical(other.avatar, avatar) || other.avatar == avatar) &&
|
||||
(identical(other.banner, banner) || other.banner == banner) &&
|
||||
(identical(other.description, description) ||
|
||||
other.description == description) &&
|
||||
(identical(other.name, name) || other.name == name) &&
|
||||
@ -457,8 +456,14 @@ class _$SnAccountImpl implements _SnAccount {
|
||||
(identical(other.profile, profile) || other.profile == profile) &&
|
||||
(identical(other.suspendedAt, suspendedAt) ||
|
||||
other.suspendedAt == suspendedAt) &&
|
||||
(identical(other.updatedAt, updatedAt) ||
|
||||
other.updatedAt == updatedAt));
|
||||
(identical(other.affiliatedId, affiliatedId) ||
|
||||
other.affiliatedId == affiliatedId) &&
|
||||
(identical(other.affiliatedTo, affiliatedTo) ||
|
||||
other.affiliatedTo == affiliatedTo) &&
|
||||
(identical(other.automatedBy, automatedBy) ||
|
||||
other.automatedBy == automatedBy) &&
|
||||
(identical(other.automatedId, automatedId) ||
|
||||
other.automatedId == automatedId));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@ -466,23 +471,23 @@ class _$SnAccountImpl implements _SnAccount {
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType,
|
||||
id,
|
||||
affiliatedId,
|
||||
affiliatedTo,
|
||||
automatedBy,
|
||||
automatedId,
|
||||
avatar,
|
||||
banner,
|
||||
createdAt,
|
||||
updatedAt,
|
||||
deletedAt,
|
||||
confirmedAt,
|
||||
const DeepCollectionEquality().hash(_contacts),
|
||||
createdAt,
|
||||
deletedAt,
|
||||
avatar,
|
||||
banner,
|
||||
description,
|
||||
name,
|
||||
nick,
|
||||
const DeepCollectionEquality().hash(_permNodes),
|
||||
profile,
|
||||
suspendedAt,
|
||||
updatedAt);
|
||||
affiliatedId,
|
||||
affiliatedTo,
|
||||
automatedBy,
|
||||
automatedId);
|
||||
|
||||
/// Create a copy of SnAccount
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@ -500,53 +505,49 @@ class _$SnAccountImpl implements _SnAccount {
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _SnAccount implements SnAccount {
|
||||
abstract class _SnAccount extends SnAccount {
|
||||
const factory _SnAccount(
|
||||
{required final int id,
|
||||
required final int? affiliatedId,
|
||||
required final int? affiliatedTo,
|
||||
required final int? automatedBy,
|
||||
required final int? automatedId,
|
||||
{@HiveField(0) required final int id,
|
||||
required final DateTime createdAt,
|
||||
required final DateTime updatedAt,
|
||||
required final DateTime? deletedAt,
|
||||
required final DateTime? confirmedAt,
|
||||
required final List<SnAccountContact>? contacts,
|
||||
required final String avatar,
|
||||
required final String banner,
|
||||
required final DateTime? confirmedAt,
|
||||
required final List<SnAccountContact> contacts,
|
||||
required final DateTime createdAt,
|
||||
required final DateTime? deletedAt,
|
||||
required final String description,
|
||||
required final String name,
|
||||
required final String nick,
|
||||
required final Map<String, dynamic> permNodes,
|
||||
required final SnAccountProfile? profile,
|
||||
required final DateTime? suspendedAt,
|
||||
required final DateTime updatedAt}) = _$SnAccountImpl;
|
||||
required final int? affiliatedId,
|
||||
required final int? affiliatedTo,
|
||||
required final int? automatedBy,
|
||||
required final int? automatedId}) = _$SnAccountImpl;
|
||||
const _SnAccount._() : super._();
|
||||
|
||||
factory _SnAccount.fromJson(Map<String, dynamic> json) =
|
||||
_$SnAccountImpl.fromJson;
|
||||
|
||||
@override
|
||||
@HiveField(0)
|
||||
int get id;
|
||||
@override
|
||||
int? get affiliatedId;
|
||||
DateTime get createdAt;
|
||||
@override
|
||||
int? get affiliatedTo;
|
||||
DateTime get updatedAt;
|
||||
@override
|
||||
int? get automatedBy;
|
||||
DateTime? get deletedAt;
|
||||
@override
|
||||
int? get automatedId;
|
||||
DateTime? get confirmedAt;
|
||||
@override
|
||||
List<SnAccountContact>? get contacts;
|
||||
@override
|
||||
String get avatar;
|
||||
@override
|
||||
String get banner;
|
||||
@override
|
||||
DateTime? get confirmedAt;
|
||||
@override
|
||||
List<SnAccountContact> get contacts;
|
||||
@override
|
||||
DateTime get createdAt;
|
||||
@override
|
||||
DateTime? get deletedAt;
|
||||
@override
|
||||
String get description;
|
||||
@override
|
||||
String get name;
|
||||
@ -559,7 +560,13 @@ abstract class _SnAccount implements SnAccount {
|
||||
@override
|
||||
DateTime? get suspendedAt;
|
||||
@override
|
||||
DateTime get updatedAt;
|
||||
int? get affiliatedId;
|
||||
@override
|
||||
int? get affiliatedTo;
|
||||
@override
|
||||
int? get automatedBy;
|
||||
@override
|
||||
int? get automatedId;
|
||||
|
||||
/// Create a copy of SnAccount
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
|
@ -9,22 +9,19 @@ part of 'account.dart';
|
||||
_$SnAccountImpl _$$SnAccountImplFromJson(Map<String, dynamic> json) =>
|
||||
_$SnAccountImpl(
|
||||
id: (json['id'] as num).toInt(),
|
||||
affiliatedId: (json['affiliated_id'] as num?)?.toInt(),
|
||||
affiliatedTo: (json['affiliated_to'] as num?)?.toInt(),
|
||||
automatedBy: (json['automated_by'] as num?)?.toInt(),
|
||||
automatedId: (json['automated_id'] as num?)?.toInt(),
|
||||
avatar: json['avatar'] as String,
|
||||
banner: json['banner'] as String,
|
||||
confirmedAt: json['confirmed_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['confirmed_at'] as String),
|
||||
contacts: (json['contacts'] as List<dynamic>)
|
||||
.map((e) => SnAccountContact.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
createdAt: DateTime.parse(json['created_at'] as String),
|
||||
updatedAt: DateTime.parse(json['updated_at'] as String),
|
||||
deletedAt: json['deleted_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['deleted_at'] as String),
|
||||
confirmedAt: json['confirmed_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['confirmed_at'] as String),
|
||||
contacts: (json['contacts'] as List<dynamic>?)
|
||||
?.map((e) => SnAccountContact.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
avatar: json['avatar'] as String,
|
||||
banner: json['banner'] as String,
|
||||
description: json['description'] as String,
|
||||
name: json['name'] as String,
|
||||
nick: json['nick'] as String,
|
||||
@ -35,29 +32,32 @@ _$SnAccountImpl _$$SnAccountImplFromJson(Map<String, dynamic> json) =>
|
||||
suspendedAt: json['suspended_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['suspended_at'] as String),
|
||||
updatedAt: DateTime.parse(json['updated_at'] as String),
|
||||
affiliatedId: (json['affiliated_id'] as num?)?.toInt(),
|
||||
affiliatedTo: (json['affiliated_to'] as num?)?.toInt(),
|
||||
automatedBy: (json['automated_by'] as num?)?.toInt(),
|
||||
automatedId: (json['automated_id'] as num?)?.toInt(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$SnAccountImplToJson(_$SnAccountImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'id': instance.id,
|
||||
'affiliated_id': instance.affiliatedId,
|
||||
'affiliated_to': instance.affiliatedTo,
|
||||
'automated_by': instance.automatedBy,
|
||||
'automated_id': instance.automatedId,
|
||||
'created_at': instance.createdAt.toIso8601String(),
|
||||
'updated_at': instance.updatedAt.toIso8601String(),
|
||||
'deleted_at': instance.deletedAt?.toIso8601String(),
|
||||
'confirmed_at': instance.confirmedAt?.toIso8601String(),
|
||||
'contacts': instance.contacts?.map((e) => e.toJson()).toList(),
|
||||
'avatar': instance.avatar,
|
||||
'banner': instance.banner,
|
||||
'confirmed_at': instance.confirmedAt?.toIso8601String(),
|
||||
'contacts': instance.contacts.map((e) => e.toJson()).toList(),
|
||||
'created_at': instance.createdAt.toIso8601String(),
|
||||
'deleted_at': instance.deletedAt?.toIso8601String(),
|
||||
'description': instance.description,
|
||||
'name': instance.name,
|
||||
'nick': instance.nick,
|
||||
'perm_nodes': instance.permNodes,
|
||||
'profile': instance.profile?.toJson(),
|
||||
'suspended_at': instance.suspendedAt?.toIso8601String(),
|
||||
'updated_at': instance.updatedAt.toIso8601String(),
|
||||
'affiliated_id': instance.affiliatedId,
|
||||
'affiliated_to': instance.affiliatedTo,
|
||||
'automated_by': instance.automatedBy,
|
||||
'automated_id': instance.automatedId,
|
||||
};
|
||||
|
||||
_$SnAccountContactImpl _$$SnAccountContactImplFromJson(
|
||||
|
@ -1,5 +1,6 @@
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:hive_flutter/hive_flutter.dart';
|
||||
import 'package:surface/types/account.dart';
|
||||
import 'package:surface/types/realm.dart';
|
||||
|
||||
part 'chat.freezed.dart';
|
||||
@ -18,8 +19,8 @@ class SnChannel with _$SnChannel {
|
||||
@HiveField(4) required String alias,
|
||||
@HiveField(5) required String name,
|
||||
@HiveField(6) required String description,
|
||||
@HiveField(7) required List<dynamic> members,
|
||||
dynamic messages,
|
||||
@HiveField(7) required List<dynamic>? members,
|
||||
List<SnChatMessage>? messages,
|
||||
dynamic calls,
|
||||
@HiveField(8) required int type,
|
||||
@HiveField(9) required int accountId,
|
||||
@ -33,4 +34,53 @@ class SnChannel with _$SnChannel {
|
||||
_$SnChannelFromJson(json);
|
||||
|
||||
String get key => '${realm?.alias ?? 'global'}:$alias';
|
||||
String get keyPath => '${realm?.alias ?? 'global'}/$alias';
|
||||
}
|
||||
|
||||
@freezed
|
||||
class SnChannelMember with _$SnChannelMember {
|
||||
const SnChannelMember._();
|
||||
|
||||
@HiveType(typeId: 3)
|
||||
const factory SnChannelMember({
|
||||
@HiveField(0) required int id,
|
||||
@HiveField(1) required DateTime createdAt,
|
||||
@HiveField(2) required DateTime updatedAt,
|
||||
@HiveField(3) required DateTime? deletedAt,
|
||||
@HiveField(4) required int channelId,
|
||||
@HiveField(5) required int accountId,
|
||||
@HiveField(6) required String? nick,
|
||||
@HiveField(7) required SnChannel? channel,
|
||||
@HiveField(8) required SnAccount? account,
|
||||
@Default(0) int notify,
|
||||
@HiveField(9) required int powerLevel,
|
||||
dynamic calls,
|
||||
dynamic events,
|
||||
}) = _SnChannelMember;
|
||||
|
||||
factory SnChannelMember.fromJson(Map<String, dynamic> json) =>
|
||||
_$SnChannelMemberFromJson(json);
|
||||
}
|
||||
|
||||
@freezed
|
||||
class SnChatMessage with _$SnChatMessage {
|
||||
const SnChatMessage._();
|
||||
|
||||
@HiveType(typeId: 4)
|
||||
const factory SnChatMessage({
|
||||
@HiveField(0) required int id,
|
||||
@HiveField(1) required DateTime createdAt,
|
||||
@HiveField(2) required DateTime updatedAt,
|
||||
@HiveField(3) required DateTime? deletedAt,
|
||||
@HiveField(4) required String uuid,
|
||||
@HiveField(5) required Map<String, dynamic> body,
|
||||
@HiveField(6) required String type,
|
||||
@HiveField(7) required SnChannel channel,
|
||||
@HiveField(8) required SnChannelMember sender,
|
||||
@HiveField(9) required int channelId,
|
||||
@HiveField(10) required int senderId,
|
||||
}) = _SnChatMessage;
|
||||
|
||||
factory SnChatMessage.fromJson(Map<String, dynamic> json) =>
|
||||
_$SnChatMessageFromJson(json);
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -24,7 +24,7 @@ class SnChannelImplAdapter extends TypeAdapter<_$SnChannelImpl> {
|
||||
alias: fields[4] as String,
|
||||
name: fields[5] as String,
|
||||
description: fields[6] as String,
|
||||
members: (fields[7] as List).cast<dynamic>(),
|
||||
members: (fields[7] as List?)?.cast<dynamic>(),
|
||||
type: fields[8] as int,
|
||||
accountId: fields[9] as int,
|
||||
realm: fields[10] as SnRealm?,
|
||||
@ -79,6 +79,131 @@ class SnChannelImplAdapter extends TypeAdapter<_$SnChannelImpl> {
|
||||
typeId == other.typeId;
|
||||
}
|
||||
|
||||
class SnChannelMemberImplAdapter extends TypeAdapter<_$SnChannelMemberImpl> {
|
||||
@override
|
||||
final int typeId = 3;
|
||||
|
||||
@override
|
||||
_$SnChannelMemberImpl read(BinaryReader reader) {
|
||||
final numOfFields = reader.readByte();
|
||||
final fields = <int, dynamic>{
|
||||
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
|
||||
};
|
||||
return _$SnChannelMemberImpl(
|
||||
id: fields[0] as int,
|
||||
createdAt: fields[1] as DateTime,
|
||||
updatedAt: fields[2] as DateTime,
|
||||
deletedAt: fields[3] as DateTime?,
|
||||
channelId: fields[4] as int,
|
||||
accountId: fields[5] as int,
|
||||
nick: fields[6] as String?,
|
||||
channel: fields[7] as SnChannel?,
|
||||
account: fields[8] as SnAccount?,
|
||||
powerLevel: fields[9] as int,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void write(BinaryWriter writer, _$SnChannelMemberImpl obj) {
|
||||
writer
|
||||
..writeByte(10)
|
||||
..writeByte(0)
|
||||
..write(obj.id)
|
||||
..writeByte(1)
|
||||
..write(obj.createdAt)
|
||||
..writeByte(2)
|
||||
..write(obj.updatedAt)
|
||||
..writeByte(3)
|
||||
..write(obj.deletedAt)
|
||||
..writeByte(4)
|
||||
..write(obj.channelId)
|
||||
..writeByte(5)
|
||||
..write(obj.accountId)
|
||||
..writeByte(6)
|
||||
..write(obj.nick)
|
||||
..writeByte(7)
|
||||
..write(obj.channel)
|
||||
..writeByte(8)
|
||||
..write(obj.account)
|
||||
..writeByte(9)
|
||||
..write(obj.powerLevel);
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => typeId.hashCode;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
other is SnChannelMemberImplAdapter &&
|
||||
runtimeType == other.runtimeType &&
|
||||
typeId == other.typeId;
|
||||
}
|
||||
|
||||
class SnChatMessageImplAdapter extends TypeAdapter<_$SnChatMessageImpl> {
|
||||
@override
|
||||
final int typeId = 4;
|
||||
|
||||
@override
|
||||
_$SnChatMessageImpl read(BinaryReader reader) {
|
||||
final numOfFields = reader.readByte();
|
||||
final fields = <int, dynamic>{
|
||||
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
|
||||
};
|
||||
return _$SnChatMessageImpl(
|
||||
id: fields[0] as int,
|
||||
createdAt: fields[1] as DateTime,
|
||||
updatedAt: fields[2] as DateTime,
|
||||
deletedAt: fields[3] as DateTime?,
|
||||
uuid: fields[4] as String,
|
||||
body: (fields[5] as Map).cast<String, dynamic>(),
|
||||
type: fields[6] as String,
|
||||
channel: fields[7] as SnChannel,
|
||||
sender: fields[8] as SnChannelMember,
|
||||
channelId: fields[9] as int,
|
||||
senderId: fields[10] as int,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void write(BinaryWriter writer, _$SnChatMessageImpl obj) {
|
||||
writer
|
||||
..writeByte(11)
|
||||
..writeByte(0)
|
||||
..write(obj.id)
|
||||
..writeByte(1)
|
||||
..write(obj.createdAt)
|
||||
..writeByte(2)
|
||||
..write(obj.updatedAt)
|
||||
..writeByte(3)
|
||||
..write(obj.deletedAt)
|
||||
..writeByte(4)
|
||||
..write(obj.uuid)
|
||||
..writeByte(6)
|
||||
..write(obj.type)
|
||||
..writeByte(7)
|
||||
..write(obj.channel)
|
||||
..writeByte(8)
|
||||
..write(obj.sender)
|
||||
..writeByte(9)
|
||||
..write(obj.channelId)
|
||||
..writeByte(10)
|
||||
..write(obj.senderId)
|
||||
..writeByte(5)
|
||||
..write(obj.body);
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => typeId.hashCode;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
other is SnChatMessageImplAdapter &&
|
||||
runtimeType == other.runtimeType &&
|
||||
typeId == other.typeId;
|
||||
}
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
@ -92,8 +217,10 @@ _$SnChannelImpl _$$SnChannelImplFromJson(Map<String, dynamic> json) =>
|
||||
alias: json['alias'] as String,
|
||||
name: json['name'] as String,
|
||||
description: json['description'] as String,
|
||||
members: json['members'] as List<dynamic>,
|
||||
messages: json['messages'],
|
||||
members: json['members'] as List<dynamic>?,
|
||||
messages: (json['messages'] as List<dynamic>?)
|
||||
?.map((e) => SnChatMessage.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
calls: json['calls'],
|
||||
type: (json['type'] as num).toInt(),
|
||||
accountId: (json['account_id'] as num).toInt(),
|
||||
@ -115,7 +242,7 @@ Map<String, dynamic> _$$SnChannelImplToJson(_$SnChannelImpl instance) =>
|
||||
'name': instance.name,
|
||||
'description': instance.description,
|
||||
'members': instance.members,
|
||||
'messages': instance.messages,
|
||||
'messages': instance.messages?.map((e) => e.toJson()).toList(),
|
||||
'calls': instance.calls,
|
||||
'type': instance.type,
|
||||
'account_id': instance.accountId,
|
||||
@ -124,3 +251,77 @@ Map<String, dynamic> _$$SnChannelImplToJson(_$SnChannelImpl instance) =>
|
||||
'is_public': instance.isPublic,
|
||||
'is_community': instance.isCommunity,
|
||||
};
|
||||
|
||||
_$SnChannelMemberImpl _$$SnChannelMemberImplFromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
_$SnChannelMemberImpl(
|
||||
id: (json['id'] as num).toInt(),
|
||||
createdAt: DateTime.parse(json['created_at'] as String),
|
||||
updatedAt: DateTime.parse(json['updated_at'] as String),
|
||||
deletedAt: json['deleted_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['deleted_at'] as String),
|
||||
channelId: (json['channel_id'] as num).toInt(),
|
||||
accountId: (json['account_id'] as num).toInt(),
|
||||
nick: json['nick'] as String?,
|
||||
channel: json['channel'] == null
|
||||
? null
|
||||
: SnChannel.fromJson(json['channel'] as Map<String, dynamic>),
|
||||
account: json['account'] == null
|
||||
? null
|
||||
: SnAccount.fromJson(json['account'] as Map<String, dynamic>),
|
||||
notify: (json['notify'] as num?)?.toInt() ?? 0,
|
||||
powerLevel: (json['power_level'] as num).toInt(),
|
||||
calls: json['calls'],
|
||||
events: json['events'],
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$SnChannelMemberImplToJson(
|
||||
_$SnChannelMemberImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'id': instance.id,
|
||||
'created_at': instance.createdAt.toIso8601String(),
|
||||
'updated_at': instance.updatedAt.toIso8601String(),
|
||||
'deleted_at': instance.deletedAt?.toIso8601String(),
|
||||
'channel_id': instance.channelId,
|
||||
'account_id': instance.accountId,
|
||||
'nick': instance.nick,
|
||||
'channel': instance.channel?.toJson(),
|
||||
'account': instance.account?.toJson(),
|
||||
'notify': instance.notify,
|
||||
'power_level': instance.powerLevel,
|
||||
'calls': instance.calls,
|
||||
'events': instance.events,
|
||||
};
|
||||
|
||||
_$SnChatMessageImpl _$$SnChatMessageImplFromJson(Map<String, dynamic> json) =>
|
||||
_$SnChatMessageImpl(
|
||||
id: (json['id'] as num).toInt(),
|
||||
createdAt: DateTime.parse(json['created_at'] as String),
|
||||
updatedAt: DateTime.parse(json['updated_at'] as String),
|
||||
deletedAt: json['deleted_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['deleted_at'] as String),
|
||||
uuid: json['uuid'] as String,
|
||||
body: json['body'] as Map<String, dynamic>,
|
||||
type: json['type'] as String,
|
||||
channel: SnChannel.fromJson(json['channel'] as Map<String, dynamic>),
|
||||
sender: SnChannelMember.fromJson(json['sender'] as Map<String, dynamic>),
|
||||
channelId: (json['channel_id'] as num).toInt(),
|
||||
senderId: (json['sender_id'] as num).toInt(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$SnChatMessageImplToJson(_$SnChatMessageImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'id': instance.id,
|
||||
'created_at': instance.createdAt.toIso8601String(),
|
||||
'updated_at': instance.updatedAt.toIso8601String(),
|
||||
'deleted_at': instance.deletedAt?.toIso8601String(),
|
||||
'uuid': instance.uuid,
|
||||
'body': instance.body,
|
||||
'type': instance.type,
|
||||
'channel': instance.channel.toJson(),
|
||||
'sender': instance.sender.toJson(),
|
||||
'channel_id': instance.channelId,
|
||||
'sender_id': instance.senderId,
|
||||
};
|
||||
|
@ -1,4 +1,5 @@
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:hive_flutter/hive_flutter.dart';
|
||||
import 'package:surface/types/account.dart';
|
||||
|
||||
part 'realm.freezed.dart';
|
||||
@ -24,21 +25,24 @@ class SnRealmMember with _$SnRealmMember {
|
||||
|
||||
@freezed
|
||||
class SnRealm with _$SnRealm {
|
||||
const SnRealm._();
|
||||
|
||||
@HiveType(typeId: 1)
|
||||
const factory SnRealm({
|
||||
required int id,
|
||||
required DateTime createdAt,
|
||||
required DateTime updatedAt,
|
||||
required DateTime? deletedAt,
|
||||
required String alias,
|
||||
required String name,
|
||||
required String description,
|
||||
required List<SnRealmMember>? members,
|
||||
required String? avatar,
|
||||
required String? banner,
|
||||
required Map<String, dynamic>? accessPolicy,
|
||||
required bool isPublic,
|
||||
required bool isCommunity,
|
||||
required int accountId,
|
||||
@HiveField(0) required int id,
|
||||
@HiveField(1) required DateTime createdAt,
|
||||
@HiveField(2) required DateTime updatedAt,
|
||||
@HiveField(3) required DateTime? deletedAt,
|
||||
@HiveField(4) required String alias,
|
||||
@HiveField(5) required String name,
|
||||
@HiveField(6) required String description,
|
||||
List<SnRealmMember>? members,
|
||||
@HiveField(7) required String? avatar,
|
||||
@HiveField(8) required String? banner,
|
||||
@HiveField(9) required Map<String, dynamic>? accessPolicy,
|
||||
@HiveField(10) required int accountId,
|
||||
@HiveField(11) required bool isPublic,
|
||||
@HiveField(12) required bool isCommunity,
|
||||
}) = _SnRealm;
|
||||
|
||||
factory SnRealm.fromJson(Map<String, dynamic> json) =>
|
||||
|
@ -367,20 +367,33 @@ SnRealm _$SnRealmFromJson(Map<String, dynamic> json) {
|
||||
|
||||
/// @nodoc
|
||||
mixin _$SnRealm {
|
||||
@HiveField(0)
|
||||
int get id => throw _privateConstructorUsedError;
|
||||
@HiveField(1)
|
||||
DateTime get createdAt => throw _privateConstructorUsedError;
|
||||
@HiveField(2)
|
||||
DateTime get updatedAt => throw _privateConstructorUsedError;
|
||||
@HiveField(3)
|
||||
DateTime? get deletedAt => throw _privateConstructorUsedError;
|
||||
@HiveField(4)
|
||||
String get alias => throw _privateConstructorUsedError;
|
||||
@HiveField(5)
|
||||
String get name => throw _privateConstructorUsedError;
|
||||
@HiveField(6)
|
||||
String get description => throw _privateConstructorUsedError;
|
||||
List<SnRealmMember>? get members => throw _privateConstructorUsedError;
|
||||
@HiveField(7)
|
||||
String? get avatar => throw _privateConstructorUsedError;
|
||||
@HiveField(8)
|
||||
String? get banner => throw _privateConstructorUsedError;
|
||||
@HiveField(9)
|
||||
Map<String, dynamic>? get accessPolicy => throw _privateConstructorUsedError;
|
||||
bool get isPublic => throw _privateConstructorUsedError;
|
||||
bool get isCommunity => throw _privateConstructorUsedError;
|
||||
@HiveField(10)
|
||||
int get accountId => throw _privateConstructorUsedError;
|
||||
@HiveField(11)
|
||||
bool get isPublic => throw _privateConstructorUsedError;
|
||||
@HiveField(12)
|
||||
bool get isCommunity => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this SnRealm to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@ -397,20 +410,20 @@ abstract class $SnRealmCopyWith<$Res> {
|
||||
_$SnRealmCopyWithImpl<$Res, SnRealm>;
|
||||
@useResult
|
||||
$Res call(
|
||||
{int id,
|
||||
DateTime createdAt,
|
||||
DateTime updatedAt,
|
||||
DateTime? deletedAt,
|
||||
String alias,
|
||||
String name,
|
||||
String description,
|
||||
{@HiveField(0) int id,
|
||||
@HiveField(1) DateTime createdAt,
|
||||
@HiveField(2) DateTime updatedAt,
|
||||
@HiveField(3) DateTime? deletedAt,
|
||||
@HiveField(4) String alias,
|
||||
@HiveField(5) String name,
|
||||
@HiveField(6) String description,
|
||||
List<SnRealmMember>? members,
|
||||
String? avatar,
|
||||
String? banner,
|
||||
Map<String, dynamic>? accessPolicy,
|
||||
bool isPublic,
|
||||
bool isCommunity,
|
||||
int accountId});
|
||||
@HiveField(7) String? avatar,
|
||||
@HiveField(8) String? banner,
|
||||
@HiveField(9) Map<String, dynamic>? accessPolicy,
|
||||
@HiveField(10) int accountId,
|
||||
@HiveField(11) bool isPublic,
|
||||
@HiveField(12) bool isCommunity});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@ -439,9 +452,9 @@ class _$SnRealmCopyWithImpl<$Res, $Val extends SnRealm>
|
||||
Object? avatar = freezed,
|
||||
Object? banner = freezed,
|
||||
Object? accessPolicy = freezed,
|
||||
Object? accountId = null,
|
||||
Object? isPublic = null,
|
||||
Object? isCommunity = null,
|
||||
Object? accountId = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
id: null == id
|
||||
@ -488,6 +501,10 @@ class _$SnRealmCopyWithImpl<$Res, $Val extends SnRealm>
|
||||
? _value.accessPolicy
|
||||
: accessPolicy // ignore: cast_nullable_to_non_nullable
|
||||
as Map<String, dynamic>?,
|
||||
accountId: null == accountId
|
||||
? _value.accountId
|
||||
: accountId // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
isPublic: null == isPublic
|
||||
? _value.isPublic
|
||||
: isPublic // ignore: cast_nullable_to_non_nullable
|
||||
@ -496,10 +513,6 @@ class _$SnRealmCopyWithImpl<$Res, $Val extends SnRealm>
|
||||
? _value.isCommunity
|
||||
: isCommunity // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
accountId: null == accountId
|
||||
? _value.accountId
|
||||
: accountId // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
@ -512,20 +525,20 @@ abstract class _$$SnRealmImplCopyWith<$Res> implements $SnRealmCopyWith<$Res> {
|
||||
@override
|
||||
@useResult
|
||||
$Res call(
|
||||
{int id,
|
||||
DateTime createdAt,
|
||||
DateTime updatedAt,
|
||||
DateTime? deletedAt,
|
||||
String alias,
|
||||
String name,
|
||||
String description,
|
||||
{@HiveField(0) int id,
|
||||
@HiveField(1) DateTime createdAt,
|
||||
@HiveField(2) DateTime updatedAt,
|
||||
@HiveField(3) DateTime? deletedAt,
|
||||
@HiveField(4) String alias,
|
||||
@HiveField(5) String name,
|
||||
@HiveField(6) String description,
|
||||
List<SnRealmMember>? members,
|
||||
String? avatar,
|
||||
String? banner,
|
||||
Map<String, dynamic>? accessPolicy,
|
||||
bool isPublic,
|
||||
bool isCommunity,
|
||||
int accountId});
|
||||
@HiveField(7) String? avatar,
|
||||
@HiveField(8) String? banner,
|
||||
@HiveField(9) Map<String, dynamic>? accessPolicy,
|
||||
@HiveField(10) int accountId,
|
||||
@HiveField(11) bool isPublic,
|
||||
@HiveField(12) bool isCommunity});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@ -552,9 +565,9 @@ class __$$SnRealmImplCopyWithImpl<$Res>
|
||||
Object? avatar = freezed,
|
||||
Object? banner = freezed,
|
||||
Object? accessPolicy = freezed,
|
||||
Object? accountId = null,
|
||||
Object? isPublic = null,
|
||||
Object? isCommunity = null,
|
||||
Object? accountId = null,
|
||||
}) {
|
||||
return _then(_$SnRealmImpl(
|
||||
id: null == id
|
||||
@ -601,6 +614,10 @@ class __$$SnRealmImplCopyWithImpl<$Res>
|
||||
? _value._accessPolicy
|
||||
: accessPolicy // ignore: cast_nullable_to_non_nullable
|
||||
as Map<String, dynamic>?,
|
||||
accountId: null == accountId
|
||||
? _value.accountId
|
||||
: accountId // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
isPublic: null == isPublic
|
||||
? _value.isPublic
|
||||
: isPublic // ignore: cast_nullable_to_non_nullable
|
||||
@ -609,51 +626,56 @@ class __$$SnRealmImplCopyWithImpl<$Res>
|
||||
? _value.isCommunity
|
||||
: isCommunity // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
accountId: null == accountId
|
||||
? _value.accountId
|
||||
: accountId // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _$SnRealmImpl implements _SnRealm {
|
||||
@HiveType(typeId: 1)
|
||||
class _$SnRealmImpl extends _SnRealm {
|
||||
const _$SnRealmImpl(
|
||||
{required this.id,
|
||||
required this.createdAt,
|
||||
required this.updatedAt,
|
||||
required this.deletedAt,
|
||||
required this.alias,
|
||||
required this.name,
|
||||
required this.description,
|
||||
required final List<SnRealmMember>? members,
|
||||
required this.avatar,
|
||||
required this.banner,
|
||||
required final Map<String, dynamic>? accessPolicy,
|
||||
required this.isPublic,
|
||||
required this.isCommunity,
|
||||
required this.accountId})
|
||||
{@HiveField(0) required this.id,
|
||||
@HiveField(1) required this.createdAt,
|
||||
@HiveField(2) required this.updatedAt,
|
||||
@HiveField(3) required this.deletedAt,
|
||||
@HiveField(4) required this.alias,
|
||||
@HiveField(5) required this.name,
|
||||
@HiveField(6) required this.description,
|
||||
final List<SnRealmMember>? members,
|
||||
@HiveField(7) required this.avatar,
|
||||
@HiveField(8) required this.banner,
|
||||
@HiveField(9) required final Map<String, dynamic>? accessPolicy,
|
||||
@HiveField(10) required this.accountId,
|
||||
@HiveField(11) required this.isPublic,
|
||||
@HiveField(12) required this.isCommunity})
|
||||
: _members = members,
|
||||
_accessPolicy = accessPolicy;
|
||||
_accessPolicy = accessPolicy,
|
||||
super._();
|
||||
|
||||
factory _$SnRealmImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$SnRealmImplFromJson(json);
|
||||
|
||||
@override
|
||||
@HiveField(0)
|
||||
final int id;
|
||||
@override
|
||||
@HiveField(1)
|
||||
final DateTime createdAt;
|
||||
@override
|
||||
@HiveField(2)
|
||||
final DateTime updatedAt;
|
||||
@override
|
||||
@HiveField(3)
|
||||
final DateTime? deletedAt;
|
||||
@override
|
||||
@HiveField(4)
|
||||
final String alias;
|
||||
@override
|
||||
@HiveField(5)
|
||||
final String name;
|
||||
@override
|
||||
@HiveField(6)
|
||||
final String description;
|
||||
final List<SnRealmMember>? _members;
|
||||
@override
|
||||
@ -666,11 +688,14 @@ class _$SnRealmImpl implements _SnRealm {
|
||||
}
|
||||
|
||||
@override
|
||||
@HiveField(7)
|
||||
final String? avatar;
|
||||
@override
|
||||
@HiveField(8)
|
||||
final String? banner;
|
||||
final Map<String, dynamic>? _accessPolicy;
|
||||
@override
|
||||
@HiveField(9)
|
||||
Map<String, dynamic>? get accessPolicy {
|
||||
final value = _accessPolicy;
|
||||
if (value == null) return null;
|
||||
@ -680,15 +705,18 @@ class _$SnRealmImpl implements _SnRealm {
|
||||
}
|
||||
|
||||
@override
|
||||
@HiveField(10)
|
||||
final int accountId;
|
||||
@override
|
||||
@HiveField(11)
|
||||
final bool isPublic;
|
||||
@override
|
||||
@HiveField(12)
|
||||
final bool isCommunity;
|
||||
@override
|
||||
final int accountId;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'SnRealm(id: $id, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, alias: $alias, name: $name, description: $description, members: $members, avatar: $avatar, banner: $banner, accessPolicy: $accessPolicy, isPublic: $isPublic, isCommunity: $isCommunity, accountId: $accountId)';
|
||||
return 'SnRealm(id: $id, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, alias: $alias, name: $name, description: $description, members: $members, avatar: $avatar, banner: $banner, accessPolicy: $accessPolicy, accountId: $accountId, isPublic: $isPublic, isCommunity: $isCommunity)';
|
||||
}
|
||||
|
||||
@override
|
||||
@ -712,12 +740,12 @@ class _$SnRealmImpl implements _SnRealm {
|
||||
(identical(other.banner, banner) || other.banner == banner) &&
|
||||
const DeepCollectionEquality()
|
||||
.equals(other._accessPolicy, _accessPolicy) &&
|
||||
(identical(other.accountId, accountId) ||
|
||||
other.accountId == accountId) &&
|
||||
(identical(other.isPublic, isPublic) ||
|
||||
other.isPublic == isPublic) &&
|
||||
(identical(other.isCommunity, isCommunity) ||
|
||||
other.isCommunity == isCommunity) &&
|
||||
(identical(other.accountId, accountId) ||
|
||||
other.accountId == accountId));
|
||||
other.isCommunity == isCommunity));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@ -735,9 +763,9 @@ class _$SnRealmImpl implements _SnRealm {
|
||||
avatar,
|
||||
banner,
|
||||
const DeepCollectionEquality().hash(_accessPolicy),
|
||||
accountId,
|
||||
isPublic,
|
||||
isCommunity,
|
||||
accountId);
|
||||
isCommunity);
|
||||
|
||||
/// Create a copy of SnRealm
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@ -755,53 +783,67 @@ class _$SnRealmImpl implements _SnRealm {
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _SnRealm implements SnRealm {
|
||||
abstract class _SnRealm extends SnRealm {
|
||||
const factory _SnRealm(
|
||||
{required final int id,
|
||||
required final DateTime createdAt,
|
||||
required final DateTime updatedAt,
|
||||
required final DateTime? deletedAt,
|
||||
required final String alias,
|
||||
required final String name,
|
||||
required final String description,
|
||||
required final List<SnRealmMember>? members,
|
||||
required final String? avatar,
|
||||
required final String? banner,
|
||||
required final Map<String, dynamic>? accessPolicy,
|
||||
required final bool isPublic,
|
||||
required final bool isCommunity,
|
||||
required final int accountId}) = _$SnRealmImpl;
|
||||
{@HiveField(0) required final int id,
|
||||
@HiveField(1) required final DateTime createdAt,
|
||||
@HiveField(2) required final DateTime updatedAt,
|
||||
@HiveField(3) required final DateTime? deletedAt,
|
||||
@HiveField(4) required final String alias,
|
||||
@HiveField(5) required final String name,
|
||||
@HiveField(6) required final String description,
|
||||
final List<SnRealmMember>? members,
|
||||
@HiveField(7) required final String? avatar,
|
||||
@HiveField(8) required final String? banner,
|
||||
@HiveField(9) required final Map<String, dynamic>? accessPolicy,
|
||||
@HiveField(10) required final int accountId,
|
||||
@HiveField(11) required final bool isPublic,
|
||||
@HiveField(12) required final bool isCommunity}) = _$SnRealmImpl;
|
||||
const _SnRealm._() : super._();
|
||||
|
||||
factory _SnRealm.fromJson(Map<String, dynamic> json) = _$SnRealmImpl.fromJson;
|
||||
|
||||
@override
|
||||
@HiveField(0)
|
||||
int get id;
|
||||
@override
|
||||
@HiveField(1)
|
||||
DateTime get createdAt;
|
||||
@override
|
||||
@HiveField(2)
|
||||
DateTime get updatedAt;
|
||||
@override
|
||||
@HiveField(3)
|
||||
DateTime? get deletedAt;
|
||||
@override
|
||||
@HiveField(4)
|
||||
String get alias;
|
||||
@override
|
||||
@HiveField(5)
|
||||
String get name;
|
||||
@override
|
||||
@HiveField(6)
|
||||
String get description;
|
||||
@override
|
||||
List<SnRealmMember>? get members;
|
||||
@override
|
||||
@HiveField(7)
|
||||
String? get avatar;
|
||||
@override
|
||||
@HiveField(8)
|
||||
String? get banner;
|
||||
@override
|
||||
@HiveField(9)
|
||||
Map<String, dynamic>? get accessPolicy;
|
||||
@override
|
||||
@HiveField(10)
|
||||
int get accountId;
|
||||
@override
|
||||
@HiveField(11)
|
||||
bool get isPublic;
|
||||
@override
|
||||
@HiveField(12)
|
||||
bool get isCommunity;
|
||||
@override
|
||||
int get accountId;
|
||||
|
||||
/// Create a copy of SnRealm
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
|
@ -2,6 +2,80 @@
|
||||
|
||||
part of 'realm.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// TypeAdapterGenerator
|
||||
// **************************************************************************
|
||||
|
||||
class SnRealmImplAdapter extends TypeAdapter<_$SnRealmImpl> {
|
||||
@override
|
||||
final int typeId = 1;
|
||||
|
||||
@override
|
||||
_$SnRealmImpl read(BinaryReader reader) {
|
||||
final numOfFields = reader.readByte();
|
||||
final fields = <int, dynamic>{
|
||||
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
|
||||
};
|
||||
return _$SnRealmImpl(
|
||||
id: fields[0] as int,
|
||||
createdAt: fields[1] as DateTime,
|
||||
updatedAt: fields[2] as DateTime,
|
||||
deletedAt: fields[3] as DateTime?,
|
||||
alias: fields[4] as String,
|
||||
name: fields[5] as String,
|
||||
description: fields[6] as String,
|
||||
avatar: fields[7] as String?,
|
||||
banner: fields[8] as String?,
|
||||
accessPolicy: (fields[9] as Map?)?.cast<String, dynamic>(),
|
||||
accountId: fields[10] as int,
|
||||
isPublic: fields[11] as bool,
|
||||
isCommunity: fields[12] as bool,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void write(BinaryWriter writer, _$SnRealmImpl obj) {
|
||||
writer
|
||||
..writeByte(13)
|
||||
..writeByte(0)
|
||||
..write(obj.id)
|
||||
..writeByte(1)
|
||||
..write(obj.createdAt)
|
||||
..writeByte(2)
|
||||
..write(obj.updatedAt)
|
||||
..writeByte(3)
|
||||
..write(obj.deletedAt)
|
||||
..writeByte(4)
|
||||
..write(obj.alias)
|
||||
..writeByte(5)
|
||||
..write(obj.name)
|
||||
..writeByte(6)
|
||||
..write(obj.description)
|
||||
..writeByte(7)
|
||||
..write(obj.avatar)
|
||||
..writeByte(8)
|
||||
..write(obj.banner)
|
||||
..writeByte(10)
|
||||
..write(obj.accountId)
|
||||
..writeByte(11)
|
||||
..write(obj.isPublic)
|
||||
..writeByte(12)
|
||||
..write(obj.isCommunity)
|
||||
..writeByte(9)
|
||||
..write(obj.accessPolicy);
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => typeId.hashCode;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
other is SnRealmImplAdapter &&
|
||||
runtimeType == other.runtimeType &&
|
||||
typeId == other.typeId;
|
||||
}
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
@ -51,9 +125,9 @@ _$SnRealmImpl _$$SnRealmImplFromJson(Map<String, dynamic> json) =>
|
||||
avatar: json['avatar'] as String?,
|
||||
banner: json['banner'] as String?,
|
||||
accessPolicy: json['access_policy'] as Map<String, dynamic>?,
|
||||
accountId: (json['account_id'] as num).toInt(),
|
||||
isPublic: json['is_public'] as bool,
|
||||
isCommunity: json['is_community'] as bool,
|
||||
accountId: (json['account_id'] as num).toInt(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$SnRealmImplToJson(_$SnRealmImpl instance) =>
|
||||
@ -69,7 +143,7 @@ Map<String, dynamic> _$$SnRealmImplToJson(_$SnRealmImpl instance) =>
|
||||
'avatar': instance.avatar,
|
||||
'banner': instance.banner,
|
||||
'access_policy': instance.accessPolicy,
|
||||
'account_id': instance.accountId,
|
||||
'is_public': instance.isPublic,
|
||||
'is_community': instance.isCommunity,
|
||||
'account_id': instance.accountId,
|
||||
};
|
||||
|
43
lib/widgets/chat/chat_message.dart
Normal file
43
lib/widgets/chat/chat_message.dart
Normal file
@ -0,0 +1,43 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:gap/gap.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
import 'package:surface/providers/user_directory.dart';
|
||||
import 'package:surface/types/chat.dart';
|
||||
import 'package:surface/widgets/account/account_image.dart';
|
||||
import 'package:surface/widgets/markdown_content.dart';
|
||||
|
||||
class ChatMessage extends StatelessWidget {
|
||||
final SnChatMessage data;
|
||||
const ChatMessage({super.key, required this.data});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final ud = context.read<UserDirectoryProvider>();
|
||||
final user = ud.getAccountFromCache(data.sender.accountId);
|
||||
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
AccountImage(
|
||||
content: user?.avatar,
|
||||
),
|
||||
const Gap(8),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
(data.sender.nick?.isNotEmpty ?? false)
|
||||
? data.sender.nick!
|
||||
: user!.nick,
|
||||
).bold(),
|
||||
if (data.body['text'] != null)
|
||||
MarkdownTextContent(content: data.body['text']),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
76
lib/widgets/chat/chat_message_input.dart
Normal file
76
lib/widgets/chat/chat_message_input.dart
Normal file
@ -0,0 +1,76 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:gap/gap.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
import 'package:surface/controllers/chat_message_controller.dart';
|
||||
|
||||
class ChatMessageInput extends StatefulWidget {
|
||||
final ChatMessageController controller;
|
||||
const ChatMessageInput({super.key, required this.controller});
|
||||
|
||||
@override
|
||||
State<ChatMessageInput> createState() => _ChatMessageInputState();
|
||||
}
|
||||
|
||||
class _ChatMessageInputState extends State<ChatMessageInput> {
|
||||
final TextEditingController _contentController = TextEditingController();
|
||||
final FocusNode _focusNode = FocusNode();
|
||||
|
||||
void _sendMessage() {
|
||||
widget.controller.sendMessage(
|
||||
'messages.new',
|
||||
_contentController.text,
|
||||
);
|
||||
_contentController.clear();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_contentController.dispose();
|
||||
_focusNode.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SizedBox(
|
||||
height: 72,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: TextField(
|
||||
focusNode: _focusNode,
|
||||
controller: _contentController,
|
||||
decoration: InputDecoration(
|
||||
isCollapsed: true,
|
||||
hintText: 'Type a message...',
|
||||
border: InputBorder.none,
|
||||
),
|
||||
onSubmitted: (_) {
|
||||
_sendMessage();
|
||||
_focusNode.requestFocus();
|
||||
},
|
||||
),
|
||||
),
|
||||
const Gap(8),
|
||||
IconButton(
|
||||
onPressed: _sendMessage,
|
||||
icon: Icon(
|
||||
Symbols.send,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
visualDensity: const VisualDensity(
|
||||
horizontal: -4,
|
||||
vertical: -4,
|
||||
),
|
||||
),
|
||||
],
|
||||
).padding(horizontal: 16, vertical: 12),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -950,10 +950,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: material_symbols_icons
|
||||
sha256: "7b723abea4ad37e16fe921f1f1971cbb9b0f66d223a8c99981168a2306416b98"
|
||||
sha256: "1dea2aef1c83434f832f14341a5ffa1254e76b68e4d90333f95f8a2643bf1024"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.2791.1"
|
||||
version: "4.2799.0"
|
||||
meta:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
Loading…
Reference in New Issue
Block a user