all_view.dart 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. import 'package:clean/base/base_page.dart';
  2. import 'package:clean/module/contact/all/all_controller.dart';
  3. import 'package:clean/module/contact/contact_state.dart';
  4. import 'package:clean/resource/assets.gen.dart';
  5. import 'package:clean/utils/expand.dart';
  6. import 'package:flutter/Material.dart';
  7. import 'package:flutter_contacts/flutter_contacts.dart';
  8. import 'package:flutter_screenutil/flutter_screenutil.dart';
  9. import 'package:get/get.dart';
  10. import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
  11. class AllPage extends BasePage<AllController> {
  12. const AllPage({super.key});
  13. @override
  14. bool immersive() {
  15. return true;
  16. }
  17. @override
  18. bool statusBarDarkFont() => false;
  19. @override
  20. Widget buildBody(BuildContext context) {
  21. return Stack(
  22. children: [
  23. buildMain(context),
  24. IgnorePointer(
  25. child: Assets.images.bgHome.image(
  26. width: 360.w,
  27. ),
  28. ),
  29. ],
  30. );
  31. }
  32. Widget buildMain(BuildContext context) {
  33. return SafeArea(
  34. child: Container(
  35. padding: EdgeInsets.only(left: 16.w, top: 14.h, right: 16.w),
  36. child: Obx(() {
  37. return Column(
  38. mainAxisAlignment: MainAxisAlignment.start,
  39. crossAxisAlignment: CrossAxisAlignment.start,
  40. children: [
  41. !controller.isEdit.value
  42. ? Row(
  43. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  44. children: [
  45. GestureDetector(
  46. onTap: () {
  47. Get.back();
  48. },
  49. child: Assets.images.iconCommonBack
  50. .image(width: 28.w, height: 28.w),
  51. ),
  52. GestureDetector(
  53. onTap: () {
  54. controller.isEdit.value = true;
  55. },
  56. child: Container(
  57. width: 71.w,
  58. height: 30.h,
  59. decoration: BoxDecoration(
  60. color: "#1F2D3F".color,
  61. borderRadius: BorderRadius.all(
  62. Radius.circular(15.h),
  63. ),
  64. ),
  65. child: Center(
  66. child: Text(
  67. "Select",
  68. style: TextStyle(
  69. color: Colors.white,
  70. fontSize: 14.sp,
  71. ),
  72. ),
  73. ),
  74. ),
  75. ),
  76. ],
  77. )
  78. : Row(
  79. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  80. children: [
  81. GestureDetector(
  82. onTap: () {
  83. controller.isEdit.value = false;
  84. },
  85. child: Container(
  86. width: 71.w,
  87. height: 30.h,
  88. decoration: BoxDecoration(
  89. color: "#1F2D3F".color,
  90. borderRadius: BorderRadius.all(
  91. Radius.circular(15.h),
  92. ),
  93. ),
  94. child: Center(
  95. child: Text(
  96. "Cancel",
  97. style: TextStyle(
  98. color: Colors.white,
  99. fontSize: 14.sp,
  100. ),
  101. ),
  102. ),
  103. ),
  104. ),
  105. GestureDetector(
  106. onTap: () {
  107. controller.toggleSelectAll();
  108. },
  109. child: Text(
  110. controller.isAllSelected.value
  111. ? "Deselect all"
  112. : "Select All",
  113. style: TextStyle(
  114. color: Colors.white.withOpacity(0.65),
  115. fontSize: 14.sp,
  116. ),
  117. ),
  118. ),
  119. ],
  120. ),
  121. SizedBox(
  122. height: 12.h,
  123. ),
  124. Row(
  125. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  126. children: [
  127. Text(
  128. "All Contacts",
  129. style: TextStyle(
  130. color: Colors.white,
  131. fontWeight: FontWeight.w700,
  132. fontSize: 24.sp,
  133. ),
  134. ),
  135. ],
  136. ),
  137. Expanded(
  138. child: Row(
  139. children: [
  140. Expanded(
  141. child: Obx(() {
  142. return ScrollablePositionedList.builder(
  143. itemCount: ContactState.initials.length,
  144. itemScrollController: controller.itemScrollController,
  145. itemPositionsListener:
  146. controller.itemPositionsListener,
  147. itemBuilder: (context, index) {
  148. String initial = ContactState.initials[index];
  149. return Column(
  150. crossAxisAlignment: CrossAxisAlignment.start,
  151. children: [
  152. SizedBox(
  153. height: 12.h,
  154. ),
  155. Padding(
  156. padding: EdgeInsets.symmetric(vertical: 8.h),
  157. child: Text(
  158. initial,
  159. style: TextStyle(
  160. color: Colors.white.withOpacity(0.7),
  161. fontSize: 14.sp,
  162. fontWeight: FontWeight.w500,
  163. ),
  164. ),
  165. ),
  166. ...ContactState.groupedContacts[initial]!
  167. .asMap()
  168. .entries
  169. .map((entry) {
  170. int index = entry.key; // 当前联系人的索引
  171. Contact contact = entry.value; // 当前联系人
  172. bool isFirst = index == 0; // 是否是第一个
  173. bool isLast = index ==
  174. (ContactState.groupedContacts[initial]
  175. ?.length ??
  176. 0) -
  177. 1; // 是否是最后一个
  178. return Container(
  179. padding: EdgeInsets.only(
  180. left: 10.w,
  181. top: 10.h,
  182. right: 10.w,
  183. ),
  184. width: double.infinity,
  185. // height: 62.h,
  186. decoration: BoxDecoration(
  187. borderRadius: BorderRadius.vertical(
  188. top: isFirst
  189. ? Radius.circular(12)
  190. : Radius.zero, // 第一个设置上圆角
  191. bottom: isLast
  192. ? Radius.circular(12)
  193. : Radius.zero, // 最后一个设置下圆角
  194. ),
  195. color: Colors.white.withOpacity(0.12),
  196. ),
  197. child: Column(
  198. children: [
  199. Row(
  200. mainAxisAlignment:
  201. MainAxisAlignment.spaceBetween,
  202. children: [
  203. Column(
  204. mainAxisAlignment:
  205. MainAxisAlignment.start,
  206. crossAxisAlignment:
  207. CrossAxisAlignment.start,
  208. children: [
  209. Text(
  210. contact.displayName.isEmpty
  211. ? 'No contact name'
  212. : contact.displayName,
  213. style: TextStyle(
  214. color: Colors.white,
  215. fontSize: 14.sp,
  216. fontWeight:
  217. FontWeight.w500,
  218. ),
  219. ),
  220. SizedBox(
  221. height: 5.h,
  222. ),
  223. Text(
  224. contact.phones.isEmpty
  225. ? 'No contact number'
  226. : contact.phones.first
  227. .number,
  228. style: TextStyle(
  229. color: Colors.white,
  230. fontSize: 14.sp,
  231. fontWeight:
  232. FontWeight.w500,
  233. ),
  234. ),
  235. ],
  236. ),
  237. // 删除按钮
  238. Visibility(
  239. visible:
  240. controller.isEdit.value,
  241. child: GestureDetector(
  242. onTap: () {
  243. controller
  244. .toggleSelectContact(
  245. contact);
  246. },
  247. child: Container(
  248. child: controller
  249. .selectedContacts
  250. .contains(
  251. contact.id)
  252. ? Center(
  253. child: Assets.images
  254. .iconSelected
  255. .image(
  256. width: 20.w,
  257. height: 20.h,
  258. ),
  259. )
  260. : Center(
  261. child: Assets.images
  262. .iconUnselected
  263. .image(
  264. width: 20.w,
  265. height: 20.h,
  266. ),
  267. ),
  268. ),
  269. ),
  270. ),
  271. ],
  272. ),
  273. SizedBox(
  274. height: 10.h,
  275. ),
  276. Visibility(
  277. visible: !isLast,
  278. child: Container(
  279. height: 1.h,
  280. color: "#3E3E47".color,
  281. )),
  282. ],
  283. ));
  284. }),
  285. SizedBox(
  286. height: 12.h,
  287. ),
  288. ],
  289. );
  290. },
  291. );
  292. }),
  293. ),
  294. Container(
  295. width: 30,
  296. child: ListView.builder(
  297. // physics: NeverScrollableScrollPhysics(),
  298. itemCount: ContactState.initials.length,
  299. itemBuilder: (context, index) {
  300. return GestureDetector(
  301. onTap: () => controller
  302. .scrollToInitial(ContactState.initials[index]),
  303. child: Padding(
  304. padding: EdgeInsets.symmetric(vertical: 2),
  305. child: Text(
  306. ContactState.initials[index],
  307. textAlign: TextAlign.center,
  308. style: TextStyle(
  309. fontSize: 14,
  310. color: "#0279FB".color,
  311. fontWeight: FontWeight.bold,
  312. ),
  313. ),
  314. ),
  315. );
  316. },
  317. ),
  318. ),
  319. ],
  320. ),
  321. ),
  322. Visibility(
  323. visible: controller.isEdit.value,
  324. child: GestureDetector(
  325. onTap: () {
  326. controller.deleteBtnClick();
  327. },
  328. child: Container(
  329. width: 328.w,
  330. height: 48.h,
  331. decoration: BoxDecoration(
  332. color: "#0279FB".color,
  333. borderRadius: BorderRadius.all(
  334. Radius.circular(10.r),
  335. ),
  336. ),
  337. child: Center(
  338. child: Row(
  339. mainAxisAlignment: MainAxisAlignment.center,
  340. children: [
  341. Text(
  342. "Delete",
  343. style: TextStyle(
  344. color: Colors.white,
  345. fontSize: 16.sp,
  346. fontWeight: FontWeight.w500,
  347. ),
  348. ),
  349. ],
  350. ),
  351. ),
  352. ),
  353. ),
  354. )
  355. ],
  356. );
  357. }),
  358. ),
  359. );
  360. }
  361. }