Friend management

This commit is contained in:
LittleSheep 2024-11-30 22:39:49 +08:00
parent a2a42f66a2
commit 0c2df45337
14 changed files with 1060 additions and 37 deletions

View File

@ -24,6 +24,7 @@
"screenRealmNew": "New Realm",
"screenNotification": "Notification",
"screenPostSearch": "Search Posts",
"screenFriend": "Friends",
"dialogOkay": "Okay",
"dialogCancel": "Cancel",
"dialogConfirm": "Confirm",
@ -35,6 +36,7 @@
"errorRequestNotFound": "The resource that you looking for is not found.",
"errorRequestConnection": "Network connection error, please check your network or the service status.",
"errorRequestUnknown": "Unknown request error, maybe you want to take screenshot and report it to us.",
"unknown": "Unknown",
"prev": "Previous",
"next": "Next",
"edit": "Edit",
@ -189,7 +191,7 @@
"channelNotifyLevelAll": "All",
"channelNotifyLevelMentioned": "Only Mentioned",
"channelNotifyLevelNone": "Muted",
"channelNotifyLevelApplied": "Channel notify level has been applied.",
"channelNotifyLevelApplie": "Channel notify level has been applied.",
"fieldChannelProfileNick": "In-Channel Display Name",
"fieldChannelProfileNickHint": "The nickname to display in the channel, leave blank to use the account display name.",
"fieldRealmAlias": "Realm Alias",
@ -296,5 +298,31 @@
"dailyCheckNegativeHint5Description": "Lost connection at a crucial moment",
"dailyCheckNegativeHint6": "Going out",
"dailyCheckNegativeHint6Description": "Forgot your umbrella and got caught in the rain",
"happyBirthday": "Happy birthday, {}!"
"happyBirthday": "Happy birthday, {}!",
"friendNew": "Add Friend",
"friendRequests": "Friend Requests",
"friendRequestsDescription": {
"zero": "You have no friend request",
"one": "You have {} friend request",
"other": "You have {} friend requests"
},
"friendBlocklist": "Blocklist",
"friendBlocklistDescription": {
"zero": "You blocked no one",
"one": "You blocked {} user",
"other": "You blocked {} users"
},
"friendStatusPending": "Pending",
"friendStatusWaiting": "Waiting",
"friendStatusActive": "Friend",
"friendStatusBlocked": "Blocked",
"friendRequestSent": "Friend request has been sent.",
"fieldFriendRelatedName": "Friend name / account ID",
"friendBlock": "Block",
"friendUnblock": "Unblock",
"friendDeleteAction": "Delete",
"friendDelete": "Delete relation with {}",
"friendDeleteDescription": "Are you sure you want to delete the relation with {}? This operation is irreversible.",
"friendRequestAccept": "Accept",
"friendRequestDecline": "Decline"
}

View File

@ -24,6 +24,7 @@
"screenRealmNew": "新建领域",
"screenNotification": "通知",
"screenPostSearch": "搜索帖子",
"screenFriend": "好友",
"dialogOkay": "好的",
"dialogCancel": "取消",
"dialogConfirm": "确认",
@ -35,6 +36,7 @@
"errorRequestNotFound": "您正查找的资源无法被找到。",
"errorRequestConnection": "网络连接错误,请检查您的网络状态或者检查我们的服务状态。",
"errorRequestUnknown": "位置请求错误,您可能想将此对话框截图并发送给我们。",
"unknown": "未知",
"loading": "加载中…",
"prev": "上一步",
"next": "下一步",
@ -296,5 +298,31 @@
"dailyCheckNegativeHint5Description": "关键时刻断网",
"dailyCheckNegativeHint6": "出门",
"dailyCheckNegativeHint6Description": "忘带伞遇上大雨",
"happyBirthday": "生日快乐,{}"
"happyBirthday": "生日快乐,{}",
"friendNew": "添加好友",
"friendRequests": "好友请求",
"friendRequestsDescription": {
"zero": "你没有好友请求",
"one": "你有 {} 个好友请求",
"other": "你有 {} 个好友请求"
},
"friendBlocklist": "屏蔽列表",
"friendBlocklistDescription": {
"zero": "你没有屏蔽任何人",
"one": "你屏蔽了 {} 个用户",
"other": "你屏蔽了 {} 个用户"
},
"friendStatusPending": "待处理",
"friendStatusWaiting": "等待中",
"friendStatusActive": "正活跃",
"friendStatusBlocked": "已屏蔽",
"friendRequestSent": "好友请求已发送。",
"fieldFriendRelatedName": "好友名 / 账户 ID",
"friendBlock": "屏蔽",
"friendUnblock": "解除屏蔽",
"friendDeleteAction": "遗忘",
"friendDelete": "遗忘跟 {} 的关系",
"friendDeleteDescription": "你确定要遗忘跟 {} 的关系吗?这个操作无法撤销。",
"friendRequestAccept": "接受",
"friendRequestDecline": "拒绝"
}

View File

