profile_page.dart 15 KB

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