fix: 图片提交4x,提示画质。iOS logo提交;

This commit is contained in:
chengsiwen committed 2026-07-01 16:24:15 +08:00
1 parent 2f1ec27802
commit 9e10608245
85 files changed
+1027 -645

No files matched your search

+25 -323
View File
@@ -6,6 +6,7 @@ import 'package:skywood/pages/like/widget/like_header.dart';
import 'package:skywood/pages/widgets/common_bg_page.dart';
import 'package:skywood/pages/widgets/pixel_widgets.dart';
import 'package:skywood/utils/extend/app_keep_alive.dart';
import 'package:skywood/utils/tools/app_sp.dart';
class LikePage extends StatefulWidget {
const LikePage({super.key});
@@ -17,17 +18,21 @@ class LikePage extends StatefulWidget {
}
class _MainRootState extends State<LikePage> {
int _tabIndex = 0;
final _pageController = PageController(initialPage: 0);
PageController _pageController = PageController(initialPage: 0);
int _currentIndex = 0;
static const String _keyIndex = 'LIKE_PAGE_INDEX';
final List<String> _collectionTitles = const [
'Undercover Play',
"Don't Cross Me",
'Two Worlds Apart',
'Rekindled Scorn',
'My Revenge is You',
"Mr. Gu's Sweet Weakness",
];
@override
void initState() {
super.initState();
_loadInitIndex();
}
_loadInitIndex() async {
}
@override
Widget build(BuildContext context) {
@@ -35,7 +40,10 @@ class _MainRootState extends State<LikePage> {
child: SafeArea(
bottom: false,
child: Padding(
padding: EdgeInsets.only(left: 15.w, right: 15.w, top: 20.h, bottom: 10.h+50.h),
padding: EdgeInsets.only(left: 15.w, right: 15.w,
top: AppScreen.isIos ? 0 : 20.h,
bottom: (AppScreen.isIos ? 30.h : 10.h)+50.h
),
child: Stack(
children: [
HelpImg.asset(ConstImg.likeBg, width: AppScreen.screenWidth - 30.w, height: 700.h,
@@ -48,8 +56,10 @@ class _MainRootState extends State<LikePage> {
Padding(
padding: const EdgeInsets.only(left: 10, top: 10),
child: LikeHeader(
initIndex: _currentIndex,
onSelectedIndex: (index) {
_pageController.jumpToPage(index);
_currentIndex = index;
},
),
),
@@ -58,8 +68,10 @@ class _MainRootState extends State<LikePage> {
child: PageView(
controller: _pageController,
children: [
AppKeepAlive(child: CollectionPage()),
AppKeepAlive(child: PlayLogPage())
CollectionPage(),
PlayLogPage()
// AppKeepAlive(child: CollectionPage()),
// AppKeepAlive(child: PlayLogPage())
],
),
)
@@ -71,315 +83,5 @@ class _MainRootState extends State<LikePage> {
)),
);
}
Widget _buildTabs() {
return Row(
children: [
Expanded(
child: _LibraryTab(
title: 'My Collection',
selected: _tabIndex == 0,
onTap: () => setState(() => _tabIndex = 0),
),
),
SizedBox(width: 8.w),
Expanded(
child: _LibraryTab(
title: 'Play Log',
selected: _tabIndex == 1,
onTap: () => setState(() => _tabIndex = 1),
),
),
],
);
}
Widget _buildCollection() {
return GridView.builder(
key: const ValueKey('collection'),
padding: EdgeInsets.only(top: 2.h, bottom: 120.h),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
mainAxisSpacing: 10.h,
crossAxisSpacing: 7.w,
childAspectRatio: 100 / 174,
),
itemCount: _collectionTitles.length,
itemBuilder: (context, index) {
return _CollectionCard(title: _collectionTitles[index]);
},
);
}
Widget _buildPlayLog() {
return ListView(
key: const ValueKey('play-log'),
padding: EdgeInsets.only(bottom: 120.h),
children: [
_ContinueCard(),
SizedBox(height: 18.h),
Text(
'Watch History',
style: TextStyle(
color: const Color(0xFF1C1E1F),
fontSize: 16.sp,
fontWeight: FontWeight.w700,
height: 1,
),
),
SizedBox(height: 10.h),
_HistoryItem(title: 'As A Mafia Boss, I Refuse To Be An Extra'),
SizedBox(height: 10.h),
_HistoryItem(title: 'Fatal Vengeance'),
SizedBox(height: 10.h),
_HistoryItem(title: "Don't Cross Me"),
],
);
}
}
class _LibraryTab extends StatelessWidget {
const _LibraryTab({
required this.title,
required this.selected,
required this.onTap,
});
final String title;
final bool selected;
final VoidCallback onTap;
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onTap,
child: Container(
height: 45.h,
alignment: Alignment.center,
decoration: BoxDecoration(
color: selected ? const Color(0xFF16ED1E) : const Color(0xFFF6F6F6),
border: Border.all(
color: selected ? CommonColor.black : const Color(0xFFD6D6D6),
width: 1.5.w,
),
boxShadow: selected
? const [
BoxShadow(color: Color(0xFF1C1E1F), offset: Offset(2, 2)),
]
: null,
),
child: Text(
title,
style: TextStyle(
color: selected ? Colors.white : const Color(0xFFB2B2B2),
fontSize: 14.sp,
fontWeight: FontWeight.w900,
height: 1,
shadows: selected
? const [Shadow(color: Color(0xFF1C1E1F), offset: Offset(1, 1))]
: null,
),
),
),
);
}
}
class _CollectionCard extends StatelessWidget {
const _CollectionCard({required this.title});
final String title;
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.fromLTRB(4.w, 8.h, 4.w, 6.h),
decoration: BoxDecoration(
color: const Color(0xFFF4FFB6),
border: Border.all(color: const Color(0xFF1C1E1F), width: 1.w),
boxShadow: const [
BoxShadow(color: Color(0xFF653CFA), offset: Offset(3, 3)),
],
),
child: Column(
children: [
Row(
children: List.generate(4, (index) {
return Container(
width: 11.w,
height: 6.h,
margin: EdgeInsets.only(right: 5.w),
decoration: BoxDecoration(
color: index == 3
? const Color(0xFFEAEAEA)
: const Color(0xFF96FE9B),
border: Border.all(
color: const Color(0xFF1C1E1F),
width: 0.8.w,
),
),
);
}),
),
SizedBox(height: 8.h),
const Expanded(child: PosterImage()),
SizedBox(height: 8.h),
Text(
title,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
color: const Color(0xFF1C1E1F),
fontSize: 13.sp,
fontWeight: FontWeight.w500,
height: 1,
),
),
],
),
);
}
}
class _ContinueCard extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
height: 140.h,
padding: EdgeInsets.all(10.w),
decoration: BoxDecoration(
color: const Color(0xFFEAE6FF),
border: Border.all(color: const Color(0xFF1C1E1F), width: 1.w),
),
child: Row(
children: [
const PosterImage(width: 90, height: 120, borderRadius: 2),
SizedBox(width: 10.w),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Mogul And His Runaway Bride',
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle(
color: const Color(0xFF1B1926),
fontSize: 14.sp,
fontWeight: FontWeight.w600,
height: 1.25,
),
),
SizedBox(height: 18.h),
Text(
'Chapter 10 / 28',
style: TextStyle(
color: CommonColor.primacyColor,
fontSize: 11.sp,
height: 1,
),
),
SizedBox(height: 6.h),
_ProgressLine(value: 0.46),
const Spacer(),
const PixelButton(
label: 'Continue Watch',
width: 145,
height: 29,
),
],
),
),
],
),
);
}
}
class _HistoryItem extends StatelessWidget {
const _HistoryItem({required this.title});
final String title;
@override
Widget build(BuildContext context) {
return Container(
height: 100.h,
padding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 6.h),
decoration: BoxDecoration(
color: const Color(0xFFEAE6FF),
border: Border.all(color: const Color(0xFF1C1E1F), width: 1.w),
),
child: Row(
children: [
const PosterImage(width: 66, height: 88, borderRadius: 2),
SizedBox(width: 10.w),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
title,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle(
color: CommonColor.black,
fontSize: 13.sp,
fontWeight: FontWeight.w600,
height: 1.2,
),
),
Text(
'EP.40/85',
style: TextStyle(
color: CommonColor.primacyColor,
fontSize: 11.sp,
height: 1,
),
),
_ProgressLine(value: 0.46),
],
),
),
],
),
);
}
}
class _ProgressLine extends StatelessWidget {
const _ProgressLine({required this.value});
final double value;
@override
Widget build(BuildContext context) {
return Row(
children: [
Expanded(
child: Container(
height: 6.h,
decoration: BoxDecoration(
color: Colors.white.withValues(alpha: 0.7),
border: Border.all(color: const Color(0xFF1C1E1F), width: 0.5.w),
borderRadius: BorderRadius.circular(10.r),
),
alignment: Alignment.centerLeft,
child: FractionallySizedBox(
widthFactor: value,
child: Container(
decoration: BoxDecoration(
color: const Color(0xFF00EE02),
borderRadius: BorderRadius.circular(10.r),
),
),
),
),
),
SizedBox(width: 4.w),
Text('46%', style: TextStyle(fontSize: 10.sp, height: 1)),
],
);
}
}
+9 -1
View File
@@ -2,7 +2,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/pages/like/widget/no_data_view.dart';
import 'package:skywood/utils/models/drama/skywood_drama.dart';
import 'package:skywood/utils/tools/app_toast.dart';
import 'package:skywood/utils/tools/widgets/sky_common_widget.dart';
class CollectionPage extends StatefulWidget {
@@ -18,6 +20,7 @@ class CollectionPage extends StatefulWidget {
class _CollectionPageState extends State<CollectionPage> {
List<SkywoodDrama> _collectionList = [];
bool _isLoading = false;
@override
void initState() {
@@ -26,7 +29,12 @@ class _CollectionPageState extends State<CollectionPage> {
}
void _getCollection() {
_isLoading = true;
AppToast.showLottieLoading();
PlayClient.getCollections().then((value) {
_isLoading = false;
AppToast.dismiss();
if (!mounted) return;
setState(() {
_collectionList = value;
});
@@ -35,7 +43,7 @@ class _CollectionPageState extends State<CollectionPage> {
@override
Widget build(BuildContext context) {
return GridView.builder(
return !_isLoading&&_collectionList.isEmpty ? NoDataView() : GridView.builder(
padding: EdgeInsets.symmetric(horizontal: 5.w, vertical: 10.h),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
+140 -38
View File
@@ -1,8 +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/page/drama_detail_page.dart';
import 'package:skywood/utils/models/drama/skywood_drama.dart';
import 'package:skywood/utils/tools/widgets/sky_common_widget.dart';
import '../../../utils/tools/app_toast.dart';
import '../widget/no_data_view.dart';
class PlayLogPage extends StatefulWidget {
const PlayLogPage({super.key});
@@ -15,6 +20,9 @@ class PlayLogPage extends StatefulWidget {
class _CollectionPageState extends State<PlayLogPage> {
List<SkywoodDrama> _historyList = [];
bool _isLoading = false;
@override
void initState() {
super.initState();
@@ -22,16 +30,25 @@ class _CollectionPageState extends State<PlayLogPage> {
}
void _getHistory() {
PlayClient.getHistory().then((value) {});
_isLoading = true;
AppToast.showLottieLoading();
PlayClient.getHistory().then((value) {
_isLoading = false;
AppToast.dismiss();
setState(() {
_historyList = value;
});
});
}
@override
Widget build(BuildContext context) {
return ListView.separated(
return !_isLoading&&_historyList.isEmpty ? NoDataView() : ListView.separated(
padding: const EdgeInsets.only(top: 20, left: 12, right: 12),
itemCount: 5,
itemCount: _historyList.length,
itemBuilder: (context, index) {
return index == 0 ? _buildFirstItem() : _buildNormalItem();
final item = _historyList[index];
return index == 0 ? _buildFirstItem(item) : _buildNormalItem(item);
},
separatorBuilder: (context, index) {
return SizedBox(height: 5);
@@ -39,25 +56,103 @@ class _CollectionPageState extends State<PlayLogPage> {
);
}
Widget _buildNormalItem() {
Widget _buildNormalItem(SkywoodDrama item) {
return Stack(
children: [
HelpImg.asset(ConstImg.playlogBg, width: double.infinity, height: 90, fit: BoxFit.fill),
_ProgressLine(value: 0.2)
HelpImg.asset(ConstImg.playlogBg, width: double.infinity, height: 100, fit: BoxFit.fill),
Positioned(
left: 10, top: 5, right: 5, bottom: 5,
child: Row(
children: [
HelpImg.network(item.imageUrl, width: 66, height: 88, fit: BoxFit.fill),
const SizedBox(width: 10),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 6),
Expanded(child: SizedBox(
width: 192.w,
child: SkyText(text: item.name,
fontSize: 14,
fontWeight: FontWeight.bold,
color: CommonColor.black,
maxLines: 2,
),
)),
SkyText(text: 'EP.${item.currentEpisode} / ${item.episodeTotal}',
fontSize: 11,
color: CommonColor.primacyColor,
),
const SizedBox(height: 5),
_ProgressLine(value: (item.currentEpisode ?? 1) / item.episodeTotal, width: 150,),
const SizedBox(height: 10),
],
)
],
),
)
],
).addInkWell(onTap: () {
HelpNav.to(DramaDetailPage(dramaBean: item));
});
}
Widget _buildFirstItem(SkywoodDrama item) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildFirstCard(item),
const SizedBox(height: 20),
if (_historyList.length > 1)
SkyText(text: 'Watch History',
color: CommonColor.black,
fontSize: 16,
fontWeight: FontWeight.bold,
)
],
);
}
Widget _buildFirstItem() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
Widget _buildFirstCard(SkywoodDrama item) {
return Stack(
children: [
HelpImg.asset(ConstImg.playlogBg, width: double.infinity, height: 140, fit: BoxFit.fill),
const SizedBox(height: 20),
SkyText(text: 'Watch History',
color: CommonColor.black,
fontSize: 16,
fontWeight: FontWeight.bold,
HelpImg.asset(ConstImg.playlogBg, width: 297.w, height: 140, fit: BoxFit.fill),
Positioned(
left: 10, top: 5, right: 5, bottom: 5,
child: Row(
children: [
HelpImg.network(item.imageUrl, width: 90, height: 120, fit: BoxFit.fill),
const SizedBox(width: 10),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 6),
Expanded(child: SizedBox(
width: 170.w,
child: SkyText(text: item.name,
fontSize: 14,
fontWeight: FontWeight.bold,
color: CommonColor.black,
maxLines: 2,
),
)),
SkyText(text: 'Chapter ${item.currentEpisode} / ${item.episodeTotal}',
fontSize: 11,
color: CommonColor.primacyColor,
),
const SizedBox(height: 5),
_ProgressLine(value: (item.currentEpisode ?? 1) / item.episodeTotal, width: 150,),
const SizedBox(height: 10),
HelpImg.asset(ConstImg.continueWatch, width: 144, height: 30).addInkWell(
onTap: () {
HelpNav.to(DramaDetailPage(dramaBean: item));
}
),
const SizedBox(height: 8),
],
)
],
),
)
],
);
@@ -67,37 +162,44 @@ class _CollectionPageState extends State<PlayLogPage> {
class _ProgressLine extends StatelessWidget {
const _ProgressLine({required this.value});
const _ProgressLine({
required this.value,
this.width = 140,
});
final double value;
final double width;
@override
Widget build(BuildContext context) {
return Row(
children: [
Expanded(
child: Container(
height: 6.h,
decoration: BoxDecoration(
color: Colors.white.withValues(alpha: 0.7),
border: Border.all(color: const Color(0xFF1C1E1F), width: 0.5.w),
borderRadius: BorderRadius.circular(10.r),
),
alignment: Alignment.centerLeft,
child: FractionallySizedBox(
widthFactor: value,
child: Container(
decoration: BoxDecoration(
color: const Color(0xFF00EE02),
borderRadius: BorderRadius.circular(10.r),
return SizedBox(
width: width,
child: Row(
children: [
Expanded(
child: Container(
height: 6.h,
decoration: BoxDecoration(
color: Colors.white.withValues(alpha: 0.7),
border: Border.all(color: const Color(0xFF1C1E1F), width: 0.5.w),
borderRadius: BorderRadius.circular(10.r),
),
alignment: Alignment.centerLeft,
child: FractionallySizedBox(
widthFactor: value,
child: Container(
decoration: BoxDecoration(
color: const Color(0xFF00EE02),
borderRadius: BorderRadius.circular(10.r),
),
),
),
),
),
),
SizedBox(width: 4.w),
Text('${(value * 100.0).toInt()}%', style: TextStyle(fontSize: 10.sp, height: 1)),
],
SizedBox(width: 4.w),
Text('${(value * 100.0).toInt()}%', style: TextStyle(fontSize: 10.sp, height: 1)),
],
),
);
}
}
+14
View File
@@ -6,9 +6,11 @@ class LikeHeader extends StatefulWidget {
const LikeHeader({super.key,
required this.onSelectedIndex,
required this.initIndex,
});
final Function(int) onSelectedIndex;
final int initIndex;
@override
State<StatefulWidget> createState() {
@@ -20,6 +22,18 @@ class _LikeHeaderState extends State<LikeHeader> {
int _selectedIndex = 0;
@override
void initState() {
super.initState();
if (widget.initIndex != 0) {
if (!mounted) return;
setState(() {
_selectedIndex = widget.initIndex;
});
}
}
@override
Widget build(BuildContext context) {
return SizedBox(
+96
View File
@@ -0,0 +1,96 @@
import 'package:flutter/material.dart';
import 'package:skywood/main/lib_file.dart';
import 'package:skywood/utils/tools/widgets/sky_common_widget.dart';
class NoDataView extends StatelessWidget {
const NoDataView({super.key,
this.title = 'No Data',
// 'Nothing here yet.\nCome back later for more fun!',
// Something went wrong.\nPlease try again.
this.subtitle = 'Nothing here yet.\nCome back later for more fun!',
this.btnText = 'RETRY',
this.imgName,
this.onTap,
});
final String title;
final String subtitle;
final String btnText;
final String? imgName;
final VoidCallback? onTap;
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const SizedBox(height: 100),
HelpImg.asset(ConstImg.nodataImg, width: 136),
const SizedBox(height: 14),
_customText(title),
const SizedBox(height: 10),
SkyText(text: subtitle, maxLines: 2,
fontSize: 14,
color: CommonColor.black,
textAlign: TextAlign.center,
),
const SizedBox(height: 14),
if (onTap != null)
InkWell(
onTap: onTap,
child: Stack(
children: [
HelpImg.asset(imgName ?? ConstImg.btnBg, width: 140, height: 46, fit: BoxFit.fill,),
Positioned.fill(
child: Center(
child: SkyText(text: btnText, color: Colors.white),
),
)
],
)
)
],
),
);
}
_customText(String text) {
return Text(
text,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 16,
color: Colors.white, // 内部字体白色
fontStyle: FontStyle.italic,
fontFamily: 'Inter',
fontWeight: FontWeight.w600,
shadows: [
Shadow(
color: Colors.black, // 描边颜色
offset: Offset(1, 1), // 偏移量
blurRadius: 0, // 不模糊,形成硬边描边
),
Shadow(
color: Colors.black,
offset: Offset(-1, -1),
blurRadius: 0,
),
Shadow(
color: Colors.black,
offset: Offset(1, -1),
blurRadius: 0,
),
Shadow(
color: Colors.black,
offset: Offset(-1, 1),
blurRadius: 0,
),
],
),
);
}
}