mirror of
https://github.com/HChaZZY/PiliPlus.git
synced 2025-12-17 07:36:14 +08:00
opt member page
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
@@ -1,180 +0,0 @@
|
|||||||
import 'package:flutter/foundation.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
|
|
||||||
/// https://github.com/flutter/flutter/issues/18345#issuecomment-1627644396
|
|
||||||
class DynamicSliverAppBar extends StatefulWidget {
|
|
||||||
const DynamicSliverAppBar({
|
|
||||||
this.flexibleSpace,
|
|
||||||
super.key,
|
|
||||||
this.leading,
|
|
||||||
this.automaticallyImplyLeading = true,
|
|
||||||
this.title,
|
|
||||||
this.actions,
|
|
||||||
this.bottom,
|
|
||||||
this.elevation,
|
|
||||||
this.scrolledUnderElevation,
|
|
||||||
this.shadowColor,
|
|
||||||
this.surfaceTintColor,
|
|
||||||
this.forceElevated = false,
|
|
||||||
this.backgroundColor,
|
|
||||||
this.backgroundGradient,
|
|
||||||
this.foregroundColor,
|
|
||||||
this.iconTheme,
|
|
||||||
this.actionsIconTheme,
|
|
||||||
this.primary = true,
|
|
||||||
this.centerTitle,
|
|
||||||
this.excludeHeaderSemantics = false,
|
|
||||||
this.titleSpacing,
|
|
||||||
this.collapsedHeight,
|
|
||||||
this.expandedHeight,
|
|
||||||
this.floating = false,
|
|
||||||
this.pinned = false,
|
|
||||||
this.snap = false,
|
|
||||||
this.stretch = false,
|
|
||||||
this.stretchTriggerOffset = 100.0,
|
|
||||||
this.onStretchTrigger,
|
|
||||||
this.shape,
|
|
||||||
this.toolbarHeight = kToolbarHeight,
|
|
||||||
this.leadingWidth,
|
|
||||||
this.toolbarTextStyle,
|
|
||||||
this.titleTextStyle,
|
|
||||||
this.systemOverlayStyle,
|
|
||||||
this.forceMaterialTransparency = false,
|
|
||||||
this.clipBehavior,
|
|
||||||
this.appBarClipper,
|
|
||||||
this.callback,
|
|
||||||
});
|
|
||||||
|
|
||||||
final ValueChanged<double>? callback;
|
|
||||||
final Widget? flexibleSpace;
|
|
||||||
final Widget? leading;
|
|
||||||
final bool automaticallyImplyLeading;
|
|
||||||
final Widget? title;
|
|
||||||
final List<Widget>? actions;
|
|
||||||
final PreferredSizeWidget? bottom;
|
|
||||||
final double? elevation;
|
|
||||||
final double? scrolledUnderElevation;
|
|
||||||
final Color? shadowColor;
|
|
||||||
final Color? surfaceTintColor;
|
|
||||||
final bool forceElevated;
|
|
||||||
final Color? backgroundColor;
|
|
||||||
|
|
||||||
/// If backgroundGradient is non null, backgroundColor will be ignored
|
|
||||||
final LinearGradient? backgroundGradient;
|
|
||||||
final Color? foregroundColor;
|
|
||||||
final IconThemeData? iconTheme;
|
|
||||||
final IconThemeData? actionsIconTheme;
|
|
||||||
final bool primary;
|
|
||||||
final bool? centerTitle;
|
|
||||||
final bool excludeHeaderSemantics;
|
|
||||||
final double? titleSpacing;
|
|
||||||
final double? expandedHeight;
|
|
||||||
final double? collapsedHeight;
|
|
||||||
final bool floating;
|
|
||||||
final bool pinned;
|
|
||||||
final ShapeBorder? shape;
|
|
||||||
final double toolbarHeight;
|
|
||||||
final double? leadingWidth;
|
|
||||||
final TextStyle? toolbarTextStyle;
|
|
||||||
final TextStyle? titleTextStyle;
|
|
||||||
final SystemUiOverlayStyle? systemOverlayStyle;
|
|
||||||
final bool forceMaterialTransparency;
|
|
||||||
final Clip? clipBehavior;
|
|
||||||
final bool snap;
|
|
||||||
final bool stretch;
|
|
||||||
final double stretchTriggerOffset;
|
|
||||||
final AsyncCallback? onStretchTrigger;
|
|
||||||
final CustomClipper<Path>? appBarClipper;
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<DynamicSliverAppBar> createState() => _DynamicSliverAppBarState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _DynamicSliverAppBarState extends State<DynamicSliverAppBar> {
|
|
||||||
final GlobalKey _childKey = GlobalKey();
|
|
||||||
|
|
||||||
// As long as the height is 0 instead of the sliver app bar a sliver to box adapter will be used
|
|
||||||
// to calculate dynamically the size for the sliver app bar
|
|
||||||
double _height = 0;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
_updateHeight();
|
|
||||||
}
|
|
||||||
|
|
||||||
void _updateHeight() {
|
|
||||||
// Gets the new height and updates the sliver app bar. Needs to be called after the last frame has been rebuild
|
|
||||||
// otherwise this will throw an error
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
|
|
||||||
if (_childKey.currentContext == null) return;
|
|
||||||
setState(() {
|
|
||||||
_height = (_childKey.currentContext!.findRenderObject()! as RenderBox)
|
|
||||||
.size
|
|
||||||
.height;
|
|
||||||
widget.callback?.call(_height);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void didChangeDependencies() {
|
|
||||||
_height = 0;
|
|
||||||
_updateHeight();
|
|
||||||
super.didChangeDependencies();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
//Needed to lay out the flexibleSpace the first time, so we can calculate its intrinsic height
|
|
||||||
if (_height == 0) {
|
|
||||||
return SliverToBoxAdapter(
|
|
||||||
child: SizedBox(
|
|
||||||
key: _childKey,
|
|
||||||
child: widget.flexibleSpace ?? const SizedBox(height: kToolbarHeight),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
MediaQuery.orientationOf(context);
|
|
||||||
|
|
||||||
return SliverAppBar(
|
|
||||||
leading: widget.leading,
|
|
||||||
automaticallyImplyLeading: widget.automaticallyImplyLeading,
|
|
||||||
title: widget.title,
|
|
||||||
actions: widget.actions,
|
|
||||||
bottom: widget.bottom,
|
|
||||||
elevation: widget.elevation,
|
|
||||||
scrolledUnderElevation: widget.scrolledUnderElevation,
|
|
||||||
shadowColor: widget.shadowColor,
|
|
||||||
surfaceTintColor: widget.surfaceTintColor,
|
|
||||||
forceElevated: widget.forceElevated,
|
|
||||||
backgroundColor: widget.backgroundColor,
|
|
||||||
foregroundColor: widget.foregroundColor,
|
|
||||||
iconTheme: widget.iconTheme,
|
|
||||||
actionsIconTheme: widget.actionsIconTheme,
|
|
||||||
primary: widget.primary,
|
|
||||||
centerTitle: widget.centerTitle,
|
|
||||||
excludeHeaderSemantics: widget.excludeHeaderSemantics,
|
|
||||||
titleSpacing: widget.titleSpacing,
|
|
||||||
collapsedHeight: widget.collapsedHeight,
|
|
||||||
floating: widget.floating,
|
|
||||||
pinned: widget.pinned,
|
|
||||||
snap: widget.snap,
|
|
||||||
stretch: widget.stretch,
|
|
||||||
stretchTriggerOffset: widget.stretchTriggerOffset,
|
|
||||||
onStretchTrigger: widget.onStretchTrigger,
|
|
||||||
shape: widget.shape,
|
|
||||||
toolbarHeight: widget.toolbarHeight,
|
|
||||||
expandedHeight: _height,
|
|
||||||
leadingWidth: widget.leadingWidth,
|
|
||||||
toolbarTextStyle: widget.toolbarTextStyle,
|
|
||||||
titleTextStyle: widget.titleTextStyle,
|
|
||||||
systemOverlayStyle: widget.systemOverlayStyle,
|
|
||||||
forceMaterialTransparency: widget.forceMaterialTransparency,
|
|
||||||
clipBehavior: widget.clipBehavior,
|
|
||||||
flexibleSpace: FlexibleSpaceBar(background: widget.flexibleSpace),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -99,12 +99,6 @@ class _DynamicSliverAppBarMediumState extends State<DynamicSliverAppBarMedium> {
|
|||||||
// to calculate dynamically the size for the sliver app bar
|
// to calculate dynamically the size for the sliver app bar
|
||||||
double _height = 0;
|
double _height = 0;
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
_updateHeight();
|
|
||||||
}
|
|
||||||
|
|
||||||
void _updateHeight() {
|
void _updateHeight() {
|
||||||
// Gets the new height and updates the sliver app bar. Needs to be called after the last frame has been rebuild
|
// Gets the new height and updates the sliver app bar. Needs to be called after the last frame has been rebuild
|
||||||
// otherwise this will throw an error
|
// otherwise this will throw an error
|
||||||
@@ -120,26 +114,39 @@ class _DynamicSliverAppBarMediumState extends State<DynamicSliverAppBarMedium> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Orientation? _orientation;
|
Orientation? _orientation;
|
||||||
|
late Size size;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
void didChangeDependencies() {
|
||||||
final orientation = MediaQuery.orientationOf(context);
|
super.didChangeDependencies();
|
||||||
|
size = MediaQuery.sizeOf(context);
|
||||||
|
final orientation = size.width > size.height
|
||||||
|
? Orientation.landscape
|
||||||
|
: Orientation.portrait;
|
||||||
if (orientation != _orientation) {
|
if (orientation != _orientation) {
|
||||||
_orientation = orientation;
|
_orientation = orientation;
|
||||||
_height = 0;
|
_height = 0;
|
||||||
_updateHeight();
|
_updateHeight();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
//Needed to lay out the flexibleSpace the first time, so we can calculate its intrinsic height
|
//Needed to lay out the flexibleSpace the first time, so we can calculate its intrinsic height
|
||||||
if (_height == 0) {
|
if (_height == 0) {
|
||||||
return SliverToBoxAdapter(
|
return SliverToBoxAdapter(
|
||||||
|
child: UnconstrainedBox(
|
||||||
|
alignment: Alignment.topLeft,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
key: _childKey,
|
key: _childKey,
|
||||||
child: widget.flexibleSpace ?? const SizedBox(height: kToolbarHeight),
|
width: size.width,
|
||||||
|
child: widget.flexibleSpace,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final padding = MediaQuery.paddingOf(context).top;
|
||||||
return SliverAppBar.medium(
|
return SliverAppBar.medium(
|
||||||
leading: widget.leading,
|
leading: widget.leading,
|
||||||
automaticallyImplyLeading: widget.automaticallyImplyLeading,
|
automaticallyImplyLeading: widget.automaticallyImplyLeading,
|
||||||
@@ -159,7 +166,6 @@ class _DynamicSliverAppBarMediumState extends State<DynamicSliverAppBarMedium> {
|
|||||||
centerTitle: widget.centerTitle,
|
centerTitle: widget.centerTitle,
|
||||||
excludeHeaderSemantics: widget.excludeHeaderSemantics,
|
excludeHeaderSemantics: widget.excludeHeaderSemantics,
|
||||||
titleSpacing: widget.titleSpacing,
|
titleSpacing: widget.titleSpacing,
|
||||||
collapsedHeight: widget.collapsedHeight,
|
|
||||||
floating: widget.floating,
|
floating: widget.floating,
|
||||||
pinned: widget.pinned,
|
pinned: widget.pinned,
|
||||||
snap: widget.snap,
|
snap: widget.snap,
|
||||||
@@ -167,8 +173,9 @@ class _DynamicSliverAppBarMediumState extends State<DynamicSliverAppBarMedium> {
|
|||||||
stretchTriggerOffset: widget.stretchTriggerOffset,
|
stretchTriggerOffset: widget.stretchTriggerOffset,
|
||||||
onStretchTrigger: widget.onStretchTrigger,
|
onStretchTrigger: widget.onStretchTrigger,
|
||||||
shape: widget.shape,
|
shape: widget.shape,
|
||||||
toolbarHeight: widget.toolbarHeight,
|
toolbarHeight: kToolbarHeight,
|
||||||
expandedHeight: _height - MediaQuery.paddingOf(context).top,
|
collapsedHeight: kToolbarHeight + padding + 1,
|
||||||
|
expandedHeight: _height - padding,
|
||||||
leadingWidth: widget.leadingWidth,
|
leadingWidth: widget.leadingWidth,
|
||||||
toolbarTextStyle: widget.toolbarTextStyle,
|
toolbarTextStyle: widget.toolbarTextStyle,
|
||||||
titleTextStyle: widget.titleTextStyle,
|
titleTextStyle: widget.titleTextStyle,
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ class _DynTopicPageState extends State<DynTopicPage> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final ThemeData theme = Theme.of(context);
|
final ThemeData theme = Theme.of(context);
|
||||||
|
final padding = MediaQuery.paddingOf(context);
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
resizeToAvoidBottomInset: false,
|
resizeToAvoidBottomInset: false,
|
||||||
floatingActionButton: FloatingActionButton.extended(
|
floatingActionButton: FloatingActionButton.extended(
|
||||||
@@ -70,7 +71,13 @@ class _DynTopicPageState extends State<DynTopicPage> {
|
|||||||
controller: _controller.scrollController,
|
controller: _controller.scrollController,
|
||||||
physics: const AlwaysScrollableScrollPhysics(),
|
physics: const AlwaysScrollableScrollPhysics(),
|
||||||
slivers: [
|
slivers: [
|
||||||
Obx(() => _buildAppBar(theme, _controller.topState.value)),
|
Obx(
|
||||||
|
() => _buildAppBar(
|
||||||
|
theme,
|
||||||
|
padding.top,
|
||||||
|
_controller.topState.value,
|
||||||
|
),
|
||||||
|
),
|
||||||
Obx(() {
|
Obx(() {
|
||||||
final allSortBy = _controller.topicSortByConf.value?.allSortBy;
|
final allSortBy = _controller.topicSortByConf.value?.allSortBy;
|
||||||
if (allSortBy != null && allSortBy.isNotEmpty) {
|
if (allSortBy != null && allSortBy.isNotEmpty) {
|
||||||
@@ -133,9 +140,7 @@ class _DynTopicPageState extends State<DynTopicPage> {
|
|||||||
return const SliverToBoxAdapter();
|
return const SliverToBoxAdapter();
|
||||||
}),
|
}),
|
||||||
SliverPadding(
|
SliverPadding(
|
||||||
padding: EdgeInsets.only(
|
padding: EdgeInsets.only(bottom: padding.bottom + 80),
|
||||||
bottom: MediaQuery.paddingOf(context).bottom + 80,
|
|
||||||
),
|
|
||||||
sliver: Obx(() => _buildBody(_controller.loadingState.value)),
|
sliver: Obx(() => _buildBody(_controller.loadingState.value)),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -145,15 +150,18 @@ class _DynTopicPageState extends State<DynTopicPage> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildAppBar(ThemeData theme, LoadingState<TopDetails?> topState) {
|
Widget _buildAppBar(
|
||||||
late final paddingTop = MediaQuery.paddingOf(context).top;
|
ThemeData theme,
|
||||||
|
double paddingTop,
|
||||||
|
LoadingState<TopDetails?> topState,
|
||||||
|
) {
|
||||||
return switch (topState) {
|
return switch (topState) {
|
||||||
Loading() => const SliverAppBar(),
|
Loading() => const SliverAppBar(),
|
||||||
Success(:var response) when (topState.dataOrNull != null) =>
|
Success(:var response) when (topState.dataOrNull != null) =>
|
||||||
DynamicSliverAppBarMedium(
|
DynamicSliverAppBarMedium(
|
||||||
pinned: true,
|
pinned: true,
|
||||||
callback: (value) => _controller.appbarOffset =
|
callback: (value) =>
|
||||||
value - kToolbarHeight - paddingTop - 7,
|
_controller.appbarOffset = value - kToolbarHeight - paddingTop,
|
||||||
title: IgnorePointer(child: Text(response!.topicItem!.name)),
|
title: IgnorePointer(child: Text(response!.topicItem!.name)),
|
||||||
flexibleSpace: Container(
|
flexibleSpace: Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
|
|||||||
@@ -47,7 +47,6 @@ class MemberController extends CommonDataController<SpaceData, SpaceData?>
|
|||||||
final fromViewAid = Get.parameters['from_view_aid'];
|
final fromViewAid = Get.parameters['from_view_aid'];
|
||||||
|
|
||||||
final key = GlobalKey<ExtendedNestedScrollViewState>();
|
final key = GlobalKey<ExtendedNestedScrollViewState>();
|
||||||
int offset = 120;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onInit() {
|
void onInit() {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import 'package:PiliPlus/common/widgets/dialog/report_member.dart';
|
import 'package:PiliPlus/common/widgets/dialog/report_member.dart';
|
||||||
import 'package:PiliPlus/common/widgets/dynamic_sliver_appbar.dart';
|
import 'package:PiliPlus/common/widgets/dynamic_sliver_appbar_medium.dart';
|
||||||
import 'package:PiliPlus/common/widgets/loading_widget/loading_widget.dart';
|
import 'package:PiliPlus/common/widgets/loading_widget/loading_widget.dart';
|
||||||
import 'package:PiliPlus/common/widgets/scroll_physics.dart';
|
import 'package:PiliPlus/common/widgets/scroll_physics.dart';
|
||||||
import 'package:PiliPlus/http/loading_state.dart';
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
@@ -43,41 +43,56 @@ class _MemberPageState extends State<MemberPage> {
|
|||||||
MemberController(mid: _mid),
|
MemberController(mid: _mid),
|
||||||
tag: _heroTag,
|
tag: _heroTag,
|
||||||
);
|
);
|
||||||
_userController.scrollController.addListener(listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
void listener() {
|
|
||||||
if (_userController.scrollController.hasClients) {
|
|
||||||
_userController.showUname.value =
|
|
||||||
_userController.scrollController.offset >= _userController.offset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
_userController.scrollController.removeListener(listener);
|
|
||||||
super.dispose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
return Scaffold(
|
return Material(
|
||||||
extendBody: true,
|
color: theme.colorScheme.surface,
|
||||||
extendBodyBehindAppBar: true,
|
child: Obx(() {
|
||||||
resizeToAvoidBottomInset: false,
|
if (_userController.loadingState.value.isSuccess) {
|
||||||
appBar: AppBar(
|
return ExtendedNestedScrollView(
|
||||||
forceMaterialTransparency: true,
|
key: _userController.key,
|
||||||
title: IgnorePointer(
|
controller: _userController.scrollController,
|
||||||
child: Obx(
|
onlyOneScrollInBody: true,
|
||||||
() =>
|
pinnedHeaderSliverHeightBuilder: () =>
|
||||||
_userController.showUname.value &&
|
kToolbarHeight + MediaQuery.paddingOf(context).top,
|
||||||
_userController.username != null
|
headerSliverBuilder: (context, innerBoxIsScrolled) {
|
||||||
? Text(_userController.username!)
|
return [
|
||||||
: const SizedBox.shrink(),
|
_buildUserInfo(
|
||||||
|
theme,
|
||||||
|
_userController.loadingState.value,
|
||||||
),
|
),
|
||||||
|
];
|
||||||
|
},
|
||||||
|
body: _userController.tab2?.isNotEmpty == true
|
||||||
|
? SafeArea(
|
||||||
|
top: false,
|
||||||
|
bottom: false,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
if ((_userController.tab2?.length ?? 0) > 1)
|
||||||
|
TabBar(
|
||||||
|
controller: _userController.tabController,
|
||||||
|
tabs: _userController.tabs,
|
||||||
|
onTap: _userController.onTapTab,
|
||||||
),
|
),
|
||||||
actions: [
|
Expanded(child: _buildBody),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: const Center(child: Text('EMPTY')),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return Center(
|
||||||
|
child: _buildUserInfo(theme, _userController.loadingState.value),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Widget> _actions(ThemeData theme) => [
|
||||||
IconButton(
|
IconButton(
|
||||||
tooltip: '搜索',
|
tooltip: '搜索',
|
||||||
onPressed: () => Get.toNamed(
|
onPressed: () => Get.toNamed(
|
||||||
@@ -98,9 +113,7 @@ class _MemberPageState extends State<MemberPage> {
|
|||||||
const Icon(Icons.block, size: 19),
|
const Icon(Icons.block, size: 19),
|
||||||
const SizedBox(width: 10),
|
const SizedBox(width: 10),
|
||||||
Text(
|
Text(
|
||||||
_userController.relation.value != 128
|
_userController.relation.value != 128 ? '加入黑名单' : '移除黑名单',
|
||||||
? '加入黑名单'
|
|
||||||
: '移除黑名单',
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -126,9 +139,7 @@ class _MemberPageState extends State<MemberPage> {
|
|||||||
const Icon(Icons.share_outlined, size: 19),
|
const Icon(Icons.share_outlined, size: 19),
|
||||||
const SizedBox(width: 10),
|
const SizedBox(width: 10),
|
||||||
Text(
|
Text(
|
||||||
_userController.accountService.mid != _mid
|
_userController.accountService.mid != _mid ? '分享UP主' : '分享我的主页',
|
||||||
? '分享UP主'
|
|
||||||
: '分享我的主页',
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -150,8 +161,7 @@ class _MemberPageState extends State<MemberPage> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (_userController.accountService.isLogin.value)
|
if (_userController.accountService.isLogin.value)
|
||||||
if (_userController.mid ==
|
if (_userController.mid == _userController.accountService.mid) ...[
|
||||||
_userController.accountService.mid) ...[
|
|
||||||
if ((_userController
|
if ((_userController
|
||||||
.loadingState
|
.loadingState
|
||||||
.value
|
.value
|
||||||
@@ -262,58 +272,7 @@ class _MemberPageState extends State<MemberPage> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(width: 4),
|
const SizedBox(width: 4),
|
||||||
],
|
|
||||||
),
|
|
||||||
body: Obx(
|
|
||||||
() => _userController.loadingState.value.isSuccess
|
|
||||||
? LayoutBuilder(
|
|
||||||
builder: (context, constraints) {
|
|
||||||
return ExtendedNestedScrollView(
|
|
||||||
key: _userController.key,
|
|
||||||
controller: _userController.scrollController,
|
|
||||||
onlyOneScrollInBody: true,
|
|
||||||
pinnedHeaderSliverHeightBuilder: () {
|
|
||||||
return kToolbarHeight +
|
|
||||||
MediaQuery.paddingOf(this.context).top.toInt();
|
|
||||||
},
|
|
||||||
headerSliverBuilder: (context, innerBoxIsScrolled) {
|
|
||||||
return [
|
|
||||||
_buildAppBar(
|
|
||||||
isV: constraints.maxHeight > constraints.maxWidth,
|
|
||||||
),
|
|
||||||
];
|
];
|
||||||
},
|
|
||||||
body: _userController.tab2?.isNotEmpty == true
|
|
||||||
? SafeArea(
|
|
||||||
top: false,
|
|
||||||
bottom: false,
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
if ((_userController.tab2?.length ?? 0) > 1)
|
|
||||||
_buildTab(theme),
|
|
||||||
Expanded(child: _buildBody),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: const Center(child: Text('EMPTY')),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
)
|
|
||||||
: Center(
|
|
||||||
child: _buildUserInfo(_userController.loadingState.value),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildTab(ThemeData theme) => Material(
|
|
||||||
color: theme.colorScheme.surface,
|
|
||||||
child: TabBar(
|
|
||||||
controller: _userController.tabController,
|
|
||||||
tabs: _userController.tabs,
|
|
||||||
onTap: _userController.onTapTab,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget get _buildBody => tabBarView(
|
Widget get _buildBody => tabBarView(
|
||||||
controller: _userController.tabController,
|
controller: _userController.tabController,
|
||||||
@@ -345,29 +304,18 @@ class _MemberPageState extends State<MemberPage> {
|
|||||||
}).toList(),
|
}).toList(),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildAppBar({bool isV = true}) {
|
Widget _buildUserInfo(ThemeData theme, LoadingState<SpaceData?> userState) {
|
||||||
final top = MediaQuery.paddingOf(context).top;
|
switch (userState) {
|
||||||
return DynamicSliverAppBar(
|
case Loading():
|
||||||
|
return const CircularProgressIndicator();
|
||||||
|
case Success<SpaceData?>(:var response):
|
||||||
|
if (response != null) {
|
||||||
|
return DynamicSliverAppBarMedium(
|
||||||
pinned: true,
|
pinned: true,
|
||||||
primary: false,
|
actions: _actions(theme),
|
||||||
automaticallyImplyLeading: false,
|
title: Text(_userController.username ?? ''),
|
||||||
toolbarHeight: kToolbarHeight + top,
|
flexibleSpace: Obx(
|
||||||
flexibleSpace: _buildUserInfo(_userController.loadingState.value, isV),
|
|
||||||
callback: (value) {
|
|
||||||
_userController.offset = (value - 56 - top).toInt();
|
|
||||||
listener();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildUserInfo(LoadingState<SpaceData?> userState, [bool isV = true]) {
|
|
||||||
return switch (userState) {
|
|
||||||
Loading() => const CircularProgressIndicator(),
|
|
||||||
Success(:var response) =>
|
|
||||||
response != null
|
|
||||||
? Obx(
|
|
||||||
() => UserInfoCard(
|
() => UserInfoCard(
|
||||||
isV: isV,
|
|
||||||
isOwner:
|
isOwner:
|
||||||
_userController.mid == _userController.accountService.mid,
|
_userController.mid == _userController.accountService.mid,
|
||||||
relation: _userController.relation.value,
|
relation: _userController.relation.value,
|
||||||
@@ -377,16 +325,23 @@ class _MemberPageState extends State<MemberPage> {
|
|||||||
live: _userController.live,
|
live: _userController.live,
|
||||||
silence: _userController.silence,
|
silence: _userController.silence,
|
||||||
),
|
),
|
||||||
)
|
),
|
||||||
: GestureDetector(
|
);
|
||||||
|
}
|
||||||
|
return SliverAppBar(
|
||||||
|
pinned: true,
|
||||||
|
actions: _actions(theme),
|
||||||
|
title: GestureDetector(
|
||||||
onTap: _userController.onReload,
|
onTap: _userController.onReload,
|
||||||
behavior: HitTestBehavior.opaque,
|
behavior: HitTestBehavior.opaque,
|
||||||
child: const SizedBox(height: 56, width: double.infinity),
|
child: Text(_userController.username ?? ''),
|
||||||
),
|
),
|
||||||
Error(:var errMsg) => scrollErrorWidget(
|
);
|
||||||
|
case Error(:var errMsg):
|
||||||
|
return scrollErrorWidget(
|
||||||
errMsg: errMsg,
|
errMsg: errMsg,
|
||||||
onReload: _userController.onReload,
|
onReload: _userController.onReload,
|
||||||
),
|
);
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import 'package:PiliPlus/models_new/space/space/card.dart';
|
|||||||
import 'package:PiliPlus/models_new/space/space/images.dart';
|
import 'package:PiliPlus/models_new/space/space/images.dart';
|
||||||
import 'package:PiliPlus/models_new/space/space/live.dart';
|
import 'package:PiliPlus/models_new/space/space/live.dart';
|
||||||
import 'package:PiliPlus/utils/accounts.dart';
|
import 'package:PiliPlus/utils/accounts.dart';
|
||||||
|
import 'package:PiliPlus/utils/context_ext.dart';
|
||||||
import 'package:PiliPlus/utils/extension.dart';
|
import 'package:PiliPlus/utils/extension.dart';
|
||||||
import 'package:PiliPlus/utils/image_util.dart';
|
import 'package:PiliPlus/utils/image_util.dart';
|
||||||
import 'package:PiliPlus/utils/num_util.dart';
|
import 'package:PiliPlus/utils/num_util.dart';
|
||||||
@@ -12,12 +13,11 @@ import 'package:PiliPlus/utils/page_utils.dart';
|
|||||||
import 'package:PiliPlus/utils/utils.dart';
|
import 'package:PiliPlus/utils/utils.dart';
|
||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart' hide ContextExtensionss;
|
||||||
|
|
||||||
class UserInfoCard extends StatelessWidget {
|
class UserInfoCard extends StatelessWidget {
|
||||||
const UserInfoCard({
|
const UserInfoCard({
|
||||||
super.key,
|
super.key,
|
||||||
required this.isV,
|
|
||||||
required this.isOwner,
|
required this.isOwner,
|
||||||
required this.card,
|
required this.card,
|
||||||
required this.images,
|
required this.images,
|
||||||
@@ -27,7 +27,6 @@ class UserInfoCard extends StatelessWidget {
|
|||||||
this.silence,
|
this.silence,
|
||||||
});
|
});
|
||||||
|
|
||||||
final bool isV;
|
|
||||||
final bool isOwner;
|
final bool isOwner;
|
||||||
final int relation;
|
final int relation;
|
||||||
final SpaceCard card;
|
final SpaceCard card;
|
||||||
@@ -39,7 +38,9 @@ class UserInfoCard extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
return isV ? _buildV(context, theme) : _buildH(context, theme);
|
return context.isPortrait
|
||||||
|
? _buildV(context, theme)
|
||||||
|
: _buildH(context, theme);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _countWidget({
|
Widget _countWidget({
|
||||||
@@ -541,11 +542,8 @@ class UserInfoCard extends StatelessWidget {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
// _buildHeader(context),
|
// _buildHeader(context),
|
||||||
SizedBox(
|
const SizedBox(height: 56),
|
||||||
height: Get.mediaQuery.padding.top + 56,
|
|
||||||
),
|
|
||||||
SafeArea(
|
SafeArea(
|
||||||
top: false,
|
|
||||||
bottom: false,
|
bottom: false,
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
|
|||||||
Reference in New Issue
Block a user