feat: 播放处理,个人中心,

This commit is contained in:
csw 2026-06-30 16:05:17 +08:00
parent e59ac2177b
commit 4ccea08472
37 changed files with 1425 additions and 115 deletions

BIN
assets/mine/copy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 306 B

BIN
assets/mine/def_avatar.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

BIN
assets/mine/little_left.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 231 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 203 B

BIN
assets/mine/mine_top.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

BIN
assets/mine/section_bg1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
assets/mine/section_bg2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
assets/mine/section_bg3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1018 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 389 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
assets/pics/esp_bg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

BIN
assets/pics/play_tag.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
assets/pics/rank1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
assets/pics/rank2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
assets/pics/rank3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -1,4 +1,3 @@
import 'package:skywood/global/request/api_const.dart';
import 'package:skywood/global/request/app_request.dart';
import 'package:skywood/global/tool/sky_log.dart';
@ -8,7 +7,6 @@ import 'package:skywood/utils/models/drama/skywood_drama.dart';
import 'package:skywood/utils/models/drama/skywood_home.dart';
class PlayClient {
static Future<List<SkywoodHome>> getHomeData() {
return AppRequest.get(ApiStringPlay.getHomeModules).then((value) {
if (value.isSuccess) {
@ -42,6 +40,20 @@ class PlayClient {
});
}
static Future<List<SkywoodDrama>> getCategoriesDetail({
required int categoryId,
int page = 1,
int pageSize = 20,
}) {
return AppRequest.fetchPage<SkywoodDrama>(
ApiStringPlay.getCategoriesDetail,
page: page,
pageSize: pageSize,
extraParams: {'category_id': categoryId},
fromJson: (json) => SkywoodDrama.fromJson(json),
);
}
// getSearchHots
static Future<List<SkywoodDrama>> getSearchHots() {
return AppRequest.get(ApiStringPlay.getSearchHots).then((value) {
@ -54,29 +66,53 @@ class PlayClient {
});
}
// search
static Future<List<SkywoodDrama>> search({required String keyword}) {
return AppRequest.get(ApiStringPlay.getSearch, queryParameters: {
'search': keyword,
}).then((value) {
if (value.isSuccess) {
SkyLog.print('getSearchHots: ${value.data}');
List list = parseDataForList(value.data);
return list.map((e) => SkywoodDrama.fromJson(e)).toList();
}
return [];
});
}
//getCollections
static Future<List> getCollections({
int page = 1, int pageSize = 10
static Future<List<SkywoodDrama>> getCollections({
int page = 1,
int pageSize = 10,
}) {
Map<String, dynamic> params = _setPage(page: page, pageSize: pageSize);
return AppRequest.get(ApiStringPlay.getCollections, queryParameters: params).then((value) {
return AppRequest.get(
ApiStringPlay.getCollections,
queryParameters: params,
).then((value) {
if (value.isSuccess) {
SkyLog.print('getCollections: ${value.data}');
List list = parseDataForList(value.data);
return list.map((e) => SkywoodDrama.fromJson(e)).toList();
}
return [];
});
}
// getHistory
static Future<List> getHistory({
int page = 1, int pageSize = 10
static Future<List<SkywoodDrama>> getHistory({
int page = 1,
int pageSize = 10,
}) {
Map<String, dynamic> params = _setPage(page: page, pageSize: pageSize);
return AppRequest.get(ApiStringPlay.getHistories, queryParameters: params).then((value) {
return AppRequest.get(
ApiStringPlay.getHistories,
queryParameters: params,
).then((value) {
if (value.isSuccess) {
SkyLog.print('getHistory: ${value.data}');
List list = parseDataForList(value.data);
return list.map((e) => SkywoodDrama.fromJson(e)).toList();
}
return [];
});
@ -90,19 +126,48 @@ class PlayClient {
Map<String, dynamic> params = {};
params['short_play_id'] = shortPlayId;
params['short_play_video_id'] = shortPlayVideoId;
return AppRequest.get(ApiStringPlay.getVideoDetail, queryParameters: params).then((value) {
return AppRequest.get(
ApiStringPlay.getVideoDetail,
queryParameters: params,
).then((value) {
if (value.isSuccess) {
SkyLog.print('getVideoDetail: ${value.data}');
SkyLog.print('getVideoDetail: ${value.data['data']}');
return SkywoodDetail.fromJson(value.data['data']);
}
return null;
});
}
// collect
static Future<bool> collect({
required int shortPlayId,
required int videoId,
}) {
Map<String, dynamic> params = {};
params['short_play_id'] = shortPlayId;
params['video_id'] = videoId;
return AppRequest.post(ApiStringPlay.collect, data: params).then((value) {
SkyLog.print('collecttttt: ${value.data}');
if (value.isSuccess) {}
return value.isSuccess;
});
}
// cancelCollect
static Future<bool> cancelCollect({required int shortPlayId}) {
Map<String, dynamic> params = {};
params['short_play_id'] = shortPlayId;
return AppRequest.post(ApiStringPlay.cancelCollect, data: params).then((
value,
) {
SkyLog.print('cancelCollectttt: ${value.data}');
if (value.isSuccess) {}
return value.isSuccess;
});
}
static Map<String, dynamic> _setPage({int page = 1, int pageSize = 10}) {
return {
'current_page': page,
'page_size': pageSize,
};
return {'current_page': page, 'page_size': pageSize};
}
static List parseDataForList(Map<String, dynamic> data) {
@ -110,4 +175,4 @@ class PlayClient {
List? listData = map['list'];
return listData ?? [];
}
}
}

View File

@ -3,6 +3,7 @@ import 'package:skywood/global/request/api_const.dart';
import 'package:skywood/global/request/app_request.dart';
import 'package:skywood/global/tool/sky_log.dart';
import 'package:skywood/utils/models/user/register_bean.dart';
import 'package:skywood/utils/models/user/skywood_user.dart';
class UserClient {
@ -27,4 +28,14 @@ class UserClient {
return null;
});
}
static Future<SkywoodUser?> getUserInfo() {
return AppRequest.get(ApiString.userInfo).then((value) {
if (value.isSuccess) {
SkyLog.print(value.data, tag: 'getUserInfo');
return SkywoodUser.fromJson(value.data['data']);
}
return null;
});
}
}

View File

@ -57,15 +57,15 @@ class ApiString {
class ApiStringPlay {
// getRecommandsList GET /getRecommands current_page/page_size revolution
// getVideoDetail GET /getVideoDetails query: short_play_id, video_id
/// getVideoDetail GET /getVideoDetails query: short_play_id, video_id
// getDetailsRecommand GET /getDetailsRecommand page/pageSize/data
static const String getRecommandsList = "/getRecommands";
static const String getVideoDetail = "/getVideoDetails";
static const String getDetailsRecommand = "/getDetailsRecommand";
/// getHomeModules GET /home/all-modules
///=== getHomeModules GET /home/all-modules
// getRankingList POST /homeRanking body type most_trending/top_searched/new_releases
/// getCategoriesList GET /getCategories
///=== getCategoriesList GET /getCategories
// getCategoriesDetail GET /videoList / + extraParams
// getWaterflowList POST /newShortPlay + extraParams
static const String getHomeModules = "/home/all-modules";
@ -76,10 +76,10 @@ class ApiStringPlay {
/// getSearchHots GET /search/hots
// getSearch GET /search query: search
// collect POST /collect body: short_play_id, video_id
// cancelCollect POST /cancelCollect body: short_play_id
// getMyCollections GET /myCollections
// getMyHistorys GET /myHistorys
///==== collect POST /collect body: short_play_id, video_id
///==== cancelCollect POST /cancelCollect body: short_play_id
///==== getMyCollections GET /myCollections
///==== getMyHistorys GET /myHistorys
// getNoticeNum POST /noticeNum
// versionControl GET /customer/versionControl
// getLanguges GET /languges languges

View File

@ -4,6 +4,7 @@ import 'package:skywood/pages/home/home_page.dart';
import 'package:skywood/pages/like/like_page.dart';
import 'package:skywood/pages/mine/mine_page.dart';
import 'package:skywood/pages/search/page/search_page.dart';
import 'package:skywood/utils/extend/app_keep_alive.dart';
import 'package:skywood/utils/tools/help_img.dart';
class MainRoot extends StatefulWidget {
@ -17,10 +18,10 @@ class MainRoot extends StatefulWidget {
class _MainRootState extends State<MainRoot> {
final List<Widget> _pages = const [
HomePage(),
SearchPage(),
AppKeepAlive(child: HomePage()),
AppKeepAlive(child: SearchPage()),
LikePage(),
MinePage(),
AppKeepAlive(child: MinePage()),
];
final _pageController = PageController();

View File

@ -0,0 +1,318 @@
import 'package:flutter/material.dart';
import 'package:skywood/global/client/play_client.dart';
import 'package:skywood/main/lib_file.dart';
import 'package:skywood/pages/home/players/page/drama_detail_page.dart';
import 'package:skywood/utils/models/drama/skywood_category.dart';
import 'package:skywood/utils/models/drama/skywood_drama.dart';
import 'package:skywood/utils/tools/sky_time_tool.dart';
import 'package:skywood/utils/tools/widgets/sky_common_widget.dart';
class CatePage extends StatefulWidget {
const CatePage({super.key});
@override
State<CatePage> createState() => _CatePageState();
}
class _CatePageState extends State<CatePage> {
final List<SkywoodCategory> _categories = [];
final List<SkywoodDrama> _dramas = [];
int _selectedIndex = 0;
int? _loadingCategoryId;
bool _loadingCategories = true;
bool _loadingDramas = false;
@override
void initState() {
super.initState();
_loadCategories();
}
Future<void> _loadCategories() async {
List<SkywoodCategory> categories = [];
try {
categories = await PlayClient.getCategoriesList();
} catch (_) {
if (!mounted) return;
}
setState(() {
_categories
..clear()
..addAll(categories);
_loadingCategories = false;
});
if (categories.isNotEmpty) {
_loadCategoryDetail(categories.first.id);
}
}
Future<void> _loadCategoryDetail(int categoryId) async {
_loadingCategoryId = categoryId;
setState(() {
_loadingDramas = true;
_dramas.clear();
});
List<SkywoodDrama> dramas = [];
try {
dramas = await PlayClient.getCategoriesDetail(categoryId: categoryId);
} catch (_) {
if (!mounted || _loadingCategoryId != categoryId) return;
}
if (!mounted || _loadingCategoryId != categoryId) return;
setState(() {
_dramas.addAll(dramas);
_loadingDramas = false;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: SafeArea(
bottom: false,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildHeader(),
Expanded(
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildCategoryList(),
Expanded(child: _buildDramaList()),
],
),
),
],
),
),
);
}
Widget _buildHeader() {
return SizedBox(
height: 49.h,
child: Stack(
children: [
Positioned(
left: 13.w,
top: 16.h,
child: HelpImg.asset(
ConstImg.back,
width: 24.w,
height: 24.w,
).addInkWell(onTap: () => HelpNav.back()),
),
Positioned(
left: 94.w,
top: 22.h,
child: SkyText(
text: 'Explore Genres',
color: CommonColor.black,
fontSize: 14,
fontWeight: FontWeight.w800,
),
),
],
),
);
}
Widget _buildCategoryList() {
return Container(
width: 86.w,
height: double.infinity,
padding: EdgeInsets.only(top: 12.h, bottom: 18.h),
decoration: BoxDecoration(
color: const Color(0xFFF2FFF0),
borderRadius: BorderRadius.only(topRight: Radius.circular(8.r)),
),
child: _loadingCategories
? const SizedBox.shrink()
: ListView.builder(
padding: EdgeInsets.zero,
itemCount: _categories.length,
itemBuilder: (context, index) {
return _buildCategoryItem(index);
},
),
);
}
Widget _buildCategoryItem(int index) {
final category = _categories[index];
final selected = index == _selectedIndex;
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
if (selected) return;
setState(() {
_selectedIndex = index;
});
_loadCategoryDetail(category.id);
},
child: SizedBox(
height: 47.h,
child: Stack(
alignment: Alignment.center,
children: [
if (selected)
Positioned(
left: 0,
top: 0,
bottom: 0,
child: HelpImg.asset(
ConstImg.cateSelLeft,
width: 20.w,
height: 50.h,
fit: BoxFit.fill,
),
),
if (selected)
Positioned(
right: 0,
top: 0,
bottom: 0,
child: HelpImg.asset(
ConstImg.cateSelRight,
width: 20.w,
height: 50.h,
fit: BoxFit.fill,
),
),
Padding(
padding: EdgeInsets.symmetric(horizontal: 12.w),
child: SkyText(
text: category.name,
color: selected
? CommonColor.primacyColor
: Colors.black.withAlpha(100),
fontSize: 11,
fontWeight: selected ? FontWeight.w700 : FontWeight.w500,
textAlign: TextAlign.center,
maxLines: 2,
lineHeight: 1.05,
),
),
],
),
),
);
}
Widget _buildDramaList() {
if (_loadingDramas) {
return const Center(
child: CircularProgressIndicator(color: CommonColor.primacyColor),
);
}
if (_dramas.isEmpty) {
return Center(
child: SkyText(
text: 'No Data',
color: Colors.black.withAlpha(100),
fontSize: 13,
),
);
}
return ListView.separated(
padding: EdgeInsets.only(left: 8.w, right: 10.w, bottom: 24.h),
itemCount: _dramas.length,
separatorBuilder: (context, index) => SizedBox(height: 10.h),
itemBuilder: (context, index) {
return _DramaItem(drama: _dramas[index]);
},
);
}
}
class _DramaItem extends StatelessWidget {
const _DramaItem({required this.drama});
final SkywoodDrama drama;
@override
Widget build(BuildContext context) {
return SizedBox(
height: 80.h,
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
HelpImg.networkRadius(
drama.imageUrl,
width: 64.w,
height: 80.h,
fit: BoxFit.cover,
borderRadius: BorderRadius.circular(4.r),
),
SizedBox(width: 8.w),
Expanded(
child: Padding(
padding: EdgeInsets.only(top: 2.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SkyText(
text: drama.name,
color: CommonColor.black,
fontSize: 11,
fontWeight: FontWeight.w700,
maxLines: 2,
lineHeight: 1.08,
),
SizedBox(height: 7.h),
SkyText(
text: drama.description,
color: Colors.black.withAlpha(92),
fontSize: 9,
maxLines: 2,
lineHeight: 1.2,
),
const Spacer(),
Row(
children: [
_TipView(icon: ConstImg.star, text: '10.0'),
SizedBox(width: 12.w),
_TipView(
icon: ConstImg.look,
text: SkyTimeTool.formatNum(drama.watchTotal),
),
],
),
],
),
),
),
],
),
).addInkWell(onTap: () => HelpNav.to(DramaDetailPage(dramaBean: drama)));
}
}
class _TipView extends StatelessWidget {
const _TipView({required this.icon, required this.text});
final String icon;
final String text;
@override
Widget build(BuildContext context) {
return Row(
mainAxisSize: MainAxisSize.min,
children: [
HelpImg.asset(icon, width: 8.w, height: 8.w),
SizedBox(width: 2.w),
SkyText(text: text, color: Colors.black.withAlpha(110), fontSize: 8),
],
);
}
}

View File

@ -1,9 +1,13 @@
import 'package:flutter/material.dart';
import 'package:skywood/global/client/play_client.dart';
import 'package:skywood/main/lib_file.dart';
import 'package:skywood/pages/home/players/widget/player_bottom_widget.dart';
import 'package:skywood/pages/home/players/widget/sky_player_view.dart';
import 'package:skywood/utils/models/drama/skywood_detail.dart';
import 'package:skywood/utils/models/drama/skywood_drama.dart';
import 'package:skywood/utils/models/drama/skywood_home.dart';
import 'package:skywood/utils/tools/widgets/sky_app_bar.dart';
import 'package:skywood/utils/tools/widgets/sky_common_widget.dart';
class DramaDetailPage extends StatefulWidget {
const DramaDetailPage({super.key,
@ -20,28 +24,30 @@ class DramaDetailPage extends StatefulWidget {
class _DramaDetailPageState extends State<DramaDetailPage> {
SkywoodDetail? _detailBean;
@override
void initState() {
super.initState();
// _getDetailDrama();
_getDetailDrama();
}
// void _getDetailDrama() {
// PlayClient.getVideoDetail(
// shortPlayId: widget.shortPlayId,
// shortPlayVideoId: widget.shortPlayVideoId
// ).then((value) {});
// }
void _getDetailDrama() {
PlayClient.getVideoDetail(
shortPlayId: widget.dramaBean.shortPlayId ?? 0,
shortPlayVideoId: widget.dramaBean.shortPlayVideoId ?? 0
).then((value) {
setState(() {
_detailBean = value;
});
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
appBar: SkyAppBar(
title: widget.dramaBean.name,
backgroundColor: Colors.transparent,
),
body: _bodyWidget(),
);
}
@ -50,11 +56,43 @@ class _DramaDetailPageState extends State<DramaDetailPage> {
return Stack(
children: [
SizedBox(width: double.infinity, height: double.infinity),
if (widget.dramaBean.videoUrl != null)
Positioned(
bottom: 0, left: 0, right: 0, top: 0,
child: SkyPlayerView(
videoUrl: widget.dramaBean.videoUrl!,
detailBean: _detailBean,
dramaBean: widget.dramaBean,
),
),
Positioned(
bottom: 0, left: 0, right: 0,
child: PlayerBottomWidget(),
),
top: AppScreen.statusBarHeight + 5, left: 0, right: 0,
child: _headerWidget(),
)
],
);
}
Widget _headerWidget() {
return Container(
height: 40,
padding: const EdgeInsets.only(right: 15, left: 5),
child: Row(
children: [
IconButton(
icon: HelpImg.asset(ConstImg.back, width: 32),
onPressed: () => HelpNav.back(),
),
Expanded(child: SkyText(text: widget.dramaBean.name, color: Colors.white, fontSize: 16,
textAlign: TextAlign.center,
fontWeight: FontWeight.bold,
)),
SizedBox(width: 40,)
],
),
);
}
}

View File

@ -0,0 +1,220 @@
import 'package:flutter/material.dart';
import 'package:skywood/main/lib_file.dart';
import 'package:skywood/utils/models/drama/skywood_detail.dart';
import 'package:skywood/utils/models/drama/skywood_drama.dart';
import 'package:skywood/utils/models/drama/skywood_episode.dart';
import 'package:skywood/utils/tools/widgets/sky_common_widget.dart';
class DramaEspPage extends StatefulWidget {
const DramaEspPage({super.key, required this.detail, this.currentEpisode});
final SkywoodDetail detail;
final int? currentEpisode;
@override
State<StatefulWidget> createState() {
return _DramaEspPageState();
}
}
class _DramaEspPageState extends State<DramaEspPage> {
late int _selectedEpisode;
SkywoodDrama? get _drama =>
widget.detail.shortPlayInfo ?? widget.detail.videoInfo;
List<SkywoodEpisode> get _episodes => widget.detail.episodeList;
@override
void initState() {
super.initState();
_selectedEpisode = widget.currentEpisode ?? _drama?.episode ?? 1;
}
@override
Widget build(BuildContext context) {
final double height = 520;
return SizedBox(
width: AppScreen.screenWidth,
height: 520,
child: Stack(
children: [
HelpImg.asset(
ConstImg.espBg,
width: AppScreen.screenWidth,
height: height,
fit: BoxFit.fill,
),
Positioned.fill(
child: Padding(
padding: EdgeInsets.fromLTRB(22.w, 31.h, 22.w, 54.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildDramaInfo(),
SizedBox(height: 12),
Divider(
height: 1,
thickness: 0.5,
color: Colors.black.withAlpha(18),
),
SizedBox(height: 12),
SkyText(
text: '$_episodeTotal EP',
color: Colors.black,
fontSize: 15,
fontWeight: FontWeight.w500,
),
SizedBox(height: 8),
Expanded(child: _buildEpisodeGrid()),
],
),
),
),
],
),
);
}
Widget _buildDramaInfo() {
final SkywoodDrama? drama = _drama;
final SkywoodDrama? info = widget.detail.videoInfo;
final String imageUrl = drama?.imageUrl ?? '';
return SizedBox(
height: 130.h,
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
HelpImg.networkRadius(
imageUrl,
width: 96.w,
height: 130.h,
fit: BoxFit.cover,
borderRadius: BorderRadius.circular(2),
),
SizedBox(width: 16.w),
Expanded(
child: Padding(
padding: EdgeInsets.only(top: 7.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SkyText(
text: drama?.name ?? '',
color: Colors.black,
fontSize: 18,
fontWeight: FontWeight.w700,
maxLines: 2,
lineHeight: 1.12,
),
SizedBox(height: 10.h),
SkyText(
text: info?.description ?? '',
color: Colors.black.withAlpha(118),
fontSize: 14,
maxLines: 2,
lineHeight: 1.45,
),
SizedBox(height: 13.h),
_buildTag(),
],
),
),
),
],
),
);
}
Widget _buildTag() {
final String name = _drama?.categoryList?.isNotEmpty == true
? _drama!.categoryList!.first.name
: (_drama?.tagType ?? '');
if (name.isEmpty) return const SizedBox.shrink();
return Container(
padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 3.h),
decoration: BoxDecoration(
color: const Color(0xFFE7FFE5),
border: Border.all(color: const Color(0xFF86D57A), width: 1),
),
child: SkyText(
text: name,
color: Colors.black,
fontSize: 14,
overflow: TextOverflow.visible,
),
);
}
Widget _buildEpisodeGrid() {
if (_episodes.isEmpty) {
return const SizedBox.shrink();
}
return GridView.builder(
padding: EdgeInsets.zero,
physics: const BouncingScrollPhysics(),
itemCount: _episodes.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 5,
mainAxisSpacing: 10,
crossAxisSpacing: 10,
childAspectRatio: 61 / 50,
),
itemBuilder: (context, index) {
return _buildEpisodeItem(_episodes[index]);
},
);
}
Widget _buildEpisodeItem(SkywoodEpisode episode) {
final bool selected = episode.episode == _selectedEpisode;
final bool selectedPlayable = selected && !episode.isLock;
final bool selectedLocked = selected && episode.isLock;
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
setState(() {
_selectedEpisode = episode.episode;
});
},
child: Container(
alignment: Alignment.center,
decoration: BoxDecoration(
color: selectedPlayable
? const Color(0xFF91F476)
: const Color(0xFFF8F8F8),
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: selectedPlayable
? Colors.black
: (selectedLocked
? CommonColor.primacyColor
: Colors.transparent),
width: selected ? 1 : 0,
),
),
child: Center(
child: SkyText(
text: episode.episode.toString(),
color: Colors.black.withAlpha(220),
fontSize: 20,
fontWeight: selected ? FontWeight.w700 : FontWeight.w400,
),
),
),
);
}
int get _episodeTotal {
if (_drama?.episodeTotal != null && _drama!.episodeTotal > 0) {
return _drama!.episodeTotal;
}
return _episodes.length;
}
}

View File

@ -4,7 +4,13 @@ import 'package:skywood/utils/tools/widgets/sky_common_widget.dart';
class PlayerBottomWidget extends StatefulWidget {
const PlayerBottomWidget({super.key});
const PlayerBottomWidget({super.key,
// required this.totalTime,
// required this.currentTime,
});
// final String totalTime;
// final String currentTime;
@override
State<StatefulWidget> createState() {
@ -92,4 +98,10 @@ class _PlayerBottomWidgetState extends State<PlayerBottomWidget> {
),
);
}
String _formatDuration(Duration duration) {
final minutes = duration.inMinutes.remainder(60).toString().padLeft(2, '0');
final seconds = duration.inSeconds.remainder(60).toString().padLeft(2, '0');
return '$minutes:$seconds';
}
}

View File

@ -0,0 +1,396 @@
import 'package:flutter/material.dart';
import 'package:skywood/global/client/play_client.dart';
import 'package:skywood/main/lib_file.dart';
import 'package:skywood/pages/home/players/page/drama_esp_page.dart';
import 'package:skywood/utils/models/drama/skywood_detail.dart';
import 'package:skywood/utils/models/drama/skywood_drama.dart';
import 'package:skywood/utils/tools/widgets/sky_common_widget.dart';
import 'package:video_player/video_player.dart';
///
class SkyPlayerView extends StatefulWidget {
final String videoUrl;
final bool autoPlay;
final SkywoodDetail? detailBean;
final SkywoodDrama dramaBean;
const SkyPlayerView({
super.key,
required this.videoUrl,
this.autoPlay = true,
this.detailBean,
required this.dramaBean,
});
@override
State<SkyPlayerView> createState() => _VideoPlayerWidgetState();
}
class _VideoPlayerWidgetState extends State<SkyPlayerView> {
late VideoPlayerController _controller;
bool _controllerCreated = false;
bool _isPlaying = false;
bool _isInitialized = false;
bool _isSeeking = false;
String? _errorMessage;
Duration _currentPosition = Duration.zero;
Duration _totalDuration = Duration.zero;
bool _isLiked = false;
@override
void initState() {
super.initState();
_initializePlayer();
}
@override
void didUpdateWidget(SkyPlayerView oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.videoUrl != widget.videoUrl) {
_disposeController();
_initializePlayer();
}
}
Future<void> _initializePlayer() async {
setState(() {
_isInitialized = false;
_isPlaying = false;
_errorMessage = null;
_currentPosition = Duration.zero;
_totalDuration = Duration.zero;
_isLiked = widget.dramaBean.isCollect ?? false;
});
final controller = VideoPlayerController.networkUrl(
Uri.parse(widget.videoUrl),
);
_controller = controller;
_controllerCreated = true;
controller.addListener(_handlePlayerValueChanged);
try {
await controller.initialize();
if (!mounted || controller != _controller || !_controllerCreated) return;
if (widget.autoPlay) {
await controller.play();
}
_syncPlayerValue();
} catch (error) {
if (!mounted || controller != _controller) return;
setState(() {
_errorMessage = error.toString();
_isInitialized = false;
_isPlaying = false;
});
}
}
void _handlePlayerValueChanged() {
if (!mounted || !_controllerCreated) return;
_syncPlayerValue();
}
void _syncPlayerValue() {
final value = _controller.value;
final nextPosition = _isSeeking ? _currentPosition : value.position;
final nextDuration = value.duration;
final nextPlaying = value.isPlaying;
setState(() {
_isInitialized = value.isInitialized;
_isPlaying = nextPlaying;
_currentPosition = nextPosition;
_totalDuration = nextDuration;
});
}
void _disposeController() {
if (!_controllerCreated) return;
_controller.removeListener(_handlePlayerValueChanged);
_controller.dispose();
_controllerCreated = false;
}
@override
void dispose() {
_disposeController();
super.dispose();
}
@override
Widget build(BuildContext context) {
if (_errorMessage != null) {
return _buildErrorView();
}
return _isInitialized && _controllerCreated
? _buildVideoContent()
: _buildLoadingView();
}
Widget _buildVideoContent() {
return Stack(
fit: StackFit.expand,
children: [
FittedBox(
fit: BoxFit.cover,
child: SizedBox(
width: _controller.value.size.width,
height: _controller.value.size.height,
child: VideoPlayer(_controller),
),
),
Positioned.fill(
child: GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: _togglePlay,
child: Container(),
),
),
if (widget.detailBean != null)
Positioned(bottom: 0, left: 0, right: 0, child: _buildBottomView()),
if (!_isPlaying)
Center(
child: GestureDetector(
onTap: _togglePlay,
child: Container(
width: 60,
height: 60,
decoration: BoxDecoration(
color: Colors.white.withAlpha(204),
shape: BoxShape.circle,
),
child: const Icon(
Icons.play_arrow_rounded,
color: Colors.black,
size: 40,
),
),
),
),
],
);
}
Widget _buildLoadingView() {
return Container(
color: Colors.black,
child: const Center(
child: CircularProgressIndicator(color: Colors.white),
),
);
}
Widget _buildErrorView() {
return Container(
color: Colors.black,
alignment: Alignment.center,
padding: const EdgeInsets.symmetric(horizontal: 24),
child: SkyText(
text: 'Video failed to load',
color: Colors.white.withAlpha(180),
fontSize: 14,
),
);
}
void _togglePlay() {
if (!_isInitialized || !_controllerCreated) return;
if (_controller.value.isPlaying) {
_controller.pause();
} else {
_controller.play();
}
}
void _collectionDrama() {
if (_isLiked) {
PlayClient.cancelCollect(shortPlayId: widget.dramaBean.shortPlayId??0).then((value) {
setState(() {
_isLiked = value;
});
});
} else {
PlayClient.collect(
shortPlayId: widget.dramaBean.shortPlayId??0,
videoId: widget.dramaBean.shortPlayVideoId ?? 0,
).then((value) {
setState(() {
_isLiked = value;
});
});
}
}
Widget _buildBottomView() {
SkywoodDetail detail = widget.detailBean!;
final int currentEpisode = _currentEpisode(detail);
final int totalEpisode = _episodeTotal(detail);
return Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
InkWell(
onTap: () => _collectionDrama(),
child: HelpImg.asset(
_isLiked ? ConstImg.liked : ConstImg.unlike,
width: 40, height: 40
),
),
const SizedBox(height: 24),
Container(
height: 36,
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4),
color: Colors.white.withAlpha(30),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
HelpImg.asset(ConstImg.playLt, width: 17, height: 17),
const SizedBox(width: 10),
SkyText(
text: 'EP.$currentEpisode',
fontSize: 13,
color: Colors.white,
),
SkyText(
text: ' / EP.${detail.episodeList.length}',
fontSize: 13,
color: Colors.white.withAlpha(126),
),
],
),
Icon(Icons.arrow_forward_ios, color: Colors.white, size: 13),
],
),
).addInkWell(
onTap: () {
// HelpNav.showBottom(
// DramaEspPage(detail: detail, currentEpisode: currentEpisode),
// );
showModalBottomSheet(
context: context,
isScrollControlled: true,
backgroundColor: Colors.transparent,
builder: (context) {
return SizedBox(
height: 520,
child: DramaEspPage(
detail: detail,
currentEpisode: currentEpisode,
),
);
},
);
},
),
const SizedBox(height: 8),
_buildProgressBar(),
const SizedBox(height: 7),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
SkyText(
text: _formatDuration(_currentPosition),
fontSize: 13,
color: Colors.white,
),
SkyText(
text: ' / ${_formatDuration(_totalDuration)}',
fontSize: 13,
color: Colors.white.withAlpha(126),
),
],
),
SkyText(text: 'x1.0', fontSize: 13, color: Colors.white),
],
),
const SizedBox(height: 20),
],
),
);
}
Widget _buildProgressBar() {
final int totalMilliseconds = _totalDuration.inMilliseconds;
final double progress = totalMilliseconds <= 0
? 0
: (_currentPosition.inMilliseconds / totalMilliseconds).clamp(0.0, 1.0);
return SizedBox(
width: double.infinity,
height: 3,
child: SliderTheme(
data: SliderThemeData(
trackHeight: 3, // 3
thumbShape: const RoundSliderThumbShape(enabledThumbRadius: 1),
overlayShape: const RoundSliderOverlayShape(overlayRadius: 3),
activeTrackColor: Colors.white, // =
inactiveTrackColor: Colors.white.withAlpha(126), // =
thumbColor: Colors.white,
overlayColor: Colors.white.withAlpha(76),
),
child: Slider(
padding: EdgeInsets.zero,
value: progress,
min: 0,
max: 1,
onChangeStart: (_) {
_isSeeking = true;
},
onChanged: (value) {
setState(() {
_currentPosition = Duration(
milliseconds: (totalMilliseconds * value).round(),
);
});
},
onChangeEnd: (value) {
final position = Duration(
milliseconds: (totalMilliseconds * value).round(),
);
_controller.seekTo(position);
_isSeeking = false;
},
),
),
);
}
String _formatDuration(Duration duration) {
final minutes = duration.inMinutes.remainder(60).toString().padLeft(2, '0');
final seconds = duration.inSeconds.remainder(60).toString().padLeft(2, '0');
return '$minutes:$seconds';
}
int _currentEpisode(SkywoodDetail detail) {
final int? episode =
detail.videoInfo?.episode ??
detail.videoInfo?.currentEpisode ??
detail.shortPlayInfo?.episode ??
detail.shortPlayInfo?.currentEpisode;
if (episode != null && episode > 0) return episode;
return 1;
}
int _episodeTotal(SkywoodDetail detail) {
return detail.episodeList.length;
}
}

View File

@ -52,7 +52,13 @@ class DailyQuestWidget extends StatelessWidget {
child: Row(
spacing: 5.w,
children: List.generate(dramaList.length-1, (index) {
return HelpImg.network(dramaList[index+1].imageUrl, width: 95.w, height: 50.h, fit: BoxFit.cover);
final drama = dramaList[index+1];
return InkWell(
onTap: () {
HelpNav.to(DramaDetailPage(dramaBean: drama));
},
child: HelpImg.network(drama.imageUrl, width: 95.w, height: 50.h, fit: BoxFit.cover),
);
})
),
);

View File

@ -3,6 +3,8 @@ import 'package:skywood/main/lib_file.dart';
import 'package:skywood/utils/models/drama/skywood_category.dart';
import 'package:skywood/utils/tools/widgets/sky_common_widget.dart';
import '../players/page/drama_detail_page.dart';
class HomeCateWidget extends StatelessWidget {
const HomeCateWidget({super.key,
@ -25,7 +27,8 @@ class HomeCateWidget extends StatelessWidget {
),
itemCount: categories.length,
itemBuilder: (context, index) {
return _buildCateItem(categories[index], index);}
return _buildCateItem(categories[index], index);
}
),
);
}
@ -40,7 +43,9 @@ class HomeCateWidget extends StatelessWidget {
child: _customText(category.name,),
)
],
);
).addInkWell(onTap: () {
// HelpNav.to(DramaDetailPage(dramaBean: drama));
});
}
_customText(String text) {

View File

@ -3,6 +3,7 @@ import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:skywood/main/lib_file.dart';
import '../../../utils/models/drama/skywood_drama.dart';
import '../players/page/drama_detail_page.dart';
class HotCartridgeWidget extends StatelessWidget {
@ -38,6 +39,8 @@ class HotCartridgeWidget extends StatelessWidget {
),
HelpImg.asset(index<3?ConstImg.hotBg1:ConstImg.hotBg2, width: 110.w, height: 174.h)
],
);
).addInkWell(onTap: () {
HelpNav.to(DramaDetailPage(dramaBean: drama));
});
}
}

