medialocation_view.dart 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. import 'package:flutter/material.dart' hide Banner;
  2. import 'package:flutter_screenutil/flutter_screenutil.dart';
  3. import 'package:get/get.dart';
  4. import 'package:nomo/config/theme/dark_theme_colors.dart';
  5. import '../../../../config/translations/strings_enum.dart';
  6. import '../../../constants/assets.dart';
  7. import '../../../data/models/banner/banner_list.dart';
  8. import '../../../widgets/click_opacity.dart';
  9. import '../../../widgets/ix_image.dart';
  10. import '../../../widgets/submit_btn.dart';
  11. import '../controllers/medialocation_controller.dart';
  12. class MedialocationView extends GetView<MedialocationController> {
  13. const MedialocationView({super.key});
  14. @override
  15. Widget build(BuildContext context) {
  16. return Scaffold(
  17. backgroundColor: DarkThemeColors.scaffoldBackgroundColor,
  18. body: Stack(
  19. children: [
  20. // 背景图层(只显示顶部214高度)
  21. Positioned(
  22. top: 0,
  23. left: 0,
  24. right: 0,
  25. height: 214.w,
  26. child: ClipRect(
  27. child: Obx(
  28. () => IXImage(
  29. source: controller.bannerInfoImg.isNotEmpty
  30. ? controller.bannerInfoImg
  31. : Assets.mediaBg,
  32. width: 375.w,
  33. height: 214.w,
  34. sourceType: controller.bannerInfoImg.isNotEmpty
  35. ? ImageSourceType.network
  36. : ImageSourceType.asset,
  37. ),
  38. ),
  39. ),
  40. ),
  41. // 渐变遮罩层
  42. Positioned(
  43. top: 0,
  44. left: 0,
  45. right: 0,
  46. height: 214.w,
  47. child: Container(
  48. decoration: BoxDecoration(
  49. gradient: LinearGradient(
  50. begin: Alignment.topCenter,
  51. end: Alignment.bottomCenter,
  52. colors: [Colors.black.withValues(alpha: 0.6), Colors.black],
  53. stops: const [0.0, 1.0],
  54. ),
  55. ),
  56. ),
  57. ),
  58. // 内容层
  59. SafeArea(
  60. child: Column(
  61. children: [
  62. // 顶部标题区域
  63. _buildAppBar(),
  64. _buildHeader(),
  65. // 可滚动内容区域
  66. Expanded(
  67. child: Padding(
  68. padding: EdgeInsets.symmetric(horizontal: 14.w),
  69. child: Column(
  70. children: [
  71. 20.verticalSpace,
  72. // 流媒体服务卡片
  73. _buildStreamingServicesCard(),
  74. ],
  75. ),
  76. ),
  77. ),
  78. 20.verticalSpace,
  79. // 底部连接按钮
  80. _buildConnectButton(),
  81. ],
  82. ),
  83. ),
  84. ],
  85. ),
  86. );
  87. }
  88. // 顶部标题栏
  89. Widget _buildAppBar() {
  90. return Padding(
  91. padding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 12.h),
  92. child: Row(
  93. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  94. children: [
  95. SizedBox(width: 32.w),
  96. GestureDetector(
  97. onTap: () => Get.back(),
  98. child: Container(
  99. width: 24.w,
  100. height: 24.w,
  101. decoration: BoxDecoration(
  102. color: Colors.white.withValues(alpha: 0.1),
  103. shape: BoxShape.circle,
  104. ),
  105. child: Icon(Icons.close_rounded, color: Colors.white, size: 16.w),
  106. ),
  107. ),
  108. ],
  109. ),
  110. );
  111. }
  112. /// 构建顶部标题区域
  113. Widget _buildHeader() {
  114. return Container(
  115. padding: EdgeInsets.symmetric(vertical: 20.w),
  116. child: Column(
  117. children: [
  118. // 图标和标题
  119. Obx(
  120. () => Row(
  121. mainAxisAlignment: MainAxisAlignment.center,
  122. children: [
  123. IXImage(
  124. source: controller.bannerImg,
  125. width: 32.w,
  126. height: 32.w,
  127. sourceType: ImageSourceType.network,
  128. ),
  129. 8.horizontalSpace,
  130. Text(
  131. controller.bannerTitle,
  132. style: TextStyle(
  133. fontSize: 22.sp,
  134. fontWeight: FontWeight.w500,
  135. height: 1.3,
  136. color: Colors.white,
  137. ),
  138. ),
  139. ],
  140. ),
  141. ),
  142. 8.verticalSpace,
  143. // 连接状态
  144. Obx(() {
  145. // 访问 stateStream 以触发 Obx 响应
  146. final _ = controller.coreController.stateStream.value;
  147. final text = controller.isConnected
  148. ? Strings.connected.tr
  149. : controller.isConnecting
  150. ? Strings.connecting.tr
  151. : Strings.disconnected.tr;
  152. final textColor = controller.isConnected
  153. ? DarkThemeColors.text1
  154. : controller.isConnecting
  155. ? DarkThemeColors.text1
  156. : DarkThemeColors.text1;
  157. final statusImgPath = controller.isConnected
  158. ? Assets.connected
  159. : controller.isConnecting
  160. ? Assets.connecting
  161. : Assets.disconnected;
  162. return SizedBox(
  163. height: 20.w,
  164. child: Row(
  165. mainAxisAlignment: MainAxisAlignment.center,
  166. children: [
  167. IXImage(
  168. source: statusImgPath,
  169. sourceType: ImageSourceType.asset,
  170. width: 14.w,
  171. height: 14.w,
  172. ),
  173. 4.horizontalSpace,
  174. Text(
  175. text,
  176. style: TextStyle(
  177. fontSize: 14.sp,
  178. height: 1.4,
  179. fontWeight: FontWeight.w500,
  180. color: textColor,
  181. ),
  182. ),
  183. ],
  184. ),
  185. );
  186. }),
  187. ],
  188. ),
  189. );
  190. }
  191. /// 构建流媒体服务卡片
  192. Widget _buildStreamingServicesCard() {
  193. return Obx(() {
  194. if (controller.bannerList.isEmpty) {
  195. return const SizedBox.shrink();
  196. }
  197. return Container(
  198. decoration: BoxDecoration(
  199. color: DarkThemeColors.bg2,
  200. borderRadius: BorderRadius.circular(12.r),
  201. ),
  202. child: ListView.separated(
  203. shrinkWrap: true,
  204. physics: const NeverScrollableScrollPhysics(),
  205. padding: EdgeInsets.zero,
  206. itemCount: controller.bannerList.length,
  207. separatorBuilder: (context, index) => Divider(
  208. height: 1.w,
  209. thickness: 1.w,
  210. color: DarkThemeColors.strokes1,
  211. ),
  212. itemBuilder: (context, index) {
  213. final banner = controller.bannerList[index];
  214. return _buildStreamingServiceItem(banner);
  215. },
  216. ),
  217. );
  218. });
  219. }
  220. /// 构建单个流媒体服务项
  221. Widget _buildStreamingServiceItem(Banner banner) {
  222. return ClickOpacity(
  223. onTap: () => controller.onBannerTap(banner),
  224. child: Container(
  225. padding: EdgeInsets.all(16.w),
  226. child: Row(
  227. children: [
  228. // Logo
  229. ClipRRect(
  230. borderRadius: BorderRadius.circular(12.r),
  231. child: IXImage(
  232. source: banner.img ?? '',
  233. width: 40.w,
  234. height: 40.w,
  235. sourceType: ImageSourceType.network,
  236. ),
  237. ),
  238. 10.horizontalSpace,
  239. // 名称和描述
  240. Expanded(
  241. child: Column(
  242. crossAxisAlignment: CrossAxisAlignment.start,
  243. children: [
  244. Text(
  245. banner.title ?? '',
  246. style: TextStyle(
  247. fontSize: 14.sp,
  248. height: 1.4,
  249. fontWeight: FontWeight.w500,
  250. color: DarkThemeColors.text1,
  251. ),
  252. ),
  253. if (banner.content != null && banner.content!.isNotEmpty)
  254. Text(
  255. banner.content!,
  256. style: TextStyle(
  257. fontSize: 13.sp,
  258. height: 1.4,
  259. color: DarkThemeColors.text2,
  260. ),
  261. ),
  262. ],
  263. ),
  264. ),
  265. 16.horizontalSpace,
  266. // Open 按钮
  267. Container(
  268. padding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 4.w),
  269. decoration: BoxDecoration(
  270. color: DarkThemeColors.primaryColor,
  271. borderRadius: BorderRadius.circular(20.r),
  272. ),
  273. child: Text(
  274. Strings.open.tr,
  275. style: TextStyle(fontSize: 13.sp, color: DarkThemeColors.text1),
  276. ),
  277. ),
  278. ],
  279. ),
  280. ),
  281. );
  282. }
  283. /// 构建底部连接按钮
  284. Widget _buildConnectButton() {
  285. return Padding(
  286. padding: EdgeInsets.all(16.w),
  287. child: Obx(() {
  288. // 访问 stateStream 以触发 Obx 响应
  289. final _ = controller.coreController.stateStream.value;
  290. return SubmitButton(
  291. text: controller.isConnected
  292. ? Strings.disconnect.tr
  293. : controller.isConnecting
  294. ? Strings.connecting.tr
  295. : Strings.connect.tr,
  296. onPressed: controller.isConnected
  297. ? controller.disconnect
  298. : controller.connect,
  299. isLoading: controller.isConnecting,
  300. bgColor: controller.isConnected
  301. ? Colors.red
  302. : DarkThemeColors.primaryColor,
  303. );
  304. }),
  305. );
  306. }
  307. }