profile_page.dart 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  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. child: CircleAvatarWidget(
  355. image: Assets.images.iconKeyboardDefaultAvatar.provider(),
  356. imageUrl: imageUrl,
  357. size: 78.w,
  358. borderWidth: 0.r,
  359. borderColor: Colors.transparent,
  360. placeholder: (_, __) {
  361. return const CupertinoActivityIndicator();
  362. },
  363. ),
  364. ),
  365. Positioned(
  366. top: 0,
  367. left: genderIconAlignment == Alignment.topLeft ? 0 : null,
  368. right: genderIconAlignment == Alignment.topRight ? 0 : null,
  369. child:
  370. gender == 1
  371. ? Assets.images.iconProfileMale.image(
  372. width: 20.w,
  373. height: 20.w,
  374. )
  375. : Assets.images.iconProfileFemale.image(
  376. width: 20.w,
  377. height: 20.w,
  378. ),
  379. ),
  380. Positioned(
  381. child: Container(
  382. width: 58.w,
  383. height: 28.h,
  384. decoration: ShapeDecoration(
  385. color: Colors.white,
  386. shape: RoundedRectangleBorder(
  387. side: BorderSide(width: 1, color: const Color(0x6BE1E1E1)),
  388. borderRadius: BorderRadius.circular(50.r),
  389. ),
  390. shadows: [
  391. BoxShadow(
  392. color: Color(0x56E6D9FF),
  393. blurRadius: 4,
  394. offset: Offset(0, 3),
  395. spreadRadius: 0,
  396. ),
  397. ],
  398. ),
  399. child: Row(
  400. mainAxisAlignment: MainAxisAlignment.center,
  401. children: [
  402. Assets.images.iconProfileEdit.image(
  403. width: 12.w,
  404. height: 12.w,
  405. ),
  406. Text(
  407. StringName.profileEdit,
  408. style: Styles.getTextStyleBlack178W500(11.sp),
  409. ),
  410. ],
  411. ),
  412. ),
  413. ),
  414. ],
  415. ),
  416. );
  417. }
  418. // 没有Keyboard时
  419. _buildKeyboardListEmptyAvatar({required VoidCallback? onTap}) {
  420. return GestureDetector(
  421. onTap: onTap,
  422. child: Stack(
  423. alignment: Alignment.bottomCenter,
  424. children: [
  425. Container(
  426. margin: EdgeInsets.only(bottom: 10.h),
  427. width: 78.w,
  428. height: 78.w,
  429. child: DottedBorder(
  430. color: const Color(0xFFA595C8),
  431. strokeWidth: 1.0.w,
  432. borderType: BorderType.Circle,
  433. child: Container(
  434. width: 78.w,
  435. height: 78.w,
  436. margin: EdgeInsets.only(bottom: 10.h),
  437. alignment: Alignment.center,
  438. child: Column(
  439. crossAxisAlignment: CrossAxisAlignment.center,
  440. mainAxisAlignment: MainAxisAlignment.end,
  441. children: [
  442. Assets.images.iconProfilePlus.image(
  443. width: 22.5.w,
  444. height: 22.5.w,
  445. fit: BoxFit.cover,
  446. ),
  447. SizedBox(height: 2.h),
  448. Text(
  449. StringName.profileAdd,
  450. style: TextStyle(
  451. color: const Color(0xB2755BAB),
  452. fontSize: 12.sp,
  453. fontWeight: FontWeight.w400,
  454. ),
  455. ),
  456. ],
  457. ),
  458. ),
  459. ),
  460. ),
  461. ],
  462. ),
  463. );
  464. }
  465. }