diff --git a/lib/controllers/chat_message_controller.dart b/lib/controllers/chat_message_controller.dart new file mode 100644 index 0000000..94e64d1 --- /dev/null +++ b/lib/controllers/chat_message_controller.dart @@ -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(); + _ud = context.read(); + } + + bool isPending = true; + bool isLoading = false; + + int? messageTotal; + + bool get isAllLoaded => + messageTotal != null && messages.length >= messageTotal!; + + String? _boxKey; + SnChannel? _channel; + + List messages = List.empty(growable: true); + + Box? get _box => + (_boxKey == null || isPending) ? null : Hive.box(_boxKey!); + + Future initialize(SnChannel channel) async { + _channel = channel; + _boxKey = '$kChatMessageBoxPrefix${channel.id}'; + await Hive.openBox(_boxKey!); + isPending = false; + notifyListeners(); + } + + Future _saveMessageToLocal(Iterable messages) async { + if (_box == null) return; + await _box!.putAll({ + for (final message in messages) message.id: message, + }); + } + + Future _addMessage(SnChatMessage message) async { + messages.add(message); + notifyListeners(); + + if (_box == null) return; + await _box!.put(message.id, message); + } + + Future sendMessage( + String type, + String content, { + int? quoteId, + int? relatedId, + List? 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, + ); + 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 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> 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.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 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(); + } +} diff --git a/lib/main.dart b/lib/main.dart index eafae08..a9e3306 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -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)), diff --git a/lib/providers/channel.dart b/lib/providers/channel.dart index 9403b2a..d91b854 100644 --- a/lib/providers/channel.dart +++ b/lib/providers/channel.dart @@ -28,8 +28,11 @@ class ChatChannelProvider extends ChangeNotifier { }); } - Future> _fetchChannelsFromServer( - {scope = 'global', direct = false}) async { + Future> _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.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 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> fetchChannels() async* { if (_channelBox != null) yield _channelBox!.values.toList(); @@ -55,18 +80,34 @@ class ChatChannelProvider extends ChangeNotifier { final realms = List.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 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; diff --git a/lib/providers/user_directory.dart b/lib/providers/user_directory.dart new file mode 100644 index 0000000..a0041f4 --- /dev/null +++ b/lib/providers/user_directory.dart @@ -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(); + } + + final Map _idCache = {}; + final Map _cache = {}; + + Future> listAccount(Iterable id) async { + final out = await Future.wait( + id.map((e) => getAccount(e)), + ); + return out; + } + + Future 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, + ); + _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]; + } +} diff --git a/lib/router.dart b/lib/router.dart index e7ece8c..92bf3a9 100644 --- a/lib/router.dart +++ b/lib/router.dart @@ -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', diff --git a/lib/screens/chat.dart b/lib/screens/chat.dart index a676a79..0c2d846 100644 --- a/lib/screens/chat.dart +++ b/lib/screens/chat.dart @@ -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 { 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 { content: null, fallbackWidget: const Icon(Symbols.chat, size: 20), ), + onTap: () { + GoRouter.of(context).pushNamed( + 'chatRoom', + pathParameters: { + 'scope': channel.realm?.alias ?? 'global', + 'alias': channel.alias, + }, + ); + }, ); }, ), diff --git a/lib/screens/chat/room.dart b/lib/screens/chat/room.dart new file mode 100644 index 0000000..4d52423 --- /dev/null +++ b/lib/screens/chat/room.dart @@ -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 createState() => _ChatRoomScreenState(); +} + +class _ChatRoomScreenState extends State { + bool _isBusy = false; + + SnChannel? _channel; + + late final ChatMessageController _messageController; + + Future _fetchChannel() async { + setState(() => _isBusy = true); + + try { + final chan = context.read(); + _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), + ), + ], + ); + }, + ), + ); + } +} diff --git a/lib/types/account.dart b/lib/types/account.dart index 345c397..cf1f458 100644 --- a/lib/types/account.dart +++ b/lib/types/account.dart @@ -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? contacts, required String avatar, required String banner, - required DateTime? confirmedAt, - required List contacts, - required DateTime createdAt, - required DateTime? deletedAt, required String description, required String name, required String nick, required Map 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 json) => diff --git a/lib/types/account.freezed.dart b/lib/types/account.freezed.dart index 43f6bde..5b70147 100644 --- a/lib/types/account.freezed.dart +++ b/lib/types/account.freezed.dart @@ -20,24 +20,25 @@ SnAccount _$SnAccountFromJson(Map 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? get contacts => throw _privateConstructorUsedError; String get avatar => throw _privateConstructorUsedError; String get banner => throw _privateConstructorUsedError; - DateTime? get confirmedAt => throw _privateConstructorUsedError; - List 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 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 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? contacts, String avatar, String banner, - DateTime? confirmedAt, - List contacts, - DateTime createdAt, - DateTime? deletedAt, String description, String name, String nick, Map 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?, 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, - 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? contacts, String avatar, String banner, - DateTime? confirmedAt, - List contacts, - DateTime createdAt, - DateTime? deletedAt, String description, String name, String nick, Map 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?, 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, - 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? contacts, required this.avatar, required this.banner, - required this.confirmedAt, - required final List contacts, - required this.createdAt, - required this.deletedAt, required this.description, required this.name, required this.nick, required final Map 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 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? _contacts; + @override + List? 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 _contacts; - @override - List 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? contacts, required final String avatar, required final String banner, - required final DateTime? confirmedAt, - required final List contacts, - required final DateTime createdAt, - required final DateTime? deletedAt, required final String description, required final String name, required final String nick, required final Map 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 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? get contacts; @override String get avatar; @override String get banner; @override - DateTime? get confirmedAt; - @override - List 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. diff --git a/lib/types/account.g.dart b/lib/types/account.g.dart index bbf2f82..04cf2da 100644 --- a/lib/types/account.g.dart +++ b/lib/types/account.g.dart @@ -9,22 +9,19 @@ part of 'account.dart'; _$SnAccountImpl _$$SnAccountImplFromJson(Map 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) - .map((e) => SnAccountContact.fromJson(e as Map)) - .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?) + ?.map((e) => SnAccountContact.fromJson(e as Map)) + .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 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 _$$SnAccountImplToJson(_$SnAccountImpl instance) => { '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( diff --git a/lib/types/chat.dart b/lib/types/chat.dart index 0a6cf49..d3208ee 100644 --- a/lib/types/chat.dart +++ b/lib/types/chat.dart @@ -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 members, - dynamic messages, + @HiveField(7) required List? members, + List? 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 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 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 json) => + _$SnChatMessageFromJson(json); } diff --git a/lib/types/chat.freezed.dart b/lib/types/chat.freezed.dart index 431518c..b84509a 100644 --- a/lib/types/chat.freezed.dart +++ b/lib/types/chat.freezed.dart @@ -35,8 +35,8 @@ mixin _$SnChannel { @HiveField(6) String get description => throw _privateConstructorUsedError; @HiveField(7) - List get members => throw _privateConstructorUsedError; - dynamic get messages => throw _privateConstructorUsedError; + List? get members => throw _privateConstructorUsedError; + List? get messages => throw _privateConstructorUsedError; dynamic get calls => throw _privateConstructorUsedError; @HiveField(8) int get type => throw _privateConstructorUsedError; @@ -74,8 +74,8 @@ abstract class $SnChannelCopyWith<$Res> { @HiveField(4) String alias, @HiveField(5) String name, @HiveField(6) String description, - @HiveField(7) List members, - dynamic messages, + @HiveField(7) List? members, + List? messages, dynamic calls, @HiveField(8) int type, @HiveField(9) int accountId, @@ -109,7 +109,7 @@ class _$SnChannelCopyWithImpl<$Res, $Val extends SnChannel> Object? alias = null, Object? name = null, Object? description = null, - Object? members = null, + Object? members = freezed, Object? messages = freezed, Object? calls = freezed, Object? type = null, @@ -148,14 +148,14 @@ class _$SnChannelCopyWithImpl<$Res, $Val extends SnChannel> ? _value.description : description // ignore: cast_nullable_to_non_nullable as String, - members: null == members + members: freezed == members ? _value.members : members // ignore: cast_nullable_to_non_nullable - as List, + as List?, messages: freezed == messages ? _value.messages : messages // ignore: cast_nullable_to_non_nullable - as dynamic, + as List?, calls: freezed == calls ? _value.calls : calls // ignore: cast_nullable_to_non_nullable @@ -218,8 +218,8 @@ abstract class _$$SnChannelImplCopyWith<$Res> @HiveField(4) String alias, @HiveField(5) String name, @HiveField(6) String description, - @HiveField(7) List members, - dynamic messages, + @HiveField(7) List? members, + List? messages, dynamic calls, @HiveField(8) int type, @HiveField(9) int accountId, @@ -252,7 +252,7 @@ class __$$SnChannelImplCopyWithImpl<$Res> Object? alias = null, Object? name = null, Object? description = null, - Object? members = null, + Object? members = freezed, Object? messages = freezed, Object? calls = freezed, Object? type = null, @@ -291,14 +291,14 @@ class __$$SnChannelImplCopyWithImpl<$Res> ? _value.description : description // ignore: cast_nullable_to_non_nullable as String, - members: null == members + members: freezed == members ? _value._members : members // ignore: cast_nullable_to_non_nullable - as List, + as List?, messages: freezed == messages - ? _value.messages + ? _value._messages : messages // ignore: cast_nullable_to_non_nullable - as dynamic, + as List?, calls: freezed == calls ? _value.calls : calls // ignore: cast_nullable_to_non_nullable @@ -343,8 +343,8 @@ class _$SnChannelImpl extends _SnChannel { @HiveField(4) required this.alias, @HiveField(5) required this.name, @HiveField(6) required this.description, - @HiveField(7) required final List members, - this.messages, + @HiveField(7) required final List? members, + final List? messages, this.calls, @HiveField(8) required this.type, @HiveField(9) required this.accountId, @@ -353,6 +353,7 @@ class _$SnChannelImpl extends _SnChannel { @HiveField(12) required this.isPublic, @HiveField(13) required this.isCommunity}) : _members = members, + _messages = messages, super._(); factory _$SnChannelImpl.fromJson(Map json) => @@ -379,17 +380,27 @@ class _$SnChannelImpl extends _SnChannel { @override @HiveField(6) final String description; - final List _members; + final List? _members; @override @HiveField(7) - List get members { + List? get members { + final value = _members; + if (value == null) return null; if (_members is EqualUnmodifiableListView) return _members; // ignore: implicit_dynamic_type - return EqualUnmodifiableListView(_members); + return EqualUnmodifiableListView(value); } + final List? _messages; @override - final dynamic messages; + List? get messages { + final value = _messages; + if (value == null) return null; + if (_messages is EqualUnmodifiableListView) return _messages; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(value); + } + @override final dynamic calls; @override @@ -432,7 +443,7 @@ class _$SnChannelImpl extends _SnChannel { (identical(other.description, description) || other.description == description) && const DeepCollectionEquality().equals(other._members, _members) && - const DeepCollectionEquality().equals(other.messages, messages) && + const DeepCollectionEquality().equals(other._messages, _messages) && const DeepCollectionEquality().equals(other.calls, calls) && (identical(other.type, type) || other.type == type) && (identical(other.accountId, accountId) || @@ -457,7 +468,7 @@ class _$SnChannelImpl extends _SnChannel { name, description, const DeepCollectionEquality().hash(_members), - const DeepCollectionEquality().hash(messages), + const DeepCollectionEquality().hash(_messages), const DeepCollectionEquality().hash(calls), type, accountId, @@ -491,8 +502,8 @@ abstract class _SnChannel extends SnChannel { @HiveField(4) required final String alias, @HiveField(5) required final String name, @HiveField(6) required final String description, - @HiveField(7) required final List members, - final dynamic messages, + @HiveField(7) required final List? members, + final List? messages, final dynamic calls, @HiveField(8) required final int type, @HiveField(9) required final int accountId, @@ -528,9 +539,9 @@ abstract class _SnChannel extends SnChannel { String get description; @override @HiveField(7) - List get members; + List? get members; @override - dynamic get messages; + List? get messages; @override dynamic get calls; @override @@ -559,3 +570,928 @@ abstract class _SnChannel extends SnChannel { _$$SnChannelImplCopyWith<_$SnChannelImpl> get copyWith => throw _privateConstructorUsedError; } + +SnChannelMember _$SnChannelMemberFromJson(Map json) { + return _SnChannelMember.fromJson(json); +} + +/// @nodoc +mixin _$SnChannelMember { + @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) + int get channelId => throw _privateConstructorUsedError; + @HiveField(5) + int get accountId => throw _privateConstructorUsedError; + @HiveField(6) + String? get nick => throw _privateConstructorUsedError; + @HiveField(7) + SnChannel? get channel => throw _privateConstructorUsedError; + @HiveField(8) + SnAccount? get account => throw _privateConstructorUsedError; + int get notify => throw _privateConstructorUsedError; + @HiveField(9) + int get powerLevel => throw _privateConstructorUsedError; + dynamic get calls => throw _privateConstructorUsedError; + dynamic get events => throw _privateConstructorUsedError; + + /// Serializes this SnChannelMember to a JSON map. + Map toJson() => throw _privateConstructorUsedError; + + /// Create a copy of SnChannelMember + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $SnChannelMemberCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $SnChannelMemberCopyWith<$Res> { + factory $SnChannelMemberCopyWith( + SnChannelMember value, $Res Function(SnChannelMember) then) = + _$SnChannelMemberCopyWithImpl<$Res, SnChannelMember>; + @useResult + $Res call( + {@HiveField(0) int id, + @HiveField(1) DateTime createdAt, + @HiveField(2) DateTime updatedAt, + @HiveField(3) DateTime? deletedAt, + @HiveField(4) int channelId, + @HiveField(5) int accountId, + @HiveField(6) String? nick, + @HiveField(7) SnChannel? channel, + @HiveField(8) SnAccount? account, + int notify, + @HiveField(9) int powerLevel, + dynamic calls, + dynamic events}); + + $SnChannelCopyWith<$Res>? get channel; + $SnAccountCopyWith<$Res>? get account; +} + +/// @nodoc +class _$SnChannelMemberCopyWithImpl<$Res, $Val extends SnChannelMember> + implements $SnChannelMemberCopyWith<$Res> { + _$SnChannelMemberCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of SnChannelMember + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? createdAt = null, + Object? updatedAt = null, + Object? deletedAt = freezed, + Object? channelId = null, + Object? accountId = null, + Object? nick = freezed, + Object? channel = freezed, + Object? account = freezed, + Object? notify = null, + Object? powerLevel = null, + Object? calls = freezed, + Object? events = freezed, + }) { + return _then(_value.copyWith( + id: null == id + ? _value.id + : id // 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?, + channelId: null == channelId + ? _value.channelId + : channelId // ignore: cast_nullable_to_non_nullable + as int, + accountId: null == accountId + ? _value.accountId + : accountId // ignore: cast_nullable_to_non_nullable + as int, + nick: freezed == nick + ? _value.nick + : nick // ignore: cast_nullable_to_non_nullable + as String?, + channel: freezed == channel + ? _value.channel + : channel // ignore: cast_nullable_to_non_nullable + as SnChannel?, + account: freezed == account + ? _value.account + : account // ignore: cast_nullable_to_non_nullable + as SnAccount?, + notify: null == notify + ? _value.notify + : notify // ignore: cast_nullable_to_non_nullable + as int, + powerLevel: null == powerLevel + ? _value.powerLevel + : powerLevel // ignore: cast_nullable_to_non_nullable + as int, + calls: freezed == calls + ? _value.calls + : calls // ignore: cast_nullable_to_non_nullable + as dynamic, + events: freezed == events + ? _value.events + : events // ignore: cast_nullable_to_non_nullable + as dynamic, + ) as $Val); + } + + /// Create a copy of SnChannelMember + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $SnChannelCopyWith<$Res>? get channel { + if (_value.channel == null) { + return null; + } + + return $SnChannelCopyWith<$Res>(_value.channel!, (value) { + return _then(_value.copyWith(channel: value) as $Val); + }); + } + + /// Create a copy of SnChannelMember + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $SnAccountCopyWith<$Res>? get account { + if (_value.account == null) { + return null; + } + + return $SnAccountCopyWith<$Res>(_value.account!, (value) { + return _then(_value.copyWith(account: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$SnChannelMemberImplCopyWith<$Res> + implements $SnChannelMemberCopyWith<$Res> { + factory _$$SnChannelMemberImplCopyWith(_$SnChannelMemberImpl value, + $Res Function(_$SnChannelMemberImpl) then) = + __$$SnChannelMemberImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {@HiveField(0) int id, + @HiveField(1) DateTime createdAt, + @HiveField(2) DateTime updatedAt, + @HiveField(3) DateTime? deletedAt, + @HiveField(4) int channelId, + @HiveField(5) int accountId, + @HiveField(6) String? nick, + @HiveField(7) SnChannel? channel, + @HiveField(8) SnAccount? account, + int notify, + @HiveField(9) int powerLevel, + dynamic calls, + dynamic events}); + + @override + $SnChannelCopyWith<$Res>? get channel; + @override + $SnAccountCopyWith<$Res>? get account; +} + +/// @nodoc +class __$$SnChannelMemberImplCopyWithImpl<$Res> + extends _$SnChannelMemberCopyWithImpl<$Res, _$SnChannelMemberImpl> + implements _$$SnChannelMemberImplCopyWith<$Res> { + __$$SnChannelMemberImplCopyWithImpl( + _$SnChannelMemberImpl _value, $Res Function(_$SnChannelMemberImpl) _then) + : super(_value, _then); + + /// Create a copy of SnChannelMember + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? createdAt = null, + Object? updatedAt = null, + Object? deletedAt = freezed, + Object? channelId = null, + Object? accountId = null, + Object? nick = freezed, + Object? channel = freezed, + Object? account = freezed, + Object? notify = null, + Object? powerLevel = null, + Object? calls = freezed, + Object? events = freezed, + }) { + return _then(_$SnChannelMemberImpl( + id: null == id + ? _value.id + : id // 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?, + channelId: null == channelId + ? _value.channelId + : channelId // ignore: cast_nullable_to_non_nullable + as int, + accountId: null == accountId + ? _value.accountId + : accountId // ignore: cast_nullable_to_non_nullable + as int, + nick: freezed == nick + ? _value.nick + : nick // ignore: cast_nullable_to_non_nullable + as String?, + channel: freezed == channel + ? _value.channel + : channel // ignore: cast_nullable_to_non_nullable + as SnChannel?, + account: freezed == account + ? _value.account + : account // ignore: cast_nullable_to_non_nullable + as SnAccount?, + notify: null == notify + ? _value.notify + : notify // ignore: cast_nullable_to_non_nullable + as int, + powerLevel: null == powerLevel + ? _value.powerLevel + : powerLevel // ignore: cast_nullable_to_non_nullable + as int, + calls: freezed == calls + ? _value.calls + : calls // ignore: cast_nullable_to_non_nullable + as dynamic, + events: freezed == events + ? _value.events + : events // ignore: cast_nullable_to_non_nullable + as dynamic, + )); + } +} + +/// @nodoc +@JsonSerializable() +@HiveType(typeId: 3) +class _$SnChannelMemberImpl extends _SnChannelMember { + const _$SnChannelMemberImpl( + {@HiveField(0) required this.id, + @HiveField(1) required this.createdAt, + @HiveField(2) required this.updatedAt, + @HiveField(3) required this.deletedAt, + @HiveField(4) required this.channelId, + @HiveField(5) required this.accountId, + @HiveField(6) required this.nick, + @HiveField(7) required this.channel, + @HiveField(8) required this.account, + this.notify = 0, + @HiveField(9) required this.powerLevel, + this.calls, + this.events}) + : super._(); + + factory _$SnChannelMemberImpl.fromJson(Map json) => + _$$SnChannelMemberImplFromJson(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 int channelId; + @override + @HiveField(5) + final int accountId; + @override + @HiveField(6) + final String? nick; + @override + @HiveField(7) + final SnChannel? channel; + @override + @HiveField(8) + final SnAccount? account; + @override + @JsonKey() + final int notify; + @override + @HiveField(9) + final int powerLevel; + @override + final dynamic calls; + @override + final dynamic events; + + @override + String toString() { + return 'SnChannelMember(id: $id, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, channelId: $channelId, accountId: $accountId, nick: $nick, channel: $channel, account: $account, notify: $notify, powerLevel: $powerLevel, calls: $calls, events: $events)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$SnChannelMemberImpl && + (identical(other.id, id) || other.id == id) && + (identical(other.createdAt, createdAt) || + other.createdAt == createdAt) && + (identical(other.updatedAt, updatedAt) || + other.updatedAt == updatedAt) && + (identical(other.deletedAt, deletedAt) || + other.deletedAt == deletedAt) && + (identical(other.channelId, channelId) || + other.channelId == channelId) && + (identical(other.accountId, accountId) || + other.accountId == accountId) && + (identical(other.nick, nick) || other.nick == nick) && + (identical(other.channel, channel) || other.channel == channel) && + (identical(other.account, account) || other.account == account) && + (identical(other.notify, notify) || other.notify == notify) && + (identical(other.powerLevel, powerLevel) || + other.powerLevel == powerLevel) && + const DeepCollectionEquality().equals(other.calls, calls) && + const DeepCollectionEquality().equals(other.events, events)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash( + runtimeType, + id, + createdAt, + updatedAt, + deletedAt, + channelId, + accountId, + nick, + channel, + account, + notify, + powerLevel, + const DeepCollectionEquality().hash(calls), + const DeepCollectionEquality().hash(events)); + + /// Create a copy of SnChannelMember + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$SnChannelMemberImplCopyWith<_$SnChannelMemberImpl> get copyWith => + __$$SnChannelMemberImplCopyWithImpl<_$SnChannelMemberImpl>( + this, _$identity); + + @override + Map toJson() { + return _$$SnChannelMemberImplToJson( + this, + ); + } +} + +abstract class _SnChannelMember extends SnChannelMember { + const factory _SnChannelMember( + {@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 int channelId, + @HiveField(5) required final int accountId, + @HiveField(6) required final String? nick, + @HiveField(7) required final SnChannel? channel, + @HiveField(8) required final SnAccount? account, + final int notify, + @HiveField(9) required final int powerLevel, + final dynamic calls, + final dynamic events}) = _$SnChannelMemberImpl; + const _SnChannelMember._() : super._(); + + factory _SnChannelMember.fromJson(Map json) = + _$SnChannelMemberImpl.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) + int get channelId; + @override + @HiveField(5) + int get accountId; + @override + @HiveField(6) + String? get nick; + @override + @HiveField(7) + SnChannel? get channel; + @override + @HiveField(8) + SnAccount? get account; + @override + int get notify; + @override + @HiveField(9) + int get powerLevel; + @override + dynamic get calls; + @override + dynamic get events; + + /// Create a copy of SnChannelMember + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$SnChannelMemberImplCopyWith<_$SnChannelMemberImpl> get copyWith => + throw _privateConstructorUsedError; +} + +SnChatMessage _$SnChatMessageFromJson(Map json) { + return _SnChatMessage.fromJson(json); +} + +/// @nodoc +mixin _$SnChatMessage { + @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 uuid => throw _privateConstructorUsedError; + @HiveField(5) + Map get body => throw _privateConstructorUsedError; + @HiveField(6) + String get type => throw _privateConstructorUsedError; + @HiveField(7) + SnChannel get channel => throw _privateConstructorUsedError; + @HiveField(8) + SnChannelMember get sender => throw _privateConstructorUsedError; + @HiveField(9) + int get channelId => throw _privateConstructorUsedError; + @HiveField(10) + int get senderId => throw _privateConstructorUsedError; + + /// Serializes this SnChatMessage to a JSON map. + Map toJson() => throw _privateConstructorUsedError; + + /// Create a copy of SnChatMessage + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $SnChatMessageCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $SnChatMessageCopyWith<$Res> { + factory $SnChatMessageCopyWith( + SnChatMessage value, $Res Function(SnChatMessage) then) = + _$SnChatMessageCopyWithImpl<$Res, SnChatMessage>; + @useResult + $Res call( + {@HiveField(0) int id, + @HiveField(1) DateTime createdAt, + @HiveField(2) DateTime updatedAt, + @HiveField(3) DateTime? deletedAt, + @HiveField(4) String uuid, + @HiveField(5) Map body, + @HiveField(6) String type, + @HiveField(7) SnChannel channel, + @HiveField(8) SnChannelMember sender, + @HiveField(9) int channelId, + @HiveField(10) int senderId}); + + $SnChannelCopyWith<$Res> get channel; + $SnChannelMemberCopyWith<$Res> get sender; +} + +/// @nodoc +class _$SnChatMessageCopyWithImpl<$Res, $Val extends SnChatMessage> + implements $SnChatMessageCopyWith<$Res> { + _$SnChatMessageCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of SnChatMessage + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? createdAt = null, + Object? updatedAt = null, + Object? deletedAt = freezed, + Object? uuid = null, + Object? body = null, + Object? type = null, + Object? channel = null, + Object? sender = null, + Object? channelId = null, + Object? senderId = null, + }) { + return _then(_value.copyWith( + id: null == id + ? _value.id + : id // 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?, + uuid: null == uuid + ? _value.uuid + : uuid // ignore: cast_nullable_to_non_nullable + as String, + body: null == body + ? _value.body + : body // ignore: cast_nullable_to_non_nullable + as Map, + type: null == type + ? _value.type + : type // ignore: cast_nullable_to_non_nullable + as String, + channel: null == channel + ? _value.channel + : channel // ignore: cast_nullable_to_non_nullable + as SnChannel, + sender: null == sender + ? _value.sender + : sender // ignore: cast_nullable_to_non_nullable + as SnChannelMember, + channelId: null == channelId + ? _value.channelId + : channelId // ignore: cast_nullable_to_non_nullable + as int, + senderId: null == senderId + ? _value.senderId + : senderId // ignore: cast_nullable_to_non_nullable + as int, + ) as $Val); + } + + /// Create a copy of SnChatMessage + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $SnChannelCopyWith<$Res> get channel { + return $SnChannelCopyWith<$Res>(_value.channel, (value) { + return _then(_value.copyWith(channel: value) as $Val); + }); + } + + /// Create a copy of SnChatMessage + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $SnChannelMemberCopyWith<$Res> get sender { + return $SnChannelMemberCopyWith<$Res>(_value.sender, (value) { + return _then(_value.copyWith(sender: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$SnChatMessageImplCopyWith<$Res> + implements $SnChatMessageCopyWith<$Res> { + factory _$$SnChatMessageImplCopyWith( + _$SnChatMessageImpl value, $Res Function(_$SnChatMessageImpl) then) = + __$$SnChatMessageImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {@HiveField(0) int id, + @HiveField(1) DateTime createdAt, + @HiveField(2) DateTime updatedAt, + @HiveField(3) DateTime? deletedAt, + @HiveField(4) String uuid, + @HiveField(5) Map body, + @HiveField(6) String type, + @HiveField(7) SnChannel channel, + @HiveField(8) SnChannelMember sender, + @HiveField(9) int channelId, + @HiveField(10) int senderId}); + + @override + $SnChannelCopyWith<$Res> get channel; + @override + $SnChannelMemberCopyWith<$Res> get sender; +} + +/// @nodoc +class __$$SnChatMessageImplCopyWithImpl<$Res> + extends _$SnChatMessageCopyWithImpl<$Res, _$SnChatMessageImpl> + implements _$$SnChatMessageImplCopyWith<$Res> { + __$$SnChatMessageImplCopyWithImpl( + _$SnChatMessageImpl _value, $Res Function(_$SnChatMessageImpl) _then) + : super(_value, _then); + + /// Create a copy of SnChatMessage + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? id = null, + Object? createdAt = null, + Object? updatedAt = null, + Object? deletedAt = freezed, + Object? uuid = null, + Object? body = null, + Object? type = null, + Object? channel = null, + Object? sender = null, + Object? channelId = null, + Object? senderId = null, + }) { + return _then(_$SnChatMessageImpl( + id: null == id + ? _value.id + : id // 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?, + uuid: null == uuid + ? _value.uuid + : uuid // ignore: cast_nullable_to_non_nullable + as String, + body: null == body + ? _value._body + : body // ignore: cast_nullable_to_non_nullable + as Map, + type: null == type + ? _value.type + : type // ignore: cast_nullable_to_non_nullable + as String, + channel: null == channel + ? _value.channel + : channel // ignore: cast_nullable_to_non_nullable + as SnChannel, + sender: null == sender + ? _value.sender + : sender // ignore: cast_nullable_to_non_nullable + as SnChannelMember, + channelId: null == channelId + ? _value.channelId + : channelId // ignore: cast_nullable_to_non_nullable + as int, + senderId: null == senderId + ? _value.senderId + : senderId // ignore: cast_nullable_to_non_nullable + as int, + )); + } +} + +/// @nodoc +@JsonSerializable() +@HiveType(typeId: 4) +class _$SnChatMessageImpl extends _SnChatMessage { + const _$SnChatMessageImpl( + {@HiveField(0) required this.id, + @HiveField(1) required this.createdAt, + @HiveField(2) required this.updatedAt, + @HiveField(3) required this.deletedAt, + @HiveField(4) required this.uuid, + @HiveField(5) required final Map body, + @HiveField(6) required this.type, + @HiveField(7) required this.channel, + @HiveField(8) required this.sender, + @HiveField(9) required this.channelId, + @HiveField(10) required this.senderId}) + : _body = body, + super._(); + + factory _$SnChatMessageImpl.fromJson(Map json) => + _$$SnChatMessageImplFromJson(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 uuid; + final Map _body; + @override + @HiveField(5) + Map get body { + if (_body is EqualUnmodifiableMapView) return _body; + // ignore: implicit_dynamic_type + return EqualUnmodifiableMapView(_body); + } + + @override + @HiveField(6) + final String type; + @override + @HiveField(7) + final SnChannel channel; + @override + @HiveField(8) + final SnChannelMember sender; + @override + @HiveField(9) + final int channelId; + @override + @HiveField(10) + final int senderId; + + @override + String toString() { + return 'SnChatMessage(id: $id, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, uuid: $uuid, body: $body, type: $type, channel: $channel, sender: $sender, channelId: $channelId, senderId: $senderId)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$SnChatMessageImpl && + (identical(other.id, id) || other.id == id) && + (identical(other.createdAt, createdAt) || + other.createdAt == createdAt) && + (identical(other.updatedAt, updatedAt) || + other.updatedAt == updatedAt) && + (identical(other.deletedAt, deletedAt) || + other.deletedAt == deletedAt) && + (identical(other.uuid, uuid) || other.uuid == uuid) && + const DeepCollectionEquality().equals(other._body, _body) && + (identical(other.type, type) || other.type == type) && + (identical(other.channel, channel) || other.channel == channel) && + (identical(other.sender, sender) || other.sender == sender) && + (identical(other.channelId, channelId) || + other.channelId == channelId) && + (identical(other.senderId, senderId) || + other.senderId == senderId)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash( + runtimeType, + id, + createdAt, + updatedAt, + deletedAt, + uuid, + const DeepCollectionEquality().hash(_body), + type, + channel, + sender, + channelId, + senderId); + + /// Create a copy of SnChatMessage + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$SnChatMessageImplCopyWith<_$SnChatMessageImpl> get copyWith => + __$$SnChatMessageImplCopyWithImpl<_$SnChatMessageImpl>(this, _$identity); + + @override + Map toJson() { + return _$$SnChatMessageImplToJson( + this, + ); + } +} + +abstract class _SnChatMessage extends SnChatMessage { + const factory _SnChatMessage( + {@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 uuid, + @HiveField(5) required final Map body, + @HiveField(6) required final String type, + @HiveField(7) required final SnChannel channel, + @HiveField(8) required final SnChannelMember sender, + @HiveField(9) required final int channelId, + @HiveField(10) required final int senderId}) = _$SnChatMessageImpl; + const _SnChatMessage._() : super._(); + + factory _SnChatMessage.fromJson(Map json) = + _$SnChatMessageImpl.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 uuid; + @override + @HiveField(5) + Map get body; + @override + @HiveField(6) + String get type; + @override + @HiveField(7) + SnChannel get channel; + @override + @HiveField(8) + SnChannelMember get sender; + @override + @HiveField(9) + int get channelId; + @override + @HiveField(10) + int get senderId; + + /// Create a copy of SnChatMessage + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$SnChatMessageImplCopyWith<_$SnChatMessageImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/types/chat.g.dart b/lib/types/chat.g.dart index 289a817..7367ea4 100644 --- a/lib/types/chat.g.dart +++ b/lib/types/chat.g.dart @@ -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(), + members: (fields[7] as List?)?.cast(), 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 = { + 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 = { + 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(), + 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 json) => alias: json['alias'] as String, name: json['name'] as String, description: json['description'] as String, - members: json['members'] as List, - messages: json['messages'], + members: json['members'] as List?, + messages: (json['messages'] as List?) + ?.map((e) => SnChatMessage.fromJson(e as Map)) + .toList(), calls: json['calls'], type: (json['type'] as num).toInt(), accountId: (json['account_id'] as num).toInt(), @@ -115,7 +242,7 @@ Map _$$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 _$$SnChannelImplToJson(_$SnChannelImpl instance) => 'is_public': instance.isPublic, 'is_community': instance.isCommunity, }; + +_$SnChannelMemberImpl _$$SnChannelMemberImplFromJson( + Map 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), + account: json['account'] == null + ? null + : SnAccount.fromJson(json['account'] as Map), + notify: (json['notify'] as num?)?.toInt() ?? 0, + powerLevel: (json['power_level'] as num).toInt(), + calls: json['calls'], + events: json['events'], + ); + +Map _$$SnChannelMemberImplToJson( + _$SnChannelMemberImpl instance) => + { + '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 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, + type: json['type'] as String, + channel: SnChannel.fromJson(json['channel'] as Map), + sender: SnChannelMember.fromJson(json['sender'] as Map), + channelId: (json['channel_id'] as num).toInt(), + senderId: (json['sender_id'] as num).toInt(), + ); + +Map _$$SnChatMessageImplToJson(_$SnChatMessageImpl instance) => + { + '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, + }; diff --git a/lib/types/realm.dart b/lib/types/realm.dart index 2370fe3..90a41b1 100644 --- a/lib/types/realm.dart +++ b/lib/types/realm.dart @@ -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? members, - required String? avatar, - required String? banner, - required Map? 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? members, + @HiveField(7) required String? avatar, + @HiveField(8) required String? banner, + @HiveField(9) required Map? accessPolicy, + @HiveField(10) required int accountId, + @HiveField(11) required bool isPublic, + @HiveField(12) required bool isCommunity, }) = _SnRealm; factory SnRealm.fromJson(Map json) => diff --git a/lib/types/realm.freezed.dart b/lib/types/realm.freezed.dart index a3b6f9b..32b6b54 100644 --- a/lib/types/realm.freezed.dart +++ b/lib/types/realm.freezed.dart @@ -367,20 +367,33 @@ SnRealm _$SnRealmFromJson(Map 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? get members => throw _privateConstructorUsedError; + @HiveField(7) String? get avatar => throw _privateConstructorUsedError; + @HiveField(8) String? get banner => throw _privateConstructorUsedError; + @HiveField(9) Map? 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 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? members, - String? avatar, - String? banner, - Map? accessPolicy, - bool isPublic, - bool isCommunity, - int accountId}); + @HiveField(7) String? avatar, + @HiveField(8) String? banner, + @HiveField(9) Map? 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?, + 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? members, - String? avatar, - String? banner, - Map? accessPolicy, - bool isPublic, - bool isCommunity, - int accountId}); + @HiveField(7) String? avatar, + @HiveField(8) String? banner, + @HiveField(9) Map? 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?, + 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? members, - required this.avatar, - required this.banner, - required final Map? 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? members, + @HiveField(7) required this.avatar, + @HiveField(8) required this.banner, + @HiveField(9) required final Map? 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 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? _members; @override @@ -666,11 +688,14 @@ class _$SnRealmImpl implements _SnRealm { } @override + @HiveField(7) final String? avatar; @override + @HiveField(8) final String? banner; final Map? _accessPolicy; @override + @HiveField(9) Map? 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? members, - required final String? avatar, - required final String? banner, - required final Map? 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? members, + @HiveField(7) required final String? avatar, + @HiveField(8) required final String? banner, + @HiveField(9) required final Map? 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 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? get members; @override + @HiveField(7) String? get avatar; @override + @HiveField(8) String? get banner; @override + @HiveField(9) Map? 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. diff --git a/lib/types/realm.g.dart b/lib/types/realm.g.dart index 88e67bd..12eecb9 100644 --- a/lib/types/realm.g.dart +++ b/lib/types/realm.g.dart @@ -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 = { + 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(), + 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 json) => avatar: json['avatar'] as String?, banner: json['banner'] as String?, accessPolicy: json['access_policy'] as Map?, + 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 _$$SnRealmImplToJson(_$SnRealmImpl instance) => @@ -69,7 +143,7 @@ Map _$$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, }; diff --git a/lib/widgets/chat/chat_message.dart b/lib/widgets/chat/chat_message.dart new file mode 100644 index 0000000..9991d54 --- /dev/null +++ b/lib/widgets/chat/chat_message.dart @@ -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(); + 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']), + ], + ), + ) + ], + ); + } +} diff --git a/lib/widgets/chat/chat_message_input.dart b/lib/widgets/chat/chat_message_input.dart new file mode 100644 index 0000000..39808ed --- /dev/null +++ b/lib/widgets/chat/chat_message_input.dart @@ -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 createState() => _ChatMessageInputState(); +} + +class _ChatMessageInputState extends State { + 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), + ], + ), + ); + } +} diff --git a/pubspec.lock b/pubspec.lock index a70fb34..480aede 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -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: