✨ Social credit points & quick send friend request
This commit is contained in:
parent
4552dfd3f3
commit
33d69908a6
@ -112,6 +112,7 @@ class SolianApp extends StatelessWidget {
|
|||||||
|
|
||||||
Get.find<WebSocketProvider>().connect();
|
Get.find<WebSocketProvider>().connect();
|
||||||
Get.find<ChannelProvider>().refreshAvailableChannel();
|
Get.find<ChannelProvider>().refreshAvailableChannel();
|
||||||
|
Get.find<RelationshipProvider>().refreshFriendList();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Get.find<WebSocketProvider>().registerPushNotifications();
|
Get.find<WebSocketProvider>().registerPushNotifications();
|
||||||
|
@ -208,7 +208,6 @@ class AuthProvider extends GetConnect {
|
|||||||
|
|
||||||
Future<void> refreshUserProfile() async {
|
Future<void> refreshUserProfile() async {
|
||||||
final client = configureClient('auth');
|
final client = configureClient('auth');
|
||||||
|
|
||||||
final resp = await client.get('/users/me');
|
final resp = await client.get('/users/me');
|
||||||
if (resp.statusCode != 200) {
|
if (resp.statusCode != 200) {
|
||||||
throw Exception(resp.bodyString);
|
throw Exception(resp.bodyString);
|
||||||
|
@ -1,24 +1,42 @@
|
|||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:solian/models/account.dart';
|
||||||
import 'package:solian/models/relations.dart';
|
import 'package:solian/models/relations.dart';
|
||||||
import 'package:solian/providers/auth.dart';
|
import 'package:solian/providers/auth.dart';
|
||||||
import 'package:solian/services.dart';
|
|
||||||
|
|
||||||
class RelationshipProvider extends GetConnect {
|
class RelationshipProvider extends GetxController {
|
||||||
@override
|
final RxList<Relationship> _friends = RxList.empty(growable: true);
|
||||||
void onInit() {
|
|
||||||
final AuthProvider auth = Get.find();
|
|
||||||
|
|
||||||
httpClient.baseUrl = ServiceFinder.buildUrl('auth', null);
|
Future<void> refreshFriendList() async {
|
||||||
httpClient.addAuthenticator(auth.requestAuthenticator);
|
final resp = await listRelationWithStatus(1);
|
||||||
|
_friends.value = resp.body
|
||||||
|
.map((e) => Relationship.fromJson(e))
|
||||||
|
.toList()
|
||||||
|
.cast<Relationship>();
|
||||||
|
_friends.refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Response> listRelation() => get('/users/me/relations');
|
bool hasFriend(Account account) {
|
||||||
|
final auth = Get.find<AuthProvider>();
|
||||||
|
if (auth.userProfile.value!['id'] == account.id) return true;
|
||||||
|
return _friends.any((x) => x.id == account.id);
|
||||||
|
}
|
||||||
|
|
||||||
Future<Response> listRelationWithStatus(int status) =>
|
Future<Response> listRelation() {
|
||||||
get('/users/me/relations?status=$status');
|
final AuthProvider auth = Get.find();
|
||||||
|
final client = auth.configureClient('auth');
|
||||||
|
return client.get('/users/me/relations');
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Response> listRelationWithStatus(int status) {
|
||||||
|
final AuthProvider auth = Get.find();
|
||||||
|
final client = auth.configureClient('auth');
|
||||||
|
return client.get('/users/me/relations?status=$status');
|
||||||
|
}
|
||||||
|
|
||||||
Future<Response> makeFriend(String username) async {
|
Future<Response> makeFriend(String username) async {
|
||||||
final resp = await post('/users/me/relations?related=$username', {});
|
final AuthProvider auth = Get.find();
|
||||||
|
final client = auth.configureClient('auth');
|
||||||
|
final resp = await client.post('/users/me/relations?related=$username', {});
|
||||||
if (resp.statusCode != 200) {
|
if (resp.statusCode != 200) {
|
||||||
throw Exception(resp.bodyString);
|
throw Exception(resp.bodyString);
|
||||||
}
|
}
|
||||||
@ -44,10 +62,10 @@ class RelationshipProvider extends GetConnect {
|
|||||||
Future<Response> editRelation(Relationship relationship, int status) async {
|
Future<Response> editRelation(Relationship relationship, int status) async {
|
||||||
final AuthProvider auth = Get.find();
|
final AuthProvider auth = Get.find();
|
||||||
final client = auth.configureClient('auth');
|
final client = auth.configureClient('auth');
|
||||||
final resp =
|
final resp = await client.patch(
|
||||||
await client.patch('/users/me/relations/${relationship.relatedId}', {
|
'/users/me/relations/${relationship.relatedId}',
|
||||||
'status': status,
|
{'status': status},
|
||||||
});
|
);
|
||||||
if (resp.statusCode != 200) {
|
if (resp.statusCode != 200) {
|
||||||
throw Exception(resp.bodyString);
|
throw Exception(resp.bodyString);
|
||||||
}
|
}
|
||||||
|
@ -7,13 +7,12 @@ import 'package:solian/models/account.dart';
|
|||||||
import 'package:solian/models/attachment.dart';
|
import 'package:solian/models/attachment.dart';
|
||||||
import 'package:solian/models/pagination.dart';
|
import 'package:solian/models/pagination.dart';
|
||||||
import 'package:solian/models/post.dart';
|
import 'package:solian/models/post.dart';
|
||||||
import 'package:solian/screens/account/notification.dart';
|
import 'package:solian/providers/relation.dart';
|
||||||
import 'package:solian/services.dart';
|
import 'package:solian/services.dart';
|
||||||
import 'package:solian/theme.dart';
|
import 'package:solian/theme.dart';
|
||||||
import 'package:solian/widgets/account/account_avatar.dart';
|
import 'package:solian/widgets/account/account_avatar.dart';
|
||||||
import 'package:solian/widgets/app_bar_leading.dart';
|
import 'package:solian/widgets/app_bar_leading.dart';
|
||||||
import 'package:solian/widgets/attachments/attachment_list.dart';
|
import 'package:solian/widgets/attachments/attachment_list.dart';
|
||||||
import 'package:solian/widgets/current_state_action.dart';
|
|
||||||
import 'package:solian/widgets/feed/feed_list.dart';
|
import 'package:solian/widgets/feed/feed_list.dart';
|
||||||
import 'package:solian/widgets/posts/post_list.dart';
|
import 'package:solian/widgets/posts/post_list.dart';
|
||||||
import 'package:solian/widgets/sized_container.dart';
|
import 'package:solian/widgets/sized_container.dart';
|
||||||
@ -28,11 +27,13 @@ class AccountProfilePage extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _AccountProfilePageState extends State<AccountProfilePage> {
|
class _AccountProfilePageState extends State<AccountProfilePage> {
|
||||||
|
late final RelationshipProvider _relationshipProvider;
|
||||||
late final PostListController _postController;
|
late final PostListController _postController;
|
||||||
final PagingController<int, Attachment> _albumPagingController =
|
final PagingController<int, Attachment> _albumPagingController =
|
||||||
PagingController(firstPageKey: 0);
|
PagingController(firstPageKey: 0);
|
||||||
|
|
||||||
bool _isBusy = true;
|
bool _isBusy = true;
|
||||||
|
bool _isMakingFriend = false;
|
||||||
bool _showMature = false;
|
bool _showMature = false;
|
||||||
|
|
||||||
Account? _userinfo;
|
Account? _userinfo;
|
||||||
@ -63,22 +64,35 @@ class _AccountProfilePageState extends State<AccountProfilePage> {
|
|||||||
_totalDownvote = resp.body['total_downvote'];
|
_totalDownvote = resp.body['total_downvote'];
|
||||||
}
|
}
|
||||||
|
|
||||||
resp = await client.get('/users/${widget.name}/pin');
|
setState(() => _isBusy = false);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> getPinnedPosts() async {
|
||||||
|
final client = ServiceFinder.configureClient('interactive');
|
||||||
|
final resp = await client.get('/users/${widget.name}/pin');
|
||||||
if (resp.statusCode != 200) {
|
if (resp.statusCode != 200) {
|
||||||
context.showErrorDialog(resp.bodyString).then((_) {
|
context.showErrorDialog(resp.bodyString).then((_) {
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
_pinnedPosts =
|
setState(() {
|
||||||
resp.body.map((x) => Post.fromJson(x)).toList().cast<Post>();
|
_pinnedPosts =
|
||||||
|
resp.body.map((x) => Post.fromJson(x)).toList().cast<Post>();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setState(() => _isBusy = false);
|
int get _userSocialCreditPoints {
|
||||||
|
int birthPart =
|
||||||
|
DateTime.now().difference(_userinfo!.createdAt.toLocal()).inSeconds;
|
||||||
|
birthPart = birthPart >> 16;
|
||||||
|
return _totalUpvote * 2 - _totalDownvote + birthPart;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
_relationshipProvider = Get.find();
|
||||||
_postController = PostListController(author: widget.name);
|
_postController = PostListController(author: widget.name);
|
||||||
_albumPagingController.addPageRequestListener((pageKey) async {
|
_albumPagingController.addPageRequestListener((pageKey) async {
|
||||||
final client = ServiceFinder.configureClient('files');
|
final client = ServiceFinder.configureClient('files');
|
||||||
@ -99,7 +113,26 @@ class _AccountProfilePageState extends State<AccountProfilePage> {
|
|||||||
_albumPagingController.error = resp.bodyString;
|
_albumPagingController.error = resp.bodyString;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
getUserinfo();
|
getUserinfo();
|
||||||
|
getPinnedPosts();
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildStatisticsEntry(String label, String content) {
|
||||||
|
return Expanded(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
label,
|
||||||
|
style: Theme.of(context).textTheme.bodySmall,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
content,
|
||||||
|
style: Theme.of(context).textTheme.bodyLarge,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -147,8 +180,29 @@ class _AccountProfilePageState extends State<AccountProfilePage> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const BackgroundStateWidget(),
|
if (_userinfo != null &&
|
||||||
const NotificationButton(),
|
!_relationshipProvider.hasFriend(_userinfo!))
|
||||||
|
IconButton(
|
||||||
|
icon: const Icon(Icons.person_add),
|
||||||
|
onPressed: _isMakingFriend
|
||||||
|
? null
|
||||||
|
: () async {
|
||||||
|
setState(() => _isMakingFriend = true);
|
||||||
|
try {
|
||||||
|
await _relationshipProvider.makeFriend(widget.name);
|
||||||
|
context.showSnackbar('accountFriendRequestSent'.tr);
|
||||||
|
} catch (e) {
|
||||||
|
context.showErrorDialog(e);
|
||||||
|
} finally {
|
||||||
|
setState(() => _isMakingFriend = false);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
else
|
||||||
|
const IconButton(
|
||||||
|
icon: Icon(Icons.handshake),
|
||||||
|
onPressed: null,
|
||||||
|
),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: SolianTheme.isLargeScreen(context) ? 8 : 16,
|
width: SolianTheme.isLargeScreen(context) ? 8 : 16,
|
||||||
),
|
),
|
||||||
@ -167,33 +221,42 @@ class _AccountProfilePageState extends State<AccountProfilePage> {
|
|||||||
physics: const NeverScrollableScrollPhysics(),
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
children: [
|
children: [
|
||||||
RefreshIndicator(
|
RefreshIndicator(
|
||||||
onRefresh: () => _postController.reloadAllOver(),
|
onRefresh: () => Future.wait([
|
||||||
|
_postController.reloadAllOver(),
|
||||||
|
getPinnedPosts(),
|
||||||
|
]),
|
||||||
child: CustomScrollView(slivers: [
|
child: CustomScrollView(slivers: [
|
||||||
SliverToBoxAdapter(
|
SliverToBoxAdapter(
|
||||||
child: Row(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
|
||||||
children: [
|
children: [
|
||||||
Column(
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
_buildStatisticsEntry(
|
||||||
'totalUpvote'.tr,
|
'totalSocialCreditPoints'.tr,
|
||||||
style: Theme.of(context).textTheme.bodySmall,
|
_userinfo != null
|
||||||
),
|
? _userSocialCreditPoints.toString()
|
||||||
Text(
|
: 0.toString(),
|
||||||
_totalUpvote.toString(),
|
|
||||||
style: Theme.of(context).textTheme.bodyLarge,
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Column(
|
const SizedBox(height: 16),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Obx(
|
||||||
'totalDownvote'.tr,
|
() => _buildStatisticsEntry(
|
||||||
style: Theme.of(context).textTheme.bodySmall,
|
'totalPostCount'.tr,
|
||||||
|
_postController.postTotal.value.toString(),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
Text(
|
_buildStatisticsEntry(
|
||||||
|
'totalUpvote'.tr,
|
||||||
|
_totalUpvote.toString(),
|
||||||
|
),
|
||||||
|
_buildStatisticsEntry(
|
||||||
|
'totalDownvote'.tr,
|
||||||
_totalDownvote.toString(),
|
_totalDownvote.toString(),
|
||||||
style: Theme.of(context).textTheme.bodyLarge,
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -62,8 +62,10 @@ class _SignInPopupState extends State<SignInPopup> with ProtocolListener {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
await auth.signin(context, username, password);
|
await auth.signin(context, username, password);
|
||||||
await auth.refreshAuthorizeStatus();
|
await Future.delayed(const Duration(milliseconds: 250), () async {
|
||||||
await auth.refreshUserProfile();
|
await auth.refreshAuthorizeStatus();
|
||||||
|
await auth.refreshUserProfile();
|
||||||
|
});
|
||||||
} on RiskyAuthenticateException catch (e) {
|
} on RiskyAuthenticateException catch (e) {
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
@ -77,7 +79,8 @@ class _SignInPopupState extends State<SignInPopup> with ProtocolListener {
|
|||||||
onPressed: () {
|
onPressed: () {
|
||||||
const redirect = 'solink://auth?status=done';
|
const redirect = 'solink://auth?status=done';
|
||||||
launchUrlString(
|
launchUrlString(
|
||||||
ServiceFinder.buildUrl('passport', '/mfa?redirect_uri=$redirect&ticketId=${e.ticketId}'),
|
ServiceFinder.buildUrl('passport',
|
||||||
|
'/mfa?redirect_uri=$redirect&ticketId=${e.ticketId}'),
|
||||||
mode: LaunchMode.inAppWebView,
|
mode: LaunchMode.inAppWebView,
|
||||||
);
|
);
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
|
@ -53,6 +53,7 @@ const messagesEnglish = {
|
|||||||
'accountFriendPending': 'Friend requests',
|
'accountFriendPending': 'Friend requests',
|
||||||
'accountFriendBlocked': 'Friend blocklist',
|
'accountFriendBlocked': 'Friend blocklist',
|
||||||
'accountFriendListHint': 'Swipe left to decline, right to approve',
|
'accountFriendListHint': 'Swipe left to decline, right to approve',
|
||||||
|
'accountFriendRequestSent': 'Friend request sent, waiting for processing...',
|
||||||
'accountSuspended': 'Account was suspended',
|
'accountSuspended': 'Account was suspended',
|
||||||
'accountSuspendedAt': 'Account was suspended since @date',
|
'accountSuspendedAt': 'Account was suspended since @date',
|
||||||
'aspectRatio': 'Aspect Ratio',
|
'aspectRatio': 'Aspect Ratio',
|
||||||
@ -86,6 +87,8 @@ const messagesEnglish = {
|
|||||||
'notifyAllRead': 'Mark all as read',
|
'notifyAllRead': 'Mark all as read',
|
||||||
'notifyEmpty': 'All notifications read',
|
'notifyEmpty': 'All notifications read',
|
||||||
'notifyEmptyCaption': 'It seems like nothing happened recently',
|
'notifyEmptyCaption': 'It seems like nothing happened recently',
|
||||||
|
'totalSocialCreditPoints': 'Social Credit Points',
|
||||||
|
'totalPostCount': 'Posts',
|
||||||
'totalUpvote': 'Upvote',
|
'totalUpvote': 'Upvote',
|
||||||
'totalDownvote': 'Downvote',
|
'totalDownvote': 'Downvote',
|
||||||
'pinPost': 'Pin this post',
|
'pinPost': 'Pin this post',
|
||||||
|
@ -52,6 +52,7 @@ const simplifiedChineseMessages = {
|
|||||||
'accountFriendPending': '好友请求',
|
'accountFriendPending': '好友请求',
|
||||||
'accountFriendBlocked': '好友黑名单',
|
'accountFriendBlocked': '好友黑名单',
|
||||||
'accountFriendListHint': '左滑来拒绝,右滑来接受',
|
'accountFriendListHint': '左滑来拒绝,右滑来接受',
|
||||||
|
'accountFriendRequestSent': '好友请求已发送,等待处理对方中……',
|
||||||
'accountSuspended': '帐号被停用',
|
'accountSuspended': '帐号被停用',
|
||||||
'accountSuspendedAt': '该帐号自 @date 起被停用',
|
'accountSuspendedAt': '该帐号自 @date 起被停用',
|
||||||
'aspectRatio': '纵横比',
|
'aspectRatio': '纵横比',
|
||||||
@ -80,6 +81,8 @@ const simplifiedChineseMessages = {
|
|||||||
'notifyAllRead': '已读所有通知',
|
'notifyAllRead': '已读所有通知',
|
||||||
'notifyEmpty': '通知箱为空',
|
'notifyEmpty': '通知箱为空',
|
||||||
'notifyEmptyCaption': '看起来最近没发生什么呢',
|
'notifyEmptyCaption': '看起来最近没发生什么呢',
|
||||||
|
'totalSocialCreditPoints': '社会信用点 async',
|
||||||
|
'totalPostCount': '总帖数',
|
||||||
'totalUpvote': '获顶数',
|
'totalUpvote': '获顶数',
|
||||||
'totalDownvote': '获踩数',
|
'totalDownvote': '获踩数',
|
||||||
'pinPost': '置顶本帖',
|
'pinPost': '置顶本帖',
|
||||||
|
Loading…
Reference in New Issue
Block a user