keyboard_view.dart 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702
  1. import 'package:cached_network_image/cached_network_image.dart';
  2. import 'package:flutter/cupertino.dart';
  3. import 'package:flutter/material.dart';
  4. import 'package:flutter_screenutil/flutter_screenutil.dart';
  5. import 'package:keyboard/base/base_view.dart';
  6. import 'package:get/get.dart';
  7. import 'package:keyboard/resource/string.gen.dart';
  8. import '../../resource/assets.gen.dart';
  9. import '../../utils/styles.dart';
  10. import 'keyboard_controller.dart';
  11. class KeyBoardView extends BaseView<KeyBoardController> {
  12. const KeyBoardView({super.key});
  13. @override
  14. Widget buildBody(BuildContext context) {
  15. return Stack(
  16. children: [
  17. IgnorePointer(child: Assets.images.bgKeyboard.image(width: 360.w)),
  18. SafeArea(
  19. child: Column(
  20. children: [
  21. _buildTitle(),
  22. Expanded(
  23. child: SingleChildScrollView(
  24. child: Column(
  25. children: [
  26. _buildAvatarCard(),
  27. _buildLoveIndexCard(),
  28. _buildPopularFeatures(),
  29. _buildKeyboardSettings(),
  30. ],
  31. ),
  32. ),
  33. ),
  34. ],
  35. ),
  36. ),
  37. ],
  38. );
  39. }
  40. // 顶部标题栏
  41. Widget _buildTitle() {
  42. return Container(
  43. padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 12.h),
  44. color: Colors.transparent,
  45. child: Row(
  46. children: [
  47. Assets.images.iconKeyboardTitle.image(
  48. width: 110.w,
  49. height: 26.h,
  50. fit: BoxFit.cover,
  51. ),
  52. const Spacer(),
  53. Container(
  54. padding: EdgeInsets.symmetric(horizontal: 6.w, vertical: 6.w),
  55. decoration: ShapeDecoration(
  56. color: Colors.white.withAlpha(204),
  57. shape: RoundedRectangleBorder(
  58. side: BorderSide(width: 1, color: Colors.white),
  59. borderRadius: BorderRadius.circular(13.r),
  60. ),
  61. ),
  62. child: Row(
  63. children: [
  64. Assets.images.iconKeyboardVipLogo.image(
  65. width: 12.w,
  66. height: 12.w,
  67. ),
  68. const SizedBox(width: 2),
  69. Text(
  70. StringName.keyboardMemberOpen,
  71. style: TextStyle(
  72. color: Color(0xFFA85600),
  73. fontSize: 12,
  74. fontWeight: FontWeight.w400,
  75. ),
  76. ),
  77. Icon(Icons.chevron_right, color: Color(0xFFA85600), size: 11.r),
  78. ],
  79. ),
  80. ),
  81. ],
  82. ),
  83. );
  84. }
  85. // 用户头像卡片
  86. Widget _buildAvatarCard() {
  87. return Obx(() {
  88. return Container(
  89. padding: EdgeInsets.symmetric(horizontal: 22.w),
  90. decoration: BoxDecoration(color: Colors.transparent),
  91. child: Column(
  92. crossAxisAlignment: CrossAxisAlignment.start,
  93. children: [
  94. Row(
  95. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  96. children: [
  97. _buildUserAvatar(true),
  98. const SizedBox(width: 16),
  99. _buildLovePercentage(),
  100. const SizedBox(width: 16),
  101. controller.hasPartner.value
  102. ? _buildUserAvatar(false)
  103. : _buildAddPartnerButton(),
  104. ],
  105. ),
  106. SizedBox(height: 10.h),
  107. ],
  108. ),
  109. );
  110. });
  111. }
  112. // 爱情指数卡片
  113. Widget _buildLoveIndexCard() {
  114. return Container(
  115. margin: EdgeInsets.symmetric(horizontal: 16.w),
  116. padding: EdgeInsets.symmetric(vertical: 5.h, horizontal: 11.w),
  117. decoration: BoxDecoration(
  118. color: Colors.white,
  119. borderRadius: BorderRadius.circular(12.r),
  120. ),
  121. child: Row(
  122. children: [
  123. Assets.images.iconKeyboardLoveIndex.image(width: 72.w, height: 23.h),
  124. Container(
  125. height: 42.w,
  126. width: 215.h,
  127. decoration: BoxDecoration(
  128. color: Color(0xFFFAFAFC),
  129. borderRadius: BorderRadius.circular(12.r),
  130. ),
  131. child: Column(
  132. children: [
  133. Row(
  134. children: [
  135. Expanded(
  136. child: ProgressBar(
  137. title: "爱情",
  138. value: controller.appearancePercentage,
  139. color: Colors.pink.shade100,
  140. ),
  141. ),
  142. Expanded(
  143. child: ProgressBar(
  144. title: "爱情",
  145. value: controller.appearancePercentage,
  146. color: Colors.pink.shade100,
  147. ),
  148. ),
  149. ],
  150. ),
  151. Row(
  152. children: [
  153. Expanded(
  154. child: ProgressBar(
  155. title: "爱情",
  156. value: controller.appearancePercentage,
  157. color: Colors.pink.shade100,
  158. ),
  159. ),
  160. Expanded(
  161. child: ProgressBar(
  162. title: "爱情",
  163. value: controller.appearancePercentage,
  164. color: Colors.pink.shade100,
  165. ),
  166. ),
  167. ],
  168. ),
  169. ],
  170. ),
  171. ),
  172. ],
  173. ),
  174. );
  175. }
  176. // 用户头像
  177. Widget _buildUserAvatar(bool isUser) {
  178. return Column(
  179. children: [
  180. Stack(
  181. alignment: Alignment.bottomCenter,
  182. children: [
  183. Column(
  184. children: [
  185. Container(
  186. width: 98.r,
  187. height: 98.r,
  188. decoration: ShapeDecoration(
  189. shape: RoundedRectangleBorder(
  190. borderRadius: BorderRadius.circular(50.r),
  191. ),
  192. ),
  193. child: CachedNetworkImage(
  194. imageUrl:
  195. isUser
  196. ? controller.userInfo.value?.imageUrl ?? ""
  197. : controller.currentChooseKeyboard.value.avatar ??
  198. "",
  199. placeholder: (_, __) => const CupertinoActivityIndicator(),
  200. errorWidget:
  201. (context, url, error) => CircleAvatar(
  202. backgroundImage:
  203. Assets.images.iconKeyboardDefaultAvatar
  204. .provider(),
  205. ),
  206. imageBuilder:
  207. (context, imageProvider) => Container(
  208. decoration: ShapeDecoration(
  209. shape: RoundedRectangleBorder(
  210. side: BorderSide(width: 2.r, color: Colors.white),
  211. borderRadius: BorderRadius.circular(50.r),
  212. ),
  213. ),
  214. child: CircleAvatar(backgroundImage: imageProvider),
  215. ),
  216. ),
  217. ),
  218. SizedBox(height: 10.h),
  219. ],
  220. ),
  221. Container(
  222. padding: EdgeInsets.symmetric(horizontal: 24.w, vertical: 4.w),
  223. decoration: BoxDecoration(
  224. color: Colors.white,
  225. borderRadius: BorderRadius.circular(22.r),
  226. ),
  227. child: Text(
  228. isUser
  229. ? controller.userInfo.value?.name ?? ""
  230. : controller.currentChooseKeyboard.value.name ?? "",
  231. style: Styles.getTextStyleBlack204W400(14.sp),
  232. ),
  233. ),
  234. ],
  235. ),
  236. const SizedBox(height: 4),
  237. // Text(name, style: const TextStyle(fontSize: 12)),
  238. ],
  239. );
  240. }
  241. // 爱情百分比
  242. Widget _buildLovePercentage() {
  243. return Container(
  244. decoration: BoxDecoration(shape: BoxShape.circle),
  245. child: Center(
  246. child: Column(
  247. mainAxisSize: MainAxisSize.min,
  248. children: [
  249. Container(
  250. padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 4.h),
  251. decoration: ShapeDecoration(
  252. color: Colors.white.withValues(alpha: 153),
  253. shape: RoundedRectangleBorder(
  254. borderRadius: BorderRadius.circular(17.r),
  255. ),
  256. ),
  257. child: Row(
  258. children: [
  259. Assets.images.iconKeyboardLoveLogo.image(
  260. width: 18.w,
  261. height: 18.w,
  262. ),
  263. Text(
  264. '追爱ing',
  265. textAlign: TextAlign.center,
  266. style: Styles.getTextStyleBlack153W400(14.sp),
  267. ),
  268. ],
  269. ),
  270. ),
  271. SizedBox(height: 7.h),
  272. SizedBox(
  273. width: 88.w,
  274. height: 72.h,
  275. child: Stack(
  276. children: [
  277. Assets.images.bgKeyboardLove.image(width: 88.w, height: 72.h),
  278. Positioned.fill(
  279. child: Center(
  280. child: Obx(
  281. () => Text.rich(
  282. TextSpan(
  283. children: [
  284. TextSpan(
  285. text:
  286. controller.hasPartner.value &&
  287. controller
  288. .currentChooseKeyboard
  289. .value
  290. .intimacy !=
  291. null
  292. ? controller
  293. .currentChooseKeyboard
  294. .value
  295. .intimacy
  296. .toString()
  297. : "?",
  298. style: TextStyle(
  299. color: Colors.white,
  300. fontSize: 33.sp,
  301. fontWeight: FontWeight.w700,
  302. shadows: [
  303. Shadow(
  304. offset: Offset(0, 1),
  305. blurRadius: 4.r,
  306. color: const Color(
  307. 0xFFFF6BD3,
  308. ).withValues(alpha: 0.63),
  309. ),
  310. ],
  311. ),
  312. ),
  313. TextSpan(
  314. text: '%',
  315. style: TextStyle(
  316. color: Colors.white,
  317. fontSize: 14.sp,
  318. fontWeight: FontWeight.w700,
  319. shadows: [
  320. Shadow(
  321. offset: Offset(0, 1),
  322. blurRadius: 4.r,
  323. color: const Color(
  324. 0xFFFF6BD3,
  325. ).withValues(alpha: 0.63),
  326. ),
  327. ],
  328. ),
  329. ),
  330. ],
  331. ),
  332. ),
  333. ),
  334. ),
  335. ),
  336. ],
  337. ),
  338. ),
  339. ],
  340. ),
  341. ),
  342. );
  343. }
  344. // 添加伴侣按钮
  345. Widget _buildAddPartnerButton() {
  346. return Column(
  347. children: [
  348. Container(
  349. width: 60,
  350. height: 60,
  351. decoration: BoxDecoration(
  352. shape: BoxShape.circle,
  353. color: Colors.grey.shade200,
  354. ),
  355. child: const Icon(Icons.mail_outline, color: Colors.grey),
  356. ),
  357. const SizedBox(height: 4),
  358. const Text('添加', style: TextStyle(fontSize: 12)),
  359. ],
  360. );
  361. }
  362. // 爱情指数项目
  363. Widget _buildLoveIndexItems() {
  364. return Obx(() {
  365. return Row(
  366. children: [
  367. _buildIndexItem(
  368. '心情',
  369. controller.moodPercentage.value,
  370. Colors.pink.shade100,
  371. ),
  372. _buildIndexItem(
  373. '颜值',
  374. controller.appearancePercentage.value,
  375. Colors.purple.shade100,
  376. ),
  377. _buildIndexItem(
  378. '财富',
  379. controller.wealthPercentage.value,
  380. Colors.amber.shade100,
  381. ),
  382. _buildIndexItem(
  383. '洁净',
  384. controller.cleanlinessPercentage.value,
  385. Colors.blue.shade100,
  386. ),
  387. ],
  388. );
  389. });
  390. }
  391. // 单个指数项
  392. Widget _buildIndexItem(String title, int percentage, Color color) {
  393. return Expanded(
  394. child: Column(
  395. crossAxisAlignment: CrossAxisAlignment.start,
  396. children: [
  397. Text(title, style: const TextStyle(fontSize: 12)),
  398. const SizedBox(height: 4),
  399. Stack(
  400. children: [
  401. Container(
  402. height: 6,
  403. decoration: BoxDecoration(
  404. color: Colors.grey.shade200,
  405. borderRadius: BorderRadius.circular(3),
  406. ),
  407. ),
  408. FractionallySizedBox(
  409. widthFactor: percentage / 100,
  410. child: Container(
  411. height: 6,
  412. decoration: BoxDecoration(
  413. color: color,
  414. borderRadius: BorderRadius.circular(3),
  415. ),
  416. ),
  417. ),
  418. ],
  419. ),
  420. const SizedBox(height: 2),
  421. Text(
  422. '$percentage%',
  423. style: TextStyle(fontSize: 10, color: Colors.grey.shade600),
  424. ),
  425. ],
  426. ),
  427. );
  428. }
  429. // 爆款玩法区域
  430. Widget _buildPopularFeatures() {
  431. return Container(
  432. margin: const EdgeInsets.symmetric(horizontal: 16),
  433. padding: const EdgeInsets.all(16),
  434. decoration: BoxDecoration(
  435. color: Colors.white,
  436. borderRadius: BorderRadius.circular(16),
  437. ),
  438. child: Column(
  439. crossAxisAlignment: CrossAxisAlignment.start,
  440. children: [
  441. Row(
  442. children: [
  443. Container(
  444. width: 8,
  445. height: 8,
  446. decoration: BoxDecoration(
  447. shape: BoxShape.circle,
  448. color: Colors.purple.shade200,
  449. ),
  450. ),
  451. const SizedBox(width: 8),
  452. const Text(
  453. '爆款玩法',
  454. style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
  455. ),
  456. ],
  457. ),
  458. const SizedBox(height: 16),
  459. Row(
  460. children: [
  461. _buildFeatureCard(
  462. '追爱小键盘',
  463. '轻松回复TA',
  464. Colors.purple.shade50,
  465. Icons.keyboard,
  466. Colors.purple.shade200,
  467. ),
  468. const SizedBox(width: 12),
  469. _buildFeatureCard(
  470. '亲密度分析',
  471. '探索人格密码',
  472. Colors.orange.shade50,
  473. Icons.favorite_border,
  474. Colors.orange.shade200,
  475. ),
  476. ],
  477. ),
  478. const SizedBox(height: 12),
  479. Row(
  480. children: [
  481. _buildFeatureCard(
  482. '截图回复',
  483. '上下文义分析',
  484. Colors.blue.shade50,
  485. Icons.screenshot_monitor,
  486. Colors.blue.shade200,
  487. ),
  488. const SizedBox(width: 12),
  489. _buildFeatureCard(
  490. '截图回复',
  491. '上下文义分析',
  492. Colors.green.shade50,
  493. Icons.message,
  494. Colors.green.shade200,
  495. ),
  496. ],
  497. ),
  498. ],
  499. ),
  500. );
  501. }
  502. // 功能卡片
  503. Widget _buildFeatureCard(
  504. String title,
  505. String subtitle,
  506. Color bgColor,
  507. IconData icon,
  508. Color iconColor,
  509. ) {
  510. return Expanded(
  511. child: Container(
  512. padding: const EdgeInsets.all(12),
  513. decoration: BoxDecoration(
  514. color: bgColor,
  515. borderRadius: BorderRadius.circular(12),
  516. ),
  517. child: Row(
  518. children: [
  519. Expanded(
  520. child: Column(
  521. crossAxisAlignment: CrossAxisAlignment.start,
  522. children: [
  523. Text(
  524. title,
  525. style: const TextStyle(
  526. fontSize: 14,
  527. fontWeight: FontWeight.bold,
  528. ),
  529. ),
  530. const SizedBox(height: 4),
  531. Text(
  532. subtitle,
  533. style: TextStyle(fontSize: 12, color: Colors.grey.shade700),
  534. ),
  535. ],
  536. ),
  537. ),
  538. Container(
  539. width: 40,
  540. height: 40,
  541. decoration: BoxDecoration(
  542. color: Colors.white,
  543. borderRadius: BorderRadius.circular(8),
  544. ),
  545. child: Icon(icon, color: iconColor),
  546. ),
  547. ],
  548. ),
  549. ),
  550. );
  551. }
  552. // 键盘设置区域
  553. Widget _buildKeyboardSettings() {
  554. return Container(
  555. margin: const EdgeInsets.all(16),
  556. padding: const EdgeInsets.all(16),
  557. decoration: BoxDecoration(
  558. color: Colors.white,
  559. borderRadius: BorderRadius.circular(16),
  560. ),
  561. child: Column(
  562. crossAxisAlignment: CrossAxisAlignment.start,
  563. children: [
  564. Row(
  565. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  566. children: [
  567. const Text(
  568. '当前键盘人设',
  569. style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold),
  570. ),
  571. Row(
  572. children: [
  573. const Text(
  574. '去管理',
  575. style: TextStyle(fontSize: 12, color: Colors.grey),
  576. ),
  577. Icon(
  578. Icons.chevron_right,
  579. size: 16,
  580. color: Colors.grey.shade400,
  581. ),
  582. ],
  583. ),
  584. ],
  585. ),
  586. const SizedBox(height: 16),
  587. Wrap(
  588. spacing: 8,
  589. runSpacing: 8,
  590. children: [
  591. _buildPersonaTag('高冷'),
  592. _buildPersonaTag('幽默搞笑'),
  593. _buildPersonaTag('粘心暖男'),
  594. _buildPersonaTag('温柔体贴'),
  595. _buildPersonaTag('阳光大男孩'),
  596. _buildPersonaTag('都市精英'),
  597. ],
  598. ),
  599. ],
  600. ),
  601. );
  602. }
  603. // 人设标签
  604. Widget _buildPersonaTag(String text) {
  605. return Container(
  606. padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
  607. decoration: BoxDecoration(
  608. color: Colors.grey.shade100,
  609. borderRadius: BorderRadius.circular(16),
  610. ),
  611. child: Row(
  612. mainAxisSize: MainAxisSize.min,
  613. children: [
  614. const Icon(Icons.emoji_emotions, size: 16, color: Colors.amber),
  615. const SizedBox(width: 4),
  616. Text(text, style: const TextStyle(fontSize: 12)),
  617. ],
  618. ),
  619. );
  620. }
  621. @override
  622. Color backgroundColor() {
  623. return const Color(0xFFF5F5F5);
  624. }
  625. }
  626. class ProgressBar extends StatelessWidget {
  627. final String title;
  628. final RxInt value; // 例如传入 50,代表 50%
  629. final Color color;
  630. const ProgressBar({
  631. super.key,
  632. required this.title,
  633. required this.value,
  634. required this.color,
  635. });
  636. @override
  637. Widget build(BuildContext context) {
  638. return Obx(() {
  639. final double progress = (value.value / 100).clamp(0.0, 1.0); // 保证 0~1 范围
  640. return Container(
  641. child: Row(
  642. children: [
  643. SizedBox(width: 40, child: Text(title)),
  644. const SizedBox(width: 8),
  645. Expanded(
  646. child: Stack(
  647. children: [
  648. Container(
  649. height: 20,
  650. decoration: BoxDecoration(
  651. color: color.withOpacity(0.15), // 修正:用 withOpacity
  652. borderRadius: BorderRadius.circular(20.r),
  653. ),
  654. ),
  655. FractionallySizedBox(
  656. widthFactor: progress,
  657. child: Container(
  658. height: 20.h,
  659. decoration: BoxDecoration(
  660. color: color,
  661. borderRadius: BorderRadius.circular(20.r),
  662. ),
  663. ),
  664. ),
  665. Positioned.fill(
  666. child: Center(
  667. child: Text(
  668. "${value.value}%",
  669. style: const TextStyle(
  670. color: Colors.white,
  671. fontSize: 12,
  672. ),
  673. ),
  674. ),
  675. ),
  676. ],
  677. ),
  678. ),
  679. ],
  680. ),
  681. );
  682. });
  683. }
  684. }