show live rank

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2025-12-28 20:48:24 +08:00
parent a037d8e793
commit 2a52157c3f
24 changed files with 490 additions and 47 deletions

View File

@@ -205,10 +205,10 @@ class CustomGridView extends StatelessWidget {
final radius = borderRadius(column, length, index); final radius = borderRadius(column, length, index);
return LayoutId( return LayoutId(
id: index, id: index,
child: Hero( child: GestureDetector(
tag: item.url, onTap: () => onTap(context, index),
child: GestureDetector( child: Hero(
onTap: () => onTap(context, index), tag: item.url,
child: Stack( child: Stack(
clipBehavior: Clip.none, clipBehavior: Clip.none,
alignment: Alignment.center, alignment: Alignment.center,

View File

@@ -978,4 +978,7 @@ abstract final class Api {
static const String followeeVotes = static const String followeeVotes =
'${HttpString.tUrl}/vote_svr/v1/vote_svr/followee_votes'; '${HttpString.tUrl}/vote_svr/v1/vote_svr/followee_votes';
static const String liveContributionRank =
'${HttpString.liveBaseUrl}/xlive/general-interface/v1/rank/queryContributionRank';
} }

View File

@@ -5,9 +5,11 @@ import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/http/login.dart'; import 'package:PiliPlus/http/login.dart';
import 'package:PiliPlus/http/ua_type.dart'; import 'package:PiliPlus/http/ua_type.dart';
import 'package:PiliPlus/models/common/account_type.dart'; import 'package:PiliPlus/models/common/account_type.dart';
import 'package:PiliPlus/models/common/live_search_type.dart'; import 'package:PiliPlus/models/common/live/live_contribution_rank_type.dart';
import 'package:PiliPlus/models/common/live/live_search_type.dart';
import 'package:PiliPlus/models_new/live/live_area_list/area_item.dart'; import 'package:PiliPlus/models_new/live/live_area_list/area_item.dart';
import 'package:PiliPlus/models_new/live/live_area_list/area_list.dart'; import 'package:PiliPlus/models_new/live/live_area_list/area_list.dart';
import 'package:PiliPlus/models_new/live/live_contribution_rank/data.dart';
import 'package:PiliPlus/models_new/live/live_dm_block/data.dart'; import 'package:PiliPlus/models_new/live/live_dm_block/data.dart';
import 'package:PiliPlus/models_new/live/live_dm_block/shield_info.dart'; import 'package:PiliPlus/models_new/live/live_dm_block/shield_info.dart';
import 'package:PiliPlus/models_new/live/live_dm_block/shield_user_list.dart'; import 'package:PiliPlus/models_new/live/live_dm_block/shield_user_list.dart';
@@ -658,4 +660,34 @@ abstract final class LiveHttp {
return Error(res.data['message']); return Error(res.data['message']);
} }
} }
static Future<LoadingState<LiveContributionRankData>> liveContributionRank({
required Object ruid,
required Object roomId,
required int page,
required LiveContributionRankType type,
}) async {
final res = await Request().get(
Api.liveContributionRank,
queryParameters: await WbiSign.makSign({
'ruid': ruid,
'room_id': roomId,
'page': page,
'page_size': 100,
'type': type.name,
'switch': type.sw1tch,
'platform': 'web',
'web_location': 444.8,
}),
);
if (res.data['code'] == 0) {
try {
return Success(LiveContributionRankData.fromJson(res.data['data']));
} catch (e, s) {
return Error('$e\n\n$s');
}
} else {
return Error(res.data['message']);
}
}
} }

View File

@@ -0,0 +1,13 @@
// ignore_for_file: constant_identifier_names
enum LiveContributionRankType {
online_rank('在线榜', 'contribution_rank'),
daily_rank('日榜', 'today_rank'),
weekly_rank('周榜', 'current_week_rank'),
monthly_rank('月榜', 'current_month_rank')
;
final String title;
final String sw1tch;
const LiveContributionRankType(this.title, this.sw1tch);
}

View File

@@ -0,0 +1,19 @@
import 'package:PiliPlus/models_new/live/live_contribution_rank/item.dart';
class LiveContributionRankData {
List<LiveContributionRankItem>? item;
LiveContributionRankData({
this.item,
});
factory LiveContributionRankData.fromJson(Map<String, dynamic> json) =>
LiveContributionRankData(
item: (json['item'] as List<dynamic>?)
?.map(
(e) =>
LiveContributionRankItem.fromJson(e as Map<String, dynamic>),
)
.toList(),
);
}

View File

@@ -0,0 +1,31 @@
import 'package:PiliPlus/models_new/live/live_contribution_rank/medal_info.dart';
class LiveContributionRankItem {
int? uid;
String? name;
String? face;
int? rank;
int? score;
MedalInfo? medalInfo;
LiveContributionRankItem({
this.uid,
this.name,
this.face,
this.rank,
this.score,
this.medalInfo,
});
factory LiveContributionRankItem.fromJson(Map<String, dynamic> json) =>
LiveContributionRankItem(
uid: json['uid'] as int?,
name: json['name'] as String?,
face: json['face'] as String?,
rank: json['rank'] as int?,
score: json['score'] as int?,
medalInfo: json['medal_info'] == null
? null
: MedalInfo.fromJson(json['medal_info'] as Map<String, dynamic>),
);
}

View File

@@ -0,0 +1,14 @@
class MedalInfo {
String? medalName;
int? level;
MedalInfo({
this.medalName,
this.level,
});
factory MedalInfo.fromJson(Map<String, dynamic> json) => MedalInfo(
medalName: json['medal_name'] as String?,
level: json['level'] as int?,
);
}

View File

@@ -46,13 +46,13 @@ Widget htmlRender({
); );
} }
final size = isEmote ? 22.0 : null; final size = isEmote ? 22.0 : null;
return Hero( return GestureDetector(
tag: imgUrl, onTap: () => PageUtils.imageView(
child: GestureDetector( imgList: [SourceModel(url: imgUrl)],
onTap: () => PageUtils.imageView( quality: 60,
imgList: [SourceModel(url: imgUrl)], ),
quality: 60, child: Hero(
), tag: imgUrl,
child: CachedNetworkImage( child: CachedNetworkImage(
width: size, width: size,
height: size, height: size,

View File

@@ -220,14 +220,14 @@ class OpusContent extends StatelessWidget {
final height = width == null || pic.height == null final height = width == null || pic.height == null
? null ? null
: width * pic.height! / pic.width!; : width * pic.height! / pic.width!;
return Hero( return GestureDetector(
tag: pic.url!, onTap: () => PageUtils.imageView(
child: GestureDetector( imgList: [SourceModel(url: pic.url!)],
onTap: () => PageUtils.imageView( quality: 60,
imgList: [SourceModel(url: pic.url!)], ),
quality: 60, child: Center(
), child: Hero(
child: Center( tag: pic.url!,
child: CachedNetworkImage( child: CachedNetworkImage(
width: width, width: width,
height: height, height: height,

View File

@@ -1,6 +1,6 @@
import 'package:PiliPlus/http/live.dart'; import 'package:PiliPlus/http/live.dart';
import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/models/common/live_dm_silent_type.dart'; import 'package:PiliPlus/models/common/live/live_dm_silent_type.dart';
import 'package:PiliPlus/models_new/live/live_dm_block/shield_user_list.dart'; import 'package:PiliPlus/models_new/live/live_dm_block/shield_user_list.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';

View File

@@ -3,7 +3,7 @@ import 'package:PiliPlus/common/widgets/dialog/dialog.dart';
import 'package:PiliPlus/common/widgets/keep_alive_wrapper.dart'; import 'package:PiliPlus/common/widgets/keep_alive_wrapper.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/models/common/live_dm_silent_type.dart'; import 'package:PiliPlus/models/common/live/live_dm_silent_type.dart';
import 'package:PiliPlus/models_new/live/live_dm_block/shield_user_list.dart'; import 'package:PiliPlus/models_new/live/live_dm_block/shield_user_list.dart';
import 'package:PiliPlus/pages/live_dm_block/controller.dart'; import 'package:PiliPlus/pages/live_dm_block/controller.dart';
import 'package:PiliPlus/pages/search/widgets/search_text.dart'; import 'package:PiliPlus/pages/search/widgets/search_text.dart';

View File

@@ -0,0 +1,45 @@
import 'package:PiliPlus/http/live.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/models/common/live/live_contribution_rank_type.dart';
import 'package:PiliPlus/models_new/live/live_contribution_rank/data.dart';
import 'package:PiliPlus/models_new/live/live_contribution_rank/item.dart';
import 'package:PiliPlus/pages/common/common_list_controller.dart';
class ContributionRankController
extends
CommonListController<
LiveContributionRankData,
LiveContributionRankItem
> {
final Object ruid;
final Object roomId;
final LiveContributionRankType type;
ContributionRankController({
required this.ruid,
required this.roomId,
required this.type,
});
@override
void onInit() {
super.onInit();
queryData();
}
@override
List<LiveContributionRankItem>? getDataList(
LiveContributionRankData response,
) {
return response.item;
}
@override
Future<LoadingState<LiveContributionRankData>> customGetData() =>
LiveHttp.liveContributionRank(
ruid: ruid,
roomId: roomId,
page: page,
type: type,
);
}

View File

@@ -0,0 +1,248 @@
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';
import 'package:PiliPlus/common/widgets/pendant_avatar.dart';
import 'package:PiliPlus/common/widgets/scroll_physics.dart';
import 'package:PiliPlus/common/widgets/view_sliver_safe_area.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/models/common/live/live_contribution_rank_type.dart';
import 'package:PiliPlus/models_new/live/live_contribution_rank/item.dart';
import 'package:PiliPlus/models_new/live/live_contribution_rank/medal_info.dart';
import 'package:PiliPlus/pages/live_room/contribution_rank/controller.dart';
import 'package:PiliPlus/utils/extension/scroll_controller_ext.dart';
import 'package:PiliPlus/utils/utils.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
class ContributionRankPanel extends StatefulWidget {
const ContributionRankPanel({
super.key,
required this.ruid,
required this.roomId,
});
final Object ruid;
final Object roomId;
@override
State<ContributionRankPanel> createState() => _ContributionRankPanelState();
}
class _ContributionRankPanelState extends State<ContributionRankPanel>
with SingleTickerProviderStateMixin {
late final TabController _tabController;
@override
void initState() {
super.initState();
_tabController = TabController(
length: LiveContributionRankType.values.length,
vsync: this,
);
}
@override
void dispose() {
_tabController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Column(
children: [
SizedBox(
height: 45,
child: TabBar(
controller: _tabController,
tabs: LiveContributionRankType.values
.map((e) => Tab(text: e.title))
.toList(),
dividerColor: Theme.of(
context,
).colorScheme.outline.withValues(alpha: 0.3),
onTap: (index) {
if (!_tabController.indexIsChanging) {
Get.find<ContributionRankController>(
tag:
'${widget.roomId}${LiveContributionRankType.values[index].name}',
).scrollController.animToTop();
}
},
),
),
Expanded(
child: tabBarView(
controller: _tabController,
children: LiveContributionRankType.values
.map(
(e) => _ContributionRankType(
ruid: widget.ruid,
roomId: widget.roomId,
type: e,
),
)
.toList(),
),
),
],
);
}
}
class _ContributionRankType extends StatefulWidget {
const _ContributionRankType({
required this.ruid,
required this.roomId,
required this.type,
});
final Object ruid;
final Object roomId;
final LiveContributionRankType type;
@override
State<_ContributionRankType> createState() => _ContributionRankTypeState();
}
class _ContributionRankTypeState extends State<_ContributionRankType>
with AutomaticKeepAliveClientMixin {
late final _controller = Get.put(
ContributionRankController(
ruid: widget.ruid,
roomId: widget.roomId,
type: widget.type,
),
tag: '${widget.roomId}${widget.type.name}',
);
@override
Widget build(BuildContext context) {
super.build(context);
final showScore = widget.type == .online_rank;
return Material(
type: .transparency,
child: refreshIndicator(
onRefresh: _controller.onRefresh,
child: CustomScrollView(
controller: _controller.scrollController,
slivers: [
ViewSliverSafeArea(
sliver: Obx(
() => _buildBody(showScore, _controller.loadingState.value),
),
),
],
),
),
);
}
Widget _buildBody(
bool showScore,
LoadingState<List<LiveContributionRankItem>?> state,
) {
return switch (state) {
Loading() => linearLoading,
Success(:final response) =>
response != null && response.isNotEmpty
? SliverFixedExtentList.builder(
itemCount: response.length,
itemBuilder: (context, index) {
final item = response[index];
return _Item(
index: index,
item: item,
showScore: showScore,
);
},
itemExtent: 60,
)
: HttpError(onReload: _controller.onReload),
Error(:final errMsg) => HttpError(
errMsg: errMsg,
onReload: _controller.onReload,
),
};
}
@override
bool get wantKeepAlive => true;
}
class _Item extends StatelessWidget {
const _Item({
required this.index,
required this.item,
required this.showScore,
});
final int index;
final bool showScore;
final LiveContributionRankItem item;
@override
Widget build(BuildContext context) {
late final colorScheme = ColorScheme.of(context);
return InkWell(
onTap: () => Get.toNamed('/member?mid=${item.uid}'),
child: Padding(
padding: const .only(left: 10, top: 9, bottom: 8, right: 16),
child: Row(
spacing: 10,
children: [
SizedBox(
width: 32,
child: Center(
child: Text(
'${index + 1}',
textAlign: .center,
textScaler: .noScaling,
style: TextStyle(
fontWeight: FontWeight.bold,
color: Utils.index2Color(index, colorScheme.outline),
fontSize: 16,
fontStyle: FontStyle.italic,
),
),
),
),
PendantAvatar(
avatar: item.face,
size: 42,
),
Expanded(
child: Column(
spacing: 3,
crossAxisAlignment: .start,
children: [
Text(item.name!),
Row(
children: [
if (item.medalInfo case MedalInfo(
:final medalName,
:final level,
))
Text(
'$medalName$level',
style: TextStyle(
fontSize: 12,
color: colorScheme.onSurfaceVariant,
),
),
],
),
],
),
),
if (showScore)
Text(
item.score.toString(),
style: TextStyle(color: colorScheme.outline),
),
],
),
),
);
}
}

View File

@@ -15,6 +15,7 @@ import 'package:PiliPlus/models_new/live/live_room_play_info/codec.dart';
import 'package:PiliPlus/models_new/live/live_superchat/item.dart'; import 'package:PiliPlus/models_new/live/live_superchat/item.dart';
import 'package:PiliPlus/pages/common/publish/publish_route.dart'; import 'package:PiliPlus/pages/common/publish/publish_route.dart';
import 'package:PiliPlus/pages/danmaku/danmaku_model.dart'; import 'package:PiliPlus/pages/danmaku/danmaku_model.dart';
import 'package:PiliPlus/pages/live_room/contribution_rank/view.dart';
import 'package:PiliPlus/pages/live_room/send_danmaku/view.dart'; import 'package:PiliPlus/pages/live_room/send_danmaku/view.dart';
import 'package:PiliPlus/pages/video/widgets/header_control.dart'; import 'package:PiliPlus/pages/video/widgets/header_control.dart';
import 'package:PiliPlus/plugin/pl_player/controller.dart'; import 'package:PiliPlus/plugin/pl_player/controller.dart';
@@ -26,6 +27,7 @@ import 'package:PiliPlus/utils/accounts.dart';
import 'package:PiliPlus/utils/danmaku_utils.dart'; import 'package:PiliPlus/utils/danmaku_utils.dart';
import 'package:PiliPlus/utils/duration_utils.dart'; import 'package:PiliPlus/utils/duration_utils.dart';
import 'package:PiliPlus/utils/extension/iterable_ext.dart'; import 'package:PiliPlus/utils/extension/iterable_ext.dart';
import 'package:PiliPlus/utils/extension/size_ext.dart';
import 'package:PiliPlus/utils/num_utils.dart'; import 'package:PiliPlus/utils/num_utils.dart';
import 'package:PiliPlus/utils/platform_utils.dart'; import 'package:PiliPlus/utils/platform_utils.dart';
import 'package:PiliPlus/utils/storage_pref.dart'; import 'package:PiliPlus/utils/storage_pref.dart';
@@ -43,6 +45,7 @@ class LiveRoomController extends GetxController {
final String heroTag; final String heroTag;
int roomId = Get.arguments; int roomId = Get.arguments;
int? ruid;
DanmakuController<DanmakuExtra>? danmakuController; DanmakuController<DanmakuExtra>? danmakuController;
PlPlayerController plPlayerController = PlPlayerController.getInstance( PlPlayerController plPlayerController = PlPlayerController.getInstance(
isLive: true, isLive: true,
@@ -109,7 +112,6 @@ class LiveRoomController extends GetxController {
late final bool isLogin; late final bool isLogin;
late final int mid; late final int mid;
late final int mainMid = Accounts.main.mid;
String? videoUrl; String? videoUrl;
bool? isPlaying; bool? isPlaying;
@@ -123,18 +125,40 @@ class LiveRoomController extends GetxController {
final RxString title = ''.obs; final RxString title = ''.obs;
final RxnString onlineCount = RxnString(); final RxnString onlineCount = RxnString();
Widget get onlineWidget => Obx(() { Widget get onlineWidget => GestureDetector(
if (onlineCount.value case final onlineCount?) { onTap: _showRank,
return Text( child: Obx(() {
'高能观众($onlineCount)', if (onlineCount.value case final onlineCount?) {
style: const TextStyle( return Text(
fontSize: 12, '高能观众($onlineCount)',
color: Colors.white, style: const TextStyle(
fontSize: 12,
color: Colors.white,
),
);
}
return const SizedBox.shrink();
}),
);
void _showRank() {
if (ruid case final ruid?) {
final heightFactor =
PlatformUtils.isMobile && !Get.mediaQuery.size.isPortrait ? 1.0 : 0.7;
showModalBottomSheet(
context: Get.context!,
useSafeArea: true,
clipBehavior: .hardEdge,
isScrollControlled: true,
constraints: const BoxConstraints(maxWidth: 450),
builder: (context) => FractionallySizedBox(
widthFactor: 1.0,
heightFactor: heightFactor,
child: ContributionRankPanel(ruid: ruid, roomId: roomId),
), ),
); );
} }
return const SizedBox.shrink(); }
});
final RxnString watchedShow = RxnString(); final RxnString watchedShow = RxnString();
Widget get watchedWidget => Obx(() { Widget get watchedWidget => Obx(() {
@@ -207,6 +231,7 @@ class LiveRoomController extends GetxController {
_showDialog('无法获取播放地址'); _showDialog('无法获取播放地址');
return; return;
} }
ruid = data.uid;
if (data.roomId != null) { if (data.roomId != null) {
roomId = data.roomId!; roomId = data.roomId!;
} }
@@ -439,7 +464,7 @@ class LiveRoomController extends GetxController {
: DmUtils.decimalToColor(extra['color']), : DmUtils.decimalToColor(extra['color']),
type: DmUtils.getPosition(extra['mode']), type: DmUtils.getPosition(extra['mode']),
// extra['send_from_me'] is invalid // extra['send_from_me'] is invalid
selfSend: uid == mainMid, selfSend: isLogin && uid == mid,
extra: LiveDanmaku( extra: LiveDanmaku(
id: extra['id_str'], id: extra['id_str'],
mid: uid, mid: uid,

View File

@@ -8,9 +8,11 @@ import 'package:PiliPlus/common/widgets/image/network_img_layer.dart';
import 'package:PiliPlus/common/widgets/keep_alive_wrapper.dart'; import 'package:PiliPlus/common/widgets/keep_alive_wrapper.dart';
import 'package:PiliPlus/common/widgets/scroll_physics.dart'; import 'package:PiliPlus/common/widgets/scroll_physics.dart';
import 'package:PiliPlus/models/common/image_type.dart'; import 'package:PiliPlus/models/common/image_type.dart';
import 'package:PiliPlus/models/common/live/live_contribution_rank_type.dart';
import 'package:PiliPlus/models_new/live/live_room_info_h5/data.dart'; import 'package:PiliPlus/models_new/live/live_room_info_h5/data.dart';
import 'package:PiliPlus/models_new/live/live_superchat/item.dart'; import 'package:PiliPlus/models_new/live/live_superchat/item.dart';
import 'package:PiliPlus/pages/danmaku/danmaku_model.dart'; import 'package:PiliPlus/pages/danmaku/danmaku_model.dart';
import 'package:PiliPlus/pages/live_room/contribution_rank/controller.dart';
import 'package:PiliPlus/pages/live_room/controller.dart'; import 'package:PiliPlus/pages/live_room/controller.dart';
import 'package:PiliPlus/pages/live_room/superchat/superchat_card.dart'; import 'package:PiliPlus/pages/live_room/superchat/superchat_card.dart';
import 'package:PiliPlus/pages/live_room/superchat/superchat_panel.dart'; import 'package:PiliPlus/pages/live_room/superchat/superchat_panel.dart';
@@ -155,6 +157,11 @@ class _LiveRoomPageState extends State<LiveRoomPage>
..removeStatusLister(playerListener) ..removeStatusLister(playerListener)
..dispose(); ..dispose();
PageUtils.routeObserver.unsubscribe(this); PageUtils.routeObserver.unsubscribe(this);
for (final e in LiveContributionRankType.values) {
Get.delete<ContributionRankController>(
tag: '${_liveRoomController.roomId}${e.name}',
);
}
super.dispose(); super.dispose();
} }

View File

@@ -1,6 +1,6 @@
import 'package:PiliPlus/http/live.dart'; import 'package:PiliPlus/http/live.dart';
import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/models/common/live_search_type.dart'; import 'package:PiliPlus/models/common/live/live_search_type.dart';
import 'package:PiliPlus/models_new/live/live_search/data.dart'; import 'package:PiliPlus/models_new/live/live_search/data.dart';
import 'package:PiliPlus/pages/common/common_list_controller.dart'; import 'package:PiliPlus/pages/common/common_list_controller.dart';
import 'package:PiliPlus/pages/live_search/controller.dart'; import 'package:PiliPlus/pages/live_search/controller.dart';

View File

@@ -4,7 +4,7 @@ import 'package:PiliPlus/common/skeleton/video_card_v.dart';
import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.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/http_error.dart';
import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/models/common/live_search_type.dart'; import 'package:PiliPlus/models/common/live/live_search_type.dart';
import 'package:PiliPlus/pages/live_search/child/controller.dart'; import 'package:PiliPlus/pages/live_search/child/controller.dart';
import 'package:PiliPlus/pages/live_search/widgets/live_search_room.dart'; import 'package:PiliPlus/pages/live_search/widgets/live_search_room.dart';
import 'package:PiliPlus/pages/live_search/widgets/live_search_user.dart'; import 'package:PiliPlus/pages/live_search/widgets/live_search_user.dart';

View File

@@ -1,4 +1,4 @@
import 'package:PiliPlus/models/common/live_search_type.dart'; import 'package:PiliPlus/models/common/live/live_search_type.dart';
import 'package:PiliPlus/pages/live_search/child/controller.dart'; import 'package:PiliPlus/pages/live_search/child/controller.dart';
import 'package:PiliPlus/utils/extension/scroll_controller_ext.dart'; import 'package:PiliPlus/utils/extension/scroll_controller_ext.dart';
import 'package:PiliPlus/utils/id_utils.dart'; import 'package:PiliPlus/utils/id_utils.dart';

View File

@@ -1,6 +1,6 @@
import 'package:PiliPlus/common/widgets/scroll_physics.dart'; import 'package:PiliPlus/common/widgets/scroll_physics.dart';
import 'package:PiliPlus/common/widgets/view_safe_area.dart'; import 'package:PiliPlus/common/widgets/view_safe_area.dart';
import 'package:PiliPlus/models/common/live_search_type.dart'; import 'package:PiliPlus/models/common/live/live_search_type.dart';
import 'package:PiliPlus/pages/live_search/child/view.dart'; import 'package:PiliPlus/pages/live_search/child/view.dart';
import 'package:PiliPlus/pages/live_search/controller.dart'; import 'package:PiliPlus/pages/live_search/controller.dart';
import 'package:PiliPlus/utils/utils.dart'; import 'package:PiliPlus/utils/utils.dart';

View File

@@ -115,10 +115,10 @@ class UserInfoCard extends StatelessWidget {
? images.imgUrl ? images.imgUrl
: images.nightImgurl) : images.nightImgurl)
.http2https; .http2https;
return Hero( return GestureDetector(
tag: imgUrl, onTap: () => PageUtils.imageView(imgList: [SourceModel(url: imgUrl)]),
child: GestureDetector( child: Hero(
onTap: () => PageUtils.imageView(imgList: [SourceModel(url: imgUrl)]), tag: imgUrl,
child: CachedNetworkImage( child: CachedNetworkImage(
imageUrl: ImageUtils.thumbnailUrl(imgUrl), imageUrl: ImageUtils.thumbnailUrl(imgUrl),
width: double.infinity, width: double.infinity,

View File

@@ -11,6 +11,7 @@ import 'package:PiliPlus/utils/extension/context_ext.dart';
import 'package:PiliPlus/utils/extension/get_ext.dart'; import 'package:PiliPlus/utils/extension/get_ext.dart';
import 'package:PiliPlus/utils/extension/size_ext.dart'; import 'package:PiliPlus/utils/extension/size_ext.dart';
import 'package:PiliPlus/utils/image_utils.dart'; import 'package:PiliPlus/utils/image_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/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart' hide ListTile; import 'package:flutter/material.dart' hide ListTile;
@@ -177,12 +178,10 @@ class _SearchTrendingPageState extends State<SearchTrendingPage> {
'${index + 1 - _controller.topCount}', '${index + 1 - _controller.topCount}',
style: TextStyle( style: TextStyle(
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: switch (index - _controller.topCount) { color: Utils.index2Color(
0 => const Color(0xFFfdad13), index - _controller.topCount,
1 => const Color(0xFF8aace1), theme.colorScheme.outline,
2 => const Color(0xFFdfa777), ),
_ => theme.colorScheme.outline,
},
fontSize: 17, fontSize: 17,
fontStyle: FontStyle.italic, fontStyle: FontStyle.italic,
), ),

View File

@@ -21,6 +21,13 @@ abstract final class Utils {
static const jsonEncoder = JsonEncoder.withIndent(' '); static const jsonEncoder = JsonEncoder.withIndent(' ');
static Color index2Color(int index, Color color) => switch (index) {
0 => const Color(0xFFfdad13),
1 => const Color(0xFF8aace1),
2 => const Color(0xFFdfa777),
_ => color,
};
static String themeUrl(bool isDark) => static String themeUrl(bool isDark) =>
'native.theme=${isDark ? 2 : 1}&night=${isDark ? 1 : 0}'; 'native.theme=${isDark ? 2 : 1}&night=${isDark ? 1 : 0}';