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