profile_page.dart 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  1. import 'package:dotted_border/dotted_border.dart';
  2. import 'package:flutter/cupertino.dart';
  3. import 'package:flutter/material.dart';
  4. import 'package:flutter/rendering.dart';
  5. import 'package:flutter_screenutil/flutter_screenutil.dart';
  6. import 'package:get/get.dart';
  7. import 'package:keyboard/base/base_page.dart';
  8. import 'package:keyboard/data/bean/keyboard_info.dart';
  9. import 'package:keyboard/module/profile/profile_controller.dart';
  10. import 'package:keyboard/utils/intimacy_util.dart';
  11. import '../../resource/assets.gen.dart';
  12. import '../../resource/string.gen.dart';
  13. import '../../router/app_pages.dart';
  14. import '../../utils/styles.dart';
  15. import '../../widget/avatar/avatar_image_widget.dart';
  16. class ProfilePage extends BasePage<ProfileController> {
  17. const ProfilePage({super.key});
  18. static Future<dynamic> start() async {
  19. return await Get.toNamed(RoutePath.profile);
  20. }
  21. @override
  22. Color backgroundColor() {
  23. return const Color(0xFFF6F5FA);
  24. }
  25. @override
  26. immersive() {
  27. return true;
  28. }
  29. @override
  30. Widget buildBody(BuildContext context) {
  31. return Stack(
  32. children: [
  33. SafeArea(
  34. child: Column(
  35. crossAxisAlignment: CrossAxisAlignment.start,
  36. children: [
  37. _buildTitle(),
  38. SizedBox(height: 16.w),
  39. Expanded(
  40. child: Obx(() {
  41. final list = controller.customKeyboardInfoList;
  42. return CustomScrollView(
  43. physics: const ScrollPhysics(),
  44. slivers: [
  45. SliverToBoxAdapter(child: Container(height: 10.h)),
  46. if (list.isEmpty)
  47. SliverToBoxAdapter(
  48. child: _buildKeyboardListItem(
  49. keyboardInfo: null,
  50. isChosen: false,
  51. hasKeyboard: false,
  52. ),
  53. )
  54. else
  55. SliverList(
  56. delegate: SliverChildBuilderDelegate((
  57. context,
  58. index,
  59. ) {
  60. return Obx(() {
  61. final keyboardInfo = list[index];
  62. final isChosen =
  63. keyboardInfo.id ==
  64. controller.currentCustomKeyboardInfo.id;
  65. return _buildKeyboardListItem(
  66. keyboardInfo: keyboardInfo,
  67. isChosen: isChosen,
  68. hasKeyboard: true,
  69. );
  70. });
  71. }, childCount: list.length),
  72. ),
  73. SliverToBoxAdapter(child: SizedBox(height: 110.h)),
  74. ],
  75. );
  76. }),
  77. ),
  78. ],
  79. ),
  80. ),
  81. Positioned(
  82. bottom: 20.h,
  83. left: 16.w,
  84. right: 16.w,
  85. child: InkWell(
  86. onTap: () {
  87. controller.clickSaveButton();
  88. },
  89. child: Container(
  90. height: 48.h,
  91. alignment: Alignment.center,
  92. decoration: Styles.getActivateButtonDecoration(31.r),
  93. child: Text(
  94. StringName.profileSave,
  95. style: Styles.getTextStyleWhiteW500(16.sp),
  96. ),
  97. ),
  98. ),
  99. ),
  100. // 背景图片
  101. IgnorePointer(child: Assets.images.bgMine.image(width: 360.w)),
  102. ],
  103. );
  104. }
  105. // 爱心
  106. _buildLoveIndex(int? intimacy) {
  107. return Container(
  108. width: 87.w,
  109. height: 71.h,
  110. decoration: BoxDecoration(
  111. image: DecorationImage(image: Assets.images.bgProfileLove.provider()),
  112. ),
  113. child: Column(
  114. children: [
  115. SizedBox(height: 45.h),
  116. Row(
  117. mainAxisAlignment: MainAxisAlignment.center,
  118. children: [
  119. Container(
  120. padding: EdgeInsets.only(left: 8.w, right: 8.w),
  121. decoration: ShapeDecoration(
  122. color: Colors.white,
  123. shape: RoundedRectangleBorder(
  124. side: BorderSide(
  125. width: 1.18.w,
  126. color: const Color(0xFFFD649B),
  127. ),
  128. borderRadius: BorderRadius.circular(12.36.r),
  129. ),
  130. ),
  131. child:
  132. (intimacy != null)
  133. ? Center(
  134. child: Text(
  135. IntimacyUtil.getIntimacyName(intimacy),
  136. style: TextStyle(
  137. color: const Color(0xFFFF73E0),
  138. fontSize: 11.sp,
  139. fontWeight: FontWeight.w500,
  140. ),
  141. ),
  142. )
  143. : Center(
  144. child: Text(
  145. "?",
  146. style: TextStyle(
  147. color: const Color(0xFFFF73E0),
  148. fontSize: 11.sp,
  149. fontWeight: FontWeight.w500,
  150. ),
  151. ),
  152. ),
  153. ),
  154. ],
  155. ),
  156. ],
  157. ),
  158. );
  159. }
  160. _buildTitle() {
  161. return Container(
  162. alignment: Alignment.centerLeft,
  163. padding: EdgeInsets.only(top: 12.h, left: 16.w, right: 16.w),
  164. child: Row(
  165. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  166. children: [
  167. GestureDetector(
  168. onTap: () => controller.clickBack(),
  169. child: Assets.images.iconMineBackArrow.image(
  170. width: 24.w,
  171. height: 24.w,
  172. ),
  173. ),
  174. Text(
  175. StringName.profileList,
  176. style: Styles.getTextStyleBlack204W500(17.sp),
  177. ),
  178. GestureDetector(
  179. onTap: () => controller.clickAddButton(),
  180. child: Assets.images.iconProfileAdd.image(
  181. width: 24.w,
  182. height: 24.w,
  183. ),
  184. ),
  185. ],
  186. ),
  187. );
  188. }
  189. Widget _buildKeyboardListItem({
  190. KeyboardInfo? keyboardInfo,
  191. bool isChosen = false,
  192. required bool hasKeyboard,
  193. }) {
  194. final String title = hasKeyboard ? '我&${keyboardInfo?.name ?? ""}' : '我';
  195. final int? intimacy = hasKeyboard ? keyboardInfo?.intimacy : null;
  196. final String? keyboardAvatar = hasKeyboard ? keyboardInfo?.imageUrl : null;
  197. final int gender = hasKeyboard ? (keyboardInfo?.gender ?? 1) : 1;
  198. return GestureDetector(
  199. onTap:
  200. hasKeyboard
  201. ? () => controller.clickOnChangeKeyboard(keyboardInfo!)
  202. : null,
  203. child: Container(
  204. height: 164.h,
  205. margin: EdgeInsets.only(left: 16.w, right: 16.w, bottom: 12.h),
  206. decoration:
  207. isChosen
  208. ? ShapeDecoration(
  209. gradient: LinearGradient(
  210. begin: Alignment(0.02, 0.04),
  211. end: Alignment(1.00, 1.00),
  212. colors: [const Color(0xFFE7A0FF), const Color(0xFFAB8FFA)],
  213. ),
  214. shape: RoundedRectangleBorder(
  215. borderRadius: BorderRadius.circular(22.r),
  216. ),
  217. shadows: [
  218. BoxShadow(
  219. color: Color(0x1CD6C1FF),
  220. blurRadius: 4.r,
  221. offset: Offset(0, 4.r),
  222. spreadRadius: 0,
  223. ),
  224. ],
  225. )
  226. : ShapeDecoration(
  227. color: Colors.white,
  228. shape: RoundedRectangleBorder(
  229. borderRadius: BorderRadius.circular(20.r),
  230. ),
  231. ),
  232. child: Stack(
  233. children: [
  234. if (isChosen)
  235. Opacity(
  236. opacity: 0.1,
  237. child: Assets.images.bgProfileSelected.image(),
  238. ),
  239. Column(
  240. crossAxisAlignment: CrossAxisAlignment.center,
  241. children: [
  242. Padding(
  243. padding: EdgeInsets.only(left: 16.w, right: 16.w, top: 10.h),
  244. child: Row(
  245. mainAxisAlignment: MainAxisAlignment.start,
  246. children: [
  247. Text(
  248. title,
  249. style: TextStyle(
  250. color:
  251. isChosen ? Colors.white : const Color(0xFF202020),
  252. fontSize: 16.sp,
  253. fontWeight: FontWeight.w700,
  254. ),
  255. ),
  256. const Spacer(),
  257. isChosen ?Text(StringName.profileSelect,style: TextStyle(
  258. color: Colors.white,
  259. fontSize: 14.sp,
  260. fontWeight: FontWeight.w400,
  261. ),):SizedBox(),
  262. SizedBox(width: 4.w),
  263. isChosen?Assets.images.iconProfileKeyboardSelect.image(
  264. width: 17.w,
  265. height: 17.w,
  266. ):SizedBox(),
  267. ],
  268. ),
  269. ),
  270. SizedBox(height: 10.h),
  271. Padding(
  272. padding: EdgeInsets.symmetric(horizontal: 16.w),
  273. child: Divider(
  274. height: 1.h,
  275. color: isChosen ? Colors.transparent : Color(0xffF5F5F5),
  276. ),
  277. ),
  278. Expanded(
  279. child: Container(
  280. margin:
  281. isChosen
  282. ? EdgeInsets.symmetric(
  283. horizontal: 4.w,
  284. vertical: 4.w,
  285. )
  286. : EdgeInsets.zero,
  287. decoration: ShapeDecoration(
  288. color: Colors.white,
  289. shape: RoundedRectangleBorder(
  290. borderRadius: BorderRadius.circular(20.r),
  291. ),
  292. shadows: [
  293. BoxShadow(
  294. color: Color(0x1CD6C1FF),
  295. blurRadius: 4.r,
  296. offset: Offset(0, 4),
  297. spreadRadius: 0,
  298. ),
  299. ],
  300. ),
  301. child: Row(
  302. mainAxisAlignment: MainAxisAlignment.center,
  303. children: [
  304. _buildProfileAvatar(
  305. imageUrl: controller.userInfo?.imageUrl,
  306. gender: controller.userGender,
  307. onTap: () => controller.clickAvatar(isUser: true),
  308. genderIconAlignment: Alignment.topRight,
  309. ),
  310. SizedBox(width: 8.w),
  311. _buildLoveIndex(intimacy),
  312. SizedBox(width: 8.w),
  313. hasKeyboard
  314. ? _buildProfileAvatar(
  315. imageUrl: keyboardAvatar,
  316. gender: gender,
  317. onTap:
  318. () => controller.clickAvatar(
  319. isUser: false,
  320. keyboardInfo: keyboardInfo,
  321. ),
  322. genderIconAlignment: Alignment.topLeft,
  323. )
  324. : _buildKeyboardListEmptyAvatar(
  325. onTap: () => controller.clickAddButton(),
  326. ),
  327. ],
  328. ),
  329. ),
  330. ),
  331. ],
  332. ),
  333. ],
  334. ),
  335. ),
  336. );
  337. }
  338. // 头像
  339. Widget _buildProfileAvatar({
  340. required String? imageUrl,
  341. required int gender,
  342. required VoidCallback? onTap,
  343. Alignment genderIconAlignment = Alignment.topRight,
  344. }) {
  345. return GestureDetector(
  346. onTap: onTap,
  347. child: Stack(
  348. alignment: Alignment.bottomCenter,
  349. children: [
  350. Container(
  351. margin: EdgeInsets.only(bottom: 10.h),
  352. width: 78.w,
  353. height: 78.w,
  354. decoration: ShapeDecoration(
  355. color: gender == 1 ? const Color(0xFFB7B6FF) : null,
  356. gradient:
  357. gender == 1
  358. ? null
  359. : const LinearGradient(
  360. begin: Alignment(0.5, 0),
  361. end: Alignment(0.5, 1.0),
  362. colors: [Color(0xFFEBE6FF), Color(0xFFFFE6FE)],
  363. ),
  364. shape: RoundedRectangleBorder(
  365. side: BorderSide(width: 1.5.w, color: Colors.white),
  366. borderRadius: BorderRadius.circular(40.r),
  367. ),
  368. ),
  369. child: CircleAvatarWidget(
  370. image: Assets.images.iconKeyboardDefaultAvatar.provider(),
  371. imageUrl: imageUrl,
  372. size: 78.w,
  373. borderWidth: 0.r,
  374. borderColor: Colors.transparent,
  375. placeholder: (_, __) {
  376. return const CupertinoActivityIndicator();
  377. },
  378. ),
  379. ),
  380. Positioned(
  381. top: 0,
  382. left: genderIconAlignment == Alignment.topLeft ? 0 : null,
  383. right: genderIconAlignment == Alignment.topRight ? 0 : null,
  384. child:
  385. gender == 1
  386. ? Assets.images.iconProfileMale.image(
  387. width: 20.w,
  388. height: 20.w,
  389. )
  390. : Assets.images.iconProfileFemale.image(
  391. width: 20.w,
  392. height: 20.w,
  393. ),
  394. ),
  395. Positioned(
  396. child: Container(
  397. width: 58.w,
  398. height: 28.h,
  399. decoration: ShapeDecoration(
  400. color: Colors.white,
  401. shape: RoundedRectangleBorder(
  402. side: BorderSide(width: 1, color: const Color(0x6BE1E1E1)),
  403. borderRadius: BorderRadius.circular(50.r),
  404. ),
  405. shadows: [
  406. BoxShadow(
  407. color: Color(0x56E6D9FF),
  408. blurRadius: 4,
  409. offset: Offset(0, 3),
  410. spreadRadius: 0,
  411. ),
  412. ],
  413. ),
  414. child: Row(
  415. mainAxisAlignment: MainAxisAlignment.center,
  416. children: [
  417. Assets.images.iconProfileEdit.image(
  418. width: 12.w,
  419. height: 12.w,
  420. ),
  421. Text(
  422. StringName.profileEdit,
  423. style: Styles.getTextStyleBlack178W500(11.sp),
  424. ),
  425. ],
  426. ),
  427. ),
  428. ),
  429. ],
  430. ),
  431. );
  432. }
  433. // 没有Keyboard时
  434. _buildKeyboardListEmptyAvatar({required VoidCallback? onTap}) {
  435. return GestureDetector(
  436. onTap: onTap,
  437. child: Stack(
  438. alignment: Alignment.bottomCenter,
  439. children: [
  440. Container(
  441. margin: EdgeInsets.only(bottom: 10.h),
  442. width: 78.w,
  443. height: 78.w,
  444. child: DottedBorder(
  445. color: const Color(0xFFA595C8),
  446. strokeWidth: 1.0.w,
  447. borderType: BorderType.Circle,
  448. child: Container(
  449. width: 78.w,
  450. height: 78.w,
  451. margin: EdgeInsets.only(bottom: 10.h),
  452. alignment: Alignment.center,
  453. child: Column(
  454. crossAxisAlignment: CrossAxisAlignment.center,
  455. mainAxisAlignment: MainAxisAlignment.end,
  456. children: [
  457. Assets.images.iconProfilePlus.image(
  458. width: 22.5.w,
  459. height: 22.5.w,
  460. fit: BoxFit.cover,
  461. ),
  462. SizedBox(height: 2.h),
  463. Text(
  464. StringName.profileAdd,
  465. style: TextStyle(
  466. color: const Color(0xB2755BAB),
  467. fontSize: 12.sp,
  468. fontWeight: FontWeight.w400,
  469. ),
  470. ),
  471. ],
  472. ),
  473. ),
  474. ),
  475. ),
  476. ],
  477. ),
  478. );
  479. }
  480. }