feat: 播放处理,个人中心,
BIN
assets/mine/copy.png
Normal file
|
After Width: | Height: | Size: 306 B |
BIN
assets/mine/def_avatar.png
Normal file
|
After Width: | Height: | Size: 9.3 KiB |
BIN
assets/mine/little_left.png
Normal file
|
After Width: | Height: | Size: 231 B |
BIN
assets/mine/little_right.png
Normal file
|
After Width: | Height: | Size: 203 B |
BIN
assets/mine/mine_top.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
assets/mine/section_bg1.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
assets/mine/section_bg2.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
assets/mine/section_bg3.png
Normal file
|
After Width: | Height: | Size: 1018 B |
BIN
assets/mine/section_top_bg.png
Normal file
|
After Width: | Height: | Size: 389 B |
BIN
assets/pics/cate_sel_left.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
assets/pics/cate_sel_right.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
assets/pics/esp_bg.png
Normal file
|
After Width: | Height: | Size: 8.2 KiB |
BIN
assets/pics/play_tag.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
assets/pics/rank1.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
assets/pics/rank2.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
assets/pics/rank3.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import 'package:skywood/global/request/api_const.dart';
|
import 'package:skywood/global/request/api_const.dart';
|
||||||
import 'package:skywood/global/request/app_request.dart';
|
import 'package:skywood/global/request/app_request.dart';
|
||||||
import 'package:skywood/global/tool/sky_log.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';
|
import 'package:skywood/utils/models/drama/skywood_home.dart';
|
||||||
|
|
||||||
class PlayClient {
|
class PlayClient {
|
||||||
|
|
||||||
static Future<List<SkywoodHome>> getHomeData() {
|
static Future<List<SkywoodHome>> getHomeData() {
|
||||||
return AppRequest.get(ApiStringPlay.getHomeModules).then((value) {
|
return AppRequest.get(ApiStringPlay.getHomeModules).then((value) {
|
||||||
if (value.isSuccess) {
|
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
|
// getSearchHots
|
||||||
static Future<List<SkywoodDrama>> getSearchHots() {
|
static Future<List<SkywoodDrama>> getSearchHots() {
|
||||||
return AppRequest.get(ApiStringPlay.getSearchHots).then((value) {
|
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
|
//getCollections
|
||||||
static Future<List> getCollections({
|
static Future<List<SkywoodDrama>> getCollections({
|
||||||
int page = 1, int pageSize = 10
|
int page = 1,
|
||||||
|
int pageSize = 10,
|
||||||
}) {
|
}) {
|
||||||
Map<String, dynamic> params = _setPage(page: page, pageSize: pageSize);
|
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) {
|
if (value.isSuccess) {
|
||||||
SkyLog.print('getCollections: ${value.data}');
|
SkyLog.print('getCollections: ${value.data}');
|
||||||
|
List list = parseDataForList(value.data);
|
||||||
|
return list.map((e) => SkywoodDrama.fromJson(e)).toList();
|
||||||
}
|
}
|
||||||
return [];
|
return [];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// getHistory
|
// getHistory
|
||||||
static Future<List> getHistory({
|
static Future<List<SkywoodDrama>> getHistory({
|
||||||
int page = 1, int pageSize = 10
|
int page = 1,
|
||||||
|
int pageSize = 10,
|
||||||
}) {
|
}) {
|
||||||
Map<String, dynamic> params = _setPage(page: page, pageSize: pageSize);
|
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) {
|
if (value.isSuccess) {
|
||||||
SkyLog.print('getHistory: ${value.data}');
|
SkyLog.print('getHistory: ${value.data}');
|
||||||
|
List list = parseDataForList(value.data);
|
||||||
|
return list.map((e) => SkywoodDrama.fromJson(e)).toList();
|
||||||
}
|
}
|
||||||
return [];
|
return [];
|
||||||
});
|
});
|
||||||
@ -90,19 +126,48 @@ class PlayClient {
|
|||||||
Map<String, dynamic> params = {};
|
Map<String, dynamic> params = {};
|
||||||
params['short_play_id'] = shortPlayId;
|
params['short_play_id'] = shortPlayId;
|
||||||
params['short_play_video_id'] = shortPlayVideoId;
|
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) {
|
if (value.isSuccess) {
|
||||||
SkyLog.print('getVideoDetail: ${value.data}');
|
SkyLog.print('getVideoDetail: ${value.data['data']}');
|
||||||
|
return SkywoodDetail.fromJson(value.data['data']);
|
||||||
}
|
}
|
||||||
return null;
|
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}) {
|
static Map<String, dynamic> _setPage({int page = 1, int pageSize = 10}) {
|
||||||
return {
|
return {'current_page': page, 'page_size': pageSize};
|
||||||
'current_page': page,
|
|
||||||
'page_size': pageSize,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static List parseDataForList(Map<String, dynamic> data) {
|
static List parseDataForList(Map<String, dynamic> data) {
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import 'package:skywood/global/request/api_const.dart';
|
|||||||
import 'package:skywood/global/request/app_request.dart';
|
import 'package:skywood/global/request/app_request.dart';
|
||||||
import 'package:skywood/global/tool/sky_log.dart';
|
import 'package:skywood/global/tool/sky_log.dart';
|
||||||
import 'package:skywood/utils/models/user/register_bean.dart';
|
import 'package:skywood/utils/models/user/register_bean.dart';
|
||||||
|
import 'package:skywood/utils/models/user/skywood_user.dart';
|
||||||
|
|
||||||
class UserClient {
|
class UserClient {
|
||||||
|
|
||||||
@ -27,4 +28,14 @@ class UserClient {
|
|||||||
return null;
|
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;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -57,15 +57,15 @@ class ApiString {
|
|||||||
|
|
||||||
class ApiStringPlay {
|
class ApiStringPlay {
|
||||||
// getRecommandsList GET /getRecommands 推荐列表,分页参数 current_page/page_size,可带 revolution
|
// 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 当前没有传入请求
|
// getDetailsRecommand GET /getDetailsRecommand 详情页推荐列表;注意方法参数 page/pageSize/data 当前没有传入请求
|
||||||
static const String getRecommandsList = "/getRecommands";
|
static const String getRecommandsList = "/getRecommands";
|
||||||
static const String getVideoDetail = "/getVideoDetails";
|
static const String getVideoDetail = "/getVideoDetails";
|
||||||
static const String getDetailsRecommand = "/getDetailsRecommand";
|
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
|
// getRankingList POST /homeRanking 首页榜单,body 带 type,支持 most_trending/top_searched/new_releases
|
||||||
/// getCategoriesList GET /getCategories 分类列表
|
///=== getCategoriesList GET /getCategories 分类列表
|
||||||
// getCategoriesDetail GET /videoList 分类详情/剧列表,分页 + extraParams
|
// getCategoriesDetail GET /videoList 分类详情/剧列表,分页 + extraParams
|
||||||
// getWaterflowList POST /newShortPlay 首页瀑布流,分页 + extraParams
|
// getWaterflowList POST /newShortPlay 首页瀑布流,分页 + extraParams
|
||||||
static const String getHomeModules = "/home/all-modules";
|
static const String getHomeModules = "/home/all-modules";
|
||||||
@ -76,10 +76,10 @@ class ApiStringPlay {
|
|||||||
|
|
||||||
/// getSearchHots GET /search/hots 搜索热门列表
|
/// getSearchHots GET /search/hots 搜索热门列表
|
||||||
// getSearch GET /search 关键词搜索,query: search
|
// getSearch GET /search 关键词搜索,query: search
|
||||||
// collect POST /collect 收藏,body: short_play_id, video_id
|
///==== collect POST /collect 收藏,body: short_play_id, video_id
|
||||||
// cancelCollect POST /cancelCollect 取消收藏,body: short_play_id
|
///==== cancelCollect POST /cancelCollect 取消收藏,body: short_play_id
|
||||||
// getMyCollections GET /myCollections 我的收藏列表,分页
|
///==== getMyCollections GET /myCollections 我的收藏列表,分页
|
||||||
// getMyHistorys GET /myHistorys 播放历史列表,分页
|
///==== getMyHistorys GET /myHistorys 播放历史列表,分页
|
||||||
// getNoticeNum POST /noticeNum 获取通知数量
|
// getNoticeNum POST /noticeNum 获取通知数量
|
||||||
// versionControl GET /customer/versionControl 版本检查
|
// versionControl GET /customer/versionControl 版本检查
|
||||||
// getLanguges GET /languges 获取语言列表,接口名拼写就是 languges
|
// getLanguges GET /languges 获取语言列表,接口名拼写就是 languges
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import 'package:skywood/pages/home/home_page.dart';
|
|||||||
import 'package:skywood/pages/like/like_page.dart';
|
import 'package:skywood/pages/like/like_page.dart';
|
||||||
import 'package:skywood/pages/mine/mine_page.dart';
|
import 'package:skywood/pages/mine/mine_page.dart';
|
||||||
import 'package:skywood/pages/search/page/search_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';
|
import 'package:skywood/utils/tools/help_img.dart';
|
||||||
|
|
||||||
class MainRoot extends StatefulWidget {
|
class MainRoot extends StatefulWidget {
|
||||||
@ -17,10 +18,10 @@ class MainRoot extends StatefulWidget {
|
|||||||
|
|
||||||
class _MainRootState extends State<MainRoot> {
|
class _MainRootState extends State<MainRoot> {
|
||||||
final List<Widget> _pages = const [
|
final List<Widget> _pages = const [
|
||||||
HomePage(),
|
AppKeepAlive(child: HomePage()),
|
||||||
SearchPage(),
|
AppKeepAlive(child: SearchPage()),
|
||||||
LikePage(),
|
LikePage(),
|
||||||
MinePage(),
|
AppKeepAlive(child: MinePage()),
|
||||||
];
|
];
|
||||||
|
|
||||||
final _pageController = PageController();
|
final _pageController = PageController();
|
||||||
|
|||||||
318
lib/pages/home/cate_page.dart
Normal 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),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,9 +1,13 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:skywood/global/client/play_client.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/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_drama.dart';
|
||||||
import 'package:skywood/utils/models/drama/skywood_home.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_app_bar.dart';
|
||||||
|
import 'package:skywood/utils/tools/widgets/sky_common_widget.dart';
|
||||||
|
|
||||||
class DramaDetailPage extends StatefulWidget {
|
class DramaDetailPage extends StatefulWidget {
|
||||||
const DramaDetailPage({super.key,
|
const DramaDetailPage({super.key,
|
||||||
@ -20,28 +24,30 @@ class DramaDetailPage extends StatefulWidget {
|
|||||||
|
|
||||||
class _DramaDetailPageState extends State<DramaDetailPage> {
|
class _DramaDetailPageState extends State<DramaDetailPage> {
|
||||||
|
|
||||||
|
SkywoodDetail? _detailBean;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
// _getDetailDrama();
|
_getDetailDrama();
|
||||||
}
|
}
|
||||||
|
|
||||||
// void _getDetailDrama() {
|
void _getDetailDrama() {
|
||||||
// PlayClient.getVideoDetail(
|
PlayClient.getVideoDetail(
|
||||||
// shortPlayId: widget.shortPlayId,
|
shortPlayId: widget.dramaBean.shortPlayId ?? 0,
|
||||||
// shortPlayVideoId: widget.shortPlayVideoId
|
shortPlayVideoId: widget.dramaBean.shortPlayVideoId ?? 0
|
||||||
// ).then((value) {});
|
).then((value) {
|
||||||
// }
|
setState(() {
|
||||||
|
_detailBean = value;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: Colors.black,
|
backgroundColor: Colors.black,
|
||||||
appBar: SkyAppBar(
|
|
||||||
title: widget.dramaBean.name,
|
|
||||||
backgroundColor: Colors.transparent,
|
|
||||||
),
|
|
||||||
body: _bodyWidget(),
|
body: _bodyWidget(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -50,11 +56,43 @@ class _DramaDetailPageState extends State<DramaDetailPage> {
|
|||||||
return Stack(
|
return Stack(
|
||||||
children: [
|
children: [
|
||||||
SizedBox(width: double.infinity, height: double.infinity),
|
SizedBox(width: double.infinity, height: double.infinity),
|
||||||
|
|
||||||
|
if (widget.dramaBean.videoUrl != null)
|
||||||
Positioned(
|
Positioned(
|
||||||
bottom: 0, left: 0, right: 0,
|
bottom: 0, left: 0, right: 0, top: 0,
|
||||||
child: PlayerBottomWidget(),
|
child: SkyPlayerView(
|
||||||
|
videoUrl: widget.dramaBean.videoUrl!,
|
||||||
|
detailBean: _detailBean,
|
||||||
|
dramaBean: widget.dramaBean,
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
Positioned(
|
||||||
|
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,)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
220
lib/pages/home/players/page/drama_esp_page.dart
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -4,7 +4,13 @@ import 'package:skywood/utils/tools/widgets/sky_common_widget.dart';
|
|||||||
|
|
||||||
class PlayerBottomWidget extends StatefulWidget {
|
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
|
@override
|
||||||
State<StatefulWidget> createState() {
|
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';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -52,7 +52,13 @@ class DailyQuestWidget extends StatelessWidget {
|
|||||||
child: Row(
|
child: Row(
|
||||||
spacing: 5.w,
|
spacing: 5.w,
|
||||||
children: List.generate(dramaList.length-1, (index) {
|
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),
|
||||||
|
);
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@ -3,6 +3,8 @@ import 'package:skywood/main/lib_file.dart';
|
|||||||
import 'package:skywood/utils/models/drama/skywood_category.dart';
|
import 'package:skywood/utils/models/drama/skywood_category.dart';
|
||||||
import 'package:skywood/utils/tools/widgets/sky_common_widget.dart';
|
import 'package:skywood/utils/tools/widgets/sky_common_widget.dart';
|
||||||
|
|
||||||
|
import '../players/page/drama_detail_page.dart';
|
||||||
|
|
||||||
class HomeCateWidget extends StatelessWidget {
|
class HomeCateWidget extends StatelessWidget {
|
||||||
|
|
||||||
const HomeCateWidget({super.key,
|
const HomeCateWidget({super.key,
|
||||||
@ -25,7 +27,8 @@ class HomeCateWidget extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
itemCount: categories.length,
|
itemCount: categories.length,
|
||||||
itemBuilder: (context, index) {
|
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,),
|
child: _customText(category.name,),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
);
|
).addInkWell(onTap: () {
|
||||||
|
// HelpNav.to(DramaDetailPage(dramaBean: drama));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_customText(String text) {
|
_customText(String text) {
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import 'package:flutter_screenutil/flutter_screenutil.dart';
|
|||||||
import 'package:skywood/main/lib_file.dart';
|
import 'package:skywood/main/lib_file.dart';
|
||||||
|
|
||||||
import '../../../utils/models/drama/skywood_drama.dart';
|
import '../../../utils/models/drama/skywood_drama.dart';
|
||||||
|
import '../players/page/drama_detail_page.dart';
|
||||||
|
|
||||||
class HotCartridgeWidget extends StatelessWidget {
|
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)
|
HelpImg.asset(index<3?ConstImg.hotBg1:ConstImg.hotBg2, width: 110.w, height: 174.h)
|
||||||
],
|
],
|
||||||
);
|
).addInkWell(onTap: () {
|
||||||
|
HelpNav.to(DramaDetailPage(dramaBean: drama));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -67,7 +67,7 @@ class RankListWidget extends StatelessWidget {
|
|||||||
Widget _rankIndex(int index) {
|
Widget _rankIndex(int index) {
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
width: 40.w,
|
width: 40.w,
|
||||||
child: SkyText(text: formatNumber(index + 1),
|
child: index < 3 ? _rank123(index) : SkyText(text: formatNumber(index + 1),
|
||||||
fontSize: 15,
|
fontSize: 15,
|
||||||
color: CommonColor.black,
|
color: CommonColor.black,
|
||||||
fontFamily: 'Anton',
|
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) {
|
String formatNumber(int number) {
|
||||||
return number.toString().padLeft(2, '0');
|
return number.toString().padLeft(2, '0');
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:skywood/global/client/play_client.dart';
|
import 'package:skywood/global/client/play_client.dart';
|
||||||
import 'package:skywood/main/lib_file.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 {
|
class CollectionPage extends StatefulWidget {
|
||||||
|
|
||||||
@ -14,16 +17,19 @@ class CollectionPage extends StatefulWidget {
|
|||||||
|
|
||||||
class _CollectionPageState extends State<CollectionPage> {
|
class _CollectionPageState extends State<CollectionPage> {
|
||||||
|
|
||||||
|
List<SkywoodDrama> _collectionList = [];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
// TODO: implement initState
|
|
||||||
super.initState();
|
super.initState();
|
||||||
_getCollection();
|
_getCollection();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _getCollection() {
|
void _getCollection() {
|
||||||
PlayClient.getCollections().then((value) {
|
PlayClient.getCollections().then((value) {
|
||||||
|
setState(() {
|
||||||
|
_collectionList = value;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,16 +46,36 @@ class _CollectionPageState extends State<CollectionPage> {
|
|||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
return _buildItem(index);
|
return _buildItem(index);
|
||||||
},
|
},
|
||||||
itemCount: 5,
|
itemCount: _collectionList.length,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildItem(int index) {
|
Widget _buildItem(int index) {
|
||||||
|
final SkywoodDrama drama = _collectionList[index];
|
||||||
return Stack(
|
return Stack(
|
||||||
children: [
|
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));
|
||||||
|
},);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,6 +1,14 @@
|
|||||||
import 'package:flutter/material.dart';
|
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/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/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 {
|
class MinePage extends StatefulWidget {
|
||||||
const MinePage({super.key});
|
const MinePage({super.key});
|
||||||
@ -12,29 +20,89 @@ class MinePage extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _MainRootState extends State<MinePage> {
|
class _MainRootState extends State<MinePage> {
|
||||||
|
|
||||||
|
SkywoodUser? _userInfo;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
|
||||||
|
_getUserData();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _getUserData() {
|
||||||
|
UserClient.getUserInfo().then((value) {
|
||||||
|
setState(() {
|
||||||
|
_userInfo = value;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return CommonBgPage(
|
||||||
body: PixelPageBackground(
|
|
||||||
child: SafeArea(
|
child: SafeArea(
|
||||||
bottom: false,
|
bottom: false,
|
||||||
child: CustomScrollView(
|
child: Padding(
|
||||||
slivers: [
|
padding: const EdgeInsets.all(15),
|
||||||
SliverToBoxAdapter(child: SizedBox(height: 12.h)),
|
child: Column(
|
||||||
SliverToBoxAdapter(child: _buildHeader()),
|
children: [
|
||||||
SliverToBoxAdapter(child: SizedBox(height: 18.h)),
|
const SizedBox(height: 5),
|
||||||
SliverToBoxAdapter(child: _buildPlayerCard()),
|
mImgBg(imgName: ConstImg.mineTop),
|
||||||
SliverToBoxAdapter(child: SizedBox(height: 10.h)),
|
const SizedBox(height: 10),
|
||||||
SliverToBoxAdapter(child: _buildWalletShop()),
|
MineSectionView(title: 'PLAYER CARD', imgName: ConstImg.sectionBg2, paddingSpace: 16,
|
||||||
SliverToBoxAdapter(child: SizedBox(height: 10.h)),
|
child: _userInfo==null ? null : _showUserInfo(),
|
||||||
SliverToBoxAdapter(child: _buildCheckpoint()),
|
),
|
||||||
SliverToBoxAdapter(child: SizedBox(height: 10.h)),
|
const SizedBox(height: 6),
|
||||||
SliverToBoxAdapter(child: _buildGameMenu()),
|
MineSectionView(title: 'GAME MENU', imgName: ConstImg.sectionBg1),
|
||||||
SliverToBoxAdapter(child: SizedBox(height: 120.h)),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
)
|
||||||
),
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
93
lib/pages/mine/widget/mine_section_view.dart
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,10 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:skywood/global/client/play_client.dart';
|
||||||
import 'package:skywood/main/lib_file.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/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_app_bar.dart';
|
||||||
import 'package:skywood/utils/tools/widgets/sky_common_widget.dart';
|
import 'package:skywood/utils/tools/widgets/sky_common_widget.dart';
|
||||||
|
|
||||||
@ -25,12 +29,24 @@ class _ResultPageState extends State<ResultPage> {
|
|||||||
List<String> _searchHistory = [];
|
List<String> _searchHistory = [];
|
||||||
final _searchController = TextEditingController();
|
final _searchController = TextEditingController();
|
||||||
final _searchFocus = FocusNode();
|
final _searchFocus = FocusNode();
|
||||||
|
List<SkywoodDrama> _searchResult = [];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
_searchController.text = widget.keyword;
|
_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
|
@override
|
||||||
@ -56,9 +72,14 @@ class _ResultPageState extends State<ResultPage> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
body: ListView.separated(
|
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),
|
separatorBuilder: (context, index) => SizedBox(height: 12),
|
||||||
itemCount: 2
|
itemCount: _searchResult.length
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -66,29 +87,41 @@ class _ResultPageState extends State<ResultPage> {
|
|||||||
|
|
||||||
class ResultItemView extends StatelessWidget {
|
class ResultItemView extends StatelessWidget {
|
||||||
|
|
||||||
const ResultItemView({super.key});
|
const ResultItemView({super.key,
|
||||||
|
required this.drama,
|
||||||
|
this.onTap
|
||||||
|
});
|
||||||
|
|
||||||
|
final SkywoodDrama drama;
|
||||||
|
final Function()? onTap;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
String tag = 'Satisfying';
|
||||||
|
if (drama.categoryList!.isNotEmpty) {
|
||||||
|
tag = drama.categoryList![0].name;
|
||||||
|
}
|
||||||
return Container(
|
return Container(
|
||||||
height: 140.h,
|
height: 140.h,
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
padding: const EdgeInsets.symmetric(horizontal: 15),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
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),
|
const SizedBox(width: 10),
|
||||||
Expanded(child: Column(
|
Expanded(child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
SkyText(text: 'Love in the City of Twilight',
|
SkyText(text: drama.name,
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: CommonColor.black,
|
color: CommonColor.black,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
_tagView(),
|
_tagView(tag),
|
||||||
const SizedBox(height: 12),
|
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,
|
fontSize: 11,
|
||||||
color: CommonColor.withValue('4D4047'),
|
color: CommonColor.withValue('4D4047'),
|
||||||
maxLines: 2,
|
maxLines: 2,
|
||||||
@ -98,14 +131,14 @@ class ResultItemView extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
_tipView(true, text: '10.0'),
|
_tipView(true, text: '10.0'),
|
||||||
const SizedBox(width: 15),
|
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}) {
|
Widget _tipView(bool isStar, {required String text}) {
|
||||||
@ -119,7 +152,7 @@ class ResultItemView extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _tagView() {
|
Widget _tagView(String tag) {
|
||||||
return Container(
|
return Container(
|
||||||
padding: const EdgeInsets.only(top: 3, left: 6, right: 6, bottom: 4),
|
padding: const EdgeInsets.only(top: 3, left: 6, right: 6, bottom: 4),
|
||||||
decoration: ShapeDecoration(
|
decoration: ShapeDecoration(
|
||||||
@ -139,7 +172,7 @@ class ResultItemView extends StatelessWidget {
|
|||||||
spacing: 10,
|
spacing: 10,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Satisfying',
|
tag,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: const Color(0xFF040408) /* 主题黑 */,
|
color: const Color(0xFF040408) /* 主题黑 */,
|
||||||
fontSize: 10,
|
fontSize: 10,
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:skywood/global/client/play_client.dart';
|
import 'package:skywood/global/client/play_client.dart';
|
||||||
import 'package:skywood/main/lib_file.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/page/result_page.dart';
|
||||||
import 'package:skywood/pages/search/widget/search_util.dart';
|
import 'package:skywood/pages/search/widget/search_util.dart';
|
||||||
import 'package:skywood/pages/search/widget/search_view.dart';
|
import 'package:skywood/pages/search/widget/search_view.dart';
|
||||||
@ -174,39 +175,23 @@ class _MainRootState extends State<SearchPage> {
|
|||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
children: group.map((drama) {
|
children: group.map((drama) {
|
||||||
return _TrendingItem(drama: drama);
|
return _TrendingItem(drama: drama, onTap: () {
|
||||||
|
HelpNav.to(DramaDetailPage(dramaBean: drama));
|
||||||
|
});
|
||||||
}).toList(),
|
}).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 {
|
class _TrendingItem extends StatelessWidget {
|
||||||
const _TrendingItem({required this.drama});
|
const _TrendingItem({required this.drama,
|
||||||
|
this.onTap
|
||||||
|
});
|
||||||
|
|
||||||
final SkywoodDrama drama;
|
final SkywoodDrama drama;
|
||||||
|
final Function()? onTap;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -261,6 +246,6 @@ class _TrendingItem extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
).addInkWell(onTap: onTap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import '../model_parser.dart';
|
import '../model_parser.dart';
|
||||||
|
|
||||||
class GlimzoUser {
|
class SkywoodUser {
|
||||||
final String customerId;
|
final String customerId;
|
||||||
final bool isTourist;
|
final bool isTourist;
|
||||||
final String userLevel;
|
final String userLevel;
|
||||||
@ -8,7 +8,7 @@ class GlimzoUser {
|
|||||||
final String? familyName;
|
final String? familyName;
|
||||||
final String? givingName;
|
final String? givingName;
|
||||||
|
|
||||||
const GlimzoUser({
|
const SkywoodUser({
|
||||||
required this.customerId,
|
required this.customerId,
|
||||||
required this.isTourist,
|
required this.isTourist,
|
||||||
required this.userLevel,
|
required this.userLevel,
|
||||||
@ -17,8 +17,8 @@ class GlimzoUser {
|
|||||||
this.givingName,
|
this.givingName,
|
||||||
});
|
});
|
||||||
|
|
||||||
factory GlimzoUser.fromJson(Map<String, dynamic> json) {
|
factory SkywoodUser.fromJson(Map<String, dynamic> json) {
|
||||||
return GlimzoUser(
|
return SkywoodUser(
|
||||||
customerId: parseString(json['customer_id']),
|
customerId: parseString(json['customer_id']),
|
||||||
isTourist: parseBool(json['is_tourist']),
|
isTourist: parseBool(json['is_tourist']),
|
||||||
userLevel: parseString(json['user_level']),
|
userLevel: parseString(json['user_level']),
|
||||||
@ -39,7 +39,7 @@ class GlimzoUser {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
GlimzoUser copyWith({
|
SkywoodUser copyWith({
|
||||||
String? customerId,
|
String? customerId,
|
||||||
bool? isTourist,
|
bool? isTourist,
|
||||||
String? userLevel,
|
String? userLevel,
|
||||||
@ -47,7 +47,7 @@ class GlimzoUser {
|
|||||||
String? familyName,
|
String? familyName,
|
||||||
String? givingName,
|
String? givingName,
|
||||||
}) {
|
}) {
|
||||||
return GlimzoUser(
|
return SkywoodUser(
|
||||||
customerId: customerId ?? this.customerId,
|
customerId: customerId ?? this.customerId,
|
||||||
isTourist: isTourist ?? this.isTourist,
|
isTourist: isTourist ?? this.isTourist,
|
||||||
userLevel: userLevel ?? this.userLevel,
|
userLevel: userLevel ?? this.userLevel,
|
||||||
@ -61,6 +61,26 @@ class ConstImg {
|
|||||||
static const String playLt = "assets/pics/player_lt.png";
|
static const String playLt = "assets/pics/player_lt.png";
|
||||||
static const String liked = "assets/pics/liked.png";
|
static const String liked = "assets/pics/liked.png";
|
||||||
static const String unlike = "assets/pics/unlike.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
|
// nodata
|
||||||
|
|||||||
@ -16,7 +16,7 @@ class SkyTimeTool {
|
|||||||
num value, {
|
num value, {
|
||||||
int decimalDigits = 1,
|
int decimalDigits = 1,
|
||||||
String separator = ',',
|
String separator = ',',
|
||||||
String unit = 'K',
|
String unit = 'k',
|
||||||
}) {
|
}) {
|
||||||
String removeTrailingZeros(String str) {
|
String removeTrailingZeros(String str) {
|
||||||
if (str.contains('.')) {
|
if (str.contains('.')) {
|
||||||
|
|||||||