Compare commits

..

No commits in common. "4616f3a3e2219d267c94163cea86c3fb25868961" and "0ad4854443664f7e2edc190343bf00f52ef0e5f6" have entirely different histories.

9 changed files with 75 additions and 144 deletions

View File

@ -85,7 +85,7 @@ class _BootstrapperShellState extends State<BootstrapperShell> {
await Future.wait([ await Future.wait([
Get.find<RealmProvider>().refreshAvailableRealms(), Get.find<RealmProvider>().refreshAvailableRealms(),
Get.find<ChannelProvider>().refreshAvailableChannel(), Get.find<ChannelProvider>().refreshAvailableChannel(),
Get.find<RelationshipProvider>().refreshRelativeList(), Get.find<RelationshipProvider>().refreshFriendList(),
]); ]);
} }
}, },

View File

@ -2,6 +2,7 @@ import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:get/get_rx/get_rx.dart';
import 'package:livekit_client/livekit_client.dart'; import 'package:livekit_client/livekit_client.dart';
import 'package:permission_handler/permission_handler.dart'; import 'package:permission_handler/permission_handler.dart';
import 'package:solian/models/call.dart'; import 'package:solian/models/call.dart';

View File

@ -4,7 +4,6 @@ import 'dart:typed_data';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:path/path.dart'; import 'package:path/path.dart';
import 'package:solian/models/attachment.dart'; import 'package:solian/models/attachment.dart';
import 'package:solian/models/pagination.dart';
import 'package:solian/providers/auth.dart'; import 'package:solian/providers/auth.dart';
import 'package:solian/services.dart'; import 'package:solian/services.dart';
import 'package:dio/dio.dart' as dio; import 'package:dio/dio.dart' as dio;
@ -22,48 +21,6 @@ class AttachmentProvider extends GetConnect {
final Map<int, Attachment> _cachedResponses = {}; final Map<int, Attachment> _cachedResponses = {};
Future<List<Attachment?>> listMetadata(
List<int> id, {
noCache = false,
}) async {
List<Attachment?> result = List.filled(id.length, null);
List<int> pendingQuery = List.empty(growable: true);
if (!noCache) {
for (var idx = 0; idx < id.length; idx++) {
if (_cachedResponses.containsKey(id[idx])) {
result[idx] = _cachedResponses[id[idx]];
} else {
pendingQuery.add(id[idx]);
}
}
}
final resp = await get(
'/attachments?take=${pendingQuery.length}&id=${pendingQuery.join(',')}',
);
if (resp.statusCode != 200) return result;
final rawOut = PaginationResult.fromJson(resp.body);
if (rawOut.data == null) return result;
final List<Attachment> out =
rawOut.data!.map((x) => Attachment.fromJson(x)).toList();
for (final item in out) {
if (item.destination != 0 && item.isAnalyzed) {
_cachedResponses[item.id] = item;
}
}
for (var i = 0; i < out.length; i++) {
for (var j = 0; j < id.length; j++) {
if (out[i].id == id[j]) {
result[j] = out[i];
}
}
}
return result;
}
Future<Attachment?> getMetadata(int id, {noCache = false}) async { Future<Attachment?> getMetadata(int id, {noCache = false}) async {
if (!noCache && _cachedResponses.containsKey(id)) { if (!noCache && _cachedResponses.containsKey(id)) {
return _cachedResponses[id]!; return _cachedResponses[id]!;

View File

@ -4,19 +4,15 @@ import 'package:solian/models/relations.dart';
import 'package:solian/providers/auth.dart'; import 'package:solian/providers/auth.dart';
class RelationshipProvider extends GetxController { class RelationshipProvider extends GetxController {
final RxInt friendRequestCount = 0.obs;
final RxList<Relationship> _friends = RxList.empty(growable: true); final RxList<Relationship> _friends = RxList.empty(growable: true);
Future<void> refreshRelativeList() async { Future<void> refreshFriendList() async {
final resp = await listRelation(); final resp = await listRelationWithStatus(1);
final List<Relationship> result = resp.body _friends.value = resp.body
.map((e) => Relationship.fromJson(e)) .map((e) => Relationship.fromJson(e))
.toList() .toList()
.cast<Relationship>(); .cast<Relationship>();
_friends.value = result.where((x) => x.status == 1).toList();
_friends.refresh(); _friends.refresh();
friendRequestCount.value = result.where((x) => x.status == 0).length;
} }
bool hasFriend(Account account) { bool hasFriend(Account account) {

View File

@ -3,13 +3,11 @@ import 'package:get/get.dart';
import 'package:solian/models/account.dart'; import 'package:solian/models/account.dart';
import 'package:solian/providers/auth.dart'; import 'package:solian/providers/auth.dart';
import 'package:solian/providers/account_status.dart'; import 'package:solian/providers/account_status.dart';
import 'package:solian/providers/relation.dart';
import 'package:solian/router.dart'; import 'package:solian/router.dart';
import 'package:solian/screens/auth/signin.dart'; import 'package:solian/screens/auth/signin.dart';
import 'package:solian/screens/auth/signup.dart'; import 'package:solian/screens/auth/signup.dart';
import 'package:solian/widgets/account/account_heading.dart'; import 'package:solian/widgets/account/account_heading.dart';
import 'package:solian/widgets/sized_container.dart'; import 'package:solian/widgets/sized_container.dart';
import 'package:badges/badges.dart' as badges;
class AccountScreen extends StatefulWidget { class AccountScreen extends StatefulWidget {
const AccountScreen({super.key}); const AccountScreen({super.key});
@ -25,27 +23,9 @@ class _AccountScreenState extends State<AccountScreen> {
( (
const Icon(Icons.color_lens), const Icon(Icons.color_lens),
'accountPersonalize'.tr, 'accountPersonalize'.tr,
'accountPersonalize', 'accountPersonalize'
),
(
Obx(() {
final RelationshipProvider relations = Get.find();
return badges.Badge(
badgeContent: Text(
relations.friendRequestCount.value.toString(),
style: const TextStyle(color: Colors.white),
),
showBadge: relations.friendRequestCount.value > 0,
position: badges.BadgePosition.topEnd(
top: -12,
end: -8,
),
child: const Icon(Icons.diversity_1),
);
}),
'accountFriend'.tr,
'accountFriend',
), ),
(const Icon(Icons.diversity_1), 'accountFriend'.tr, 'accountFriend'),
]; ];
final AuthProvider auth = Get.find(); final AuthProvider auth = Get.find();

View File

@ -1,9 +1,9 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.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/relations.dart'; import 'package:solian/models/relations.dart';
import 'package:solian/providers/relation.dart'; import 'package:solian/providers/relation.dart';
import 'package:solian/theme.dart';
import 'package:solian/widgets/account/relative_list.dart'; import 'package:solian/widgets/account/relative_list.dart';
class FriendScreen extends StatefulWidget { class FriendScreen extends StatefulWidget {
@ -21,15 +21,15 @@ class _FriendScreenState extends State<FriendScreen>
List<Relationship> _relations = List.empty(); List<Relationship> _relations = List.empty();
List<Relationship> _filterByStatus(int status) { List<Relationship> filterByStatus(int status) {
return _relations.where((x) => x.status == status).toList(); return _relations.where((x) => x.status == status).toList();
} }
Future<void> _loadRelations() async { Future<void> loadRelations() async {
setState(() => _isBusy = true); setState(() => _isBusy = true);
final RelationshipProvider relations = Get.find(); final RelationshipProvider provider = Get.find();
final resp = await relations.listRelation(); final resp = await provider.listRelation();
setState(() { setState(() {
_relations = resp.body _relations = resp.body
@ -38,9 +38,6 @@ class _FriendScreenState extends State<FriendScreen>
.cast<Relationship>(); .cast<Relationship>();
_isBusy = false; _isBusy = false;
}); });
relations.friendRequestCount.value =
_relations.where((x) => x.status == 0).length;
} }
void promptAddFriend() async { void promptAddFriend() async {
@ -107,8 +104,8 @@ class _FriendScreenState extends State<FriendScreen>
super.initState(); super.initState();
_tabController = TabController(length: 3, vsync: this); _tabController = TabController(length: 3, vsync: this);
_loadRelations().then((_) { loadRelations().then((_) {
if (_filterByStatus(0).isEmpty) { if (filterByStatus(0).isEmpty) {
_tabController.animateTo(1); _tabController.animateTo(1);
} }
}); });
@ -122,19 +119,6 @@ class _FriendScreenState extends State<FriendScreen>
appBar: AppBar( appBar: AppBar(
centerTitle: false, centerTitle: false,
title: Text('accountFriend'.tr), title: Text('accountFriend'.tr),
actions: [
if (_isBusy)
SizedBox(
height: 48,
width: 48,
child: const CircularProgressIndicator(
strokeWidth: 3,
).paddingAll(14),
),
SizedBox(
width: SolianTheme.isLargeScreen(context) ? 8 : 16,
),
],
bottom: TabBar( bottom: TabBar(
controller: _tabController, controller: _tabController,
tabs: const [ tabs: const [
@ -152,34 +136,46 @@ class _FriendScreenState extends State<FriendScreen>
controller: _tabController, controller: _tabController,
children: [ children: [
RefreshIndicator( RefreshIndicator(
onRefresh: () => _loadRelations(), onRefresh: () => loadRelations(),
child: CustomScrollView( child: CustomScrollView(
slivers: [ slivers: [
if (_isBusy)
SliverToBoxAdapter(
child: const LinearProgressIndicator().animate().scaleX(),
),
SilverRelativeList( SilverRelativeList(
items: _filterByStatus(0), items: filterByStatus(0),
onUpdate: () => _loadRelations(), onUpdate: () => loadRelations(),
), ),
], ],
), ),
), ),
RefreshIndicator( RefreshIndicator(
onRefresh: () => _loadRelations(), onRefresh: () => loadRelations(),
child: CustomScrollView( child: CustomScrollView(
slivers: [ slivers: [
if (_isBusy)
SliverToBoxAdapter(
child: const LinearProgressIndicator().animate().scaleX(),
),
SilverRelativeList( SilverRelativeList(
items: _filterByStatus(1), items: filterByStatus(1),
onUpdate: () => _loadRelations(), onUpdate: () => loadRelations(),
), ),
], ],
), ),
), ),
RefreshIndicator( RefreshIndicator(
onRefresh: () => _loadRelations(), onRefresh: () => loadRelations(),
child: CustomScrollView( child: CustomScrollView(
slivers: [ slivers: [
if (_isBusy)
SliverToBoxAdapter(
child: const LinearProgressIndicator().animate().scaleX(),
),
SilverRelativeList( SilverRelativeList(
items: _filterByStatus(3), items: filterByStatus(3),
onUpdate: () => _loadRelations(), onUpdate: () => loadRelations(),
), ),
], ],
), ),

View File

@ -222,13 +222,19 @@ class _AttachmentEditorPopupState extends State<AttachmentEditorPopup> {
setState(() => _isBusy = true); setState(() => _isBusy = true);
attach.listMetadata(widget.initialAttachments).then((result) { int progress = 0;
setState(() { for (var idx = 0; idx < widget.initialAttachments.length; idx++) {
_attachments = result; attach.getMetadata(widget.initialAttachments[idx]).then((resp) {
_isBusy = false; progress++;
_isFirstTimeBusy = false; _attachments[idx] = resp;
if (progress == widget.initialAttachments.length) {
setState(() {
_isBusy = false;
_isFirstTimeBusy = false;
});
}
}); });
}); }
} }
void _showAttachmentPreview(Attachment element) { void _showAttachmentPreview(Attachment element) {

View File

@ -45,7 +45,7 @@ class _AttachmentListState extends State<AttachmentList> {
List<Attachment?> _attachmentsMeta = List.empty(); List<Attachment?> _attachmentsMeta = List.empty();
void _getMetadataList() { void _getMetadataList() {
final AttachmentProvider attach = Get.find(); final AttachmentProvider provider = Get.find();
if (widget.attachmentsId.isEmpty) { if (widget.attachmentsId.isEmpty) {
return; return;
@ -53,16 +53,25 @@ class _AttachmentListState extends State<AttachmentList> {
_attachmentsMeta = List.filled(widget.attachmentsId.length, null); _attachmentsMeta = List.filled(widget.attachmentsId.length, null);
} }
attach.listMetadata(widget.attachmentsId).then((result) { int progress = 0;
setState(() { for (var idx = 0; idx < widget.attachmentsId.length; idx++) {
_attachmentsMeta = result; provider.getMetadata(widget.attachmentsId[idx]).then((resp) {
_isLoading = false; progress++;
if (resp != null) {
_attachmentsMeta[idx] = resp;
}
if (progress == widget.attachmentsId.length) {
calculateAspectRatio();
if (mounted) {
setState(() => _isLoading = false);
}
}
}); });
_calculateAspectRatio(); }
});
} }
void _calculateAspectRatio() { void calculateAspectRatio() {
bool isConsistent = true; bool isConsistent = true;
double? consistentValue; double? consistentValue;
int portrait = 0, square = 0, landscape = 0; int portrait = 0, square = 0, landscape = 0;

View File

@ -4,7 +4,6 @@ import 'package:solian/models/account_status.dart';
import 'package:solian/providers/account_status.dart'; import 'package:solian/providers/account_status.dart';
import 'package:solian/providers/auth.dart'; import 'package:solian/providers/auth.dart';
import 'package:solian/providers/content/channel.dart'; import 'package:solian/providers/content/channel.dart';
import 'package:solian/providers/relation.dart';
import 'package:solian/router.dart'; import 'package:solian/router.dart';
import 'package:solian/shells/root_shell.dart'; import 'package:solian/shells/root_shell.dart';
import 'package:solian/theme.dart'; import 'package:solian/theme.dart';
@ -61,7 +60,8 @@ class _AppNavigationDrawerState extends State<AppNavigationDrawer> {
AppRouter.instance.pushNamed('settings'); AppRouter.instance.pushNamed('settings');
setState(() => _selectedIndex = null); setState(() => _selectedIndex = null);
_closeDrawer(); _closeDrawer();
}); }
);
} }
@override @override
@ -130,36 +130,22 @@ class _AppNavigationDrawerState extends State<AppNavigationDrawer> {
); );
}, },
), ),
leading: Obx(() { leading: Builder(builder: (context) {
final statusBadgeColor = _accountStatus != null final badgeColor = _accountStatus != null
? StatusProvider.determineStatus( ? StatusProvider.determineStatus(
_accountStatus!, _accountStatus!,
).$2 ).$2
: Colors.grey; : Colors.grey;
final RelationshipProvider relations = Get.find();
final accountNotifications = relations.friendRequestCount.value;
return badges.Badge( return badges.Badge(
badgeContent: Text( showBadge: _accountStatus != null,
accountNotifications.toString(), badgeStyle: badges.BadgeStyle(badgeColor: badgeColor),
style: const TextStyle(color: Colors.white), position: badges.BadgePosition.bottomEnd(
bottom: 0,
end: -2,
), ),
showBadge: accountNotifications > 0, child: AccountAvatar(
position: badges.BadgePosition.topEnd( content: auth.userProfile.value!['avatar'],
top: -10,
end: -6,
),
child: badges.Badge(
showBadge: _accountStatus != null,
badgeStyle: badges.BadgeStyle(badgeColor: statusBadgeColor),
position: badges.BadgePosition.bottomEnd(
bottom: 0,
end: -2,
),
child: AccountAvatar(
content: auth.userProfile.value!['avatar'],
),
), ),
); );
}), }),