View File

@ -67,7 +67,7 @@ class RankListWidget extends StatelessWidget {
Widget _rankIndex(int index) {
return SizedBox(
width: 40.w,
child: SkyText(text: formatNumber(index + 1),
child: index < 3 ? _rank123(index) : SkyText(text: formatNumber(index + 1),
fontSize: 15,
color: CommonColor.black,
fontFamily: 'Anton',
@ -77,6 +77,16 @@ class RankListWidget extends StatelessWidget {
);
}
Widget _rank123(int index) {
String img = '';
if (index == 0) img = ConstImg.rank1;
if (index == 1) img = ConstImg.rank2;
if (index == 2) img = ConstImg.rank3;
return Padding(padding: EdgeInsets.only(right: 16.w),
child: HelpImg.asset(img, width: 24.w),
);
}
String formatNumber(int number) {
return number.toString().padLeft(2, '0');
}

View File

@ -1,6 +1,9 @@
import 'package:flutter/material.dart';
import 'package:skywood/global/client/play_client.dart';
import 'package:skywood/main/lib_file.dart';
import 'package:skywood/pages/home/players/page/drama_detail_page.dart';
import 'package:skywood/utils/models/drama/skywood_drama.dart';
import 'package:skywood/utils/tools/widgets/sky_common_widget.dart';
class CollectionPage extends StatefulWidget {
@ -14,16 +17,19 @@ class CollectionPage extends StatefulWidget {
class _CollectionPageState extends State<CollectionPage> {
List<SkywoodDrama> _collectionList = [];
@override
void initState() {
// TODO: implement initState
super.initState();
_getCollection();
}
void _getCollection() {
PlayClient.getCollections().then((value) {
setState(() {
_collectionList = value;
});
});
}
@ -40,16 +46,36 @@ class _CollectionPageState extends State<CollectionPage> {
itemBuilder: (context, index) {
return _buildItem(index);
},
itemCount: 5,
itemCount: _collectionList.length,
);
}
Widget _buildItem(int index) {
final SkywoodDrama drama = _collectionList[index];
return Stack(
children: [
HelpImg.asset(ConstImg.collectionBg, width: 100.w, height: 174.w, fit: BoxFit.fill,),
SizedBox(
width: 100.w, height: 174.w,
child: HelpImg.asset(ConstImg.collectionBg, width: 100.w, height: 174.w, fit: BoxFit.fill,),
),
Positioned(
left: 5, right: 5, top: 32.w,
child: HelpImg.network(drama.imageUrl, height: 110.w, width: 90.w, fit: BoxFit.fill,),
),
Positioned(
bottom: 6, left: 2, right: 2,
child: SkyText(text: drama.name,
fontSize: 13,
color: CommonColor.black,
),
),
Positioned(
right: 10, top: 15,
child: HelpImg.asset(ConstImg.liked, width: 18, height: 18,),
)
],
);
).addInkWell(onTap: () {
HelpNav.to(DramaDetailPage(dramaBean: drama));
},);
}
}

View File

@ -1,6 +1,14 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:skywood/global/client/user_client.dart';
import 'package:skywood/main/lib_file.dart';
import 'package:skywood/pages/mine/widget/mine_section_view.dart';
import 'package:skywood/pages/widgets/pixel_widgets.dart';
import 'package:skywood/utils/models/user/skywood_user.dart';
import 'package:skywood/utils/tools/app_toast.dart';
import 'package:skywood/utils/tools/widgets/sky_common_widget.dart';
import '../widgets/common_bg_page.dart';
class MinePage extends StatefulWidget {
const MinePage({super.key});
@ -12,32 +20,92 @@ class MinePage extends StatefulWidget {
}
class _MainRootState extends State<MinePage> {
SkywoodUser? _userInfo;
@override
void initState() {
super.initState();
_getUserData();
}
void _getUserData() {
UserClient.getUserInfo().then((value) {
setState(() {
_userInfo = value;
});
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: PixelPageBackground(
child: SafeArea(
return CommonBgPage(
child: SafeArea(
bottom: false,
child: CustomScrollView(
slivers: [
SliverToBoxAdapter(child: SizedBox(height: 12.h)),
SliverToBoxAdapter(child: _buildHeader()),
SliverToBoxAdapter(child: SizedBox(height: 18.h)),
SliverToBoxAdapter(child: _buildPlayerCard()),
SliverToBoxAdapter(child: SizedBox(height: 10.h)),
SliverToBoxAdapter(child: _buildWalletShop()),
SliverToBoxAdapter(child: SizedBox(height: 10.h)),
SliverToBoxAdapter(child: _buildCheckpoint()),
SliverToBoxAdapter(child: SizedBox(height: 10.h)),
SliverToBoxAdapter(child: _buildGameMenu()),
SliverToBoxAdapter(child: SizedBox(height: 120.h)),
],
),
),
child: Padding(
padding: const EdgeInsets.all(15),
child: Column(
children: [
const SizedBox(height: 5),
mImgBg(imgName: ConstImg.mineTop),
const SizedBox(height: 10),
MineSectionView(title: 'PLAYER CARD', imgName: ConstImg.sectionBg2, paddingSpace: 16,
child: _userInfo==null ? null : _showUserInfo(),
),
const SizedBox(height: 6),
MineSectionView(title: 'GAME MENU', imgName: ConstImg.sectionBg1),
],
),
)
),
);
}
Widget _showUserInfo() {
String _name = _userInfo!.givingName!.isEmpty || _userInfo!.givingName==''
? 'Visitor'
: _userInfo!.givingName!;
return Column(
children: [
Row(
children: [
_userInfo!.avator.isEmpty || _userInfo!.avator==''
? HelpImg.asset(ConstImg.defAvatar, width: 60)
: HelpImg.asset(ConstImg.defAvatar),
const SizedBox(width: 10),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 5),
SkyText(text: _name, fontSize: 18, fontWeight: FontWeight.bold,
color: Colors.white,
),
const SizedBox(height: 15),
Row(
children: [
SkyText(text: _userInfo!.customerId,
fontSize: 10,
color: Colors.white.withAlpha(200),
),
const SizedBox(width: 6),
HelpImg.asset(ConstImg.copy, width: 12),
],
).addInkWell(onTap: () async {
// copy
if (_userInfo!.customerId.isEmpty) return;
await Clipboard.setData(ClipboardData(text: _userInfo!.customerId));
AppToast.showSuccess('ID is Copied!');
}),
const SizedBox(height: 10),
],
)
],
)
],
);
}
Widget _buildHeader() {
return Padding(
padding: EdgeInsets.symmetric(horizontal: 15.w),

View File

@ -0,0 +1,93 @@
import 'package:flutter/material.dart';
import 'package:skywood/main/lib_file.dart';
import 'package:skywood/utils/tools/widgets/sky_common_widget.dart';
class MineSectionView extends StatelessWidget {
const MineSectionView({
super.key,
this.width,
this.height,
required this.title,
required this.imgName,
this.type = 1, // 1,2
this.paddingSpace = 5,
this.child
});
final String title;
final double? width;
final double? height;
final String imgName;
final int type;
final double paddingSpace;
final Widget? child;
@override
Widget build(BuildContext context) {
return Stack(
children: [
HelpImg.asset(imgName, width: width, height: height, fit: BoxFit.fill),
Positioned(
left: paddingSpace, right: paddingSpace, top: 8,
child: Column(
children: [
_buildHeader(),
const SizedBox(height: 10),
child ?? SizedBox()
],
),
),
],
);
}
Widget _buildHeader() {
return Stack(
children: [
HelpImg.asset(ConstImg.sectionTopBg, width: width, height: 20.h),
Positioned(
left: 7, right: 7,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
HelpImg.asset(ConstImg.littleLeft, width: 7),
const SizedBox(width: 2),
SkyText(text: title, fontSize: 12, color: Colors.white)
],
),
Row(
children: List.generate(3, (i) {
return HelpImg.asset(ConstImg.littleRight, width: 5);
}),
)
],
),
)
],
);
}
}
class mImgBg extends StatelessWidget {
const mImgBg({super.key,
this.width,
this.height,
this.fit = BoxFit.fill,
required this.imgName,
});
final double? width;
final double? height;
final String imgName;
final BoxFit fit;
@override
Widget build(BuildContext context) {
return HelpImg.asset(imgName, width: width, height: height, fit: fit);
}
}

View File

@ -1,6 +1,10 @@
import 'package:flutter/material.dart';
import 'package:skywood/global/client/play_client.dart';
import 'package:skywood/main/lib_file.dart';
import 'package:skywood/pages/home/players/page/drama_detail_page.dart';
import 'package:skywood/pages/widgets/pixel_widgets.dart';
import 'package:skywood/utils/models/drama/skywood_drama.dart';
import 'package:skywood/utils/tools/sky_time_tool.dart';
import 'package:skywood/utils/tools/widgets/sky_app_bar.dart';
import 'package:skywood/utils/tools/widgets/sky_common_widget.dart';
@ -25,12 +29,24 @@ class _ResultPageState extends State<ResultPage> {
List<String> _searchHistory = [];
final _searchController = TextEditingController();
final _searchFocus = FocusNode();
List<SkywoodDrama> _searchResult = [];
@override
void initState() {
super.initState();
_searchController.text = widget.keyword;
_search();
}
void _search() {
String keyword = _searchController.text;
if (keyword.trim().isEmpty) return;
PlayClient.search(keyword: keyword).then((valuer) {
setState(() {
_searchResult = valuer;
});
});
}
@override
@ -56,9 +72,14 @@ class _ResultPageState extends State<ResultPage> {
),
),
body: ListView.separated(
itemBuilder: (context, index) => ResultItemView(),
itemBuilder: (context, index) => ResultItemView(
drama: _searchResult[index],
onTap: () {
HelpNav.to(DramaDetailPage(dramaBean: _searchResult[index]));
},
),
separatorBuilder: (context, index) => SizedBox(height: 12),
itemCount: 2
itemCount: _searchResult.length
),
);
}
@ -66,29 +87,41 @@ class _ResultPageState extends State<ResultPage> {
class ResultItemView extends StatelessWidget {
const ResultItemView({super.key});
const ResultItemView({super.key,
required this.drama,
this.onTap
});
final SkywoodDrama drama;
final Function()? onTap;
@override
Widget build(BuildContext context) {
String tag = 'Satisfying';
if (drama.categoryList!.isNotEmpty) {
tag = drama.categoryList![0].name;
}
return Container(
height: 140.h,
padding: const EdgeInsets.symmetric(horizontal: 15),
child: Row(
children: [
PosterImage(width: 105.w, height: 140.h),
HelpImg.networkRadius(drama.imageUrl, width: 105.w, height: 140.h,
borderRadius: BorderRadius.circular(6),
),
const SizedBox(width: 10),
Expanded(child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SkyText(text: 'Love in the City of Twilight',
SkyText(text: drama.name,
fontSize: 14,
fontWeight: FontWeight.bold,
color: CommonColor.black,
),
const SizedBox(height: 12),
_tagView(),
_tagView(tag),
const SizedBox(height: 12),
SkyText(text: 'Haunted by fading memories, a man navigates a labyrinth of dreams and reality ds dsajkj',
SkyText(text: '${drama.description}',
fontSize: 11,
color: CommonColor.withValue('4D4047'),
maxLines: 2,
@ -98,14 +131,14 @@ class ResultItemView extends StatelessWidget {
children: [
_tipView(true, text: '10.0'),
const SizedBox(width: 15),
_tipView(false, text: '10.2k'),
_tipView(false, text: SkyTimeTool.formatNum(drama.watchTotal, unit: 'k')),
],
)
],
))
],
),
);
).addInkWell(onTap: onTap);
}
Widget _tipView(bool isStar, {required String text}) {
@ -119,7 +152,7 @@ class ResultItemView extends StatelessWidget {
);
}
Widget _tagView() {
Widget _tagView(String tag) {
return Container(
padding: const EdgeInsets.only(top: 3, left: 6, right: 6, bottom: 4),
decoration: ShapeDecoration(
@ -139,7 +172,7 @@ class ResultItemView extends StatelessWidget {
spacing: 10,
children: [
Text(
'Satisfying',
tag,
style: TextStyle(
color: const Color(0xFF040408) /* 主题黑 */,
fontSize: 10,

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:skywood/global/client/play_client.dart';
import 'package:skywood/main/lib_file.dart';
import 'package:skywood/pages/home/players/page/drama_detail_page.dart';
import 'package:skywood/pages/search/page/result_page.dart';
import 'package:skywood/pages/search/widget/search_util.dart';
import 'package:skywood/pages/search/widget/search_view.dart';
@ -174,39 +175,23 @@ class _MainRootState extends State<SearchPage> {
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: group.map((drama) {
return _TrendingItem(drama: drama);
return _TrendingItem(drama: drama, onTap: () {
HelpNav.to(DramaDetailPage(dramaBean: drama));
});
}).toList(),
),
);
}
// Widget _buildTrendingList() {
// return Container(
// height: 114 * 4, width: AppScreen.screenWidth,
// color: Colors.green,
// child: GridView.builder(
// padding: EdgeInsets.only(left: 15.w),
// scrollDirection: Axis.horizontal,
// gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
// crossAxisCount: 4, // 4
// crossAxisSpacing: 10, //
// mainAxisSpacing: 10, //
// childAspectRatio: 236 / 104.0, // /
// ),
// itemCount: _searchHots.length,
// itemBuilder: (context, index) {
// final drama = _searchHots[index];
// return Container(width: 236, height: 104, color: index%2==0 ? Colors.orangeAccent : Colors.redAccent,);
// return _TrendingItem(drama: drama);
// }
// ),
// );
// }
}
class _TrendingItem extends StatelessWidget {
const _TrendingItem({required this.drama});
const _TrendingItem({required this.drama,
this.onTap
});
final SkywoodDrama drama;
final Function()? onTap;
@override
Widget build(BuildContext context) {
@ -261,6 +246,6 @@ class _TrendingItem extends StatelessWidget {
),
],
),
);
).addInkWell(onTap: onTap);
}
}

View File

@ -1,6 +1,6 @@
import '../model_parser.dart';
class GlimzoUser {
class SkywoodUser {
final String customerId;
final bool isTourist;
final String userLevel;
@ -8,7 +8,7 @@ class GlimzoUser {
final String? familyName;
final String? givingName;
const GlimzoUser({
const SkywoodUser({
required this.customerId,
required this.isTourist,
required this.userLevel,
@ -17,8 +17,8 @@ class GlimzoUser {
this.givingName,
});
factory GlimzoUser.fromJson(Map<String, dynamic> json) {
return GlimzoUser(
factory SkywoodUser.fromJson(Map<String, dynamic> json) {
return SkywoodUser(
customerId: parseString(json['customer_id']),
isTourist: parseBool(json['is_tourist']),
userLevel: parseString(json['user_level']),
@ -39,7 +39,7 @@ class GlimzoUser {
};
}
GlimzoUser copyWith({
SkywoodUser copyWith({
String? customerId,
bool? isTourist,
String? userLevel,
@ -47,7 +47,7 @@ class GlimzoUser {
String? familyName,
String? givingName,
}) {
return GlimzoUser(
return SkywoodUser(
customerId: customerId ?? this.customerId,
isTourist: isTourist ?? this.isTourist,
userLevel: userLevel ?? this.userLevel,

View File

@ -61,6 +61,26 @@ class ConstImg {
static const String playLt = "assets/pics/player_lt.png";
static const String liked = "assets/pics/liked.png";
static const String unlike = "assets/pics/unlike.png";
static const String espBg = "assets/pics/esp_bg.png";
static const String cateSelLeft = "assets/pics/cate_sel_left.png";
static const String cateSelRight = "assets/pics/cate_sel_right.png";
static const String playTag = "assets/pics/play_tag.png";
static const String rank1 = "assets/pics/rank1.png";
static const String rank2 = "assets/pics/rank2.png";
static const String rank3 = "assets/pics/rank3.png";
/// mine
static const String copy = "assets/mine/copy.png";
static const String littleLeft = "assets/mine/little_left.png";
static const String littleRight = "assets/mine/little_right.png";
static const String mineTop = "assets/mine/mine_top.png";
static const String sectionTopBg = "assets/mine/section_top_bg.png";
static const String sectionBg1 = "assets/mine/section_bg1.png";
static const String sectionBg2 = "assets/mine/section_bg2.png";
static const String sectionBg3 = "assets/mine/section_bg3.png";
static const String defAvatar = "assets/mine/def_avatar.png";
// nodata

View File

@ -16,7 +16,7 @@ class SkyTimeTool {
num value, {
int decimalDigits = 1,
String separator = ',',
String unit = 'K',
String unit = 'k',
}) {
String removeTrailingZeros(String str) {
if (str.contains('.')) {