@ -16,6 +16,7 @@ import 'package:surface/providers/chat_call.dart';
import 'package:surface/providers/navigation.dart';
import 'package:surface/providers/notification.dart';
import 'package:surface/providers/post.dart';
import 'package:surface/providers/relationship.dart';
import 'package:surface/providers/sn_attachment.dart';
import 'package:surface/providers/sn_network.dart';
import 'package:surface/providers/theme.dart';
@ -85,6 +86,7 @@ class SolianApp extends StatelessWidget {
Provider(create: (ctx) => SnAttachmentProvider(ctx)),
Provider(create: (ctx) => SnPostContentProvider(ctx)),
Provider(create: (ctx) => UserDirectoryProvider(ctx)),
Provider(create: (ctx) => SnRelationshipProvider(ctx)),
ChangeNotifierProvider(create: (ctx) => UserProvider(ctx)),
ChangeNotifierProvider(create: (ctx) => WebSocketProvider(ctx)),
ChangeNotifierProvider(create: (ctx) => NotificationProvider(ctx)),

View File

@ -63,6 +63,11 @@ class NavigationProvider extends ChangeNotifier {
screen: 'album',
label: 'screenAlbum',
),
AppNavDestination(
icon: Icon(Symbols.diversity_4, weight: 400, opticalSize: 20),
screen: 'friend',
label: 'screenFriend',
),
AppNavDestination(
icon: Icon(Symbols.notifications, weight: 400, opticalSize: 20),
screen: 'notification',

View File

@ -0,0 +1,34 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:surface/providers/sn_network.dart';
class SnRelationshipProvider {
late final SnNetworkProvider _sn;
SnRelationshipProvider(BuildContext context) {
_sn = context.read<SnNetworkProvider>();
}
Future<void> updateRelationship(
int relatedId,
int status,
Map<String, dynamic> permNodes,
) async {
await _sn.client.put('/cgi/id/users/me/relations/$relatedId', data: {
'status': status,
'perm_nodes': permNodes,
});
}
Future<void> deleteRelationship(int relatedId) async {
await _sn.client.delete('/cgi/id/users/me/relations/$relatedId');
}
Future<void> acceptFriendRequest(int relatedId) async {
await _sn.client.post('/cgi/id/users/me/relations/$relatedId/accept');
}
Future<void> declineFriendRequest(int relatedId) async {
await _sn.client.post('/cgi/id/users/me/relations/$relatedId/decline');
}
}

View File

@ -15,6 +15,7 @@ import 'package:surface/screens/chat/channel_detail.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/friend.dart';
import 'package:surface/screens/home.dart';
import 'package:surface/screens/notification.dart';
import 'package:surface/screens/post/post_detail.dart';
@ -192,6 +193,13 @@ final _appRoutes = [
child: const AlbumScreen(),
),
),
GoRoute(
path: '/friend',
name: 'friend',
pageBuilder: (context, state) => NoTransitionPage(
child: const FriendScreen(),
),
),
GoRoute(
path: '/notification',
name: 'notification',

View File

@ -357,6 +357,12 @@ class _ChannelProfileDetailDialogState
_nickController.text = widget.current.nick ?? '';
}
@override
void dispose() {
_nickController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return AlertDialog(

487
lib/screens/friend.dart Normal file
View File

@ -0,0 +1,487 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:material_symbols_icons/symbols.dart';
import 'package:provider/provider.dart';
import 'package:styled_widget/styled_widget.dart';
import 'package:surface/providers/relationship.dart';
import 'package:surface/providers/sn_network.dart';
import 'package:surface/types/account.dart';
import 'package:surface/widgets/account/account_image.dart';
import 'package:surface/widgets/dialog.dart';
import 'package:surface/widgets/loading_indicator.dart';
const kFriendStatus = {
0: 'friendStatusPending',
1: 'friendStatusActive',
2: 'friendStatusBlocked',
3: 'friendStatusWaiting',
};
class FriendScreen extends StatefulWidget {
const FriendScreen({super.key});
@override
State<FriendScreen> createState() => _FriendScreenState();
}
class _FriendScreenState extends State<FriendScreen> {
bool _isBusy = false;
List<SnRelationship> _requests = List.empty();
List<SnRelationship> _relations = List.empty();
List<SnRelationship> _blocks = List.empty();
Future<void> _fetchRelations() async {
setState(() => _isBusy = true);
try {
final sn = context.read<SnNetworkProvider>();
final resp = await sn.client.get('/cgi/id/users/me/relations?status=1');
_relations = List<SnRelationship>.from(
resp.data?.map((e) => SnRelationship.fromJson(e)) ?? [],
);
} catch (err) {
if (!mounted) return;
context.showErrorDialog(err);
} finally {
setState(() => _isBusy = false);
}
}
Future<void> _fetchRequests() async {
setState(() => _isBusy = true);
try {
final sn = context.read<SnNetworkProvider>();
final resp = await sn.client.get('/cgi/id/users/me/relations?status=0,3');
_requests = List<SnRelationship>.from(
resp.data?.map((e) => SnRelationship.fromJson(e)) ?? [],
);
} catch (err) {
if (!mounted) return;
context.showErrorDialog(err);
} finally {
setState(() => _isBusy = false);
}
}
Future<void> _fetchBlocks() async {
setState(() => _isBusy = true);
try {
final sn = context.read<SnNetworkProvider>();
final resp = await sn.client.get('/cgi/id/users/me/relations?status=2');
_blocks = List<SnRelationship>.from(
resp.data?.map((e) => SnRelationship.fromJson(e)) ?? [],
);
} catch (err) {
if (!mounted) return;
context.showErrorDialog(err);
} finally {
setState(() => _isBusy = false);
}
}
bool _isUpdating = false;
Future<void> _changeRelation(SnRelationship relation, int dstStatus) async {
setState(() => _isUpdating = true);
try {
final rel = context.read<SnRelationshipProvider>();
await rel.updateRelationship(
relation.relatedId,
dstStatus,
relation.permNodes,
);
if (!mounted) return;
_fetchRelations();
} catch (err) {
if (!mounted) return;
context.showErrorDialog(err);
} finally {
setState(() => _isUpdating = false);
}
}
Future<void> _deleteRelation(SnRelationship relation) async {
final confirm = await context.showConfirmDialog(
'friendDelete'.tr(args: [relation.related?.nick ?? 'unknown'.tr()]),
'friendDeleteDescription'.tr(args: [
relation.related?.nick ?? 'unknown'.tr(),
]),
);
if (!confirm) return;
if (!mounted) return;
setState(() => _isUpdating = true);
try {
final rel = context.read<SnRelationshipProvider>();
await rel.deleteRelationship(relation.relatedId);
if (!mounted) return;
_fetchRelations();
} catch (err) {
if (!mounted) return;
context.showErrorDialog(err);
} finally {
setState(() => _isUpdating = false);
}
}
void _showRequests() {
showModalBottomSheet(
context: context,
builder: (context) => _FriendshipPopupWidget(relations: _requests),
).then((value) {
if (value != null) {
_fetchRequests();
_fetchRelations();
}
});
}
void _showBlocks() {
showModalBottomSheet(
context: context,
builder: (context) => _FriendshipPopupWidget(relations: _blocks),
).then((value) {
if (value != null) {
_fetchBlocks();
_fetchRelations();
}
});
}
@override
void initState() {
super.initState();
_fetchRelations();
_fetchRequests();
_fetchBlocks();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('screenFriend').tr(),
),
floatingActionButton: FloatingActionButton(
child: const Icon(Symbols.add),
onPressed: () {
showModalBottomSheet(
context: context,
builder: (context) => _NewFriendWidget(),
);
},
),
body: Column(
children: [
LoadingIndicator(isActive: _isBusy || _isUpdating),
if (_requests.isNotEmpty)
ListTile(
title: Text('friendRequests').tr(),
subtitle: Text(
'friendRequestsDescription',
).plural(_requests.length),
contentPadding: const EdgeInsets.symmetric(horizontal: 24),
leading: const Icon(Symbols.group_add),
trailing: const Icon(Symbols.chevron_right),
onTap: _showRequests,
),
if (_blocks.isNotEmpty)
ListTile(
title: Text('friendBlocklist').tr(),
subtitle: Text(
'friendBlocklistDescription',
).plural(_blocks.length),
contentPadding: const EdgeInsets.symmetric(horizontal: 24),
leading: const Icon(Symbols.block),
trailing: const Icon(Symbols.chevron_right),
onTap: _showBlocks,
),
if (_requests.isNotEmpty || _blocks.isNotEmpty)
const Divider(height: 1),
Expanded(
child: RefreshIndicator(
onRefresh: () => Future.wait([
_fetchRelations(),
_fetchRequests(),
]),
child: ListView.builder(
itemCount: _relations.length,
itemBuilder: (context, index) {
final relation = _relations[index];
final other = relation.related;
return ListTile(
contentPadding: const EdgeInsets.only(right: 24, left: 16),
leading: AccountImage(content: other?.avatar),
title: Text(other?.nick ?? 'unknown'),
subtitle: Text(other?.nick ?? 'unknown'),
trailing: SizedBox(
height: 48,
width: 120,
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
InkWell(
onTap: _isUpdating
? null
: () => _changeRelation(relation, 2),
child: Text('friendBlock').tr(),
),
const Gap(8),
InkWell(
onTap: _isUpdating
? null
: () => _deleteRelation(relation),
child: Text('friendDeleteAction').tr(),
),
],
),
],
),
),
);
},
),
),
),
],
),
);
}
}
class _NewFriendWidget extends StatefulWidget {
const _NewFriendWidget({super.key});
@override
State<_NewFriendWidget> createState() => _NewFriendWidgetState();
}
class _NewFriendWidgetState extends State<_NewFriendWidget> {
bool _isBusy = false;
final TextEditingController _relatedController = TextEditingController();
Future<void> _sendRequest() async {
if (_relatedController.text.isEmpty) return;
setState(() => _isBusy = true);
try {
final sn = context.read<SnNetworkProvider>();
await sn.client.post('/cgi/id/users/me/relations', data: {
'related': _relatedController.text,
});
if (!mounted) return;
Navigator.pop(context, true);
context.showSnackbar('friendRequestSent'.tr());
} catch (err) {
if (!mounted) return;
context.showErrorDialog(err);
} finally {
setState(() => _isBusy = false);
}
}
@override
void dispose() {
super.dispose();
_relatedController.dispose();
}
@override
Widget build(BuildContext context) {
return StyledWidget(Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'friendNew',
style: Theme.of(context).textTheme.titleLarge,
).tr(),
const Gap(12),
TextField(
controller: _relatedController,
readOnly: _isBusy,
autocorrect: false,
autofocus: true,
textCapitalization: TextCapitalization.none,
decoration: InputDecoration(
labelText: 'fieldFriendRelatedName'.tr(),
suffix: SizedBox(
height: 24,
child: IconButton(
onPressed: _isBusy ? null : () => _sendRequest(),
icon: Icon(Symbols.send),
visualDensity:
const VisualDensity(horizontal: -4, vertical: -4),
padding: EdgeInsets.zero,
),
),
),
onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(),
)
],
)).padding(all: 24);
}
}
class _FriendshipPopupWidget extends StatefulWidget {
final List<SnRelationship> relations;
const _FriendshipPopupWidget({super.key, required this.relations});
@override
State<_FriendshipPopupWidget> createState() => _FriendshipPopupWidgetState();
}
class _FriendshipPopupWidgetState extends State<_FriendshipPopupWidget> {
bool _isBusy = false;
Future<void> _acceptRequest(SnRelationship relation) async {
setState(() => _isBusy = true);
try {
final rel = context.read<SnRelationshipProvider>();
await rel.acceptFriendRequest(relation.relatedId);
if (!mounted) return;
Navigator.pop(context, true);
} catch (err) {
if (!mounted) return;
context.showErrorDialog(err);
} finally {
setState(() => _isBusy = false);
}
}
Future<void> _declineRequest(SnRelationship relation) async {
setState(() => _isBusy = true);
try {
final rel = context.read<SnRelationshipProvider>();
await rel.declineFriendRequest(relation.relatedId);
if (!mounted) return;
Navigator.pop(context, true);
} catch (err) {
if (!mounted) return;
context.showErrorDialog(err);
} finally {
setState(() => _isBusy = false);
}
}
Future<void> _changeRelation(SnRelationship relation, int dstStatus) async {
setState(() => _isBusy = true);
try {
final rel = context.read<SnRelationshipProvider>();
await rel.updateRelationship(
relation.relatedId,
dstStatus,
relation.permNodes,
);
if (!mounted) return;
Navigator.pop(context, true);
} catch (err) {
if (!mounted) return;
context.showErrorDialog(err);
} finally {
setState(() => _isBusy = false);
}
}
Future<void> _deleteRelation(SnRelationship relation) async {
final confirm = await context.showConfirmDialog(
'friendDelete'.tr(args: [relation.related?.nick ?? 'unknown'.tr()]),
'friendDeleteDescription'.tr(args: [
relation.related?.nick ?? 'unknown'.tr(),
]),
);
if (!confirm) return;
if (!mounted) return;
setState(() => _isBusy = true);
try {
final rel = context.read<SnRelationshipProvider>();
await rel.deleteRelationship(relation.relatedId);
if (!mounted) return;
Navigator.pop(context, true);
} catch (err) {
if (!mounted) return;
context.showErrorDialog(err);
} finally {
setState(() => _isBusy = false);
}
}
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: widget.relations.length,
itemBuilder: (context, index) {
final relation = widget.relations[index];
final other = relation.related;
return ListTile(
contentPadding: const EdgeInsets.only(right: 24, left: 16),
leading: AccountImage(content: other?.avatar),
title: Text(other?.nick ?? 'unknown'.tr()),
subtitle: Text(other?.nick ?? 'unknown'.tr()),
trailing: SizedBox(
height: 48,
width: 120,
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(kFriendStatus[relation.status] ?? 'unknown')
.tr()
.opacity(0.75),
if (relation.status == 0)
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
InkWell(
onTap: _isBusy ? null : () => _acceptRequest(relation),
child: Text('friendRequestAccept').tr(),
),
const Gap(8),
InkWell(
onTap: _isBusy ? null : () => _declineRequest(relation),
child: Text('friendRequestDecline').tr(),
),
],
)
else if (relation.status == 2)
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
InkWell(
onTap:
_isBusy ? null : () => _changeRelation(relation, 1),
child: Text('friendUnblock').tr(),
),
const Gap(8),
InkWell(
onTap: _isBusy ? null : () => _deleteRelation(relation),
child: Text('friendDeleteAction').tr(),
),
],
),
],
),
),
);
},
);
}
}

