view.dart 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. import 'package:flutter/material.dart';
  2. import 'package:get/get.dart';
  3. import '../../../../common/api/x_organization_assemble_control.dart';
  4. import '../../../../common/models/index.dart';
  5. import '../../../../common/routers/index.dart';
  6. import '../../../../common/style/index.dart';
  7. import '../../../../common/utils/o2_api_manager.dart';
  8. import 'index.dart';
  9. import 'widgets/widgets.dart';
  10. class ContactPickerPage extends GetView<ContactPickerController> {
  11. const ContactPickerPage({Key? key}) : super(key: key);
  12. static Future<dynamic> startPicker(List<ContactPickMode> modes,
  13. {List<String>? topUnitList,
  14. String? unitType,
  15. int? maxNumber = 0,
  16. bool? multiple = false,
  17. List<String>? dutyList,
  18. List<String>? initDeptList,
  19. List<String>? initIdList,
  20. List<String>? initGroupList,
  21. List<String>? initUserList}) async {
  22. final args = ContactPickerArguments(
  23. pickerModes: modes,
  24. topUnitList: topUnitList,
  25. unitType: unitType,
  26. maxNumber: maxNumber,
  27. multiple: multiple,
  28. dutyList: dutyList,
  29. initDeptList: initDeptList,
  30. initIdList: initIdList,
  31. initGroupList: initGroupList,
  32. initUserList: initUserList);
  33. return await Get.toNamed(O2OARoutes.homeContactPicker, arguments: args);
  34. }
  35. @override
  36. Widget build(BuildContext context) {
  37. return GetBuilder<ContactPickerController>(
  38. builder: (_) {
  39. return Obx(() {
  40. if (controller.state.tabs.isEmpty) {
  41. return const CircularProgressIndicator();
  42. } else {
  43. if (controller.state.tabs.length == 1) {
  44. return singlePicker(context);
  45. }
  46. return multiplePickers(context);
  47. }
  48. });
  49. },
  50. );
  51. }
  52. Widget pickerContentView(ContactPickMode m) {
  53. switch (m) {
  54. case ContactPickMode.departmentPicker:
  55. return OrgPickerPage(initData: controller.pickerArguments!);
  56. case ContactPickMode.identityPicker:
  57. return PersonOrIdentityPickerPage(
  58. mode: m, initData: controller.pickerArguments!);
  59. case ContactPickMode.groupPicker:
  60. return GroupPickerPage(initData: controller.pickerArguments!);
  61. case ContactPickMode.personPicker:
  62. return PersonOrIdentityPickerPage(
  63. mode: m, initData: controller.pickerArguments!);
  64. }
  65. }
  66. Widget singlePicker(BuildContext context) {
  67. return Obx(() {
  68. final num = controller.state.identityPickedList.length +
  69. controller.state.personPickedList.length +
  70. controller.state.unitPickedList.length +
  71. controller.state.groupPickedList.length;
  72. final chooseTitle = '${'contact_picker_btn_title_choose'.tr}($num)';
  73. return Scaffold(
  74. appBar: AppBar(
  75. title: Text(controller.tabTitle(controller.state.tabs[0]),
  76. style: AppTheme.whitePrimaryTextStyle),
  77. actions: [
  78. TextButton(
  79. onPressed: controller.choose,
  80. child: Text(chooseTitle, style: AppTheme.whitePrimaryTextStyle))
  81. ],
  82. ),
  83. backgroundColor: Theme.of(context).scaffoldBackgroundColor,
  84. body: SafeArea(
  85. child: Column(children: [
  86. Expanded(
  87. flex: 1,
  88. child: pickerContentView(controller.state.tabs[0]),
  89. ),
  90. _choosedBarView(context),
  91. ])),
  92. );
  93. });
  94. }
  95. Widget multiplePickers(BuildContext context) {
  96. return Obx(() {
  97. final num = controller.state.identityPickedList.length +
  98. controller.state.personPickedList.length +
  99. controller.state.unitPickedList.length +
  100. controller.state.groupPickedList.length;
  101. final chooseTitle = '${'contact_picker_btn_title_choose'.tr}($num)';
  102. return DefaultTabController(
  103. length: controller.state.tabs.length,
  104. child: Scaffold(
  105. appBar: AppBar(
  106. title: Text('contact_picker_title'.tr),
  107. actions: [
  108. TextButton(
  109. onPressed: controller.choose,
  110. child: Text(chooseTitle,
  111. style: AppTheme.whitePrimaryTextStyle))
  112. ],
  113. bottom: TabBar(
  114. //生成Tab菜单
  115. tabs: controller.state.tabs
  116. .map((e) => Tab(
  117. child: Text(controller.tabTitle(e),
  118. style: AppTheme.whitePrimaryTextStyle)))
  119. .toList()),
  120. ),
  121. backgroundColor: Theme.of(context).scaffoldBackgroundColor,
  122. body: SafeArea(
  123. child: Column(children: [
  124. Expanded(
  125. flex: 1,
  126. child: TabBarView(
  127. children: controller.state.tabs.map((m) {
  128. return pickerContentView(m);
  129. }).toList(),
  130. ),
  131. ),
  132. _choosedBarView(context),
  133. ])),
  134. ));
  135. });
  136. }
  137. String _choosedBarMessage(int num) {
  138. final buffer = StringBuffer('contact_picker_choosed'.tr);
  139. List<Map<String, dynamic>> listItems = [
  140. {
  141. 'list': controller.state.personPickedList,
  142. 'key': 'contact_picker_choosed_person_num'
  143. },
  144. {
  145. 'list': controller.state.unitPickedList,
  146. 'key': 'contact_picker_choosed_unit_num'
  147. },
  148. {
  149. 'list': controller.state.groupPickedList,
  150. 'key': 'contact_picker_choosed_group_num'
  151. },
  152. {
  153. 'list': controller.state.identityPickedList,
  154. 'key': 'contact_picker_choosed_identity_num'
  155. },
  156. ];
  157. for (final item in listItems) {
  158. if (item['list'].length > 0) {
  159. final num = '${item['list'].length}';
  160. buffer.write(' ${'${item['key']}'.trArgs([num])} ');
  161. }
  162. }
  163. return buffer.toString();
  164. }
  165. Widget _choosedBarView(BuildContext context) {
  166. return GestureDetector(
  167. child: Container(
  168. color: Theme.of(context).colorScheme.background,
  169. padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 0),
  170. child: Column(children: [
  171. const Divider(height: 1, color: AppColor.borderColor),
  172. const SizedBox(height: 16),
  173. Row(children: [
  174. Expanded(
  175. flex: 1,
  176. child: Obx(() {
  177. final num = controller.state.identityPickedList.length +
  178. controller.state.personPickedList.length +
  179. controller.state.unitPickedList.length +
  180. controller.state.groupPickedList.length;
  181. return Text(_choosedBarMessage(num),
  182. style: Theme.of(context).textTheme.bodySmall,
  183. maxLines: 1,
  184. overflow: TextOverflow.ellipsis);
  185. })),
  186. const SizedBox(width: 10),
  187. Icon(
  188. Icons.arrow_drop_up,
  189. color: Theme.of(context).colorScheme.primary,
  190. size: 28,
  191. ),
  192. const SizedBox(width: 5)
  193. ]),
  194. const SizedBox(height: 16),
  195. ]),
  196. ),
  197. onTap: () => openChoosedList(context));
  198. }
  199. /// 打开已选列表
  200. void openChoosedList(BuildContext context) {
  201. final num = controller.state.identityPickedList.length +
  202. controller.state.personPickedList.length +
  203. controller.state.unitPickedList.length +
  204. controller.state.groupPickedList.length;
  205. if (num == 0) {
  206. return;
  207. }
  208. showModalBottomSheet(
  209. context: context,
  210. builder: (context) => StatefulBuilder(builder: (context, setState) {
  211. return SafeArea(
  212. child: Column(
  213. children: [
  214. Expanded(
  215. flex: 1,
  216. child: ListView(
  217. children: [
  218. if (controller.state.unitPickedList.length > 0)
  219. ..._choosedUnitList(context, setState), const SizedBox(height: 10),
  220. if (controller.state.personPickedList.length > 0)
  221. ..._choosedPersonList(context, setState), const SizedBox(height: 10),
  222. if (controller.state.groupPickedList.length > 0)
  223. ..._choosedGroupList(context, setState), const SizedBox(height: 10),
  224. if (controller.state.identityPickedList.length > 0)
  225. ..._choosedIdentityList(context, setState)
  226. ],
  227. ),
  228. ),
  229. Container(
  230. color: Theme.of(context).colorScheme.background,
  231. height: 4,
  232. ),
  233. ListTile(
  234. onTap: () => Navigator.pop(context),
  235. title: Align(
  236. alignment: Alignment.center,
  237. child: Text('cancel'.tr,
  238. style: Theme.of(context).textTheme.bodyLarge),
  239. ),
  240. )
  241. ],
  242. ));
  243. }));
  244. }
  245. List<Widget> _choosedUnitList(BuildContext context, StateSetter setState) {
  246. return controller.state.unitPickedList.map((element) {
  247. var orgName = element.name ?? '';
  248. var oneName = orgName;
  249. if (orgName.length > 1) {
  250. oneName = oneName.substring(0, 1);
  251. }
  252. return ListTile(
  253. leading: SizedBox(
  254. width: 32,
  255. height: 32,
  256. child: CircleAvatar(
  257. radius: 32,
  258. backgroundColor: Theme.of(context).colorScheme.primary,
  259. child: Text(oneName, style: const TextStyle(color: Colors.white)),
  260. ),
  261. ),
  262. title: Text(orgName),
  263. trailing: TextButton(
  264. onPressed: (() {
  265. setState(() {
  266. controller.removeUnit(element);
  267. });
  268. }),
  269. child: Text('contact_picker_choosed_remove'.tr)),
  270. );
  271. }).toList();
  272. }
  273. List<Widget> _choosedPersonList(BuildContext context, StateSetter setState) {
  274. return controller.state.personPickedList.map((element) {
  275. String? personIcon =
  276. OrganizationControlService.to.iconUrl(element.person!);
  277. return ListTile(
  278. leading: SizedBox(
  279. width: 32,
  280. height: 32,
  281. child: CircleAvatar(
  282. radius: 32,
  283. backgroundColor: Colors.white,
  284. backgroundImage: NetworkImage(personIcon, headers: {
  285. O2ApiManager.instance.tokenName:
  286. O2ApiManager.instance.o2User?.token ?? ''
  287. }),
  288. ),
  289. ),
  290. title: Text(element.name ?? ''),
  291. trailing: TextButton(
  292. onPressed: (() {
  293. setState(() {
  294. controller.removePerson(element);
  295. });
  296. }),
  297. child: Text('contact_picker_choosed_remove'.tr)),
  298. );
  299. }).toList();
  300. }
  301. List<Widget> _choosedIdentityList(
  302. BuildContext context, StateSetter setState) {
  303. return controller.state.identityPickedList.map((element) {
  304. String? personIcon =
  305. OrganizationControlService.to.iconUrl(element.person!);
  306. return ListTile(
  307. leading: SizedBox(
  308. width: 32,
  309. height: 32,
  310. child: CircleAvatar(
  311. radius: 32,
  312. backgroundColor: Colors.white,
  313. backgroundImage: NetworkImage(personIcon, headers: {
  314. O2ApiManager.instance.tokenName:
  315. O2ApiManager.instance.o2User?.token ?? ''
  316. }),
  317. ),
  318. ),
  319. title: Text(element.name ?? ''),
  320. trailing: TextButton(
  321. onPressed: (() {
  322. setState(() {
  323. controller.removeIdentity(element);
  324. });
  325. }),
  326. child: Text('contact_picker_choosed_remove'.tr)),
  327. );
  328. }).toList();
  329. }
  330. List<Widget> _choosedGroupList(BuildContext context, StateSetter setState) {
  331. return controller.state.groupPickedList.map((element) {
  332. var orgName = element.name ?? '';
  333. var oneName = orgName;
  334. if (orgName.length > 1) {
  335. oneName = oneName.substring(0, 1);
  336. }
  337. return ListTile(
  338. leading: SizedBox(
  339. width: 32,
  340. height: 32,
  341. child: CircleAvatar(
  342. radius: 32,
  343. backgroundColor: Theme.of(context).colorScheme.primary,
  344. child: Text(oneName, style: const TextStyle(color: Colors.white)),
  345. ),
  346. ),
  347. title: Text(orgName),
  348. trailing: TextButton(
  349. onPressed: (() {
  350. setState(() {
  351. controller.removeGroup(element);
  352. });
  353. }),
  354. child: Text('contact_picker_choosed_remove'.tr)),
  355. );
  356. }).toList();
  357. }
  358. }