mirror of
https://github.com/HChaZZY/PiliPlus.git
synced 2025-12-25 03:26:22 +08:00
merge mine & media
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
@@ -56,7 +56,7 @@ abstract class CommonPublishPageState<T extends CommonPublishPage>
|
||||
initPubState();
|
||||
|
||||
if (widget.autofocus) {
|
||||
Future.delayed(const Duration(milliseconds: 300)).whenComplete(() {
|
||||
Future.delayed(const Duration(milliseconds: 300), () {
|
||||
if (mounted) {
|
||||
focusNode.requestFocus();
|
||||
}
|
||||
@@ -77,9 +77,8 @@ abstract class CommonPublishPageState<T extends CommonPublishPage>
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Future<void> _requestFocus() async {
|
||||
await Future.delayed(const Duration(microseconds: 200));
|
||||
focusNode.requestFocus();
|
||||
void _requestFocus() {
|
||||
Future.delayed(const Duration(microseconds: 200), focusNode.requestFocus);
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -68,6 +68,7 @@ class DynamicsController extends GetxController
|
||||
vmid: accountService.mid,
|
||||
pn: allFollowedUpsPage,
|
||||
orderType: 'attention',
|
||||
ps: 50,
|
||||
);
|
||||
if (res.isSuccess) {
|
||||
upData.value.upList ??= <UpItem>[];
|
||||
@@ -108,6 +109,7 @@ class DynamicsController extends GetxController
|
||||
vmid: accountService.mid,
|
||||
pn: allFollowedUpsPage,
|
||||
orderType: 'attention',
|
||||
ps: 50,
|
||||
);
|
||||
final res0 = await f1;
|
||||
if (!res0.isSuccess) {
|
||||
|
||||
@@ -34,9 +34,9 @@ class _DynamicsPageState extends State<DynamicsPage>
|
||||
tooltip: '发布动态',
|
||||
style: ButtonStyle(
|
||||
padding: WidgetStateProperty.all(EdgeInsets.zero),
|
||||
backgroundColor: WidgetStateProperty.resolveWith((states) {
|
||||
return theme.colorScheme.secondaryContainer;
|
||||
}),
|
||||
backgroundColor: WidgetStatePropertyAll(
|
||||
theme.colorScheme.secondaryContainer,
|
||||
),
|
||||
),
|
||||
onPressed: () {
|
||||
if (_dynamicsController.accountService.isLogin.value) {
|
||||
|
||||
@@ -301,10 +301,8 @@ class _CreateDynPanelState extends CommonRichTextPubPageState<CreateDynPanel> {
|
||||
tooltip: '返回',
|
||||
style: ButtonStyle(
|
||||
padding: WidgetStateProperty.all(EdgeInsets.zero),
|
||||
backgroundColor: WidgetStateProperty.resolveWith(
|
||||
(states) {
|
||||
return theme.colorScheme.secondaryContainer;
|
||||
},
|
||||
backgroundColor: WidgetStatePropertyAll(
|
||||
theme.colorScheme.secondaryContainer,
|
||||
),
|
||||
),
|
||||
onPressed: Get.back,
|
||||
|
||||
@@ -285,11 +285,9 @@ class _RepostPanelState extends CommonRichTextPubPageState<RepostPanel> {
|
||||
tooltip: '返回',
|
||||
style: ButtonStyle(
|
||||
padding: WidgetStateProperty.all(EdgeInsets.zero),
|
||||
backgroundColor: WidgetStateProperty.resolveWith((
|
||||
states,
|
||||
) {
|
||||
return theme.colorScheme.secondaryContainer;
|
||||
}),
|
||||
backgroundColor: WidgetStatePropertyAll(
|
||||
theme.colorScheme.secondaryContainer,
|
||||
),
|
||||
),
|
||||
onPressed: Get.back,
|
||||
icon: Icon(
|
||||
|
||||
@@ -28,7 +28,7 @@ class DynamicsTabController
|
||||
@override
|
||||
Future<void> onRefresh() {
|
||||
if (dynamicsType == DynamicsTabType.all) {
|
||||
mainController.setCount();
|
||||
mainController.setDynCount();
|
||||
}
|
||||
offset = '';
|
||||
return super.onRefresh();
|
||||
|
||||
@@ -141,9 +141,7 @@ class _EpisodePanelState extends CommonSlidePageState<EpisodePanel> {
|
||||
widget.initialTabIndex,
|
||||
duration: const Duration(milliseconds: 200),
|
||||
);
|
||||
Future.delayed(const Duration(milliseconds: 300)).whenComplete(() {
|
||||
jumpToCurrent();
|
||||
});
|
||||
Future.delayed(const Duration(milliseconds: 300), jumpToCurrent);
|
||||
} else {
|
||||
jumpToCurrent();
|
||||
}
|
||||
|
||||
@@ -66,56 +66,59 @@ class FavNoteItem extends StatelessWidget {
|
||||
Positioned.fill(
|
||||
child: IgnorePointer(
|
||||
child: LayoutBuilder(
|
||||
builder: (context, constraints) => AnimatedOpacity(
|
||||
opacity: item.checked == true ? 1 : 0,
|
||||
duration: const Duration(milliseconds: 200),
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
height: constraints.maxHeight,
|
||||
width:
|
||||
constraints.maxHeight *
|
||||
StyleString.aspectRatio,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: StyleString.mdRadius,
|
||||
color: Colors.black.withValues(
|
||||
alpha: 0.6,
|
||||
builder: (context, constraints) =>
|
||||
AnimatedOpacity(
|
||||
opacity: item.checked == true ? 1 : 0,
|
||||
duration: const Duration(
|
||||
milliseconds: 200,
|
||||
),
|
||||
),
|
||||
child: SizedBox(
|
||||
width: 34,
|
||||
height: 34,
|
||||
child: AnimatedScale(
|
||||
scale: item.checked == true ? 1 : 0,
|
||||
duration: const Duration(
|
||||
milliseconds: 250,
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
height: constraints.maxHeight,
|
||||
width:
|
||||
constraints.maxHeight *
|
||||
StyleString.aspectRatio,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: StyleString.mdRadius,
|
||||
color: Colors.black.withValues(
|
||||
alpha: 0.6,
|
||||
),
|
||||
),
|
||||
curve: Curves.easeInOut,
|
||||
child: IconButton(
|
||||
tooltip: '取消选择',
|
||||
style: ButtonStyle(
|
||||
padding: WidgetStateProperty.all(
|
||||
EdgeInsets.zero,
|
||||
child: SizedBox(
|
||||
width: 34,
|
||||
height: 34,
|
||||
child: AnimatedScale(
|
||||
scale: item.checked == true ? 1 : 0,
|
||||
duration: const Duration(
|
||||
milliseconds: 250,
|
||||
),
|
||||
curve: Curves.easeInOut,
|
||||
child: IconButton(
|
||||
tooltip: '取消选择',
|
||||
style: ButtonStyle(
|
||||
padding:
|
||||
WidgetStateProperty.all(
|
||||
EdgeInsets.zero,
|
||||
),
|
||||
backgroundColor:
|
||||
WidgetStatePropertyAll(
|
||||
theme.colorScheme.surface
|
||||
.withValues(
|
||||
alpha: 0.8,
|
||||
),
|
||||
),
|
||||
),
|
||||
onPressed: null,
|
||||
icon: Icon(
|
||||
Icons.done_all_outlined,
|
||||
color:
|
||||
theme.colorScheme.primary,
|
||||
),
|
||||
),
|
||||
backgroundColor:
|
||||
WidgetStateProperty.resolveWith(
|
||||
(states) {
|
||||
return theme
|
||||
.colorScheme
|
||||
.surface
|
||||
.withValues(alpha: 0.8);
|
||||
},
|
||||
),
|
||||
),
|
||||
onPressed: null,
|
||||
icon: Icon(
|
||||
Icons.done_all_outlined,
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -55,98 +55,103 @@ class FavPgcItem extends StatelessWidget {
|
||||
AspectRatio(
|
||||
aspectRatio: 3 / 4,
|
||||
child: LayoutBuilder(
|
||||
builder: (BuildContext context, BoxConstraints boxConstraints) {
|
||||
return Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
NetworkImgLayer(
|
||||
radius: 4,
|
||||
src: item.cover,
|
||||
width: boxConstraints.maxWidth,
|
||||
height: boxConstraints.maxHeight,
|
||||
),
|
||||
PBadge(
|
||||
right: 4,
|
||||
top: 4,
|
||||
text: item.badge,
|
||||
size: PBadgeSize.small,
|
||||
fontSize: 10,
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 2,
|
||||
vertical: 1,
|
||||
),
|
||||
),
|
||||
Positioned.fill(
|
||||
child: IgnorePointer(
|
||||
child: LayoutBuilder(
|
||||
builder: (context, constraints) =>
|
||||
AnimatedOpacity(
|
||||
opacity: item.checked == true ? 1 : 0,
|
||||
duration: const Duration(
|
||||
milliseconds: 200,
|
||||
),
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
height: constraints.maxHeight,
|
||||
width:
|
||||
constraints.maxHeight *
|
||||
StyleString.aspectRatio,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius:
|
||||
const BorderRadius.all(
|
||||
Radius.circular(4),
|
||||
),
|
||||
color: Colors.black.withValues(
|
||||
alpha: 0.6,
|
||||
),
|
||||
),
|
||||
child: SizedBox(
|
||||
width: 34,
|
||||
height: 34,
|
||||
child: AnimatedScale(
|
||||
scale: item.checked == true
|
||||
? 1
|
||||
: 0,
|
||||
duration: const Duration(
|
||||
milliseconds: 250,
|
||||
),
|
||||
curve: Curves.easeInOut,
|
||||
child: IconButton(
|
||||
tooltip: '取消选择',
|
||||
style: ButtonStyle(
|
||||
padding:
|
||||
WidgetStateProperty.all(
|
||||
EdgeInsets.zero,
|
||||
),
|
||||
backgroundColor:
|
||||
WidgetStateProperty.resolveWith(
|
||||
(states) {
|
||||
return theme
|
||||
.colorScheme
|
||||
.surface
|
||||
.withValues(
|
||||
alpha: 0.8,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
onPressed: null,
|
||||
icon: Icon(
|
||||
Icons.done_all_outlined,
|
||||
color:
|
||||
theme.colorScheme.primary,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
builder:
|
||||
(
|
||||
BuildContext context,
|
||||
BoxConstraints boxConstraints,
|
||||
) {
|
||||
return Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
NetworkImgLayer(
|
||||
radius: 4,
|
||||
src: item.cover,
|
||||
width: boxConstraints.maxWidth,
|
||||
height: boxConstraints.maxHeight,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
PBadge(
|
||||
right: 4,
|
||||
top: 4,
|
||||
text: item.badge,
|
||||
size: PBadgeSize.small,
|
||||
fontSize: 10,
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 2,
|
||||
vertical: 1,
|
||||
),
|
||||
),
|
||||
Positioned.fill(
|
||||
child: IgnorePointer(
|
||||
child: LayoutBuilder(
|
||||
builder: (context, constraints) =>
|
||||
AnimatedOpacity(
|
||||
opacity: item.checked == true
|
||||
? 1
|
||||
: 0,
|
||||
duration: const Duration(
|
||||
milliseconds: 200,
|
||||
),
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
height: constraints.maxHeight,
|
||||
width:
|
||||
constraints.maxHeight *
|
||||
StyleString.aspectRatio,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius:
|
||||
const BorderRadius.all(
|
||||
Radius.circular(4),
|
||||
),
|
||||
color: Colors.black.withValues(
|
||||
alpha: 0.6,
|
||||
),
|
||||
),
|
||||
child: SizedBox(
|
||||
width: 34,
|
||||
height: 34,
|
||||
child: AnimatedScale(
|
||||
scale: item.checked == true
|
||||
? 1
|
||||
: 0,
|
||||
duration: const Duration(
|
||||
milliseconds: 250,
|
||||
),
|
||||
curve: Curves.easeInOut,
|
||||
child: IconButton(
|
||||
tooltip: '取消选择',
|
||||
style: ButtonStyle(
|
||||
padding:
|
||||
WidgetStateProperty.all(
|
||||
EdgeInsets.zero,
|
||||
),
|
||||
backgroundColor:
|
||||
WidgetStatePropertyAll(
|
||||
theme
|
||||
.colorScheme
|
||||
.surface
|
||||
.withValues(
|
||||
alpha: 0.8,
|
||||
),
|
||||
),
|
||||
),
|
||||
onPressed: null,
|
||||
icon: Icon(
|
||||
Icons.done_all_outlined,
|
||||
color: theme
|
||||
.colorScheme
|
||||
.primary,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
|
||||
@@ -208,9 +208,7 @@ class FavDetailController
|
||||
var res = await FavHttp.cleanFav(mediaId: mediaId);
|
||||
if (res['status']) {
|
||||
SmartDialog.showToast('清除成功');
|
||||
Future.delayed(const Duration(milliseconds: 200), () {
|
||||
onReload();
|
||||
});
|
||||
Future.delayed(const Duration(milliseconds: 200), onReload);
|
||||
} else {
|
||||
SmartDialog.showToast(res['msg']);
|
||||
}
|
||||
|
||||
@@ -541,53 +541,52 @@ class _FavDetailPageState extends State<FavDetailPage> {
|
||||
bottom: 5,
|
||||
child: IgnorePointer(
|
||||
child: LayoutBuilder(
|
||||
builder: (context, constraints) => AnimatedOpacity(
|
||||
opacity: item.checked == true ? 1 : 0,
|
||||
duration: const Duration(milliseconds: 200),
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
height: constraints.maxHeight,
|
||||
width:
|
||||
constraints.maxHeight *
|
||||
StyleString.aspectRatio,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: StyleString.mdRadius,
|
||||
color: Colors.black.withValues(alpha: 0.6),
|
||||
),
|
||||
child: SizedBox(
|
||||
width: 34,
|
||||
height: 34,
|
||||
child: AnimatedScale(
|
||||
scale: item.checked == true ? 1 : 0,
|
||||
duration: const Duration(
|
||||
milliseconds: 250,
|
||||
),
|
||||
curve: Curves.easeInOut,
|
||||
child: IconButton(
|
||||
style: ButtonStyle(
|
||||
padding: WidgetStateProperty.all(
|
||||
EdgeInsets.zero,
|
||||
),
|
||||
backgroundColor:
|
||||
WidgetStateProperty.resolveWith(
|
||||
(states) {
|
||||
return theme
|
||||
.colorScheme
|
||||
.surface
|
||||
.withValues(alpha: 0.8);
|
||||
},
|
||||
),
|
||||
builder: (context, constraints) =>
|
||||
AnimatedOpacity(
|
||||
opacity: item.checked == true ? 1 : 0,
|
||||
duration: const Duration(milliseconds: 200),
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
height: constraints.maxHeight,
|
||||
width:
|
||||
constraints.maxHeight *
|
||||
StyleString.aspectRatio,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: StyleString.mdRadius,
|
||||
color: Colors.black.withValues(
|
||||
alpha: 0.6,
|
||||
),
|
||||
onPressed: null,
|
||||
icon: Icon(
|
||||
Icons.done_all_outlined,
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
child: SizedBox(
|
||||
width: 34,
|
||||
height: 34,
|
||||
child: AnimatedScale(
|
||||
scale: item.checked == true ? 1 : 0,
|
||||
duration: const Duration(
|
||||
milliseconds: 250,
|
||||
),
|
||||
curve: Curves.easeInOut,
|
||||
child: IconButton(
|
||||
style: ButtonStyle(
|
||||
padding: WidgetStateProperty.all(
|
||||
EdgeInsets.zero,
|
||||
),
|
||||
backgroundColor:
|
||||
WidgetStatePropertyAll(
|
||||
theme.colorScheme.surface
|
||||
.withValues(alpha: 0.8),
|
||||
),
|
||||
),
|
||||
onPressed: null,
|
||||
icon: Icon(
|
||||
Icons.done_all_outlined,
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -51,7 +51,7 @@ class FollowChildController
|
||||
return MemberHttp.followUpGroup(mid: mid, tagid: tagid, pn: page);
|
||||
}
|
||||
|
||||
return FollowHttp.followingsNew(
|
||||
return FollowHttp.followings(
|
||||
vmid: mid,
|
||||
pn: page,
|
||||
orderType: orderType.value.type,
|
||||
|
||||
@@ -195,13 +195,9 @@ class HistoryItem extends StatelessWidget {
|
||||
EdgeInsets.zero,
|
||||
),
|
||||
backgroundColor:
|
||||
WidgetStateProperty.resolveWith(
|
||||
(states) {
|
||||
return theme
|
||||
.colorScheme
|
||||
.surface
|
||||
.withValues(alpha: 0.8);
|
||||
},
|
||||
WidgetStatePropertyAll(
|
||||
theme.colorScheme.surface
|
||||
.withValues(alpha: 0.8),
|
||||
),
|
||||
),
|
||||
onPressed: () {
|
||||
|
||||
@@ -5,9 +5,7 @@ import 'package:PiliPlus/http/api.dart';
|
||||
import 'package:PiliPlus/http/init.dart';
|
||||
import 'package:PiliPlus/models/common/home_tab_type.dart';
|
||||
import 'package:PiliPlus/pages/common/common_controller.dart';
|
||||
import 'package:PiliPlus/pages/mine/view.dart';
|
||||
import 'package:PiliPlus/services/account_service.dart';
|
||||
import 'package:PiliPlus/utils/feed_back.dart';
|
||||
import 'package:PiliPlus/utils/storage_pref.dart';
|
||||
import 'package:flutter/foundation.dart' show kDebugMode;
|
||||
import 'package:flutter/material.dart';
|
||||
@@ -83,17 +81,6 @@ class HomeController extends GetxController
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
void showUserInfoDialog(BuildContext context) {
|
||||
feedBack();
|
||||
showDialog(
|
||||
context: context,
|
||||
useSafeArea: true,
|
||||
builder: (context) => const Dialog(
|
||||
child: MinePage(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
searchBarStream?.close();
|
||||
|
||||
@@ -104,8 +104,7 @@ class _HomePageState extends State<HomePage>
|
||||
child: Material(
|
||||
type: MaterialType.transparency,
|
||||
child: InkWell(
|
||||
onTap: () =>
|
||||
_homeController.showUserInfoDialog(context),
|
||||
onTap: _mainController.toMinePage,
|
||||
splashColor: theme.colorScheme.primaryContainer
|
||||
.withValues(alpha: 0.3),
|
||||
customBorder: const CircleBorder(),
|
||||
@@ -141,8 +140,7 @@ class _HomePageState extends State<HomePage>
|
||||
)
|
||||
: defaultUser(
|
||||
theme: theme,
|
||||
onPressed: () =>
|
||||
_homeController.showUserInfoDialog(context),
|
||||
onPressed: _mainController.toMinePage,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -235,9 +233,9 @@ Widget defaultUser({
|
||||
tooltip: '默认用户头像',
|
||||
style: ButtonStyle(
|
||||
padding: WidgetStateProperty.all(EdgeInsets.zero),
|
||||
backgroundColor: WidgetStateProperty.resolveWith((states) {
|
||||
return theme.colorScheme.onInverseSurface;
|
||||
}),
|
||||
backgroundColor: WidgetStatePropertyAll(
|
||||
theme.colorScheme.onInverseSurface,
|
||||
),
|
||||
),
|
||||
onPressed: onPressed,
|
||||
icon: Icon(
|
||||
|
||||
@@ -121,54 +121,55 @@ class _LaterViewChildPageState extends State<LaterViewChildPage>
|
||||
bottom: 5,
|
||||
child: IgnorePointer(
|
||||
child: LayoutBuilder(
|
||||
builder: (context, constraints) => AnimatedOpacity(
|
||||
opacity: videoItem.checked == true ? 1 : 0,
|
||||
duration: const Duration(milliseconds: 200),
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
height: constraints.maxHeight,
|
||||
width:
|
||||
constraints.maxHeight *
|
||||
StyleString.aspectRatio,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: StyleString.mdRadius,
|
||||
color: Colors.black.withValues(alpha: 0.6),
|
||||
),
|
||||
child: SizedBox(
|
||||
width: 34,
|
||||
height: 34,
|
||||
child: AnimatedScale(
|
||||
scale: videoItem.checked == true ? 1 : 0,
|
||||
duration: const Duration(
|
||||
milliseconds: 250,
|
||||
),
|
||||
curve: Curves.easeInOut,
|
||||
child: IconButton(
|
||||
tooltip: '取消选择',
|
||||
style: ButtonStyle(
|
||||
padding: WidgetStateProperty.all(
|
||||
EdgeInsets.zero,
|
||||
),
|
||||
backgroundColor:
|
||||
WidgetStateProperty.resolveWith(
|
||||
(states) {
|
||||
return theme
|
||||
.colorScheme
|
||||
.surface
|
||||
.withValues(alpha: 0.8);
|
||||
},
|
||||
),
|
||||
builder: (context, constraints) =>
|
||||
AnimatedOpacity(
|
||||
opacity: videoItem.checked == true ? 1 : 0,
|
||||
duration: const Duration(milliseconds: 200),
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
height: constraints.maxHeight,
|
||||
width:
|
||||
constraints.maxHeight *
|
||||
StyleString.aspectRatio,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: StyleString.mdRadius,
|
||||
color: Colors.black.withValues(
|
||||
alpha: 0.6,
|
||||
),
|
||||
onPressed: null,
|
||||
icon: Icon(
|
||||
Icons.done_all_outlined,
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
child: SizedBox(
|
||||
width: 34,
|
||||
height: 34,
|
||||
child: AnimatedScale(
|
||||
scale: videoItem.checked == true
|
||||
? 1
|
||||
: 0,
|
||||
duration: const Duration(
|
||||
milliseconds: 250,
|
||||
),
|
||||
curve: Curves.easeInOut,
|
||||
child: IconButton(
|
||||
tooltip: '取消选择',
|
||||
style: ButtonStyle(
|
||||
padding: WidgetStateProperty.all(
|
||||
EdgeInsets.zero,
|
||||
),
|
||||
backgroundColor:
|
||||
WidgetStatePropertyAll(
|
||||
theme.colorScheme.surface
|
||||
.withValues(alpha: 0.8),
|
||||
),
|
||||
),
|
||||
onPressed: null,
|
||||
icon: Icon(
|
||||
Icons.done_all_outlined,
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -8,11 +8,15 @@ import 'package:PiliPlus/models/common/msg/msg_unread_type.dart';
|
||||
import 'package:PiliPlus/models/common/nav_bar_config.dart';
|
||||
import 'package:PiliPlus/models_new/msgfeed_unread/data.dart';
|
||||
import 'package:PiliPlus/models_new/single_unread/data.dart';
|
||||
import 'package:PiliPlus/pages/dynamics/controller.dart';
|
||||
import 'package:PiliPlus/pages/home/controller.dart';
|
||||
import 'package:PiliPlus/services/account_service.dart';
|
||||
import 'package:PiliPlus/utils/feed_back.dart';
|
||||
import 'package:PiliPlus/utils/storage.dart';
|
||||
import 'package:PiliPlus/utils/storage_key.dart';
|
||||
import 'package:PiliPlus/utils/storage_pref.dart';
|
||||
import 'package:PiliPlus/utils/update.dart';
|
||||
import 'package:easy_debounce/easy_throttle.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
@@ -21,20 +25,27 @@ class MainController extends GetxController
|
||||
AccountService accountService = Get.find<AccountService>();
|
||||
|
||||
List<NavigationBarType> navigationBars = <NavigationBarType>[];
|
||||
RxInt dynCount = 0.obs;
|
||||
|
||||
StreamController<bool>? bottomBarStream;
|
||||
late bool hideTabBar = Pref.hideTabBar;
|
||||
late dynamic controller;
|
||||
RxInt selectedIndex = 0.obs;
|
||||
|
||||
RxInt dynCount = 0.obs;
|
||||
late DynamicBadgeMode dynamicBadgeMode;
|
||||
late bool checkDynamic = Pref.checkDynamic;
|
||||
late int dynamicPeriod = Pref.dynamicPeriod;
|
||||
late int dynamicPeriod = Pref.dynamicPeriod * 60 * 1000;
|
||||
late int _lastCheckDynamicAt = 0;
|
||||
late int dynIndex = -1;
|
||||
late final DynamicsController dynamicController = Get.put(
|
||||
DynamicsController(),
|
||||
);
|
||||
|
||||
late int homeIndex = -1;
|
||||
late final HomeController? homeController = homeIndex == -1
|
||||
? null
|
||||
: Get.put(HomeController());
|
||||
|
||||
late DynamicBadgeMode msgBadgeMode = Pref.msgBadgeMode;
|
||||
late Set<MsgUnReadType> msgUnReadTypes = Pref.msgUnReadTypeV2;
|
||||
late final RxString msgUnReadCount = ''.obs;
|
||||
@@ -48,6 +59,9 @@ class MainController extends GetxController
|
||||
|
||||
late bool directExitOnBack = Pref.directExitOnBack;
|
||||
|
||||
static const _period = 5 * 60 * 1000;
|
||||
late int _lastSelectTime = 0;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
@@ -163,19 +177,19 @@ class MainController extends GetxController
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> getUnreadDynamic() async {
|
||||
void getUnreadDynamic() {
|
||||
if (!accountService.isLogin.value || dynIndex == -1) {
|
||||
return;
|
||||
}
|
||||
DynGrpc.dynRed().then((res) {
|
||||
if (res != null) {
|
||||
setCount(res);
|
||||
setDynCount(res);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> setCount([int count = 0]) async {
|
||||
if (dynIndex == -1 || dynCount.value == count) return;
|
||||
void setDynCount([int count = 0]) {
|
||||
if (dynIndex == -1) return;
|
||||
dynCount.value = count;
|
||||
}
|
||||
|
||||
@@ -187,7 +201,7 @@ class MainController extends GetxController
|
||||
return;
|
||||
}
|
||||
int now = DateTime.now().millisecondsSinceEpoch;
|
||||
if (now - _lastCheckDynamicAt >= dynamicPeriod * 60 * 1000) {
|
||||
if (now - _lastCheckDynamicAt >= dynamicPeriod) {
|
||||
_lastCheckDynamicAt = now;
|
||||
getUnreadDynamic();
|
||||
}
|
||||
@@ -198,7 +212,7 @@ class MainController extends GetxController
|
||||
(GStorage.setting.get(SettingBoxKey.navBarSort) as List?)?.cast();
|
||||
int defaultHomePage = Pref.defaultHomePage;
|
||||
late final List<NavigationBarType> navigationBars;
|
||||
if (navBarSort == null) {
|
||||
if (navBarSort == null || navBarSort.isEmpty) {
|
||||
navigationBars = NavigationBarType.values;
|
||||
} else {
|
||||
navigationBars = navBarSort
|
||||
@@ -212,6 +226,86 @@ class MainController extends GetxController
|
||||
);
|
||||
}
|
||||
|
||||
void checkDefaultSearch([bool shouldCheck = false]) {
|
||||
if (homeController?.enableSearchWord == true) {
|
||||
if (shouldCheck &&
|
||||
navigationBars[selectedIndex.value] != NavigationBarType.home) {
|
||||
return;
|
||||
}
|
||||
int now = DateTime.now().millisecondsSinceEpoch;
|
||||
if (now - homeController!.lateCheckSearchAt >= _period) {
|
||||
homeController!
|
||||
..lateCheckSearchAt = now
|
||||
..querySearchDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void checkUnread([bool shouldCheck = false]) {
|
||||
if (accountService.isLogin.value &&
|
||||
homeIndex != -1 &&
|
||||
msgBadgeMode != DynamicBadgeMode.hidden) {
|
||||
if (shouldCheck &&
|
||||
navigationBars[selectedIndex.value] != NavigationBarType.home) {
|
||||
return;
|
||||
}
|
||||
int now = DateTime.now().millisecondsSinceEpoch;
|
||||
if (now - lastCheckUnreadAt >= _period) {
|
||||
lastCheckUnreadAt = now;
|
||||
queryUnreadMsg();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void toMinePage() {
|
||||
final index = navigationBars.indexOf(NavigationBarType.mine);
|
||||
if (index != -1) {
|
||||
setIndex(index);
|
||||
}
|
||||
}
|
||||
|
||||
void setIndex(int value) {
|
||||
feedBack();
|
||||
|
||||
final currentNav = navigationBars[value];
|
||||
if (value != selectedIndex.value) {
|
||||
selectedIndex.value = value;
|
||||
if (mainTabBarView) {
|
||||
controller.animateTo(value);
|
||||
} else {
|
||||
controller.jumpToPage(value);
|
||||
}
|
||||
if (currentNav == NavigationBarType.home) {
|
||||
checkDefaultSearch();
|
||||
checkUnread();
|
||||
} else if (currentNav == NavigationBarType.dynamics) {
|
||||
setDynCount();
|
||||
}
|
||||
} else {
|
||||
int now = DateTime.now().millisecondsSinceEpoch;
|
||||
if (now - _lastSelectTime < 500) {
|
||||
EasyThrottle.throttle(
|
||||
'topOrRefresh',
|
||||
const Duration(milliseconds: 500),
|
||||
() {
|
||||
if (currentNav == NavigationBarType.home) {
|
||||
homeController!.onRefresh();
|
||||
} else if (currentNav == NavigationBarType.dynamics) {
|
||||
dynamicController.onRefresh();
|
||||
}
|
||||
},
|
||||
);
|
||||
} else {
|
||||
if (currentNav == NavigationBarType.home) {
|
||||
homeController!.toTopOrRefresh();
|
||||
} else if (currentNav == NavigationBarType.dynamics) {
|
||||
dynamicController.toTopOrRefresh();
|
||||
}
|
||||
}
|
||||
_lastSelectTime = now;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
bottomBarStream?.close();
|
||||
|
||||
@@ -5,18 +5,13 @@ import 'package:PiliPlus/common/widgets/tabs.dart';
|
||||
import 'package:PiliPlus/models/common/dynamic/dynamic_badge_mode.dart';
|
||||
import 'package:PiliPlus/models/common/image_type.dart';
|
||||
import 'package:PiliPlus/models/common/nav_bar_config.dart';
|
||||
import 'package:PiliPlus/pages/dynamics/controller.dart';
|
||||
import 'package:PiliPlus/pages/dynamics/view.dart';
|
||||
import 'package:PiliPlus/pages/home/controller.dart';
|
||||
import 'package:PiliPlus/pages/home/view.dart';
|
||||
import 'package:PiliPlus/pages/main/controller.dart';
|
||||
import 'package:PiliPlus/pages/mine/controller.dart';
|
||||
import 'package:PiliPlus/utils/app_scheme.dart';
|
||||
import 'package:PiliPlus/utils/extension.dart';
|
||||
import 'package:PiliPlus/utils/feed_back.dart';
|
||||
import 'package:PiliPlus/utils/storage.dart';
|
||||
import 'package:PiliPlus/utils/utils.dart';
|
||||
import 'package:easy_debounce/easy_throttle.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:get/get.dart';
|
||||
@@ -36,11 +31,6 @@ class MainApp extends StatefulWidget {
|
||||
class _MainAppState extends State<MainApp>
|
||||
with RouteAware, WidgetsBindingObserver {
|
||||
final MainController _mainController = Get.put(MainController());
|
||||
late final _homeController = Get.put(HomeController());
|
||||
late final _dynamicController = Get.put(DynamicsController());
|
||||
|
||||
static const _period = 5 * 60 * 1000;
|
||||
late int _lastSelectTime = 0;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -57,9 +47,10 @@ class _MainAppState extends State<MainApp>
|
||||
@override
|
||||
void didPopNext() {
|
||||
WidgetsBinding.instance.addObserver(this);
|
||||
_mainController.checkUnreadDynamic();
|
||||
_checkDefaultSearch(true);
|
||||
_checkUnread(context.orientation == Orientation.portrait);
|
||||
_mainController
|
||||
..checkUnreadDynamic()
|
||||
..checkDefaultSearch(true)
|
||||
..checkUnread(context.orientation == Orientation.portrait);
|
||||
super.didPopNext();
|
||||
}
|
||||
|
||||
@@ -72,85 +63,10 @@ class _MainAppState extends State<MainApp>
|
||||
@override
|
||||
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||
if (state == AppLifecycleState.resumed) {
|
||||
_mainController.checkUnreadDynamic();
|
||||
_checkDefaultSearch(true);
|
||||
_checkUnread(context.orientation == Orientation.portrait);
|
||||
}
|
||||
}
|
||||
|
||||
void _checkDefaultSearch([bool shouldCheck = false]) {
|
||||
if (_mainController.homeIndex != -1 && _homeController.enableSearchWord) {
|
||||
if (shouldCheck &&
|
||||
_mainController.navigationBars[_mainController.selectedIndex.value] !=
|
||||
NavigationBarType.home) {
|
||||
return;
|
||||
}
|
||||
int now = DateTime.now().millisecondsSinceEpoch;
|
||||
if (now - _homeController.lateCheckSearchAt >= _period) {
|
||||
_homeController
|
||||
..lateCheckSearchAt = now
|
||||
..querySearchDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _checkUnread([bool shouldCheck = false]) {
|
||||
if (_mainController.accountService.isLogin.value &&
|
||||
_mainController.homeIndex != -1 &&
|
||||
_mainController.msgBadgeMode != DynamicBadgeMode.hidden) {
|
||||
if (shouldCheck &&
|
||||
_mainController.navigationBars[_mainController.selectedIndex.value] !=
|
||||
NavigationBarType.home) {
|
||||
return;
|
||||
}
|
||||
int now = DateTime.now().millisecondsSinceEpoch;
|
||||
if (now - _mainController.lastCheckUnreadAt >= _period) {
|
||||
_mainController
|
||||
..lastCheckUnreadAt = now
|
||||
..queryUnreadMsg();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setIndex(int value) {
|
||||
feedBack();
|
||||
|
||||
final currentPage = _mainController.navigationBars[value].page;
|
||||
if (value != _mainController.selectedIndex.value) {
|
||||
_mainController.selectedIndex.value = value;
|
||||
if (_mainController.mainTabBarView) {
|
||||
_mainController.controller.animateTo(value);
|
||||
} else {
|
||||
_mainController.controller.jumpToPage(value);
|
||||
}
|
||||
if (currentPage is HomePage) {
|
||||
_checkDefaultSearch();
|
||||
_checkUnread();
|
||||
} else if (currentPage is DynamicsPage) {
|
||||
_mainController.setCount();
|
||||
}
|
||||
} else {
|
||||
int now = DateTime.now().millisecondsSinceEpoch;
|
||||
if (now - _lastSelectTime < 500) {
|
||||
EasyThrottle.throttle(
|
||||
'topOrRefresh',
|
||||
const Duration(milliseconds: 500),
|
||||
() {
|
||||
if (currentPage is HomePage) {
|
||||
_homeController.onRefresh();
|
||||
} else if (currentPage is DynamicsPage) {
|
||||
_dynamicController.onRefresh();
|
||||
}
|
||||
},
|
||||
);
|
||||
} else {
|
||||
if (currentPage is HomePage) {
|
||||
_homeController.toTopOrRefresh();
|
||||
} else if (currentPage is DynamicsPage) {
|
||||
_dynamicController.toTopOrRefresh();
|
||||
}
|
||||
}
|
||||
_lastSelectTime = now;
|
||||
_mainController
|
||||
..checkUnreadDynamic()
|
||||
..checkDefaultSearch(true)
|
||||
..checkUnread(context.orientation == Orientation.portrait);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,9 +98,10 @@ class _MainAppState extends State<MainApp>
|
||||
onBack();
|
||||
} else {
|
||||
if (_mainController.selectedIndex.value != 0) {
|
||||
setIndex(0);
|
||||
_mainController.bottomBarStream?.add(true);
|
||||
_homeController.searchBarStream?.add(true);
|
||||
_mainController
|
||||
..setIndex(0)
|
||||
..bottomBarStream?.add(true)
|
||||
..homeController?.searchBarStream?.add(true);
|
||||
} else {
|
||||
onBack();
|
||||
}
|
||||
@@ -229,7 +146,8 @@ class _MainAppState extends State<MainApp>
|
||||
Radius.circular(16),
|
||||
),
|
||||
),
|
||||
onDestinationSelected: setIndex,
|
||||
onDestinationSelected:
|
||||
_mainController.setIndex,
|
||||
selectedIndex: _mainController
|
||||
.selectedIndex
|
||||
.value,
|
||||
@@ -258,7 +176,8 @@ class _MainAppState extends State<MainApp>
|
||||
groupAlignment: 0.5,
|
||||
selectedIndex:
|
||||
_mainController.selectedIndex.value,
|
||||
onDestinationSelected: setIndex,
|
||||
onDestinationSelected:
|
||||
_mainController.setIndex,
|
||||
labelType: NavigationRailLabelType.selected,
|
||||
leading: userAndSearchVertical(theme),
|
||||
destinations: _mainController.navigationBars
|
||||
@@ -329,7 +248,8 @@ class _MainAppState extends State<MainApp>
|
||||
? _mainController.navigationBars.length > 1
|
||||
? Obx(
|
||||
() => NavigationBar(
|
||||
onDestinationSelected: setIndex,
|
||||
onDestinationSelected:
|
||||
_mainController.setIndex,
|
||||
selectedIndex:
|
||||
_mainController.selectedIndex.value,
|
||||
destinations: _mainController
|
||||
@@ -353,7 +273,7 @@ class _MainAppState extends State<MainApp>
|
||||
() => BottomNavigationBar(
|
||||
currentIndex:
|
||||
_mainController.selectedIndex.value,
|
||||
onTap: setIndex,
|
||||
onTap: _mainController.setIndex,
|
||||
iconSize: 16,
|
||||
selectedFontSize: 12,
|
||||
unselectedFontSize: 12,
|
||||
@@ -424,8 +344,7 @@ class _MainAppState extends State<MainApp>
|
||||
child: Material(
|
||||
type: MaterialType.transparency,
|
||||
child: InkWell(
|
||||
onTap: () =>
|
||||
_homeController.showUserInfoDialog(context),
|
||||
onTap: _mainController.toMinePage,
|
||||
splashColor: theme.colorScheme.primaryContainer
|
||||
.withValues(alpha: 0.3),
|
||||
customBorder: const CircleBorder(),
|
||||
@@ -461,8 +380,7 @@ class _MainAppState extends State<MainApp>
|
||||
)
|
||||
: defaultUser(
|
||||
theme: theme,
|
||||
onPressed: () =>
|
||||
_homeController.showUserInfoDialog(context),
|
||||
onPressed: _mainController.toMinePage,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
import 'package:PiliPlus/http/fav.dart';
|
||||
import 'package:PiliPlus/http/loading_state.dart';
|
||||
import 'package:PiliPlus/models_new/fav/fav_folder/data.dart';
|
||||
import 'package:PiliPlus/pages/common/common_data_controller.dart';
|
||||
import 'package:PiliPlus/services/account_service.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class MediaController
|
||||
extends CommonDataController<FavFolderData, FavFolderData> {
|
||||
final list = <({IconData icon, String title, VoidCallback onTap})>[
|
||||
(
|
||||
icon: Icons.history,
|
||||
title: '观看记录',
|
||||
onTap: () => Get.toNamed('/history'),
|
||||
),
|
||||
(
|
||||
icon: Icons.subscriptions_outlined,
|
||||
title: '我的订阅',
|
||||
onTap: () => Get.toNamed('/subscription'),
|
||||
),
|
||||
(
|
||||
icon: Icons.watch_later_outlined,
|
||||
title: '稍后再看',
|
||||
onTap: () => Get.toNamed('/later'),
|
||||
),
|
||||
(
|
||||
icon: Icons.create_outlined,
|
||||
title: '创作中心',
|
||||
onTap: () => Get.toNamed(
|
||||
'/webview',
|
||||
parameters: {
|
||||
'url': 'https://member.bilibili.com/platform/home',
|
||||
},
|
||||
),
|
||||
),
|
||||
];
|
||||
RxInt count = (-1).obs;
|
||||
|
||||
AccountService accountService = Get.find<AccountService>();
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
if (accountService.isLogin.value) {
|
||||
queryData();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
bool customHandleResponse(bool isRefresh, Success<FavFolderData> response) {
|
||||
count.value = response.response.count ?? -1;
|
||||
loadingState.value = response;
|
||||
return true;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<LoadingState<FavFolderData>> customGetData() {
|
||||
return FavHttp.userfavFolder(
|
||||
pn: 1,
|
||||
ps: 5,
|
||||
mid: accountService.mid,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,245 +0,0 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:PiliPlus/http/loading_state.dart';
|
||||
import 'package:PiliPlus/models/common/nav_bar_config.dart';
|
||||
import 'package:PiliPlus/models_new/fav/fav_folder/list.dart';
|
||||
import 'package:PiliPlus/pages/common/common_page.dart';
|
||||
import 'package:PiliPlus/pages/main/controller.dart';
|
||||
import 'package:PiliPlus/pages/media/controller.dart';
|
||||
import 'package:PiliPlus/pages/media/widgets/item.dart';
|
||||
import 'package:PiliPlus/utils/extension.dart';
|
||||
import 'package:PiliPlus/utils/utils.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class MediaPage extends CommonPage {
|
||||
const MediaPage({super.key});
|
||||
|
||||
@override
|
||||
State<MediaPage> createState() => _MediaPageState();
|
||||
}
|
||||
|
||||
class _MediaPageState extends CommonPageState<MediaPage, MediaController>
|
||||
with AutomaticKeepAliveClientMixin {
|
||||
@override
|
||||
MediaController controller = Get.put(MediaController());
|
||||
late final MainController _mainController = Get.find<MainController>();
|
||||
|
||||
@override
|
||||
bool get wantKeepAlive => true;
|
||||
|
||||
@override
|
||||
void listener() {
|
||||
if (_mainController.navigationBars[0] != NavigationBarType.media &&
|
||||
_mainController.selectedIndex.value == 0) {
|
||||
return;
|
||||
}
|
||||
super.listener();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
super.build(context);
|
||||
final theme = Theme.of(context);
|
||||
Color primary = theme.colorScheme.primary;
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(top: 30),
|
||||
child: Material(
|
||||
type: MaterialType.transparency,
|
||||
child: ListView(
|
||||
controller: controller.scrollController,
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
children: [
|
||||
ListTile(
|
||||
leading: null,
|
||||
title: Padding(
|
||||
padding: const EdgeInsets.only(left: 20),
|
||||
child: Text(
|
||||
'媒体库',
|
||||
style: TextStyle(
|
||||
fontSize: theme.textTheme.titleLarge!.fontSize,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
trailing: IconButton(
|
||||
tooltip: '设置',
|
||||
onPressed: () => Get.toNamed('/setting'),
|
||||
icon: const Icon(
|
||||
Icons.settings_outlined,
|
||||
size: 20,
|
||||
),
|
||||
),
|
||||
),
|
||||
for (var item in controller.list)
|
||||
ListTile(
|
||||
onTap: item.onTap,
|
||||
dense: true,
|
||||
leading: Padding(
|
||||
padding: const EdgeInsets.only(left: 15),
|
||||
child: Icon(
|
||||
item.icon,
|
||||
color: primary,
|
||||
),
|
||||
),
|
||||
contentPadding: const EdgeInsets.only(
|
||||
left: 15,
|
||||
top: 2,
|
||||
bottom: 2,
|
||||
),
|
||||
minLeadingWidth: 0,
|
||||
title: Text(
|
||||
item.title,
|
||||
style: const TextStyle(fontSize: 15),
|
||||
),
|
||||
),
|
||||
Obx(
|
||||
() => controller.loadingState.value is Loading
|
||||
? const SizedBox.shrink()
|
||||
: favFolder(theme),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget favFolder(ThemeData theme) {
|
||||
return Column(
|
||||
children: [
|
||||
Divider(
|
||||
height: 20,
|
||||
color: theme.dividerColor.withValues(alpha: 0.1),
|
||||
),
|
||||
ListTile(
|
||||
onTap: () async {
|
||||
await Get.toNamed('/fav');
|
||||
Future.delayed(const Duration(milliseconds: 150), () {
|
||||
controller.onRefresh();
|
||||
});
|
||||
},
|
||||
dense: true,
|
||||
title: Padding(
|
||||
padding: const EdgeInsets.only(left: 10),
|
||||
child: Obx(
|
||||
() {
|
||||
final count = controller.count.value;
|
||||
return Text.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text: '我的收藏 ',
|
||||
style: TextStyle(
|
||||
fontSize: theme.textTheme.titleMedium!.fontSize,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
if (count != -1)
|
||||
TextSpan(
|
||||
text: "$count ",
|
||||
style: TextStyle(
|
||||
fontSize: theme.textTheme.titleSmall!.fontSize,
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
),
|
||||
WidgetSpan(
|
||||
child: Icon(
|
||||
Icons.arrow_forward_ios,
|
||||
size: 18,
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
trailing: IconButton(
|
||||
tooltip: '刷新',
|
||||
onPressed: controller.onRefresh,
|
||||
icon: const Icon(Icons.refresh, size: 20),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
height: 200,
|
||||
child: Obx(() => _buildBody(theme, controller.loadingState.value)),
|
||||
),
|
||||
const SizedBox(height: 100),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBody(ThemeData theme, LoadingState loadingState) {
|
||||
return switch (loadingState) {
|
||||
Loading() => const SizedBox.shrink(),
|
||||
Success(:var response) => Builder(
|
||||
builder: (context) {
|
||||
List<FavFolderInfo>? favFolderList = response.list;
|
||||
if (favFolderList.isNullOrEmpty) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
bool flag = controller.count.value > favFolderList!.length;
|
||||
return ListView.separated(
|
||||
padding: const EdgeInsets.only(left: 20),
|
||||
itemCount: response.list.length + (flag ? 1 : 0),
|
||||
itemBuilder: (context, index) {
|
||||
if (flag && index == favFolderList.length) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(right: 14, bottom: 35),
|
||||
child: Center(
|
||||
child: IconButton(
|
||||
tooltip: '查看更多',
|
||||
style: ButtonStyle(
|
||||
padding: WidgetStateProperty.all(EdgeInsets.zero),
|
||||
backgroundColor: WidgetStateProperty.resolveWith((
|
||||
states,
|
||||
) {
|
||||
return theme.colorScheme.primaryContainer.withValues(
|
||||
alpha: 0.5,
|
||||
);
|
||||
}),
|
||||
),
|
||||
onPressed: () async {
|
||||
await Get.toNamed('/fav');
|
||||
Future.delayed(const Duration(milliseconds: 150), () {
|
||||
controller.onRefresh();
|
||||
});
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.arrow_forward_ios,
|
||||
size: 18,
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return FavFolderItem(
|
||||
heroTag: Utils.generateRandomString(8),
|
||||
item: response.list[index],
|
||||
callback: () => Future.delayed(
|
||||
const Duration(milliseconds: 150),
|
||||
controller.onRefresh,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
scrollDirection: Axis.horizontal,
|
||||
separatorBuilder: (context, index) => const SizedBox(width: 14),
|
||||
);
|
||||
},
|
||||
),
|
||||
Error(:var errMsg) => SizedBox(
|
||||
height: 160,
|
||||
child: Center(
|
||||
child: Text(
|
||||
errMsg ?? '',
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -47,7 +47,10 @@ class _MemberDynamicsPageState extends State<MemberDynamicsPage>
|
||||
return widget.mid == null
|
||||
? Scaffold(
|
||||
appBar: AppBar(title: const Text('我的动态')),
|
||||
body: _buildBody,
|
||||
body: SafeArea(
|
||||
bottom: false,
|
||||
child: _buildBody,
|
||||
),
|
||||
)
|
||||
: _buildBody;
|
||||
}
|
||||
|
||||
@@ -531,9 +531,7 @@ class _EditProfilePageState extends State<EditProfilePage> {
|
||||
.then((res) {
|
||||
if (res.data['code'] == 0) {
|
||||
SmartDialog.showToast('修改成功');
|
||||
Future.delayed(
|
||||
const Duration(milliseconds: 500),
|
||||
).whenComplete(_getInfo);
|
||||
Future.delayed(const Duration(milliseconds: 500), _getInfo);
|
||||
} else {
|
||||
SmartDialog.showToast(res.data['message']);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
import 'package:PiliPlus/http/fav.dart';
|
||||
import 'package:PiliPlus/http/loading_state.dart';
|
||||
import 'package:PiliPlus/http/user.dart';
|
||||
import 'package:PiliPlus/models/common/account_type.dart';
|
||||
import 'package:PiliPlus/models/common/theme/theme_type.dart';
|
||||
import 'package:PiliPlus/models/user/info.dart';
|
||||
import 'package:PiliPlus/models/user/stat.dart';
|
||||
import 'package:PiliPlus/models_new/fav/fav_folder/data.dart';
|
||||
import 'package:PiliPlus/pages/common/common_data_controller.dart';
|
||||
import 'package:PiliPlus/services/account_service.dart';
|
||||
import 'package:PiliPlus/utils/accounts.dart';
|
||||
import 'package:PiliPlus/utils/accounts/account.dart';
|
||||
@@ -14,14 +18,17 @@ import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
|
||||
|
||||
class MineController extends GetxController {
|
||||
class MineController
|
||||
extends CommonDataController<FavFolderData, FavFolderData> {
|
||||
AccountService accountService = Get.find<AccountService>();
|
||||
|
||||
int? favFoldercount;
|
||||
|
||||
// 用户信息 头像、昵称、lv
|
||||
Rx<UserInfoData> userInfo = UserInfoData().obs;
|
||||
// 用户状态 动态、关注、粉丝
|
||||
Rx<UserStat> userStat = UserStat().obs;
|
||||
|
||||
AccountService accountService = Get.find<AccountService>();
|
||||
|
||||
Rx<ThemeType> themeType = ThemeType.system.obs;
|
||||
static RxBool anonymity =
|
||||
(Accounts.account.isNotEmpty &&
|
||||
@@ -30,33 +37,73 @@ class MineController extends GetxController {
|
||||
ThemeType get nextThemeType =>
|
||||
ThemeType.values[(themeType.value.index + 1) % ThemeType.values.length];
|
||||
|
||||
late final list = <({IconData icon, String title, VoidCallback onTap})>[
|
||||
(
|
||||
icon: Icons.history,
|
||||
title: '观看记录',
|
||||
onTap: () {
|
||||
if (isLogin) {
|
||||
Get.toNamed('/history');
|
||||
}
|
||||
},
|
||||
),
|
||||
(
|
||||
icon: Icons.subscriptions_outlined,
|
||||
title: '我的订阅',
|
||||
onTap: () {
|
||||
if (isLogin) {
|
||||
Get.toNamed('/subscription');
|
||||
}
|
||||
},
|
||||
),
|
||||
(
|
||||
icon: Icons.watch_later_outlined,
|
||||
title: '稍后再看',
|
||||
onTap: () {
|
||||
if (isLogin) {
|
||||
Get.toNamed('/later');
|
||||
}
|
||||
},
|
||||
),
|
||||
(
|
||||
icon: Icons.create_outlined,
|
||||
title: '创作中心',
|
||||
onTap: () {
|
||||
if (isLogin) {
|
||||
Get.toNamed(
|
||||
'/webview',
|
||||
parameters: {
|
||||
'url': 'https://member.bilibili.com/platform/home',
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
];
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
UserInfoData? userInfoCache = GStorage.userInfo.get('userInfoCache');
|
||||
if (userInfoCache != null) {
|
||||
userInfo.value = userInfoCache;
|
||||
queryData();
|
||||
queryUserInfo();
|
||||
}
|
||||
}
|
||||
|
||||
void onLogin([bool longPress = false]) {
|
||||
if (!accountService.isLogin.value || longPress) {
|
||||
Get.toNamed('/loginPage', preventDuplicates: false);
|
||||
} else {
|
||||
Get.toNamed(
|
||||
'/member?mid=${userInfo.value.mid}',
|
||||
preventDuplicates: false,
|
||||
);
|
||||
bool get isLogin {
|
||||
if (!accountService.isLogin.value) {
|
||||
// SmartDialog.showToast('账号未登录');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Future<void> queryUserInfo() async {
|
||||
if (!accountService.isLogin.value) {
|
||||
return;
|
||||
}
|
||||
var res = await UserHttp.userInfo();
|
||||
if (res['status']) {
|
||||
UserInfoData data = res['data'];
|
||||
if (res.isSuccess) {
|
||||
UserInfoData data = res.data;
|
||||
if (data.isLogin == true) {
|
||||
userInfo.value = data;
|
||||
GStorage.userInfo.put('userInfoCache', data);
|
||||
@@ -70,8 +117,9 @@ class MineController extends GetxController {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
SmartDialog.showToast(res['msg']);
|
||||
if (res['msg'] == '账号未登录') {
|
||||
final errMsg = res.toString();
|
||||
SmartDialog.showToast(errMsg);
|
||||
if (errMsg == '账号未登录') {
|
||||
LoginUtils.onLogoutMain();
|
||||
return;
|
||||
}
|
||||
@@ -86,6 +134,22 @@ class MineController extends GetxController {
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
bool customHandleResponse(bool isRefresh, Success<FavFolderData> response) {
|
||||
favFoldercount = response.response.count;
|
||||
loadingState.value = response;
|
||||
return true;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<LoadingState<FavFolderData>> customGetData() {
|
||||
return FavHttp.userfavFolder(
|
||||
pn: 1,
|
||||
ps: 5,
|
||||
mid: accountService.mid,
|
||||
);
|
||||
}
|
||||
|
||||
static void onChangeAnonymity() {
|
||||
if (Accounts.account.isEmpty) {
|
||||
SmartDialog.showToast('请先登录');
|
||||
@@ -202,37 +266,31 @@ class MineController extends GetxController {
|
||||
void onChangeTheme() {
|
||||
final newVal = nextThemeType;
|
||||
themeType.value = newVal;
|
||||
try {
|
||||
Get.find<MineController>().themeType.value = newVal;
|
||||
} catch (_) {}
|
||||
GStorage.setting.put(SettingBoxKey.themeMode, newVal.index);
|
||||
Get.changeThemeMode(newVal.toThemeMode);
|
||||
}
|
||||
|
||||
void pushFollow() {
|
||||
if (!accountService.isLogin.value) {
|
||||
SmartDialog.showToast('账号未登录');
|
||||
return;
|
||||
void push(String name) {
|
||||
late final mid = userInfo.value.mid;
|
||||
if (isLogin && mid != null) {
|
||||
Get.toNamed('/$name?mid=$mid');
|
||||
}
|
||||
Get.toNamed('/follow?mid=${userInfo.value.mid}', preventDuplicates: false);
|
||||
}
|
||||
|
||||
void pushFans() {
|
||||
if (!accountService.isLogin.value) {
|
||||
SmartDialog.showToast('账号未登录');
|
||||
return;
|
||||
void onLogin([bool longPress = false]) {
|
||||
if (!accountService.isLogin.value || longPress) {
|
||||
Get.toNamed('/loginPage');
|
||||
} else {
|
||||
Get.toNamed('/member?mid=${userInfo.value.mid}');
|
||||
}
|
||||
Get.toNamed('/fan?mid=${userInfo.value.mid}', preventDuplicates: false);
|
||||
}
|
||||
|
||||
void pushDynamic() {
|
||||
@override
|
||||
Future<void> onRefresh() {
|
||||
if (!accountService.isLogin.value) {
|
||||
SmartDialog.showToast('账号未登录');
|
||||
return;
|
||||
return Future.value();
|
||||
}
|
||||
Get.toNamed(
|
||||
'/memberDynamics?mid=${userInfo.value.mid}',
|
||||
preventDuplicates: false,
|
||||
);
|
||||
queryUserInfo();
|
||||
return super.onRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,121 +1,208 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:PiliPlus/common/constants.dart';
|
||||
import 'package:PiliPlus/common/widgets/image/network_img_layer.dart';
|
||||
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
|
||||
import 'package:PiliPlus/http/loading_state.dart';
|
||||
import 'package:PiliPlus/models/common/image_type.dart';
|
||||
import 'package:PiliPlus/models/common/nav_bar_config.dart';
|
||||
import 'package:PiliPlus/models/user/info.dart';
|
||||
import 'package:PiliPlus/models_new/fav/fav_folder/list.dart';
|
||||
import 'package:PiliPlus/pages/common/common_page.dart';
|
||||
import 'package:PiliPlus/pages/login/controller.dart';
|
||||
import 'package:PiliPlus/pages/main/controller.dart';
|
||||
import 'package:PiliPlus/pages/mine/controller.dart';
|
||||
import 'package:PiliPlus/pages/mine/widgets/item.dart';
|
||||
import 'package:PiliPlus/utils/extension.dart';
|
||||
import 'package:PiliPlus/utils/utils.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
|
||||
|
||||
class MinePage extends StatefulWidget {
|
||||
class MinePage extends CommonPage {
|
||||
const MinePage({super.key});
|
||||
|
||||
@override
|
||||
State<MinePage> createState() => _MinePageState();
|
||||
State<MinePage> createState() => _MediaPageState();
|
||||
}
|
||||
|
||||
class _MinePageState extends State<MinePage> {
|
||||
final MineController _mineController = Get.put(MineController())
|
||||
..queryUserInfo();
|
||||
class _MediaPageState extends CommonPageState<MinePage, MineController>
|
||||
with AutomaticKeepAliveClientMixin {
|
||||
@override
|
||||
MineController controller = Get.put(MineController());
|
||||
late final MainController _mainController = Get.find<MainController>();
|
||||
|
||||
Widget _header(ThemeData theme) => Row(
|
||||
children: [
|
||||
const SizedBox(width: 12),
|
||||
Image.asset(
|
||||
'assets/images/logo/logo.png',
|
||||
width: 35,
|
||||
),
|
||||
const SizedBox(width: 5),
|
||||
Text(
|
||||
'PiliPlus',
|
||||
style: theme.textTheme.titleMedium,
|
||||
),
|
||||
const Spacer(),
|
||||
Obx(
|
||||
() {
|
||||
final anonymity = MineController.anonymity.value;
|
||||
return IconButton(
|
||||
iconSize: 40.0,
|
||||
padding: const EdgeInsets.all(8),
|
||||
style: const ButtonStyle(
|
||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
),
|
||||
tooltip: "${anonymity ? '退出' : '进入'}无痕模式",
|
||||
onPressed: MineController.onChangeAnonymity,
|
||||
icon: anonymity
|
||||
? const Icon(MdiIcons.incognito, size: 24)
|
||||
: const Icon(MdiIcons.incognitoOff, size: 24),
|
||||
);
|
||||
},
|
||||
),
|
||||
Obx(
|
||||
() {
|
||||
return IconButton(
|
||||
iconSize: 40.0,
|
||||
padding: const EdgeInsets.all(8),
|
||||
style: const ButtonStyle(
|
||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
),
|
||||
tooltip: '切换至${_mineController.nextThemeType.desc}主题',
|
||||
onPressed: _mineController.onChangeTheme,
|
||||
icon: _mineController.themeType.value.icon,
|
||||
);
|
||||
},
|
||||
),
|
||||
IconButton(
|
||||
iconSize: 40.0,
|
||||
padding: const EdgeInsets.all(8),
|
||||
style: const ButtonStyle(
|
||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
),
|
||||
tooltip: '设置',
|
||||
onPressed: () => {
|
||||
Get.back(),
|
||||
Get.toNamed('/setting', preventDuplicates: false),
|
||||
},
|
||||
icon: const Icon(MdiIcons.cogs, size: 24),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
],
|
||||
);
|
||||
@override
|
||||
bool get wantKeepAlive => true;
|
||||
|
||||
@override
|
||||
void listener() {
|
||||
if (_mainController.navigationBars[0] != NavigationBarType.mine &&
|
||||
_mainController.selectedIndex.value == 0) {
|
||||
return;
|
||||
}
|
||||
super.listener();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
super.build(context);
|
||||
final theme = Theme.of(context);
|
||||
return IntrinsicWidth(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const SizedBox(height: 8),
|
||||
_header(theme),
|
||||
const SizedBox(height: 10),
|
||||
userInfoBuild(theme),
|
||||
],
|
||||
),
|
||||
return Column(
|
||||
children: [
|
||||
const SizedBox(height: 10),
|
||||
_buildHeaderActions,
|
||||
const SizedBox(height: 10),
|
||||
Expanded(
|
||||
child: refreshIndicator(
|
||||
onRefresh: controller.onRefresh,
|
||||
child: ListView(
|
||||
controller: controller.scrollController,
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
children: [
|
||||
_buildUserInfo(theme),
|
||||
_buildActions(theme.colorScheme.primary),
|
||||
Obx(
|
||||
() => controller.loadingState.value is Loading
|
||||
? const SizedBox.shrink()
|
||||
: _buildFav(theme),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget userInfoBuild(ThemeData theme) {
|
||||
TextStyle style = TextStyle(
|
||||
Widget _buildActions(Color primary) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: controller.list
|
||||
.map(
|
||||
(e) => InkWell(
|
||||
onTap: e.onTap,
|
||||
borderRadius: StyleString.mdRadius,
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 80),
|
||||
child: AspectRatio(
|
||||
aspectRatio: 1,
|
||||
child: Column(
|
||||
spacing: 6,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
size: 22,
|
||||
e.icon,
|
||||
color: primary,
|
||||
),
|
||||
Text(
|
||||
e.title,
|
||||
style: const TextStyle(fontSize: 13),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
);
|
||||
}
|
||||
|
||||
Widget get _buildHeaderActions {
|
||||
return Row(
|
||||
spacing: 5,
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
Obx(
|
||||
() {
|
||||
final anonymity = MineController.anonymity.value;
|
||||
return IconButton(
|
||||
iconSize: 22,
|
||||
padding: const EdgeInsets.all(8),
|
||||
style: const ButtonStyle(
|
||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
),
|
||||
tooltip: "${anonymity ? '退出' : '进入'}无痕模式",
|
||||
onPressed: MineController.onChangeAnonymity,
|
||||
icon: anonymity
|
||||
? const Icon(MdiIcons.incognito)
|
||||
: const Icon(MdiIcons.incognitoOff),
|
||||
);
|
||||
},
|
||||
),
|
||||
IconButton(
|
||||
iconSize: 22,
|
||||
padding: const EdgeInsets.all(8),
|
||||
style: const ButtonStyle(
|
||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
),
|
||||
tooltip: '设置账号模式',
|
||||
onPressed: () => LoginPageController.switchAccountDialog(context),
|
||||
icon: const Icon(Icons.switch_account_outlined),
|
||||
),
|
||||
Obx(
|
||||
() {
|
||||
return IconButton(
|
||||
iconSize: 22,
|
||||
padding: const EdgeInsets.all(8),
|
||||
style: const ButtonStyle(
|
||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
),
|
||||
tooltip: '切换至${controller.nextThemeType.desc}主题',
|
||||
onPressed: controller.onChangeTheme,
|
||||
icon: controller.themeType.value.icon,
|
||||
);
|
||||
},
|
||||
),
|
||||
IconButton(
|
||||
iconSize: 22,
|
||||
padding: const EdgeInsets.all(8),
|
||||
style: const ButtonStyle(
|
||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
),
|
||||
tooltip: '设置',
|
||||
onPressed: () => Get.toNamed('/setting', preventDuplicates: false),
|
||||
icon: const Icon(Icons.settings_outlined),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildUserInfo(ThemeData theme) {
|
||||
final style = TextStyle(
|
||||
fontSize: theme.textTheme.titleMedium!.fontSize,
|
||||
color: theme.colorScheme.primary,
|
||||
fontWeight: FontWeight.bold,
|
||||
);
|
||||
final lebelStyle = theme.textTheme.labelMedium!.copyWith(
|
||||
color: theme.colorScheme.outline,
|
||||
);
|
||||
final coinLabelStyle = TextStyle(
|
||||
fontSize: theme.textTheme.labelMedium!.fontSize,
|
||||
color: theme.colorScheme.outline,
|
||||
);
|
||||
final coinValStyle = TextStyle(
|
||||
fontSize: theme.textTheme.labelMedium!.fontSize,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: theme.colorScheme.primary,
|
||||
);
|
||||
return Obx(() {
|
||||
final UserInfoData userInfo = _mineController.userInfo.value;
|
||||
final UserInfoData userInfo = controller.userInfo.value;
|
||||
final LevelInfo? levelInfo = userInfo.levelInfo;
|
||||
final isVip = userInfo.vipStatus != null && userInfo.vipStatus! > 0;
|
||||
final userStat = _mineController.userStat.value;
|
||||
final userStat = controller.userStat.value;
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onTap: _mineController.onLogin,
|
||||
onTap: controller.onLogin,
|
||||
onLongPress: () {
|
||||
Feedback.forLongPress(context);
|
||||
_mineController.onLogin(true);
|
||||
controller.onLogin(true);
|
||||
},
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
@@ -160,11 +247,11 @@ class _MinePageState extends State<MinePage> {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
spacing: 4,
|
||||
spacing: 6,
|
||||
children: [
|
||||
Flexible(
|
||||
child: Text(
|
||||
userInfo.uname ?? '点击头像登录',
|
||||
userInfo.uname ?? '点击登录',
|
||||
style: theme.textTheme.titleMedium!.copyWith(
|
||||
height: 1,
|
||||
color: isVip && userInfo.vipType == 2
|
||||
@@ -184,69 +271,44 @@ class _MinePageState extends State<MinePage> {
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
FittedBox(
|
||||
child: Text.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text: '硬币 ',
|
||||
style: TextStyle(
|
||||
fontSize:
|
||||
theme.textTheme.labelSmall!.fontSize,
|
||||
color: theme.colorScheme.outline,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: userInfo.money?.toString() ?? '-',
|
||||
style: TextStyle(
|
||||
fontSize:
|
||||
theme.textTheme.labelSmall!.fontSize,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: " 经验 ",
|
||||
style: TextStyle(
|
||||
fontSize:
|
||||
theme.textTheme.labelSmall!.fontSize,
|
||||
color: theme.colorScheme.outline,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: "${levelInfo?.currentExp ?? '-'}",
|
||||
semanticsLabel:
|
||||
"当前${levelInfo?.currentExp ?? '-'}",
|
||||
style: TextStyle(
|
||||
fontSize:
|
||||
theme.textTheme.labelSmall!.fontSize,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: "/${levelInfo?.nextExp ?? '-'}",
|
||||
semanticsLabel:
|
||||
"升级需${levelInfo?.nextExp ?? '-'}",
|
||||
style: TextStyle(
|
||||
fontSize:
|
||||
theme.textTheme.labelSmall!.fontSize,
|
||||
color: theme.colorScheme.outline,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Text.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text: '硬币 ',
|
||||
style: coinLabelStyle,
|
||||
),
|
||||
TextSpan(
|
||||
text: userInfo.money?.toString() ?? '-',
|
||||
style: coinValStyle,
|
||||
),
|
||||
TextSpan(
|
||||
text: " 经验 ",
|
||||
style: coinLabelStyle,
|
||||
),
|
||||
TextSpan(
|
||||
text: levelInfo?.currentExp?.toString() ?? '-',
|
||||
style: coinValStyle,
|
||||
),
|
||||
TextSpan(
|
||||
text: "/${levelInfo?.nextExp ?? '-'}",
|
||||
style: coinLabelStyle,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
LinearProgressIndicator(
|
||||
minHeight: 2,
|
||||
value: levelInfo != null
|
||||
? (levelInfo.currentExp! / levelInfo.nextExp!)
|
||||
: 0,
|
||||
backgroundColor: theme.colorScheme.inversePrimary,
|
||||
valueColor: AlwaysStoppedAnimation<Color>(
|
||||
theme.colorScheme.primary,
|
||||
ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 225),
|
||||
child: LinearProgressIndicator(
|
||||
minHeight: 2.25,
|
||||
value: levelInfo != null
|
||||
? (levelInfo.currentExp! / levelInfo.nextExp!)
|
||||
: 0,
|
||||
backgroundColor: theme.colorScheme.inversePrimary,
|
||||
valueColor: AlwaysStoppedAnimation<Color>(
|
||||
theme.colorScheme.primary,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -257,37 +319,32 @@ class _MinePageState extends State<MinePage> {
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Center(
|
||||
child: SizedBox(
|
||||
width: 240,
|
||||
child: Row(
|
||||
children: [
|
||||
_btn(
|
||||
count: userStat.dynamicCount,
|
||||
countStyle: style,
|
||||
name: '动态',
|
||||
nameStyle: theme.textTheme.labelMedium,
|
||||
onTap: _mineController.pushDynamic,
|
||||
),
|
||||
_btn(
|
||||
count: userStat.following,
|
||||
countStyle: style,
|
||||
name: '关注',
|
||||
nameStyle: theme.textTheme.labelMedium,
|
||||
onTap: _mineController.pushFollow,
|
||||
),
|
||||
_btn(
|
||||
count: userStat.follower,
|
||||
countStyle: style,
|
||||
name: '粉丝',
|
||||
nameStyle: theme.textTheme.labelMedium,
|
||||
onTap: _mineController.pushFans,
|
||||
),
|
||||
],
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
_btn(
|
||||
count: userStat.dynamicCount,
|
||||
countStyle: style,
|
||||
name: '动态',
|
||||
lebelStyle: lebelStyle,
|
||||
onTap: () => controller.push('memberDynamics'),
|
||||
),
|
||||
),
|
||||
_btn(
|
||||
count: userStat.following,
|
||||
countStyle: style,
|
||||
name: '关注',
|
||||
lebelStyle: lebelStyle,
|
||||
onTap: () => controller.push('follow'),
|
||||
),
|
||||
_btn(
|
||||
count: userStat.follower,
|
||||
countStyle: style,
|
||||
name: '粉丝',
|
||||
lebelStyle: lebelStyle,
|
||||
onTap: () => controller.push('fan'),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
],
|
||||
);
|
||||
});
|
||||
@@ -297,31 +354,165 @@ class _MinePageState extends State<MinePage> {
|
||||
required int? count,
|
||||
required TextStyle countStyle,
|
||||
required String name,
|
||||
required TextStyle? nameStyle,
|
||||
required TextStyle? lebelStyle,
|
||||
required VoidCallback onTap,
|
||||
}) {
|
||||
return InkWell(
|
||||
onTap: onTap,
|
||||
borderRadius: StyleString.mdRadius,
|
||||
child: SizedBox(
|
||||
width: 80,
|
||||
height: 80,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
count?.toString() ?? '-',
|
||||
style: countStyle,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
name,
|
||||
style: nameStyle,
|
||||
),
|
||||
],
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 80),
|
||||
child: AspectRatio(
|
||||
aspectRatio: 1,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
count?.toString() ?? '-',
|
||||
style: countStyle,
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
name,
|
||||
style: lebelStyle,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildFav(ThemeData theme) {
|
||||
return Column(
|
||||
children: [
|
||||
Divider(
|
||||
height: 20,
|
||||
color: theme.dividerColor.withValues(alpha: 0.1),
|
||||
),
|
||||
ListTile(
|
||||
onTap: () => Get.toNamed('/fav')?.whenComplete(
|
||||
() => Future.delayed(
|
||||
const Duration(milliseconds: 150),
|
||||
controller.onRefresh,
|
||||
),
|
||||
),
|
||||
dense: true,
|
||||
title: Padding(
|
||||
padding: const EdgeInsets.only(left: 10),
|
||||
child: Text.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text: '我的收藏 ',
|
||||
style: TextStyle(
|
||||
fontSize: theme.textTheme.titleMedium!.fontSize,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
if (controller.favFoldercount != null)
|
||||
TextSpan(
|
||||
text: "${controller.favFoldercount} ",
|
||||
style: TextStyle(
|
||||
fontSize: theme.textTheme.titleSmall!.fontSize,
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
),
|
||||
WidgetSpan(
|
||||
child: Icon(
|
||||
Icons.arrow_forward_ios,
|
||||
size: 18,
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
trailing: IconButton(
|
||||
tooltip: '刷新',
|
||||
onPressed: controller.onRefresh,
|
||||
icon: const Icon(Icons.refresh, size: 20),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
height: 200,
|
||||
child: _buildFavBody(theme, controller.loadingState.value),
|
||||
),
|
||||
const SizedBox(height: 100),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildFavBody(ThemeData theme, LoadingState loadingState) {
|
||||
return switch (loadingState) {
|
||||
Loading() => const SizedBox.shrink(),
|
||||
Success(:var response) => Builder(
|
||||
builder: (context) {
|
||||
List<FavFolderInfo>? favFolderList = response.list;
|
||||
if (favFolderList.isNullOrEmpty) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
bool flag = (controller.favFoldercount ?? 0) > favFolderList!.length;
|
||||
return ListView.separated(
|
||||
padding: const EdgeInsets.only(left: 20),
|
||||
itemCount: response.list.length + (flag ? 1 : 0),
|
||||
itemBuilder: (context, index) {
|
||||
if (flag && index == favFolderList.length) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(right: 14, bottom: 35),
|
||||
child: Center(
|
||||
child: IconButton(
|
||||
tooltip: '查看更多',
|
||||
style: ButtonStyle(
|
||||
padding: WidgetStateProperty.all(EdgeInsets.zero),
|
||||
backgroundColor: WidgetStatePropertyAll(
|
||||
theme.colorScheme.primaryContainer.withValues(
|
||||
alpha: 0.5,
|
||||
),
|
||||
),
|
||||
),
|
||||
onPressed: () => Get.toNamed('/fav')?.whenComplete(
|
||||
() => Future.delayed(
|
||||
const Duration(milliseconds: 150),
|
||||
controller.onRefresh,
|
||||
),
|
||||
),
|
||||
icon: Icon(
|
||||
Icons.arrow_forward_ios,
|
||||
size: 18,
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return FavFolderItem(
|
||||
heroTag: Utils.generateRandomString(8),
|
||||
item: response.list[index],
|
||||
callback: () => Future.delayed(
|
||||
const Duration(milliseconds: 150),
|
||||
controller.onRefresh,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
scrollDirection: Axis.horizontal,
|
||||
separatorBuilder: (context, index) => const SizedBox(width: 14),
|
||||
);
|
||||
},
|
||||
),
|
||||
Error(:var errMsg) => SizedBox(
|
||||
height: 160,
|
||||
child: Center(
|
||||
child: Text(
|
||||
errMsg ?? '',
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,7 +99,8 @@ List<SettingsModel> get extraSettings => [
|
||||
SettingBoxKey.dynamicPeriod,
|
||||
dynamicPeriod,
|
||||
);
|
||||
Get.find<MainController>().dynamicPeriod = dynamicPeriod;
|
||||
Get.find<MainController>().dynamicPeriod =
|
||||
dynamicPeriod * 60 * 1000;
|
||||
},
|
||||
child: const Text('确定'),
|
||||
),
|
||||
|
||||
@@ -91,7 +91,8 @@ class _SetDisplayModeState extends State<SetDisplayMode> {
|
||||
).whenComplete(
|
||||
() => Future.delayed(
|
||||
const Duration(milliseconds: 100),
|
||||
).whenComplete(fetchAll),
|
||||
fetchAll,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -592,9 +592,7 @@ class VideoIntroController extends CommonIntroController with ReloadMixin {
|
||||
followStatus: followStatus,
|
||||
callback: (attribute) {
|
||||
followStatus['attribute'] = attribute;
|
||||
Future.delayed(const Duration(milliseconds: 500), () {
|
||||
queryFollowStatus();
|
||||
});
|
||||
Future.delayed(const Duration(milliseconds: 500), queryFollowStatus);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -428,9 +428,10 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
await videoDetailController.playerInit();
|
||||
}
|
||||
|
||||
Future.delayed(const Duration(milliseconds: 600), () {
|
||||
AutoOrientation.fullAutoMode();
|
||||
});
|
||||
Future.delayed(
|
||||
const Duration(milliseconds: 600),
|
||||
AutoOrientation.fullAutoMode,
|
||||
);
|
||||
plPlayerController?.addStatusLister(playerListener);
|
||||
plPlayerController?.addPositionListener(positionListener);
|
||||
}
|
||||
|
||||
@@ -2163,14 +2163,9 @@ class HeaderControlState extends State<HeaderControl> {
|
||||
children: [
|
||||
TextButton(
|
||||
style: ButtonStyle(
|
||||
foregroundColor:
|
||||
WidgetStateProperty.resolveWith((
|
||||
states,
|
||||
) {
|
||||
return theme
|
||||
.snackBarTheme
|
||||
.actionTextColor;
|
||||
}),
|
||||
foregroundColor: WidgetStatePropertyAll(
|
||||
theme.snackBarTheme.actionTextColor,
|
||||
),
|
||||
),
|
||||
onPressed: () {
|
||||
plPlayerController.setBackgroundPlay(
|
||||
@@ -2183,14 +2178,9 @@ class HeaderControlState extends State<HeaderControl> {
|
||||
const SizedBox(width: 10),
|
||||
TextButton(
|
||||
style: ButtonStyle(
|
||||
foregroundColor:
|
||||
WidgetStateProperty.resolveWith((
|
||||
states,
|
||||
) {
|
||||
return theme
|
||||
.snackBarTheme
|
||||
.actionTextColor;
|
||||
}),
|
||||
foregroundColor: WidgetStatePropertyAll(
|
||||
theme.snackBarTheme.actionTextColor,
|
||||
),
|
||||
),
|
||||
onPressed: () {},
|
||||
child: const Text('不启用'),
|
||||
@@ -2203,7 +2193,7 @@ class HeaderControlState extends State<HeaderControl> {
|
||||
showCloseIcon: true,
|
||||
),
|
||||
);
|
||||
await Future.delayed(const Duration(seconds: 3), () {});
|
||||
await Future.delayed(const Duration(seconds: 3));
|
||||
}
|
||||
if (!context.mounted) return;
|
||||
PageUtils.enterPip(
|
||||
|
||||
Reference in New Issue
Block a user