View File

@ -70,3 +70,22 @@ class SnAccountProfile with _$SnAccountProfile {
factory SnAccountProfile.fromJson(Map<String, Object?> json) =>
_$SnAccountProfileFromJson(json);
}
@freezed
class SnRelationship with _$SnRelationship {
const factory SnRelationship({
required int id,
required DateTime createdAt,
required DateTime updatedAt,
required DateTime? deletedAt,
required int accountId,
required int relatedId,
required SnAccount? account,
required SnAccount? related,
required int status,
@Default({}) Map<String, dynamic> permNodes,
}) = _SnRelationship;
factory SnRelationship.fromJson(Map<String, Object?> json) =>
_$SnRelationshipFromJson(json);
}

View File

@ -1271,3 +1271,397 @@ abstract class _SnAccountProfile implements SnAccountProfile {
_$$SnAccountProfileImplCopyWith<_$SnAccountProfileImpl> get copyWith =>
throw _privateConstructorUsedError;
}
SnRelationship _$SnRelationshipFromJson(Map<String, dynamic> json) {
return _SnRelationship.fromJson(json);
}
/// @nodoc
mixin _$SnRelationship {
int get id => throw _privateConstructorUsedError;
DateTime get createdAt => throw _privateConstructorUsedError;
DateTime get updatedAt => throw _privateConstructorUsedError;
DateTime? get deletedAt => throw _privateConstructorUsedError;
int get accountId => throw _privateConstructorUsedError;
int get relatedId => throw _privateConstructorUsedError;
SnAccount? get account => throw _privateConstructorUsedError;
SnAccount? get related => throw _privateConstructorUsedError;
int get status => throw _privateConstructorUsedError;
Map<String, dynamic> get permNodes => throw _privateConstructorUsedError;
/// Serializes this SnRelationship to a JSON map.
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
/// Create a copy of SnRelationship
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$SnRelationshipCopyWith<SnRelationship> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $SnRelationshipCopyWith<$Res> {
factory $SnRelationshipCopyWith(
SnRelationship value, $Res Function(SnRelationship) then) =
_$SnRelationshipCopyWithImpl<$Res, SnRelationship>;
@useResult
$Res call(
{int id,
DateTime createdAt,
DateTime updatedAt,
DateTime? deletedAt,
int accountId,
int relatedId,
SnAccount? account,
SnAccount? related,
int status,
Map<String, dynamic> permNodes});
$SnAccountCopyWith<$Res>? get account;
$SnAccountCopyWith<$Res>? get related;
}
/// @nodoc
class _$SnRelationshipCopyWithImpl<$Res, $Val extends SnRelationship>
implements $SnRelationshipCopyWith<$Res> {
_$SnRelationshipCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of SnRelationship
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? id = null,
Object? createdAt = null,
Object? updatedAt = null,
Object? deletedAt = freezed,
Object? accountId = null,
Object? relatedId = null,
Object? account = freezed,
Object? related = freezed,
Object? status = null,
Object? permNodes = null,
}) {
return _then(_value.copyWith(
id: null == id
? _value.id
: id // ignore: cast_nullable_to_non_nullable
as int,
createdAt: null == createdAt
? _value.createdAt
: createdAt // ignore: cast_nullable_to_non_nullable
as DateTime,
updatedAt: null == updatedAt
? _value.updatedAt
: updatedAt // ignore: cast_nullable_to_non_nullable
as DateTime,
deletedAt: freezed == deletedAt
? _value.deletedAt
: deletedAt // ignore: cast_nullable_to_non_nullable
as DateTime?,
accountId: null == accountId
? _value.accountId
: accountId // ignore: cast_nullable_to_non_nullable
as int,
relatedId: null == relatedId
? _value.relatedId
: relatedId // ignore: cast_nullable_to_non_nullable
as int,
account: freezed == account
? _value.account
: account // ignore: cast_nullable_to_non_nullable
as SnAccount?,
related: freezed == related
? _value.related
: related // ignore: cast_nullable_to_non_nullable
as SnAccount?,
status: null == status
? _value.status
: status // ignore: cast_nullable_to_non_nullable
as int,
permNodes: null == permNodes
? _value.permNodes
: permNodes // ignore: cast_nullable_to_non_nullable
as Map<String, dynamic>,
) as $Val);
}
/// Create a copy of SnRelationship
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$SnAccountCopyWith<$Res>? get account {
if (_value.account == null) {
return null;
}
return $SnAccountCopyWith<$Res>(_value.account!, (value) {
return _then(_value.copyWith(account: value) as $Val);
});
}
/// Create a copy of SnRelationship
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$SnAccountCopyWith<$Res>? get related {
if (_value.related == null) {
return null;
}
return $SnAccountCopyWith<$Res>(_value.related!, (value) {
return _then(_value.copyWith(related: value) as $Val);
});
}
}
/// @nodoc
abstract class _$$SnRelationshipImplCopyWith<$Res>
implements $SnRelationshipCopyWith<$Res> {
factory _$$SnRelationshipImplCopyWith(_$SnRelationshipImpl value,
$Res Function(_$SnRelationshipImpl) then) =
__$$SnRelationshipImplCopyWithImpl<$Res>;
@override
@useResult
$Res call(
{int id,
DateTime createdAt,
DateTime updatedAt,
DateTime? deletedAt,
int accountId,
int relatedId,
SnAccount? account,
SnAccount? related,
int status,
Map<String, dynamic> permNodes});
@override
$SnAccountCopyWith<$Res>? get account;
@override
$SnAccountCopyWith<$Res>? get related;
}
/// @nodoc
class __$$SnRelationshipImplCopyWithImpl<$Res>
extends _$SnRelationshipCopyWithImpl<$Res, _$SnRelationshipImpl>
implements _$$SnRelationshipImplCopyWith<$Res> {
__$$SnRelationshipImplCopyWithImpl(
_$SnRelationshipImpl _value, $Res Function(_$SnRelationshipImpl) _then)
: super(_value, _then);
/// Create a copy of SnRelationship
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? id = null,
Object? createdAt = null,
Object? updatedAt = null,
Object? deletedAt = freezed,
Object? accountId = null,
Object? relatedId = null,
Object? account = freezed,
Object? related = freezed,
Object? status = null,
Object? permNodes = null,
}) {
return _then(_$SnRelationshipImpl(
id: null == id
? _value.id
: id // ignore: cast_nullable_to_non_nullable
as int,
createdAt: null == createdAt
? _value.createdAt
: createdAt // ignore: cast_nullable_to_non_nullable
as DateTime,
updatedAt: null == updatedAt
? _value.updatedAt
: updatedAt // ignore: cast_nullable_to_non_nullable
as DateTime,
deletedAt: freezed == deletedAt
? _value.deletedAt
: deletedAt // ignore: cast_nullable_to_non_nullable
as DateTime?,
accountId: null == accountId
? _value.accountId
: accountId // ignore: cast_nullable_to_non_nullable
as int,
relatedId: null == relatedId
? _value.relatedId
: relatedId // ignore: cast_nullable_to_non_nullable
as int,
account: freezed == account
? _value.account
: account // ignore: cast_nullable_to_non_nullable
as SnAccount?,
related: freezed == related
? _value.related
: related // ignore: cast_nullable_to_non_nullable
as SnAccount?,
status: null == status
? _value.status
: status // ignore: cast_nullable_to_non_nullable
as int,
permNodes: null == permNodes
? _value._permNodes
: permNodes // ignore: cast_nullable_to_non_nullable
as Map<String, dynamic>,
));
}
}
/// @nodoc
@JsonSerializable()
class _$SnRelationshipImpl implements _SnRelationship {
const _$SnRelationshipImpl(
{required this.id,
required this.createdAt,
required this.updatedAt,
required this.deletedAt,
required this.accountId,
required this.relatedId,
required this.account,
required this.related,
required this.status,
final Map<String, dynamic> permNodes = const {}})
: _permNodes = permNodes;
factory _$SnRelationshipImpl.fromJson(Map<String, dynamic> json) =>
_$$SnRelationshipImplFromJson(json);
@override
final int id;
@override
final DateTime createdAt;
@override
final DateTime updatedAt;
@override
final DateTime? deletedAt;
@override
final int accountId;
@override
final int relatedId;
@override
final SnAccount? account;
@override
final SnAccount? related;
@override
final int status;
final Map<String, dynamic> _permNodes;
@override
@JsonKey()
Map<String, dynamic> get permNodes {
if (_permNodes is EqualUnmodifiableMapView) return _permNodes;
// ignore: implicit_dynamic_type
return EqualUnmodifiableMapView(_permNodes);
}
@override
String toString() {
return 'SnRelationship(id: $id, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, accountId: $accountId, relatedId: $relatedId, account: $account, related: $related, status: $status, permNodes: $permNodes)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$SnRelationshipImpl &&
(identical(other.id, id) || other.id == id) &&
(identical(other.createdAt, createdAt) ||
other.createdAt == createdAt) &&
(identical(other.updatedAt, updatedAt) ||
other.updatedAt == updatedAt) &&
(identical(other.deletedAt, deletedAt) ||
other.deletedAt == deletedAt) &&
(identical(other.accountId, accountId) ||
other.accountId == accountId) &&
(identical(other.relatedId, relatedId) ||
other.relatedId == relatedId) &&
(identical(other.account, account) || other.account == account) &&
(identical(other.related, related) || other.related == related) &&
(identical(other.status, status) || other.status == status) &&
const DeepCollectionEquality()
.equals(other._permNodes, _permNodes));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(
runtimeType,
id,
createdAt,
updatedAt,
deletedAt,
accountId,
relatedId,
account,
related,
status,
const DeepCollectionEquality().hash(_permNodes));
/// Create a copy of SnRelationship
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$SnRelationshipImplCopyWith<_$SnRelationshipImpl> get copyWith =>
__$$SnRelationshipImplCopyWithImpl<_$SnRelationshipImpl>(
this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$$SnRelationshipImplToJson(
this,
);
}
}
abstract class _SnRelationship implements SnRelationship {
const factory _SnRelationship(
{required final int id,
required final DateTime createdAt,
required final DateTime updatedAt,
required final DateTime? deletedAt,
required final int accountId,
required final int relatedId,
required final SnAccount? account,
required final SnAccount? related,
required final int status,
final Map<String, dynamic> permNodes}) = _$SnRelationshipImpl;
factory _SnRelationship.fromJson(Map<String, dynamic> json) =
_$SnRelationshipImpl.fromJson;
@override
int get id;
@override
DateTime get createdAt;
@override
DateTime get updatedAt;
@override
DateTime? get deletedAt;
@override
int get accountId;
@override
int get relatedId;
@override
SnAccount? get account;
@override
SnAccount? get related;
@override
int get status;
@override
Map<String, dynamic> get permNodes;
/// Create a copy of SnRelationship
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$SnRelationshipImplCopyWith<_$SnRelationshipImpl> get copyWith =>
throw _privateConstructorUsedError;
}

