|
@@ -1,11 +1,11 @@
|
|
|
-import 'package:flutter/material.dart';
|
|
|
|
|
|
|
+import 'package:flutter/material.dart' hide Banner;
|
|
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
|
|
import 'package:get/get.dart';
|
|
import 'package:get/get.dart';
|
|
|
import 'package:nomo/config/theme/dark_theme_colors.dart';
|
|
import 'package:nomo/config/theme/dark_theme_colors.dart';
|
|
|
|
|
|
|
|
import '../../../../config/translations/strings_enum.dart';
|
|
import '../../../../config/translations/strings_enum.dart';
|
|
|
import '../../../constants/assets.dart';
|
|
import '../../../constants/assets.dart';
|
|
|
-import '../../../constants/iconfont/iconfont.dart';
|
|
|
|
|
|
|
+import '../../../data/models/banner/banner_list.dart';
|
|
|
import '../../../widgets/click_opacity.dart';
|
|
import '../../../widgets/click_opacity.dart';
|
|
|
import '../../../widgets/ix_image.dart';
|
|
import '../../../widgets/ix_image.dart';
|
|
|
import '../../../widgets/submit_btn.dart';
|
|
import '../../../widgets/submit_btn.dart';
|
|
@@ -20,18 +20,24 @@ class MedialocationView extends GetView<MedialocationController> {
|
|
|
backgroundColor: DarkThemeColors.scaffoldBackgroundColor,
|
|
backgroundColor: DarkThemeColors.scaffoldBackgroundColor,
|
|
|
body: Stack(
|
|
body: Stack(
|
|
|
children: [
|
|
children: [
|
|
|
- // 视频背景层(只显示顶部214高度)
|
|
|
|
|
|
|
+ // 背景图层(只显示顶部214高度)
|
|
|
Positioned(
|
|
Positioned(
|
|
|
top: 0,
|
|
top: 0,
|
|
|
left: 0,
|
|
left: 0,
|
|
|
right: 0,
|
|
right: 0,
|
|
|
height: 214.w,
|
|
height: 214.w,
|
|
|
child: ClipRect(
|
|
child: ClipRect(
|
|
|
- child: IXImage(
|
|
|
|
|
- source: Assets.mediaBg,
|
|
|
|
|
- width: 375.w,
|
|
|
|
|
- height: 214.w,
|
|
|
|
|
- sourceType: ImageSourceType.asset,
|
|
|
|
|
|
|
+ child: Obx(
|
|
|
|
|
+ () => IXImage(
|
|
|
|
|
+ source: controller.bannerInfoImg.isNotEmpty
|
|
|
|
|
+ ? controller.bannerInfoImg
|
|
|
|
|
+ : Assets.mediaBg,
|
|
|
|
|
+ width: 375.w,
|
|
|
|
|
+ height: 214.w,
|
|
|
|
|
+ sourceType: controller.bannerInfoImg.isNotEmpty
|
|
|
|
|
+ ? ImageSourceType.network
|
|
|
|
|
+ : ImageSourceType.asset,
|
|
|
|
|
+ ),
|
|
|
),
|
|
),
|
|
|
),
|
|
),
|
|
|
),
|
|
),
|
|
@@ -62,26 +68,18 @@ class MedialocationView extends GetView<MedialocationController> {
|
|
|
|
|
|
|
|
// 可滚动内容区域
|
|
// 可滚动内容区域
|
|
|
Expanded(
|
|
Expanded(
|
|
|
- child: SingleChildScrollView(
|
|
|
|
|
- padding: EdgeInsets.symmetric(horizontal: 16.w),
|
|
|
|
|
|
|
+ child: Padding(
|
|
|
|
|
+ padding: EdgeInsets.symmetric(horizontal: 14.w),
|
|
|
child: Column(
|
|
child: Column(
|
|
|
children: [
|
|
children: [
|
|
|
20.verticalSpace,
|
|
20.verticalSpace,
|
|
|
-
|
|
|
|
|
// 流媒体服务卡片
|
|
// 流媒体服务卡片
|
|
|
_buildStreamingServicesCard(),
|
|
_buildStreamingServicesCard(),
|
|
|
-
|
|
|
|
|
- 10.verticalSpace,
|
|
|
|
|
-
|
|
|
|
|
- // 功能说明列表
|
|
|
|
|
- _buildFeaturesList(),
|
|
|
|
|
-
|
|
|
|
|
- 32.verticalSpace,
|
|
|
|
|
],
|
|
],
|
|
|
),
|
|
),
|
|
|
),
|
|
),
|
|
|
),
|
|
),
|
|
|
-
|
|
|
|
|
|
|
+ 20.verticalSpace,
|
|
|
// 底部连接按钮
|
|
// 底部连接按钮
|
|
|
_buildConnectButton(),
|
|
_buildConnectButton(),
|
|
|
],
|
|
],
|
|
@@ -123,67 +121,76 @@ class MedialocationView extends GetView<MedialocationController> {
|
|
|
padding: EdgeInsets.symmetric(vertical: 20.w),
|
|
padding: EdgeInsets.symmetric(vertical: 20.w),
|
|
|
child: Column(
|
|
child: Column(
|
|
|
children: [
|
|
children: [
|
|
|
- // Movies&TV 图标和标题
|
|
|
|
|
- Row(
|
|
|
|
|
- mainAxisAlignment: MainAxisAlignment.center,
|
|
|
|
|
- children: [
|
|
|
|
|
- Icon(
|
|
|
|
|
- IconFont.icon19,
|
|
|
|
|
- color: DarkThemeColors.errorColor,
|
|
|
|
|
- size: 32.w,
|
|
|
|
|
- ),
|
|
|
|
|
- 4.horizontalSpace,
|
|
|
|
|
- Text(
|
|
|
|
|
- 'Movies&TV',
|
|
|
|
|
- style: TextStyle(
|
|
|
|
|
- fontSize: 22.sp,
|
|
|
|
|
- fontWeight: FontWeight.w500,
|
|
|
|
|
- height: 1.3,
|
|
|
|
|
- color: Colors.white,
|
|
|
|
|
|
|
+ // 图标和标题
|
|
|
|
|
+ Obx(
|
|
|
|
|
+ () => Row(
|
|
|
|
|
+ mainAxisAlignment: MainAxisAlignment.center,
|
|
|
|
|
+ children: [
|
|
|
|
|
+ IXImage(
|
|
|
|
|
+ source: controller.bannerImg,
|
|
|
|
|
+ width: 32.w,
|
|
|
|
|
+ height: 32.w,
|
|
|
|
|
+ sourceType: ImageSourceType.network,
|
|
|
),
|
|
),
|
|
|
- ),
|
|
|
|
|
- ],
|
|
|
|
|
|
|
+ 8.horizontalSpace,
|
|
|
|
|
+ Text(
|
|
|
|
|
+ controller.bannerTitle,
|
|
|
|
|
+ style: TextStyle(
|
|
|
|
|
+ fontSize: 22.sp,
|
|
|
|
|
+ fontWeight: FontWeight.w500,
|
|
|
|
|
+ height: 1.3,
|
|
|
|
|
+ color: Colors.white,
|
|
|
|
|
+ ),
|
|
|
|
|
+ ),
|
|
|
|
|
+ ],
|
|
|
|
|
+ ),
|
|
|
),
|
|
),
|
|
|
|
|
|
|
|
8.verticalSpace,
|
|
8.verticalSpace,
|
|
|
|
|
|
|
|
// 连接状态
|
|
// 连接状态
|
|
|
Obx(() {
|
|
Obx(() {
|
|
|
- final text = controller.isConnected.value
|
|
|
|
|
|
|
+ // 访问 stateStream 以触发 Obx 响应
|
|
|
|
|
+ final _ = controller.coreController.stateStream.value;
|
|
|
|
|
+ final text = controller.isConnected
|
|
|
? Strings.connected.tr
|
|
? Strings.connected.tr
|
|
|
- : controller.isConnecting.value
|
|
|
|
|
|
|
+ : controller.isConnecting
|
|
|
? Strings.connecting.tr
|
|
? Strings.connecting.tr
|
|
|
: Strings.disconnected.tr;
|
|
: Strings.disconnected.tr;
|
|
|
- final textColor = controller.isConnected.value
|
|
|
|
|
|
|
+ final textColor = controller.isConnected
|
|
|
? DarkThemeColors.text1
|
|
? DarkThemeColors.text1
|
|
|
- : controller.isConnecting.value
|
|
|
|
|
|
|
+ : controller.isConnecting
|
|
|
? DarkThemeColors.text1
|
|
? DarkThemeColors.text1
|
|
|
: DarkThemeColors.text1;
|
|
: DarkThemeColors.text1;
|
|
|
- final statusImgPath = controller.isConnected.value
|
|
|
|
|
|
|
+ final statusImgPath = controller.isConnected
|
|
|
? Assets.connected
|
|
? Assets.connected
|
|
|
- : controller.isConnecting.value
|
|
|
|
|
|
|
+ : controller.isConnecting
|
|
|
? Assets.connecting
|
|
? Assets.connecting
|
|
|
: Assets.disconnected;
|
|
: Assets.disconnected;
|
|
|
|
|
|
|
|
- return Row(
|
|
|
|
|
- mainAxisAlignment: MainAxisAlignment.center,
|
|
|
|
|
- children: [
|
|
|
|
|
- IXImage(
|
|
|
|
|
- source: statusImgPath,
|
|
|
|
|
- sourceType: ImageSourceType.asset,
|
|
|
|
|
- width: 14.w,
|
|
|
|
|
- height: 14.w,
|
|
|
|
|
- ),
|
|
|
|
|
- 4.horizontalSpace,
|
|
|
|
|
- Text(
|
|
|
|
|
- text,
|
|
|
|
|
- style: TextStyle(
|
|
|
|
|
- fontSize: 14.sp,
|
|
|
|
|
- fontWeight: FontWeight.w500,
|
|
|
|
|
- color: textColor,
|
|
|
|
|
|
|
+ return SizedBox(
|
|
|
|
|
+ height: 20.w,
|
|
|
|
|
+ child: Row(
|
|
|
|
|
+ mainAxisAlignment: MainAxisAlignment.center,
|
|
|
|
|
+ children: [
|
|
|
|
|
+ IXImage(
|
|
|
|
|
+ source: statusImgPath,
|
|
|
|
|
+ sourceType: ImageSourceType.asset,
|
|
|
|
|
+ width: 14.w,
|
|
|
|
|
+ height: 14.w,
|
|
|
),
|
|
),
|
|
|
- ),
|
|
|
|
|
- ],
|
|
|
|
|
|
|
+ 4.horizontalSpace,
|
|
|
|
|
+ Text(
|
|
|
|
|
+ text,
|
|
|
|
|
+ style: TextStyle(
|
|
|
|
|
+ fontSize: 14.sp,
|
|
|
|
|
+ height: 1.4,
|
|
|
|
|
+ fontWeight: FontWeight.w500,
|
|
|
|
|
+ color: textColor,
|
|
|
|
|
+ ),
|
|
|
|
|
+ ),
|
|
|
|
|
+ ],
|
|
|
|
|
+ ),
|
|
|
);
|
|
);
|
|
|
}),
|
|
}),
|
|
|
],
|
|
],
|
|
@@ -193,54 +200,50 @@ class MedialocationView extends GetView<MedialocationController> {
|
|
|
|
|
|
|
|
/// 构建流媒体服务卡片
|
|
/// 构建流媒体服务卡片
|
|
|
Widget _buildStreamingServicesCard() {
|
|
Widget _buildStreamingServicesCard() {
|
|
|
- return Container(
|
|
|
|
|
- decoration: BoxDecoration(
|
|
|
|
|
- color: DarkThemeColors.bg2,
|
|
|
|
|
- borderRadius: BorderRadius.circular(12.r),
|
|
|
|
|
- ),
|
|
|
|
|
- child: ListView.separated(
|
|
|
|
|
- shrinkWrap: true,
|
|
|
|
|
- physics: const NeverScrollableScrollPhysics(),
|
|
|
|
|
- padding: EdgeInsets.zero,
|
|
|
|
|
- itemCount: controller.streamingServices.length,
|
|
|
|
|
- separatorBuilder: (context, index) => Divider(
|
|
|
|
|
- height: 1.w,
|
|
|
|
|
- thickness: 1.w,
|
|
|
|
|
- color: DarkThemeColors.strokes1,
|
|
|
|
|
|
|
+ return Obx(() {
|
|
|
|
|
+ if (controller.bannerList.isEmpty) {
|
|
|
|
|
+ return const SizedBox.shrink();
|
|
|
|
|
+ }
|
|
|
|
|
+ return Container(
|
|
|
|
|
+ decoration: BoxDecoration(
|
|
|
|
|
+ color: DarkThemeColors.bg2,
|
|
|
|
|
+ borderRadius: BorderRadius.circular(12.r),
|
|
|
),
|
|
),
|
|
|
- itemBuilder: (context, index) {
|
|
|
|
|
- final service = controller.streamingServices[index];
|
|
|
|
|
- return _buildStreamingServiceItem(service);
|
|
|
|
|
- },
|
|
|
|
|
- ),
|
|
|
|
|
- );
|
|
|
|
|
|
|
+ child: ListView.separated(
|
|
|
|
|
+ shrinkWrap: true,
|
|
|
|
|
+ physics: const NeverScrollableScrollPhysics(),
|
|
|
|
|
+ padding: EdgeInsets.zero,
|
|
|
|
|
+ itemCount: controller.bannerList.length,
|
|
|
|
|
+ separatorBuilder: (context, index) => Divider(
|
|
|
|
|
+ height: 1.w,
|
|
|
|
|
+ thickness: 1.w,
|
|
|
|
|
+ color: DarkThemeColors.strokes1,
|
|
|
|
|
+ ),
|
|
|
|
|
+ itemBuilder: (context, index) {
|
|
|
|
|
+ final banner = controller.bannerList[index];
|
|
|
|
|
+ return _buildStreamingServiceItem(banner);
|
|
|
|
|
+ },
|
|
|
|
|
+ ),
|
|
|
|
|
+ );
|
|
|
|
|
+ });
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/// 构建单个流媒体服务项
|
|
/// 构建单个流媒体服务项
|
|
|
- Widget _buildStreamingServiceItem(StreamingService service) {
|
|
|
|
|
|
|
+ Widget _buildStreamingServiceItem(Banner banner) {
|
|
|
return ClickOpacity(
|
|
return ClickOpacity(
|
|
|
- onTap: () => controller.openStreamingService(service),
|
|
|
|
|
|
|
+ onTap: () => controller.onBannerTap(banner),
|
|
|
child: Container(
|
|
child: Container(
|
|
|
padding: EdgeInsets.all(16.w),
|
|
padding: EdgeInsets.all(16.w),
|
|
|
child: Row(
|
|
child: Row(
|
|
|
children: [
|
|
children: [
|
|
|
// Logo
|
|
// Logo
|
|
|
- Container(
|
|
|
|
|
- width: 40.w,
|
|
|
|
|
- height: 40.w,
|
|
|
|
|
- decoration: BoxDecoration(
|
|
|
|
|
- color: _getServiceColor(service.name),
|
|
|
|
|
- borderRadius: BorderRadius.circular(12.r),
|
|
|
|
|
- ),
|
|
|
|
|
- child: Center(
|
|
|
|
|
- child: Text(
|
|
|
|
|
- service.name[0].toUpperCase(),
|
|
|
|
|
- style: TextStyle(
|
|
|
|
|
- fontSize: 24.sp,
|
|
|
|
|
- fontWeight: FontWeight.bold,
|
|
|
|
|
- color: DarkThemeColors.text1,
|
|
|
|
|
- ),
|
|
|
|
|
- ),
|
|
|
|
|
|
|
+ ClipRRect(
|
|
|
|
|
+ borderRadius: BorderRadius.circular(12.r),
|
|
|
|
|
+ child: IXImage(
|
|
|
|
|
+ source: banner.img ?? '',
|
|
|
|
|
+ width: 40.w,
|
|
|
|
|
+ height: 40.w,
|
|
|
|
|
+ sourceType: ImageSourceType.network,
|
|
|
),
|
|
),
|
|
|
),
|
|
),
|
|
|
|
|
|
|
@@ -252,7 +255,7 @@ class MedialocationView extends GetView<MedialocationController> {
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
children: [
|
|
children: [
|
|
|
Text(
|
|
Text(
|
|
|
- service.name,
|
|
|
|
|
|
|
+ banner.title ?? '',
|
|
|
style: TextStyle(
|
|
style: TextStyle(
|
|
|
fontSize: 14.sp,
|
|
fontSize: 14.sp,
|
|
|
height: 1.4,
|
|
height: 1.4,
|
|
@@ -260,14 +263,15 @@ class MedialocationView extends GetView<MedialocationController> {
|
|
|
color: DarkThemeColors.text1,
|
|
color: DarkThemeColors.text1,
|
|
|
),
|
|
),
|
|
|
),
|
|
),
|
|
|
- Text(
|
|
|
|
|
- service.description,
|
|
|
|
|
- style: TextStyle(
|
|
|
|
|
- fontSize: 13.sp,
|
|
|
|
|
- height: 1.4,
|
|
|
|
|
- color: DarkThemeColors.text2,
|
|
|
|
|
|
|
+ if (banner.content != null && banner.content!.isNotEmpty)
|
|
|
|
|
+ Text(
|
|
|
|
|
+ banner.content!,
|
|
|
|
|
+ style: TextStyle(
|
|
|
|
|
+ fontSize: 13.sp,
|
|
|
|
|
+ height: 1.4,
|
|
|
|
|
+ color: DarkThemeColors.text2,
|
|
|
|
|
+ ),
|
|
|
),
|
|
),
|
|
|
- ),
|
|
|
|
|
],
|
|
],
|
|
|
),
|
|
),
|
|
|
),
|
|
),
|
|
@@ -292,94 +296,28 @@ class MedialocationView extends GetView<MedialocationController> {
|
|
|
);
|
|
);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /// 构建功能说明列表
|
|
|
|
|
- Widget _buildFeaturesList() {
|
|
|
|
|
- return Column(
|
|
|
|
|
- children: [
|
|
|
|
|
- _buildFeatureItem(
|
|
|
|
|
- icon: Icons.favorite_outline,
|
|
|
|
|
- iconColor: Colors.red,
|
|
|
|
|
- text: 'Access your favorite content',
|
|
|
|
|
- ),
|
|
|
|
|
- _buildFeatureItem(
|
|
|
|
|
- icon: Icons.public,
|
|
|
|
|
- iconColor: Colors.blue,
|
|
|
|
|
- text: 'Connection from anywhere',
|
|
|
|
|
- ),
|
|
|
|
|
- _buildFeatureItem(
|
|
|
|
|
- icon: Icons.speed,
|
|
|
|
|
- iconColor: Colors.purple,
|
|
|
|
|
- text: 'Ultra fast servers',
|
|
|
|
|
- ),
|
|
|
|
|
- ],
|
|
|
|
|
- );
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /// 构建单个功能说明项
|
|
|
|
|
- Widget _buildFeatureItem({
|
|
|
|
|
- required IconData icon,
|
|
|
|
|
- required Color iconColor,
|
|
|
|
|
- required String text,
|
|
|
|
|
- }) {
|
|
|
|
|
- return Container(
|
|
|
|
|
- decoration: BoxDecoration(
|
|
|
|
|
- color: DarkThemeColors.bg3,
|
|
|
|
|
- borderRadius: BorderRadius.circular(12.r),
|
|
|
|
|
- ),
|
|
|
|
|
- height: 40.w,
|
|
|
|
|
- margin: EdgeInsets.only(bottom: 10.w),
|
|
|
|
|
- padding: EdgeInsets.symmetric(horizontal: 14.w),
|
|
|
|
|
- child: Row(
|
|
|
|
|
- children: [
|
|
|
|
|
- Icon(icon, color: iconColor, size: 20.w),
|
|
|
|
|
- 10.horizontalSpace,
|
|
|
|
|
- Expanded(
|
|
|
|
|
- child: Text(
|
|
|
|
|
- text,
|
|
|
|
|
- style: TextStyle(fontSize: 13.sp, color: DarkThemeColors.text2),
|
|
|
|
|
- ),
|
|
|
|
|
- ),
|
|
|
|
|
- ],
|
|
|
|
|
- ),
|
|
|
|
|
- );
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
/// 构建底部连接按钮
|
|
/// 构建底部连接按钮
|
|
|
Widget _buildConnectButton() {
|
|
Widget _buildConnectButton() {
|
|
|
return Padding(
|
|
return Padding(
|
|
|
padding: EdgeInsets.all(16.w),
|
|
padding: EdgeInsets.all(16.w),
|
|
|
child: Obx(() {
|
|
child: Obx(() {
|
|
|
|
|
+ // 访问 stateStream 以触发 Obx 响应
|
|
|
|
|
+ final _ = controller.coreController.stateStream.value;
|
|
|
return SubmitButton(
|
|
return SubmitButton(
|
|
|
- text: controller.isConnected.value
|
|
|
|
|
|
|
+ text: controller.isConnected
|
|
|
? Strings.disconnect.tr
|
|
? Strings.disconnect.tr
|
|
|
- : controller.isConnecting.value
|
|
|
|
|
|
|
+ : controller.isConnecting
|
|
|
? Strings.connecting.tr
|
|
? Strings.connecting.tr
|
|
|
: Strings.connect.tr,
|
|
: Strings.connect.tr,
|
|
|
- onPressed: controller.isConnected.value
|
|
|
|
|
|
|
+ onPressed: controller.isConnected
|
|
|
? controller.disconnect
|
|
? controller.disconnect
|
|
|
: controller.connect,
|
|
: controller.connect,
|
|
|
- isLoading: controller.isConnecting.value,
|
|
|
|
|
- bgColor: controller.isConnected.value
|
|
|
|
|
|
|
+ isLoading: controller.isConnecting,
|
|
|
|
|
+ bgColor: controller.isConnected
|
|
|
? Colors.red
|
|
? Colors.red
|
|
|
: DarkThemeColors.primaryColor,
|
|
: DarkThemeColors.primaryColor,
|
|
|
);
|
|
);
|
|
|
}),
|
|
}),
|
|
|
);
|
|
);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- /// 获取服务颜色
|
|
|
|
|
- Color _getServiceColor(String serviceName) {
|
|
|
|
|
- switch (serviceName.toLowerCase()) {
|
|
|
|
|
- case 'netflix':
|
|
|
|
|
- return const Color(0xFFE50914);
|
|
|
|
|
- case 'youtube':
|
|
|
|
|
- return const Color(0xFFFF0000);
|
|
|
|
|
- case 'hulu':
|
|
|
|
|
- return const Color(0xFF1CE783);
|
|
|
|
|
- case 'amazon':
|
|
|
|
|
- return const Color(0xFF00A8E1);
|
|
|
|
|
- default:
|
|
|
|
|
- return DarkThemeColors.primaryColor;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
}
|
|
}
|