♻️ Refactored friend module
This commit is contained in:
parent
39c8597428
commit
8366bda846
@ -11,11 +11,11 @@ import 'package:solian/platform.dart';
|
|||||||
import 'package:solian/providers/websocket.dart';
|
import 'package:solian/providers/websocket.dart';
|
||||||
import 'package:solian/providers/auth.dart';
|
import 'package:solian/providers/auth.dart';
|
||||||
import 'package:solian/providers/content/attachment.dart';
|
import 'package:solian/providers/content/attachment.dart';
|
||||||
import 'package:solian/providers/content/call.dart';
|
import 'package:solian/providers/call.dart';
|
||||||
import 'package:solian/providers/content/channel.dart';
|
import 'package:solian/providers/content/channel.dart';
|
||||||
import 'package:solian/providers/content/posts.dart';
|
import 'package:solian/providers/content/posts.dart';
|
||||||
import 'package:solian/providers/content/realm.dart';
|
import 'package:solian/providers/content/realm.dart';
|
||||||
import 'package:solian/providers/friend.dart';
|
import 'package:solian/providers/relation.dart';
|
||||||
import 'package:solian/providers/account_status.dart';
|
import 'package:solian/providers/account_status.dart';
|
||||||
import 'package:solian/router.dart';
|
import 'package:solian/router.dart';
|
||||||
import 'package:solian/shells/system_shell.dart';
|
import 'package:solian/shells/system_shell.dart';
|
||||||
@ -96,7 +96,7 @@ class SolianApp extends StatelessWidget {
|
|||||||
|
|
||||||
void _initializeProviders(BuildContext context) async {
|
void _initializeProviders(BuildContext context) async {
|
||||||
Get.lazyPut(() => AuthProvider());
|
Get.lazyPut(() => AuthProvider());
|
||||||
Get.lazyPut(() => FriendProvider());
|
Get.lazyPut(() => RelationshipProvider());
|
||||||
Get.lazyPut(() => PostProvider());
|
Get.lazyPut(() => PostProvider());
|
||||||
Get.lazyPut(() => AttachmentProvider());
|
Get.lazyPut(() => AttachmentProvider());
|
||||||
Get.lazyPut(() => WebSocketProvider());
|
Get.lazyPut(() => WebSocketProvider());
|
||||||
|
@ -1,38 +1,35 @@
|
|||||||
import 'package:solian/models/account.dart';
|
import 'package:solian/models/account.dart';
|
||||||
|
|
||||||
class Friendship {
|
class Relationship {
|
||||||
int id;
|
int id;
|
||||||
DateTime createdAt;
|
DateTime createdAt;
|
||||||
DateTime updatedAt;
|
DateTime updatedAt;
|
||||||
DateTime? deletedAt;
|
DateTime? deletedAt;
|
||||||
int accountId;
|
int accountId;
|
||||||
int relatedId;
|
int relatedId;
|
||||||
int? blockedBy;
|
|
||||||
Account account;
|
Account account;
|
||||||
Account related;
|
Account related;
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
Friendship({
|
Relationship({
|
||||||
required this.id,
|
required this.id,
|
||||||
required this.createdAt,
|
required this.createdAt,
|
||||||
required this.updatedAt,
|
required this.updatedAt,
|
||||||
required this.deletedAt,
|
required this.deletedAt,
|
||||||
required this.accountId,
|
required this.accountId,
|
||||||
required this.relatedId,
|
required this.relatedId,
|
||||||
required this.blockedBy,
|
|
||||||
required this.account,
|
required this.account,
|
||||||
required this.related,
|
required this.related,
|
||||||
required this.status,
|
required this.status,
|
||||||
});
|
});
|
||||||
|
|
||||||
factory Friendship.fromJson(Map<String, dynamic> json) => Friendship(
|
factory Relationship.fromJson(Map<String, dynamic> json) => Relationship(
|
||||||
id: json['id'],
|
id: json['id'],
|
||||||
createdAt: DateTime.parse(json['created_at']),
|
createdAt: DateTime.parse(json['created_at']),
|
||||||
updatedAt: DateTime.parse(json['updated_at']),
|
updatedAt: DateTime.parse(json['updated_at']),
|
||||||
deletedAt: json['deleted_at'],
|
deletedAt: json['deleted_at'],
|
||||||
accountId: json['account_id'],
|
accountId: json['account_id'],
|
||||||
relatedId: json['related_id'],
|
relatedId: json['related_id'],
|
||||||
blockedBy: json['blocked_by'],
|
|
||||||
account: Account.fromJson(json['account']),
|
account: Account.fromJson(json['account']),
|
||||||
related: Account.fromJson(json['related']),
|
related: Account.fromJson(json['related']),
|
||||||
status: json['status'],
|
status: json['status'],
|
||||||
@ -45,7 +42,6 @@ class Friendship {
|
|||||||
'deleted_at': deletedAt,
|
'deleted_at': deletedAt,
|
||||||
'account_id': accountId,
|
'account_id': accountId,
|
||||||
'related_id': relatedId,
|
'related_id': relatedId,
|
||||||
'blocked_by': blockedBy,
|
|
||||||
'account': account.toJson(),
|
'account': account.toJson(),
|
||||||
'related': related.toJson(),
|
'related': related.toJson(),
|
||||||
'status': status,
|
'status': status,
|
@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:solian/models/channel.dart';
|
import 'package:solian/models/channel.dart';
|
||||||
import 'package:solian/providers/auth.dart';
|
import 'package:solian/providers/auth.dart';
|
||||||
import 'package:solian/widgets/account/friend_select.dart';
|
import 'package:solian/widgets/account/relative_select.dart';
|
||||||
import 'package:uuid/uuid.dart';
|
import 'package:uuid/uuid.dart';
|
||||||
|
|
||||||
class ChannelProvider extends GetxController {
|
class ChannelProvider extends GetxController {
|
||||||
@ -123,7 +123,7 @@ class ChannelProvider extends GetxController {
|
|||||||
final related = await showModalBottomSheet(
|
final related = await showModalBottomSheet(
|
||||||
useRootNavigator: true,
|
useRootNavigator: true,
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) => FriendSelect(
|
builder: (context) => RelativeSelector(
|
||||||
title: 'channelOrganizeDirectHint'.tr,
|
title: 'channelOrganizeDirectHint'.tr,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -1,43 +0,0 @@
|
|||||||
import 'package:get/get.dart';
|
|
||||||
import 'package:solian/models/friendship.dart';
|
|
||||||
import 'package:solian/providers/auth.dart';
|
|
||||||
import 'package:solian/services.dart';
|
|
||||||
|
|
||||||
class FriendProvider extends GetConnect {
|
|
||||||
@override
|
|
||||||
void onInit() {
|
|
||||||
final AuthProvider auth = Get.find();
|
|
||||||
|
|
||||||
httpClient.baseUrl = ServiceFinder.buildUrl('auth', null);
|
|
||||||
httpClient.addAuthenticator(auth.requestAuthenticator);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<Response> listFriendship() => get('/users/me/friends');
|
|
||||||
|
|
||||||
Future<Response> listFriendshipWithStatus(int status) =>
|
|
||||||
get('/users/me/friends?status=$status');
|
|
||||||
|
|
||||||
Future<Response> createFriendship(String username) async {
|
|
||||||
final resp = await post('/users/me/friends?related=$username', {});
|
|
||||||
if (resp.statusCode != 200) {
|
|
||||||
throw Exception(resp.bodyString);
|
|
||||||
}
|
|
||||||
|
|
||||||
return resp;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<Response> updateFriendship(Friendship relationship, int status) async {
|
|
||||||
final AuthProvider auth = Get.find();
|
|
||||||
final prof = await auth.getProfile();
|
|
||||||
final otherside = relationship.getOtherside(prof.body['id']);
|
|
||||||
|
|
||||||
final resp = await put('/users/me/friends/${otherside.id}', {
|
|
||||||
'status': status,
|
|
||||||
});
|
|
||||||
if (resp.statusCode != 200) {
|
|
||||||
throw Exception(resp.bodyString);
|
|
||||||
}
|
|
||||||
|
|
||||||
return resp;
|
|
||||||
}
|
|
||||||
}
|
|
57
lib/providers/relation.dart
Normal file
57
lib/providers/relation.dart
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:solian/models/relations.dart';
|
||||||
|
import 'package:solian/providers/auth.dart';
|
||||||
|
import 'package:solian/services.dart';
|
||||||
|
|
||||||
|
class RelationshipProvider extends GetConnect {
|
||||||
|
@override
|
||||||
|
void onInit() {
|
||||||
|
final AuthProvider auth = Get.find();
|
||||||
|
|
||||||
|
httpClient.baseUrl = ServiceFinder.buildUrl('auth', null);
|
||||||
|
httpClient.addAuthenticator(auth.requestAuthenticator);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Response> listRelation() => get('/users/me/relations');
|
||||||
|
|
||||||
|
Future<Response> listRelationWithStatus(int status) =>
|
||||||
|
get('/users/me/relations?status=$status');
|
||||||
|
|
||||||
|
Future<Response> makeFriend(String username) async {
|
||||||
|
final resp = await post('/users/me/relations?related=$username', {});
|
||||||
|
if (resp.statusCode != 200) {
|
||||||
|
throw Exception(resp.bodyString);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Response> handleRelation(
|
||||||
|
Relationship relationship, bool doAccept) async {
|
||||||
|
final AuthProvider auth = Get.find();
|
||||||
|
final client = auth.configureClient('auth');
|
||||||
|
final resp = await client.post(
|
||||||
|
'/users/me/relations/${relationship.relatedId}/${doAccept ? 'accept' : 'decline'}',
|
||||||
|
{},
|
||||||
|
);
|
||||||
|
if (resp.statusCode != 200) {
|
||||||
|
throw Exception(resp.bodyString);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Response> editRelation(Relationship relationship, int status) async {
|
||||||
|
final AuthProvider auth = Get.find();
|
||||||
|
final client = auth.configureClient('auth');
|
||||||
|
final resp =
|
||||||
|
await client.patch('/users/me/relations/${relationship.relatedId}', {
|
||||||
|
'status': status,
|
||||||
|
});
|
||||||
|
if (resp.statusCode != 200) {
|
||||||
|
throw Exception(resp.bodyString);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
}
|
@ -191,10 +191,7 @@ abstract class AppRouter {
|
|||||||
GoRoute(
|
GoRoute(
|
||||||
path: '/account/friend',
|
path: '/account/friend',
|
||||||
name: 'accountFriend',
|
name: 'accountFriend',
|
||||||
builder: (context, state) => TitleShell(
|
builder: (context, state) => const FriendScreen(),
|
||||||
state: state,
|
|
||||||
child: const FriendScreen(),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: '/account/personalize',
|
path: '/account/personalize',
|
||||||
|
@ -2,10 +2,9 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_animate/flutter_animate.dart';
|
import 'package:flutter_animate/flutter_animate.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:solian/exts.dart';
|
import 'package:solian/exts.dart';
|
||||||
import 'package:solian/models/friendship.dart';
|
import 'package:solian/models/relations.dart';
|
||||||
import 'package:solian/providers/auth.dart';
|
import 'package:solian/providers/relation.dart';
|
||||||
import 'package:solian/providers/friend.dart';
|
import 'package:solian/widgets/account/relative_list.dart';
|
||||||
import 'package:solian/widgets/account/friend_list.dart';
|
|
||||||
|
|
||||||
class FriendScreen extends StatefulWidget {
|
class FriendScreen extends StatefulWidget {
|
||||||
const FriendScreen({super.key});
|
const FriendScreen({super.key});
|
||||||
@ -14,71 +13,38 @@ class FriendScreen extends StatefulWidget {
|
|||||||
State<FriendScreen> createState() => _FriendScreenState();
|
State<FriendScreen> createState() => _FriendScreenState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _FriendScreenState extends State<FriendScreen> {
|
class _FriendScreenState extends State<FriendScreen>
|
||||||
|
with SingleTickerProviderStateMixin {
|
||||||
|
late final TabController _tabController;
|
||||||
|
|
||||||
bool _isBusy = false;
|
bool _isBusy = false;
|
||||||
int? _accountId;
|
|
||||||
|
|
||||||
List<Friendship> _friendships = List.empty();
|
List<Relationship> _relations = List.empty();
|
||||||
|
|
||||||
List<Friendship> filterWithStatus(int status) {
|
List<Relationship> filterByStatus(int status) {
|
||||||
return _friendships.where((x) => x.status == status).toList();
|
return _relations.where((x) => x.status == status).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> getFriendship() async {
|
Future<void> loadRelations() async {
|
||||||
setState(() => _isBusy = true);
|
setState(() => _isBusy = true);
|
||||||
|
|
||||||
final FriendProvider provider = Get.find();
|
final RelationshipProvider provider = Get.find();
|
||||||
final resp = await provider.listFriendship();
|
final resp = await provider.listRelation();
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
_friendships = resp.body
|
_relations = resp.body
|
||||||
.map((e) => Friendship.fromJson(e))
|
.map((e) => Relationship.fromJson(e))
|
||||||
.toList()
|
.toList()
|
||||||
.cast<Friendship>();
|
.cast<Relationship>();
|
||||||
_isBusy = false;
|
_isBusy = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void showScopedListPopup(String title, int status) {
|
|
||||||
showModalBottomSheet(
|
|
||||||
useRootNavigator: true,
|
|
||||||
isScrollControlled: true,
|
|
||||||
context: context,
|
|
||||||
builder: (context) {
|
|
||||||
return SizedBox(
|
|
||||||
height: MediaQuery.of(context).size.height * 0.85,
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
title,
|
|
||||||
style: Theme.of(context).textTheme.headlineSmall,
|
|
||||||
).paddingOnly(left: 24, right: 24, top: 32, bottom: 16),
|
|
||||||
Expanded(
|
|
||||||
child: CustomScrollView(
|
|
||||||
slivers: [
|
|
||||||
SliverFriendList(
|
|
||||||
accountId: _accountId!,
|
|
||||||
items: filterWithStatus(status),
|
|
||||||
onUpdate: () {
|
|
||||||
getFriendship();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void promptAddFriend() async {
|
void promptAddFriend() async {
|
||||||
final FriendProvider provider = Get.find();
|
final RelationshipProvider provider = Get.find();
|
||||||
|
|
||||||
final controller = TextEditingController();
|
final controller = TextEditingController();
|
||||||
final input = await showDialog(
|
final input = await showDialog<String?>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
@ -125,7 +91,7 @@ class _FriendScreenState extends State<FriendScreen> {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
setState(() => _isBusy = true);
|
setState(() => _isBusy = true);
|
||||||
await provider.createFriendship(input);
|
await provider.makeFriend(input);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
context.showErrorDialog(e);
|
context.showErrorDialog(e);
|
||||||
} finally {
|
} finally {
|
||||||
@ -135,12 +101,14 @@ class _FriendScreenState extends State<FriendScreen> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
Get.find<AuthProvider>().getProfile().then((value) {
|
|
||||||
_accountId = value.body['id'];
|
|
||||||
});
|
|
||||||
super.initState();
|
super.initState();
|
||||||
|
_tabController = TabController(length: 3, vsync: this);
|
||||||
|
|
||||||
Future.delayed(Duration.zero, () => getFriendship());
|
loadRelations().then((_) {
|
||||||
|
if (filterByStatus(0).isEmpty) {
|
||||||
|
_tabController.animateTo(1);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -148,65 +116,72 @@ class _FriendScreenState extends State<FriendScreen> {
|
|||||||
return Material(
|
return Material(
|
||||||
color: Theme.of(context).colorScheme.surface,
|
color: Theme.of(context).colorScheme.surface,
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
centerTitle: false,
|
||||||
|
title: Text('accountFriend'.tr),
|
||||||
|
bottom: TabBar(
|
||||||
|
controller: _tabController,
|
||||||
|
tabs: const [
|
||||||
|
Tab(icon: Icon(Icons.call_received)),
|
||||||
|
Tab(icon: Icon(Icons.people)),
|
||||||
|
Tab(icon: Icon(Icons.call_made)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
floatingActionButton: FloatingActionButton(
|
floatingActionButton: FloatingActionButton(
|
||||||
child: const Icon(Icons.add),
|
child: const Icon(Icons.add),
|
||||||
onPressed: () => promptAddFriend(),
|
onPressed: () => promptAddFriend(),
|
||||||
),
|
),
|
||||||
body: RefreshIndicator(
|
body: TabBarView(
|
||||||
onRefresh: () => getFriendship(),
|
controller: _tabController,
|
||||||
|
children: [
|
||||||
|
RefreshIndicator(
|
||||||
|
onRefresh: () => loadRelations(),
|
||||||
child: CustomScrollView(
|
child: CustomScrollView(
|
||||||
slivers: [
|
slivers: [
|
||||||
if (_isBusy)
|
if (_isBusy)
|
||||||
SliverToBoxAdapter(
|
SliverToBoxAdapter(
|
||||||
child: const LinearProgressIndicator().animate().scaleX(),
|
child: const LinearProgressIndicator().animate().scaleX(),
|
||||||
),
|
),
|
||||||
SliverToBoxAdapter(
|
SilverRelativeList(
|
||||||
child: ListTile(
|
items: filterByStatus(0),
|
||||||
tileColor: Theme.of(context).colorScheme.surfaceContainerLow,
|
onUpdate: () => loadRelations(),
|
||||||
contentPadding: const EdgeInsets.symmetric(horizontal: 20),
|
|
||||||
leading: const Icon(Icons.person_add),
|
|
||||||
trailing: const Icon(Icons.chevron_right),
|
|
||||||
title: Text(
|
|
||||||
'${'accountFriendPending'.tr} (${filterWithStatus(0).length})',
|
|
||||||
),
|
|
||||||
onTap: () =>
|
|
||||||
showScopedListPopup('accountFriendPending'.tr, 0),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SliverToBoxAdapter(
|
|
||||||
child: ListTile(
|
|
||||||
tileColor: Theme.of(context).colorScheme.surfaceContainerLow,
|
|
||||||
contentPadding: const EdgeInsets.symmetric(horizontal: 20),
|
|
||||||
leading: const Icon(Icons.block),
|
|
||||||
trailing: const Icon(Icons.chevron_right),
|
|
||||||
title: Text(
|
|
||||||
'${'accountFriendBlocked'.tr} (${filterWithStatus(2).length})',
|
|
||||||
),
|
|
||||||
onTap: () =>
|
|
||||||
showScopedListPopup('accountFriendBlocked'.tr, 2),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (_accountId != null)
|
|
||||||
SliverFriendList(
|
|
||||||
accountId: _accountId!,
|
|
||||||
items: filterWithStatus(1),
|
|
||||||
onUpdate: () {
|
|
||||||
getFriendship();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
const SliverToBoxAdapter(
|
|
||||||
child: Divider(thickness: 0.3, height: 0.3),
|
|
||||||
),
|
|
||||||
SliverToBoxAdapter(
|
|
||||||
child: Text(
|
|
||||||
'accountFriendListHint'.tr,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: Theme.of(context).textTheme.bodySmall,
|
|
||||||
).paddingOnly(top: 16, bottom: 32),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
RefreshIndicator(
|
||||||
|
onRefresh: () => loadRelations(),
|
||||||
|
child: CustomScrollView(
|
||||||
|
slivers: [
|
||||||
|
if (_isBusy)
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: const LinearProgressIndicator().animate().scaleX(),
|
||||||
|
),
|
||||||
|
SilverRelativeList(
|
||||||
|
items: filterByStatus(1),
|
||||||
|
onUpdate: () => loadRelations(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
RefreshIndicator(
|
||||||
|
onRefresh: () => loadRelations(),
|
||||||
|
child: CustomScrollView(
|
||||||
|
slivers: [
|
||||||
|
if (_isBusy)
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: const LinearProgressIndicator().animate().scaleX(),
|
||||||
|
),
|
||||||
|
SilverRelativeList(
|
||||||
|
items: filterByStatus(3),
|
||||||
|
onUpdate: () => loadRelations(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ import 'dart:math' as math;
|
|||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:solian/providers/content/call.dart';
|
import 'package:solian/providers/call.dart';
|
||||||
import 'package:solian/theme.dart';
|
import 'package:solian/theme.dart';
|
||||||
import 'package:solian/widgets/app_bar_leading.dart';
|
import 'package:solian/widgets/app_bar_leading.dart';
|
||||||
import 'package:solian/widgets/chat/call/call_controls.dart';
|
import 'package:solian/widgets/chat/call/call_controls.dart';
|
||||||
|
@ -11,7 +11,7 @@ import 'package:solian/models/channel.dart';
|
|||||||
import 'package:solian/models/event.dart';
|
import 'package:solian/models/event.dart';
|
||||||
import 'package:solian/models/packet.dart';
|
import 'package:solian/models/packet.dart';
|
||||||
import 'package:solian/providers/auth.dart';
|
import 'package:solian/providers/auth.dart';
|
||||||
import 'package:solian/providers/content/call.dart';
|
import 'package:solian/providers/call.dart';
|
||||||
import 'package:solian/providers/content/channel.dart';
|
import 'package:solian/providers/content/channel.dart';
|
||||||
import 'package:solian/providers/websocket.dart';
|
import 'package:solian/providers/websocket.dart';
|
||||||
import 'package:solian/router.dart';
|
import 'package:solian/router.dart';
|
||||||
|
@ -1,87 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:get/get.dart';
|
|
||||||
import 'package:solian/models/friendship.dart';
|
|
||||||
import 'package:solian/providers/friend.dart';
|
|
||||||
import 'package:solian/widgets/account/account_avatar.dart';
|
|
||||||
import 'package:solian/widgets/account/account_profile_popup.dart';
|
|
||||||
|
|
||||||
class SliverFriendList extends StatelessWidget {
|
|
||||||
final int accountId;
|
|
||||||
final List<Friendship> items;
|
|
||||||
final Function onUpdate;
|
|
||||||
|
|
||||||
const SliverFriendList({
|
|
||||||
super.key,
|
|
||||||
required this.accountId,
|
|
||||||
required this.items,
|
|
||||||
required this.onUpdate,
|
|
||||||
});
|
|
||||||
|
|
||||||
DismissDirection getDismissDirection(Friendship relation) {
|
|
||||||
if (relation.status == 2) return DismissDirection.endToStart;
|
|
||||||
if (relation.status == 1) return DismissDirection.startToEnd;
|
|
||||||
if (relation.status == 0 && relation.relatedId != accountId) {
|
|
||||||
return DismissDirection.startToEnd;
|
|
||||||
}
|
|
||||||
return DismissDirection.horizontal;
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget buildItem(context, index) {
|
|
||||||
final element = items[index];
|
|
||||||
final otherside = element.getOtherside(accountId);
|
|
||||||
|
|
||||||
final randomId = DateTime.now().microsecondsSinceEpoch >> 10;
|
|
||||||
|
|
||||||
return Dismissible(
|
|
||||||
key: Key(randomId.toString()),
|
|
||||||
background: Container(
|
|
||||||
color: Colors.red,
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
|
||||||
alignment: Alignment.centerLeft,
|
|
||||||
child: const Icon(Icons.close, color: Colors.white),
|
|
||||||
),
|
|
||||||
secondaryBackground: Container(
|
|
||||||
color: Colors.green,
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
|
||||||
alignment: Alignment.centerRight,
|
|
||||||
child: const Icon(Icons.check, color: Colors.white),
|
|
||||||
),
|
|
||||||
direction: getDismissDirection(element),
|
|
||||||
child: ListTile(
|
|
||||||
title: Text(otherside.nick),
|
|
||||||
subtitle: Text(otherside.name),
|
|
||||||
leading: GestureDetector(
|
|
||||||
child: AccountAvatar(content: otherside.avatar),
|
|
||||||
onTap: () {
|
|
||||||
showModalBottomSheet(
|
|
||||||
useRootNavigator: true,
|
|
||||||
isScrollControlled: true,
|
|
||||||
backgroundColor: Theme.of(context).colorScheme.surface,
|
|
||||||
context: context,
|
|
||||||
builder: (context) => AccountProfilePopup(
|
|
||||||
account: otherside,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
onDismissed: (direction) {
|
|
||||||
final FriendProvider provider = Get.find();
|
|
||||||
if (direction == DismissDirection.startToEnd) {
|
|
||||||
provider.updateFriendship(element, 2).then((_) => onUpdate());
|
|
||||||
}
|
|
||||||
if (direction == DismissDirection.endToStart) {
|
|
||||||
provider.updateFriendship(element, 1).then((_) => onUpdate());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return SliverList.builder(
|
|
||||||
itemCount: items.length,
|
|
||||||
itemBuilder: (context, idx) => buildItem(context, idx),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
83
lib/widgets/account/relative_list.dart
Normal file
83
lib/widgets/account/relative_list.dart
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:solian/models/relations.dart';
|
||||||
|
import 'package:solian/providers/relation.dart';
|
||||||
|
import 'package:solian/widgets/account/account_avatar.dart';
|
||||||
|
import 'package:solian/widgets/account/account_profile_popup.dart';
|
||||||
|
|
||||||
|
class SilverRelativeList extends StatelessWidget {
|
||||||
|
final List<Relationship> items;
|
||||||
|
final Function onUpdate;
|
||||||
|
final bool isHandleable;
|
||||||
|
|
||||||
|
const SilverRelativeList({
|
||||||
|
super.key,
|
||||||
|
required this.items,
|
||||||
|
required this.onUpdate,
|
||||||
|
this.isHandleable = true,
|
||||||
|
});
|
||||||
|
|
||||||
|
Widget buildItem(context, index) {
|
||||||
|
final element = items[index];
|
||||||
|
return ListTile(
|
||||||
|
title: Text(element.related.nick),
|
||||||
|
subtitle: Text(element.related.name),
|
||||||
|
leading: GestureDetector(
|
||||||
|
child: AccountAvatar(content: element.related.avatar),
|
||||||
|
onTap: () {
|
||||||
|
showModalBottomSheet(
|
||||||
|
useRootNavigator: true,
|
||||||
|
isScrollControlled: true,
|
||||||
|
backgroundColor: Theme
|
||||||
|
.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.surface,
|
||||||
|
context: context,
|
||||||
|
builder: (context) =>
|
||||||
|
AccountProfilePopup(
|
||||||
|
account: element.related,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
trailing: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
if(element.status != 1 && element.status != 3)
|
||||||
|
IconButton(
|
||||||
|
icon: const Icon(Icons.check),
|
||||||
|
onPressed: () {
|
||||||
|
final RelationshipProvider provider = Get.find();
|
||||||
|
if (element.status == 0) {
|
||||||
|
provider.handleRelation(element, true).then((_) => onUpdate());
|
||||||
|
} else {
|
||||||
|
provider.editRelation(element, 1).then((_) => onUpdate());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
if(element.status != 2 && element.status != 3)
|
||||||
|
IconButton(
|
||||||
|
icon: const Icon(Icons.close),
|
||||||
|
onPressed: () {
|
||||||
|
final RelationshipProvider provider = Get.find();
|
||||||
|
if (element.status == 0) {
|
||||||
|
provider.handleRelation(element, false).then((_) => onUpdate());
|
||||||
|
} else {
|
||||||
|
provider.editRelation(element, 2).then((_) => onUpdate());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
contentPadding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return SliverList.builder(
|
||||||
|
itemCount: items.length,
|
||||||
|
itemBuilder: (context, idx) => buildItem(context, idx),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -1,39 +1,39 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:solian/models/account.dart';
|
import 'package:solian/models/account.dart';
|
||||||
import 'package:solian/models/friendship.dart';
|
import 'package:solian/models/relations.dart';
|
||||||
import 'package:solian/providers/auth.dart';
|
import 'package:solian/providers/auth.dart';
|
||||||
import 'package:solian/providers/friend.dart';
|
import 'package:solian/providers/relation.dart';
|
||||||
import 'package:solian/widgets/account/account_avatar.dart';
|
import 'package:solian/widgets/account/account_avatar.dart';
|
||||||
|
|
||||||
class FriendSelect extends StatefulWidget {
|
class RelativeSelector extends StatefulWidget {
|
||||||
final String title;
|
final String title;
|
||||||
final Widget? Function(Account item)? trailingBuilder;
|
final Widget? Function(Account item)? trailingBuilder;
|
||||||
|
|
||||||
const FriendSelect({super.key, required this.title, this.trailingBuilder});
|
const RelativeSelector({super.key, required this.title, this.trailingBuilder});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<FriendSelect> createState() => _FriendSelectState();
|
State<RelativeSelector> createState() => _RelativeSelectorState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _FriendSelectState extends State<FriendSelect> {
|
class _RelativeSelectorState extends State<RelativeSelector> {
|
||||||
int _accountId = 0;
|
int _accountId = 0;
|
||||||
|
|
||||||
final List<Friendship> _friends = List.empty(growable: true);
|
final List<Relationship> _friends = List.empty(growable: true);
|
||||||
|
|
||||||
getFriends() async {
|
getFriends() async {
|
||||||
final AuthProvider auth = Get.find();
|
final AuthProvider auth = Get.find();
|
||||||
final prof = await auth.getProfile();
|
final prof = await auth.getProfile();
|
||||||
_accountId = prof.body['id'];
|
_accountId = prof.body['id'];
|
||||||
|
|
||||||
final FriendProvider provider = Get.find();
|
final RelationshipProvider provider = Get.find();
|
||||||
final resp = await provider.listFriendshipWithStatus(1);
|
final resp = await provider.listRelationWithStatus(1);
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
_friends.addAll(resp.body
|
_friends.addAll(resp.body
|
||||||
.map((e) => Friendship.fromJson(e))
|
.map((e) => Relationship.fromJson(e))
|
||||||
.toList()
|
.toList()
|
||||||
.cast<Friendship>());
|
.cast<Relationship>());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -7,7 +7,7 @@ import 'package:solian/providers/auth.dart';
|
|||||||
import 'package:solian/services.dart';
|
import 'package:solian/services.dart';
|
||||||
import 'package:solian/widgets/account/account_avatar.dart';
|
import 'package:solian/widgets/account/account_avatar.dart';
|
||||||
import 'package:solian/widgets/account/account_profile_popup.dart';
|
import 'package:solian/widgets/account/account_profile_popup.dart';
|
||||||
import 'package:solian/widgets/account/friend_select.dart';
|
import 'package:solian/widgets/account/relative_select.dart';
|
||||||
|
|
||||||
class ChannelMemberListPopup extends StatefulWidget {
|
class ChannelMemberListPopup extends StatefulWidget {
|
||||||
final Channel channel;
|
final Channel channel;
|
||||||
@ -62,7 +62,7 @@ class _ChannelMemberListPopupState extends State<ChannelMemberListPopup> {
|
|||||||
final input = await showModalBottomSheet(
|
final input = await showModalBottomSheet(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
return FriendSelect(title: 'channelMembersAdd'.tr);
|
return RelativeSelector(title: 'channelMembersAdd'.tr);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
if (input == null) return;
|
if (input == null) return;
|
||||||
|
@ -6,7 +6,7 @@ import 'package:flutter_webrtc/flutter_webrtc.dart';
|
|||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:livekit_client/livekit_client.dart';
|
import 'package:livekit_client/livekit_client.dart';
|
||||||
import 'package:solian/exts.dart';
|
import 'package:solian/exts.dart';
|
||||||
import 'package:solian/providers/content/call.dart';
|
import 'package:solian/providers/call.dart';
|
||||||
|
|
||||||
class ControlsWidget extends StatefulWidget {
|
class ControlsWidget extends StatefulWidget {
|
||||||
final Room room;
|
final Room room;
|
||||||
|
@ -6,7 +6,7 @@ import 'package:solian/exts.dart';
|
|||||||
import 'package:solian/models/call.dart';
|
import 'package:solian/models/call.dart';
|
||||||
import 'package:solian/models/channel.dart';
|
import 'package:solian/models/channel.dart';
|
||||||
import 'package:solian/providers/auth.dart';
|
import 'package:solian/providers/auth.dart';
|
||||||
import 'package:solian/providers/content/call.dart';
|
import 'package:solian/providers/call.dart';
|
||||||
|
|
||||||
class ChatCallPrejoinPopup extends StatefulWidget {
|
class ChatCallPrejoinPopup extends StatefulWidget {
|
||||||
final Call ongoingCall;
|
final Call ongoingCall;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:solian/providers/content/call.dart';
|
import 'package:solian/providers/call.dart';
|
||||||
|
|
||||||
class ChatCallCurrentIndicator extends StatelessWidget {
|
class ChatCallCurrentIndicator extends StatelessWidget {
|
||||||
const ChatCallCurrentIndicator({super.key});
|
const ChatCallCurrentIndicator({super.key});
|
||||||
|
@ -7,7 +7,7 @@ import 'package:solian/providers/auth.dart';
|
|||||||
import 'package:solian/services.dart';
|
import 'package:solian/services.dart';
|
||||||
import 'package:solian/widgets/account/account_avatar.dart';
|
import 'package:solian/widgets/account/account_avatar.dart';
|
||||||
import 'package:solian/widgets/account/account_profile_popup.dart';
|
import 'package:solian/widgets/account/account_profile_popup.dart';
|
||||||
import 'package:solian/widgets/account/friend_select.dart';
|
import 'package:solian/widgets/account/relative_select.dart';
|
||||||
|
|
||||||
class RealmMemberListPopup extends StatefulWidget {
|
class RealmMemberListPopup extends StatefulWidget {
|
||||||
final Realm realm;
|
final Realm realm;
|
||||||
@ -59,7 +59,7 @@ class _RealmMemberListPopupState extends State<RealmMemberListPopup> {
|
|||||||
final input = await showModalBottomSheet(
|
final input = await showModalBottomSheet(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
return FriendSelect(title: 'channelMembersAdd'.tr);
|
return RelativeSelector(title: 'channelMembersAdd'.tr);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
if (input == null) return;
|
if (input == null) return;
|
||||||
|
Loading…
Reference in New Issue
Block a user