View File

@ -129,3 +129,38 @@ Map<String, dynamic> _$$SnAccountProfileImplToJson(
'last_seen_at': instance.lastSeenAt?.toIso8601String(),
'updated_at': instance.updatedAt.toIso8601String(),
};
_$SnRelationshipImpl _$$SnRelationshipImplFromJson(Map<String, dynamic> json) =>
_$SnRelationshipImpl(
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),
accountId: (json['account_id'] as num).toInt(),
relatedId: (json['related_id'] as num).toInt(),
account: json['account'] == null
? null
: SnAccount.fromJson(json['account'] as Map<String, dynamic>),
related: json['related'] == null
? null
: SnAccount.fromJson(json['related'] as Map<String, dynamic>),
status: (json['status'] as num).toInt(),
permNodes: json['perm_nodes'] as Map<String, dynamic>? ?? const {},
);
Map<String, dynamic> _$$SnRelationshipImplToJson(
_$SnRelationshipImpl instance) =>
<String, dynamic>{
'id': instance.id,
'created_at': instance.createdAt.toIso8601String(),
'updated_at': instance.updatedAt.toIso8601String(),
'deleted_at': instance.deletedAt?.toIso8601String(),
'account_id': instance.accountId,
'related_id': instance.relatedId,
'account': instance.account?.toJson(),
'related': instance.related?.toJson(),
'status': instance.status,
'perm_nodes': instance.permNodes,
};

