Signed-off-by: dom <githubaccount56556@proton.me>
This commit is contained in:
dom
2026-03-17 17:09:24 +08:00
parent 7f2682bb7b
commit d1497115da
27 changed files with 118 additions and 141 deletions

View File

@@ -19,14 +19,8 @@ class HttpError extends StatelessWidget {
@override
Widget build(BuildContext context) {
return isSliver
? SliverToBoxAdapter(child: content(context))
: SizedBox(width: double.infinity, child: content(context));
}
Widget content(BuildContext context) {
final theme = Theme.of(context);
return Column(
final child = Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
@@ -63,5 +57,9 @@ class HttpError extends StatelessWidget {
SizedBox(height: 40 + MediaQuery.viewPaddingOf(context).bottom),
],
);
return isSliver
? SliverToBoxAdapter(child: child)
: SizedBox(width: double.infinity, child: child);
}
}

View File

@@ -1,17 +1,14 @@
import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart';
import 'package:flutter/material.dart';
Widget get loadingWidget => const Center(child: CircularProgressIndicator());
const Widget circularLoading = Center(child: CircularProgressIndicator());
Widget get linearLoading =>
const SliverToBoxAdapter(child: LinearProgressIndicator());
Widget errorWidget({String? errMsg, VoidCallback? onReload}) => HttpError(
isSliver: false,
errMsg: errMsg,
onReload: onReload,
const Widget linearLoading = SliverToBoxAdapter(
child: LinearProgressIndicator(),
);
const Widget scrollableError = CustomScrollView(slivers: [HttpError()]);
Widget scrollErrorWidget({
String? errMsg,
VoidCallback? onReload,

View File

@@ -340,6 +340,7 @@ class Common {
int? style;
String? subType;
String? title;
String? titlePrefix;
Common.fromJson(Map<String, dynamic> json) {
cover = json['cover'];
@@ -352,6 +353,7 @@ class Common {
style = json['style'];
subType = json['sub_type'];
title = json['title'];
titlePrefix = json['title_prefix'];
}
}

View File

@@ -82,7 +82,7 @@ class _DanmakuBlockPageState extends State<DanmakuBlockPage> {
Widget tabViewBuilder(final int tabIndex, List<SimpleRule> list) {
if (list.isEmpty) {
return scrollErrorWidget();
return scrollableError;
}
return ListView.builder(
itemCount: list.length,

View File

@@ -153,13 +153,12 @@ Widget module(
spacing: 2,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (common.title?.isNotEmpty ?? false)
Text(
common.title!,
style: TextStyle(color: theme.colorScheme.primary),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
Text(
'${common.titlePrefix ?? ''}${common.title ?? ''}',
style: TextStyle(color: theme.colorScheme.primary),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
if (common.desc?.isNotEmpty ?? false)
Text(
common.desc!,

View File

@@ -234,8 +234,8 @@ class _DynMentionPanelState
LoadingState<List<MentionGroup>?> loadingState,
) {
return switch (loadingState) {
Loading() => SliverPadding(
padding: const EdgeInsets.only(top: 8),
Loading() => const SliverPadding(
padding: EdgeInsets.only(top: 8),
sliver: linearLoading,
),
Success<List<MentionGroup>?>(:final response) =>

View File

@@ -188,7 +188,7 @@ class _SelectTopicPanelState
LoadingState<List<TopicItem>?> loadingState,
) {
return switch (loadingState) {
Loading() => loadingWidget,
Loading() => circularLoading,
Success<List<TopicItem>?>(:final response) =>
response != null && response.isNotEmpty
? ListView.builder(

View File

@@ -50,7 +50,7 @@ class _EmotePanelState extends State<EmotePanel>
Get.currentRoute.startsWith('/whisperDetail') ? 8 : 2,
);
return switch (loadingState) {
Loading() => loadingWidget,
Loading() => circularLoading,
Success(:final response) =>
response != null && response.isNotEmpty
? Column(

View File

@@ -2,6 +2,8 @@ import 'package:PiliPlus/common/constants.dart';
import 'package:PiliPlus/common/widgets/dialog/dialog.dart';
import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart';
import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart';
import 'package:PiliPlus/common/widgets/loading_widget/loading_widget.dart'
show circularLoading;
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/models_new/fav/fav_topic/topic_item.dart';
import 'package:PiliPlus/pages/fav/topic/controller.dart';
@@ -66,9 +68,7 @@ class _FavTopicPageState extends State<FavTopicPage>
Loading() => const SliverToBoxAdapter(
child: SizedBox(
height: 125,
child: Center(
child: CircularProgressIndicator(),
),
child: circularLoading,
),
),
Success(:final response) =>

View File

@@ -107,7 +107,7 @@ class _CreateFavPageState extends State<CreateFavPage> {
? _buildBody(theme)
: _errMsg?.isNotEmpty == true
? scrollErrorWidget(errMsg: _errMsg, onReload: _getFolderInfo)
: const Center(child: CircularProgressIndicator())
: circularLoading
: _buildBody(theme),
);
}

View File

@@ -41,7 +41,7 @@ class _FavPanelState extends State<FavPanel> {
Widget get _buildBody {
late final list = widget.ctr.favFolderData.value.list!;
return switch (loadingState) {
Loading() => loadingWidget,
Loading() => circularLoading,
Success() => ListView.builder(
controller: widget.scrollController,
itemCount: list.length,

View File

@@ -109,7 +109,7 @@ class _FollowPageState extends State<FollowPage> {
Widget _buildBody(LoadingState loadingState) {
return switch (loadingState) {
Loading() => loadingWidget,
Loading() => circularLoading,
Success() => Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [

View File

@@ -68,7 +68,7 @@ class _GroupPanelState extends State<GroupPanel> {
Widget get _buildBody {
return switch (loadingState) {
Loading() => loadingWidget,
Loading() => circularLoading,
Success(:final response) => ListView.builder(
controller: widget.scrollController,
itemCount: response.length,

View File

@@ -157,7 +157,7 @@ class _LiveDmBlockPageState extends State<LiveDmBlockPage> {
Widget _buildKeyword(List list) {
if (list.isEmpty) {
return scrollErrorWidget();
return scrollableError;
}
return SingleChildScrollView(
padding: EdgeInsets.only(

View File

@@ -57,7 +57,7 @@ class _LiveEmotePanelState extends State<LiveEmotePanel>
2,
);
return switch (loadingState) {
Loading() => loadingWidget,
Loading() => circularLoading,
Success(:final response) =>
response != null && response.isNotEmpty
? Column(

View File

@@ -2,6 +2,7 @@ import 'dart:io';
import 'dart:ui';
import 'package:PiliPlus/common/constants.dart';
import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart';
import 'package:PiliPlus/common/widgets/loading_widget/loading_widget.dart';
import 'package:PiliPlus/common/widgets/scroll_physics.dart';
import 'package:PiliPlus/http/loading_state.dart';
@@ -96,15 +97,12 @@ class _LoginPageState extends State<LoginPage> {
),
RepaintBoundary(
key: globalKey,
child: Obx(() {
return switch (_loginPageCtr.codeInfo.value) {
Loading() => Container(
child: Obx(
() => switch (_loginPageCtr.codeInfo.value) {
Loading() => const SizedBox(
height: 200,
width: 200,
alignment: Alignment.center,
child: const CircularProgressIndicator(
semanticsLabel: '二维码加载中',
),
child: circularLoading,
),
Success(:final response) => Container(
width: 200,
@@ -120,12 +118,13 @@ class _LoginPageState extends State<LoginPage> {
),
),
),
Error(:final errMsg) => errorWidget(
Error(:final errMsg) => HttpError(
isSliver: false,
errMsg: errMsg,
onReload: _loginPageCtr.refreshQRCode,
),
};
}),
},
),
),
const SizedBox(height: 10),
Obx(

View File

@@ -5,7 +5,6 @@ import 'package:PiliPlus/common/widgets/dynamic_sliver_app_bar/dynamic_sliver_ap
import 'package:PiliPlus/common/widgets/loading_widget/loading_widget.dart';
import 'package:PiliPlus/common/widgets/scroll_physics.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/models_new/space/space/data.dart';
import 'package:PiliPlus/pages/coin_log/controller.dart';
import 'package:PiliPlus/pages/exp_log/controller.dart';
import 'package:PiliPlus/pages/log_table/view.dart';
@@ -68,48 +67,74 @@ class _MemberPageState extends State<MemberPage> {
return Material(
color: theme.surface,
child: Obx(
() {
if (_userController.loadingState.value.isSuccess) {
return ExtendedNestedScrollView(
key: _userController.key,
onlyOneScrollInBody: true,
pinnedHeaderSliverHeightBuilder: () =>
kToolbarHeight + MediaQuery.viewPaddingOf(context).top,
headerSliverBuilder: (context, innerBoxIsScrolled) {
() => switch (_userController.loadingState.value) {
Loading() => circularLoading,
Success(:final response) => ExtendedNestedScrollView(
key: _userController.key,
onlyOneScrollInBody: true,
pinnedHeaderSliverHeightBuilder: () =>
kToolbarHeight + MediaQuery.viewPaddingOf(context).top,
headerSliverBuilder: (context, innerBoxIsScrolled) {
if (response != null) {
return [
_buildUserInfo(theme, _userController.loadingState.value),
];
},
body: _userController.tab2?.isNotEmpty == true
? Padding(
padding: EdgeInsets.only(
left: padding.left,
right: padding.right,
DynamicSliverAppBar.medium(
actions: _actions(theme),
title: Text(_userController.username ?? ''),
flexibleSpace: Obx(
() => UserInfoCard(
isOwner:
_userController.mid == _userController.account.mid,
relation: _userController.relation.value,
card: response.card!,
images: response.images!,
onFollow: () => _userController.onFollow(context),
live: _userController.live,
silence: _userController.silence,
headerControllerBuilder: getHeaderController,
),
child: Column(
children: [
if ((_userController.tab2?.length ?? 0) > 1)
SizedBox(
height: 45,
child: TabBar(
controller: _userController.tabController,
tabs: _userController.tabs,
onTap: _userController.onTapTab,
dividerColor: theme.outline.withValues(
alpha: 0.2,
),
),
),
];
}
return [
SliverAppBar(
pinned: true,
actions: _actions(theme),
title: GestureDetector(
onTap: _userController.onReload,
behavior: HitTestBehavior.opaque,
child: Text(_userController.username ?? ''),
),
),
];
},
body: _userController.tab2?.isNotEmpty == true
? Padding(
padding: .only(left: padding.left, right: padding.right),
child: Column(
children: [
if ((_userController.tab2?.length ?? 0) > 1)
SizedBox(
height: 45,
child: TabBar(
controller: _userController.tabController,
tabs: _userController.tabs,
onTap: _userController.onTapTab,
dividerColor: theme.outline.withValues(
alpha: 0.2,
),
),
Expanded(child: _buildBody),
],
),
)
: const Center(child: Text('EMPTY')),
);
}
return Center(
child: _buildUserInfo(theme, _userController.loadingState.value),
);
),
Expanded(child: _buildBody),
],
),
)
: scrollableError,
),
Error(:final errMsg) => scrollErrorWidget(
errMsg: errMsg,
onReload: _userController.onReload,
),
},
),
);
@@ -346,47 +371,4 @@ class _MemberPageState extends State<MemberPage> {
};
}).toList(),
);
Widget _buildUserInfo(
ColorScheme theme,
LoadingState<SpaceData?> userState,
) {
switch (userState) {
case Loading():
return const CircularProgressIndicator();
case Success<SpaceData?>(:final response):
if (response != null) {
return DynamicSliverAppBar.medium(
actions: _actions(theme),
title: Text(_userController.username ?? ''),
flexibleSpace: Obx(
() => UserInfoCard(
isOwner: _userController.mid == _userController.account.mid,
relation: _userController.relation.value,
card: response.card!,
images: response.images!,
onFollow: () => _userController.onFollow(context),
live: _userController.live,
silence: _userController.silence,
headerControllerBuilder: getHeaderController,
),
),
);
}
return SliverAppBar(
pinned: true,
actions: _actions(theme),
title: GestureDetector(
onTap: _userController.onReload,
behavior: HitTestBehavior.opaque,
child: Text(_userController.username ?? ''),
),
);
case Error(:final errMsg):
return scrollErrorWidget(
errMsg: errMsg,
onReload: _userController.onReload,
);
}
}
}

View File

@@ -93,7 +93,7 @@ class _MemberContributeState extends State<MemberContribute>
)
: _controller.items?.isNotEmpty == true
? _getPageFromType(_controller.items!.first)
: scrollErrorWidget();
: scrollableError;
}
Widget _getPageFromType(SpaceTab2Item item) {

View File

@@ -73,7 +73,7 @@ class _MemberHomeState extends State<MemberHome>
final isOwner = setting != null;
final color = Theme.of(context).colorScheme.outline;
return switch (loadingState) {
Loading() => loadingWidget,
Loading() => circularLoading,
Success(response: final res) =>
res != null
? CustomScrollView(
@@ -257,7 +257,7 @@ class _MemberHomeState extends State<MemberHome>
),
],
)
: scrollErrorWidget(),
: scrollableError,
Error(:final errMsg) => scrollErrorWidget(errMsg: errMsg),
};
}

View File

@@ -127,7 +127,7 @@ class _EditProfilePageState extends State<EditProfilePage> {
);
return switch (loadingState) {
Loading() => loadingWidget,
Loading() => circularLoading,
Success(:final response) => ListView(
padding: EdgeInsets.only(
bottom: MediaQuery.viewPaddingOf(context).bottom + 25,

View File

@@ -83,7 +83,7 @@ class _PgcPageState extends State<PgcPage> with AutomaticKeepAliveClientMixin {
ThemeData theme,
LoadingState<List<TimelineResult>?> loadingState,
) => switch (loadingState) {
Loading() => loadingWidget,
Loading() => circularLoading,
Success(:final response) =>
response != null && response.isNotEmpty
? Builder(
@@ -397,7 +397,7 @@ class _PgcPageState extends State<PgcPage> with AutomaticKeepAliveClientMixin {
Widget _buildFollowBody(LoadingState<List<FavPgcItemModel>?> loadingState) {
return switch (loadingState) {
Loading() => loadingWidget,
Loading() => circularLoading,
Success(:final response) =>
response != null && response.isNotEmpty
? ListView.builder(

View File

@@ -58,7 +58,7 @@ class _PgcIndexPageState extends State<PgcIndexPage>
) {
final padding = MediaQuery.viewPaddingOf(context);
return switch (loadingState) {
Loading() => loadingWidget,
Loading() => circularLoading,
Success(:final response) => Builder(
builder: (context) {
int count =

View File

@@ -184,7 +184,7 @@ class _LogsPageState extends State<LogsPage> {
],
),
)
: scrollErrorWidget(),
: scrollableError,
);
}
}

View File

@@ -81,7 +81,7 @@ class _HorizontalMemberPageState extends State<HorizontalMemberPage> {
Widget _buildUserPage(ThemeData theme, LoadingState userState) {
return switch (userState) {
Loading() => loadingWidget,
Loading() => circularLoading,
Success(:final response) => Column(
children: [
_buildUserInfo(theme, response),

View File

@@ -2,7 +2,7 @@ import 'dart:async';
import 'dart:math';
import 'package:PiliPlus/common/widgets/button/icon_button.dart';
import 'package:PiliPlus/common/widgets/loading_widget/loading_widget.dart';
import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart';
import 'package:PiliPlus/common/widgets/pair.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/http/sponsor_block.dart';
@@ -249,7 +249,7 @@ class _PostPanelState extends State<PostPanel>
@override
Widget buildList(ThemeData theme) {
if (list.isEmpty) {
return errorWidget();
return const HttpError(isSliver: false);
}
final bottom = MediaQuery.viewPaddingOf(context).bottom;
Widget child = ListView.builder(

View File

@@ -37,7 +37,7 @@ class _WhisperBlockPageState extends State<WhisperBlockPage> {
LoadingState<List<KeywordBlockingItem>?> loadingState,
) {
return switch (loadingState) {
Loading() => loadingWidget,
Loading() => circularLoading,
Success(:final response) =>
response != null && response.isNotEmpty
? Column(

View File

@@ -151,7 +151,7 @@ class _WhisperDetailPageState
Widget _buildBody(LoadingState<List<Msg>?> loadingState) {
return switch (loadingState) {
Loading() => loadingWidget,
Loading() => circularLoading,
Success(:final response) =>
response != null && response.isNotEmpty
? ChatListView.separated(