View File

@ -37,7 +37,6 @@ mixin _$SnChannel {
@HiveField(7)
List<dynamic>? get members => throw _privateConstructorUsedError;
List<SnChatMessage>? get messages => throw _privateConstructorUsedError;
dynamic get calls => throw _privateConstructorUsedError;
@HiveField(8)
int get type => throw _privateConstructorUsedError;
@HiveField(9)
@ -76,7 +75,6 @@ abstract class $SnChannelCopyWith<$Res> {
@HiveField(6) String description,
@HiveField(7) List<dynamic>? members,
List<SnChatMessage>? messages,
dynamic calls,
@HiveField(8) int type,
@HiveField(9) int accountId,
@HiveField(10) SnRealm? realm,
@ -111,7 +109,6 @@ class _$SnChannelCopyWithImpl<$Res, $Val extends SnChannel>
Object? description = null,
Object? members = freezed,
Object? messages = freezed,
Object? calls = freezed,
Object? type = null,
Object? accountId = null,
Object? realm = freezed,
@ -156,10 +153,6 @@ class _$SnChannelCopyWithImpl<$Res, $Val extends SnChannel>
? _value.messages
: messages // ignore: cast_nullable_to_non_nullable
as List<SnChatMessage>?,
calls: freezed == calls
? _value.calls
: calls // ignore: cast_nullable_to_non_nullable
as dynamic,
type: null == type
? _value.type
: type // ignore: cast_nullable_to_non_nullable
@ -220,7 +213,6 @@ abstract class _$$SnChannelImplCopyWith<$Res>
@HiveField(6) String description,
@HiveField(7) List<dynamic>? members,
List<SnChatMessage>? messages,
dynamic calls,
@HiveField(8) int type,
@HiveField(9) int accountId,
@HiveField(10) SnRealm? realm,
@ -254,7 +246,6 @@ class __$$SnChannelImplCopyWithImpl<$Res>
Object? description = null,
Object? members = freezed,
Object? messages = freezed,
Object? calls = freezed,
Object? type = null,
Object? accountId = null,
Object? realm = freezed,
@ -299,10 +290,6 @@ class __$$SnChannelImplCopyWithImpl<$Res>
? _value._messages
: messages // ignore: cast_nullable_to_non_nullable
as List<SnChatMessage>?,
calls: freezed == calls
? _value.calls
: calls // ignore: cast_nullable_to_non_nullable
as dynamic,
type: null == type
? _value.type
: type // ignore: cast_nullable_to_non_nullable
@ -345,7 +332,6 @@ class _$SnChannelImpl extends _SnChannel {
@HiveField(6) required this.description,
@HiveField(7) required final List<dynamic>? members,
final List<SnChatMessage>? messages,
this.calls,
@HiveField(8) required this.type,
@HiveField(9) required this.accountId,
@HiveField(10) required this.realm,
@ -401,8 +387,6 @@ class _$SnChannelImpl extends _SnChannel {
return EqualUnmodifiableListView(value);
}
@override
final dynamic calls;
@override
@HiveField(8)
final int type;
@ -424,7 +408,7 @@ class _$SnChannelImpl extends _SnChannel {
@override
String toString() {
return 'SnChannel(id: $id, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, alias: $alias, name: $name, description: $description, members: $members, messages: $messages, calls: $calls, type: $type, accountId: $accountId, realm: $realm, realmId: $realmId, isPublic: $isPublic, isCommunity: $isCommunity)';
return 'SnChannel(id: $id, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, alias: $alias, name: $name, description: $description, members: $members, messages: $messages, type: $type, accountId: $accountId, realm: $realm, realmId: $realmId, isPublic: $isPublic, isCommunity: $isCommunity)';
}
@override
@ -444,7 +428,6 @@ class _$SnChannelImpl extends _SnChannel {
other.description == description) &&
const DeepCollectionEquality().equals(other._members, _members) &&
const DeepCollectionEquality().equals(other._messages, _messages) &&
const DeepCollectionEquality().equals(other.calls, calls) &&
(identical(other.type, type) || other.type == type) &&
(identical(other.accountId, accountId) ||
other.accountId == accountId) &&
@ -469,7 +452,6 @@ class _$SnChannelImpl extends _SnChannel {
description,
const DeepCollectionEquality().hash(_members),
const DeepCollectionEquality().hash(_messages),
const DeepCollectionEquality().hash(calls),
type,
accountId,
realm,
@ -504,7 +486,6 @@ abstract class _SnChannel extends SnChannel {
@HiveField(6) required final String description,
@HiveField(7) required final List<dynamic>? members,
final List<SnChatMessage>? messages,
final dynamic calls,
@HiveField(8) required final int type,
@HiveField(9) required final int accountId,
@HiveField(10) required final SnRealm? realm,
@ -543,8 +524,6 @@ abstract class _SnChannel extends SnChannel {
@override
List<SnChatMessage>? get messages;
@override
dynamic get calls;
@override
@HiveField(8)
int get type;
@override

View File

@ -227,7 +227,6 @@ _$SnChannelImpl _$$SnChannelImplFromJson(Map<String, dynamic> json) =>
messages: (json['messages'] as List<dynamic>?)
?.map((e) => SnChatMessage.fromJson(e as Map<String, dynamic>))
.toList(),
calls: json['calls'],
type: (json['type'] as num).toInt(),
accountId: (json['account_id'] as num).toInt(),
realm: json['realm'] == null
@ -249,7 +248,6 @@ Map<String, dynamic> _$$SnChannelImplToJson(_$SnChannelImpl instance) =>
'description': instance.description,
'members': instance.members,
'messages': instance.messages?.map((e) => e.toJson()).toList(),
'calls': instance.calls,
'type': instance.type,
'account_id': instance.accountId,
'realm': instance.realm?.toJson(),

View File

@ -670,10 +670,10 @@ packages:
dependency: transitive
description:
name: flutter_webrtc
sha256: fcaee6f28cc1221e804fcba16fbee6f20b0848af20fe11174a0f97c3b9833381
sha256: "4838217405c42cce422698eacc9c2e17089b9c05322be899c0a725107dcddbdc"
url: "https://pub.dev"
source: hosted
version: "0.12.2"
version: "0.12.3"
freezed:
dependency: "direct dev"
description:
@ -830,10 +830,10 @@ packages:
dependency: transitive
description:
name: image_picker_android
sha256: "8faba09ba361d4b246dc0a17cb4289b3324c2b9f6db7b3d457ee69106a86bd32"
sha256: fa8141602fde3f7e2f81dbf043613eb44dfa325fa0bcf93c0f142c9f7a2c193e
url: "https://pub.dev"
source: hosted
version: "0.8.12+17"
version: "0.8.12+18"
image_picker_for_web:
dependency: transitive
description:
@ -974,10 +974,10 @@ packages:
dependency: "direct main"
description:
name: livekit_client
sha256: ad55045435fbf1a106e2da4c9a8d523755ce834db47f6d967beaa58228b21a05
sha256: "442c228f42a3b757e1a5e526b0816f2b0a93b34625ff29b2c9fb9503ce4e4f3e"
url: "https://pub.dev"
source: hosted
version: "2.3.0"
version: "2.3.1"
logging:
dependency: transitive
description:
@ -1022,10 +1022,10 @@ packages:
dependency: "direct main"
description:
name: material_symbols_icons
sha256: "8a57be605b8bc3fd57005eb776ede61f569214e48834258fb02ab80c7034b82c"
sha256: a783133f87c58e10b1cc19797f7c3192ff9c2bab301c4ade90312d8f2aed01b2
url: "https://pub.dev"
source: hosted
version: "4.2800.0"
version: "4.2800.2"
media_kit:
dependency: "direct main"
description:
@ -1899,10 +1899,10 @@ packages:
dependency: transitive
description:
name: win32
sha256: "84ba388638ed7a8cb3445a320c8273136ab2631cd5f2c57888335504ddab1bc2"
sha256: "8b338d4486ab3fbc0ba0db9f9b4f5239b6697fcee427939a40e720cbb9ee0a69"
url: "https://pub.dev"
source: hosted
version: "5.8.0"
version: "5.9.0"
win32_registry:
dependency: transitive
description: