@pi-spi/app 1.6.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (233) hide show
  1. package/README.md +64 -30
  2. package/example/App.tsx +27 -24
  3. package/lib/module/core/api.js +14 -5
  4. package/lib/module/core/api.js.map +1 -1
  5. package/lib/module/core/assets.js +0 -7
  6. package/lib/module/core/assets.js.map +1 -1
  7. package/lib/module/core/di.js +17 -8
  8. package/lib/module/core/di.js.map +1 -1
  9. package/lib/module/core/pi_spi_custom_theme.js +22 -10
  10. package/lib/module/core/pi_spi_custom_theme.js.map +1 -1
  11. package/lib/module/core/pi_spi_sdk_config.js +22 -8
  12. package/lib/module/core/pi_spi_sdk_config.js.map +1 -1
  13. package/lib/module/core/theme.js +345 -225
  14. package/lib/module/core/theme.js.map +1 -1
  15. package/lib/module/index.js +1 -1
  16. package/lib/module/index.js.map +1 -1
  17. package/lib/module/l10n/app_localizations.js.map +1 -1
  18. package/lib/module/l10n/app_localizations_en.js +22 -0
  19. package/lib/module/l10n/app_localizations_en.js.map +1 -1
  20. package/lib/module/l10n/app_localizations_fr.js +22 -0
  21. package/lib/module/l10n/app_localizations_fr.js.map +1 -1
  22. package/lib/module/l10n/app_localizations_pt.js +22 -0
  23. package/lib/module/l10n/app_localizations_pt.js.map +1 -1
  24. package/lib/module/modules/categorie/presentation/pages/categorie_edit_icon_btn.js +25 -35
  25. package/lib/module/modules/categorie/presentation/pages/categorie_edit_icon_btn.js.map +1 -1
  26. package/lib/module/modules/config/domain/models/config_keys.js +3 -1
  27. package/lib/module/modules/config/domain/models/config_keys.js.map +1 -1
  28. package/lib/module/modules/config/domain/services/config_service.js +31 -2
  29. package/lib/module/modules/config/domain/services/config_service.js.map +1 -1
  30. package/lib/module/modules/home/presentation/pages/home_tab_compte.js +0 -1
  31. package/lib/module/modules/home/presentation/pages/home_tab_compte.js.map +1 -1
  32. package/lib/module/modules/home/presentation/pages/home_tab_compte_more_menu.js +38 -37
  33. package/lib/module/modules/home/presentation/pages/home_tab_compte_more_menu.js.map +1 -1
  34. package/lib/module/modules/profile/presentation/pages/parametre/profile_parametre_page.js +2 -2
  35. package/lib/module/modules/profile/presentation/pages/parametre/profile_parametre_page.js.map +1 -1
  36. package/lib/module/modules/profile/presentation/pages/parametre/profile_parametre_page_qrcode.js +2 -2
  37. package/lib/module/modules/profile/presentation/pages/parametre/profile_parametre_page_qrcode.js.map +1 -1
  38. package/lib/module/modules/profile/presentation/pages/parametre/profile_parametre_page_theme.js +135 -199
  39. package/lib/module/modules/profile/presentation/pages/parametre/profile_parametre_page_theme.js.map +1 -1
  40. package/lib/module/modules/profile/presentation/pages/profile_menu.js +4 -3
  41. package/lib/module/modules/profile/presentation/pages/profile_menu.js.map +1 -1
  42. package/lib/module/modules/profile/presentation/pages/profile_page_avatar.js +6 -28
  43. package/lib/module/modules/profile/presentation/pages/profile_page_avatar.js.map +1 -1
  44. package/lib/module/modules/profile/presentation/pages/profile_page_contacts.js +0 -1
  45. package/lib/module/modules/profile/presentation/pages/profile_page_contacts.js.map +1 -1
  46. package/lib/module/modules/profile/presentation/pages/profile_page_contacts_actions.js +122 -162
  47. package/lib/module/modules/profile/presentation/pages/profile_page_contacts_actions.js.map +1 -1
  48. package/lib/module/modules/qrcode/presentation/pages/qrcode_alias_page.js +0 -1
  49. package/lib/module/modules/qrcode/presentation/pages/qrcode_alias_page.js.map +1 -1
  50. package/lib/module/modules/qrcode/presentation/pages/qrcode_alias_page_share.js +26 -38
  51. package/lib/module/modules/qrcode/presentation/pages/qrcode_alias_page_share.js.map +1 -1
  52. package/lib/module/modules/subscription/presentation/pages/subscription_details/subscription_details_page.js +0 -1
  53. package/lib/module/modules/subscription/presentation/pages/subscription_details/subscription_details_page.js.map +1 -1
  54. package/lib/module/modules/subscription/presentation/pages/subscription_details/subscription_details_page_actions.js +0 -1
  55. package/lib/module/modules/subscription/presentation/pages/subscription_details/subscription_details_page_actions.js.map +1 -1
  56. package/lib/module/modules/subscription/presentation/pages/subscription_details/subscription_details_page_note_sheet.js +38 -93
  57. package/lib/module/modules/subscription/presentation/pages/subscription_details/subscription_details_page_note_sheet.js.map +1 -1
  58. package/lib/module/modules/subscription/presentation/pages/subscription_list/subscription_list_empty_widget.js +0 -1
  59. package/lib/module/modules/subscription/presentation/pages/subscription_list/subscription_list_empty_widget.js.map +1 -1
  60. package/lib/module/modules/subscription/presentation/pages/subscription_list/subscription_list_widget.js +0 -1
  61. package/lib/module/modules/subscription/presentation/pages/subscription_list/subscription_list_widget.js.map +1 -1
  62. package/lib/module/modules/subscription/presentation/pages/subscription_menu_widget.js +23 -42
  63. package/lib/module/modules/subscription/presentation/pages/subscription_menu_widget.js.map +1 -1
  64. package/lib/module/modules/transactions/infra/transaction_output_remote.js +2 -1
  65. package/lib/module/modules/transactions/infra/transaction_output_remote.js.map +1 -1
  66. package/lib/module/modules/transactions/presentation/pages/transaction_details/transaction_details_page_actions.js +0 -1
  67. package/lib/module/modules/transactions/presentation/pages/transaction_details/transaction_details_page_actions.js.map +1 -1
  68. package/lib/module/modules/transactions/presentation/pages/transaction_details/transaction_details_page_actions_cancel.js +34 -61
  69. package/lib/module/modules/transactions/presentation/pages/transaction_details/transaction_details_page_actions_cancel.js.map +1 -1
  70. package/lib/module/modules/transactions/presentation/pages/transaction_details/transaction_details_page_actions_return.js +49 -62
  71. package/lib/module/modules/transactions/presentation/pages/transaction_details/transaction_details_page_actions_return.js.map +1 -1
  72. package/lib/module/modules/transactions/presentation/pages/transaction_details/transaction_details_page_recu.js +3 -1
  73. package/lib/module/modules/transactions/presentation/pages/transaction_details/transaction_details_page_recu.js.map +1 -1
  74. package/lib/module/modules/transactions/presentation/pages/transaction_details/transaction_details_page_ticket.js +68 -88
  75. package/lib/module/modules/transactions/presentation/pages/transaction_details/transaction_details_page_ticket.js.map +1 -1
  76. package/lib/module/modules/transactions/presentation/pages/transaction_form/transaction_form_input_pays.js +77 -0
  77. package/lib/module/modules/transactions/presentation/pages/transaction_form/transaction_form_input_pays.js.map +1 -0
  78. package/lib/module/modules/transactions/presentation/pages/transaction_form/transaction_form_input_psp.js +49 -155
  79. package/lib/module/modules/transactions/presentation/pages/transaction_form/transaction_form_input_psp.js.map +1 -1
  80. package/lib/module/modules/transactions/presentation/pages/transaction_form/transaction_form_page_othr.js +8 -28
  81. package/lib/module/modules/transactions/presentation/pages/transaction_form/transaction_form_page_othr.js.map +1 -1
  82. package/lib/module/modules/transactions/presentation/pages/transaction_form/transaction_form_page_verification.js +0 -1
  83. package/lib/module/modules/transactions/presentation/pages/transaction_form/transaction_form_page_verification.js.map +1 -1
  84. package/lib/module/modules/transactions/presentation/pages/transaction_recents/transaction_recents_nombre_widget.js +50 -42
  85. package/lib/module/modules/transactions/presentation/pages/transaction_recents/transaction_recents_nombre_widget.js.map +1 -1
  86. package/lib/module/modules/transactions/presentation/pages/transaction_recents/transaction_recents_widget.js +0 -1
  87. package/lib/module/modules/transactions/presentation/pages/transaction_recents/transaction_recents_widget.js.map +1 -1
  88. package/lib/module/modules/transactions/presentation/pages/transaction_rtp/transaction_rtp_page_actions.js +0 -1
  89. package/lib/module/modules/transactions/presentation/pages/transaction_rtp/transaction_rtp_page_actions.js.map +1 -1
  90. package/lib/module/modules/transactions/presentation/pages/transaction_rtp/transaction_rtp_page_actions_reject.js +37 -67
  91. package/lib/module/modules/transactions/presentation/pages/transaction_rtp/transaction_rtp_page_actions_reject.js.map +1 -1
  92. package/lib/module/modules/transactions/presentation/pages/transaction_search/transaction_search_page_filters.js +5 -4
  93. package/lib/module/modules/transactions/presentation/pages/transaction_search/transaction_search_page_filters.js.map +1 -1
  94. package/lib/module/modules/transactions/presentation/pages/transaction_split/transaction_split_page_repartition.js +2 -2
  95. package/lib/module/modules/transactions/presentation/pages/transaction_split/transaction_split_page_repartition.js.map +1 -1
  96. package/lib/module/pi_spi_sdk_entry.js +7 -2
  97. package/lib/module/pi_spi_sdk_entry.js.map +1 -1
  98. package/lib/module/shared/widgets/confirm_action_sheet_widget.js +34 -67
  99. package/lib/module/shared/widgets/confirm_action_sheet_widget.js.map +1 -1
  100. package/lib/module/shared/widgets/custom_progressbar.js +3 -2
  101. package/lib/module/shared/widgets/custom_progressbar.js.map +1 -1
  102. package/lib/module/shared/widgets/image_select_widget.js +43 -107
  103. package/lib/module/shared/widgets/image_select_widget.js.map +1 -1
  104. package/lib/module/shared/widgets/notification_dialog.js +25 -35
  105. package/lib/module/shared/widgets/notification_dialog.js.map +1 -1
  106. package/lib/module/shared/widgets/selection.js +382 -6
  107. package/lib/module/shared/widgets/selection.js.map +1 -1
  108. package/lib/typescript/src/core/api.d.ts +6 -0
  109. package/lib/typescript/src/core/api.d.ts.map +1 -1
  110. package/lib/typescript/src/core/assets.d.ts +0 -7
  111. package/lib/typescript/src/core/assets.d.ts.map +1 -1
  112. package/lib/typescript/src/core/di.d.ts.map +1 -1
  113. package/lib/typescript/src/core/pi_spi_custom_theme.d.ts +17 -8
  114. package/lib/typescript/src/core/pi_spi_custom_theme.d.ts.map +1 -1
  115. package/lib/typescript/src/core/pi_spi_sdk_config.d.ts +22 -8
  116. package/lib/typescript/src/core/pi_spi_sdk_config.d.ts.map +1 -1
  117. package/lib/typescript/src/core/theme.d.ts +123 -53
  118. package/lib/typescript/src/core/theme.d.ts.map +1 -1
  119. package/lib/typescript/src/index.d.ts +1 -1
  120. package/lib/typescript/src/index.d.ts.map +1 -1
  121. package/lib/typescript/src/l10n/app_localizations.d.ts +44 -0
  122. package/lib/typescript/src/l10n/app_localizations.d.ts.map +1 -1
  123. package/lib/typescript/src/l10n/app_localizations_en.d.ts.map +1 -1
  124. package/lib/typescript/src/l10n/app_localizations_fr.d.ts.map +1 -1
  125. package/lib/typescript/src/l10n/app_localizations_pt.d.ts.map +1 -1
  126. package/lib/typescript/src/modules/categorie/presentation/pages/categorie_edit_icon_btn.d.ts.map +1 -1
  127. package/lib/typescript/src/modules/config/domain/models/config_keys.d.ts +3 -1
  128. package/lib/typescript/src/modules/config/domain/models/config_keys.d.ts.map +1 -1
  129. package/lib/typescript/src/modules/config/domain/services/config_service.d.ts +7 -0
  130. package/lib/typescript/src/modules/config/domain/services/config_service.d.ts.map +1 -1
  131. package/lib/typescript/src/modules/home/presentation/pages/home_tab_compte_more_menu.d.ts +2 -0
  132. package/lib/typescript/src/modules/home/presentation/pages/home_tab_compte_more_menu.d.ts.map +1 -1
  133. package/lib/typescript/src/modules/profile/presentation/pages/parametre/profile_parametre_page.d.ts.map +1 -1
  134. package/lib/typescript/src/modules/profile/presentation/pages/parametre/profile_parametre_page_theme.d.ts +1 -1
  135. package/lib/typescript/src/modules/profile/presentation/pages/parametre/profile_parametre_page_theme.d.ts.map +1 -1
  136. package/lib/typescript/src/modules/profile/presentation/pages/profile_page_avatar.d.ts.map +1 -1
  137. package/lib/typescript/src/modules/profile/presentation/pages/profile_page_contacts.d.ts.map +1 -1
  138. package/lib/typescript/src/modules/profile/presentation/pages/profile_page_contacts_actions.d.ts.map +1 -1
  139. package/lib/typescript/src/modules/qrcode/presentation/pages/qrcode_alias_page.d.ts.map +1 -1
  140. package/lib/typescript/src/modules/qrcode/presentation/pages/qrcode_alias_page_share.d.ts.map +1 -1
  141. package/lib/typescript/src/modules/subscription/presentation/pages/subscription_details/subscription_details_page.d.ts.map +1 -1
  142. package/lib/typescript/src/modules/subscription/presentation/pages/subscription_details/subscription_details_page_actions.d.ts.map +1 -1
  143. package/lib/typescript/src/modules/subscription/presentation/pages/subscription_details/subscription_details_page_note_sheet.d.ts +2 -2
  144. package/lib/typescript/src/modules/subscription/presentation/pages/subscription_details/subscription_details_page_note_sheet.d.ts.map +1 -1
  145. package/lib/typescript/src/modules/subscription/presentation/pages/subscription_menu_widget.d.ts.map +1 -1
  146. package/lib/typescript/src/modules/transactions/infra/transaction_output_remote.d.ts.map +1 -1
  147. package/lib/typescript/src/modules/transactions/presentation/pages/transaction_details/transaction_details_page_actions.d.ts.map +1 -1
  148. package/lib/typescript/src/modules/transactions/presentation/pages/transaction_details/transaction_details_page_actions_cancel.d.ts.map +1 -1
  149. package/lib/typescript/src/modules/transactions/presentation/pages/transaction_details/transaction_details_page_actions_return.d.ts.map +1 -1
  150. package/lib/typescript/src/modules/transactions/presentation/pages/transaction_form/transaction_form_input_pays.d.ts +17 -0
  151. package/lib/typescript/src/modules/transactions/presentation/pages/transaction_form/transaction_form_input_pays.d.ts.map +1 -0
  152. package/lib/typescript/src/modules/transactions/presentation/pages/transaction_form/transaction_form_input_psp.d.ts +6 -2
  153. package/lib/typescript/src/modules/transactions/presentation/pages/transaction_form/transaction_form_input_psp.d.ts.map +1 -1
  154. package/lib/typescript/src/modules/transactions/presentation/pages/transaction_form/transaction_form_page_othr.d.ts.map +1 -1
  155. package/lib/typescript/src/modules/transactions/presentation/pages/transaction_form/transaction_form_page_verification.d.ts.map +1 -1
  156. package/lib/typescript/src/modules/transactions/presentation/pages/transaction_recents/transaction_recents_nombre_widget.d.ts.map +1 -1
  157. package/lib/typescript/src/modules/transactions/presentation/pages/transaction_rtp/transaction_rtp_page_actions.d.ts.map +1 -1
  158. package/lib/typescript/src/modules/transactions/presentation/pages/transaction_rtp/transaction_rtp_page_actions_reject.d.ts.map +1 -1
  159. package/lib/typescript/src/shared/widgets/confirm_action_sheet_widget.d.ts +4 -1
  160. package/lib/typescript/src/shared/widgets/confirm_action_sheet_widget.d.ts.map +1 -1
  161. package/lib/typescript/src/shared/widgets/custom_progressbar.d.ts.map +1 -1
  162. package/lib/typescript/src/shared/widgets/image_select_widget.d.ts +6 -4
  163. package/lib/typescript/src/shared/widgets/image_select_widget.d.ts.map +1 -1
  164. package/lib/typescript/src/shared/widgets/notification_dialog.d.ts +2 -2
  165. package/lib/typescript/src/shared/widgets/notification_dialog.d.ts.map +1 -1
  166. package/lib/typescript/src/shared/widgets/selection.d.ts +69 -2
  167. package/lib/typescript/src/shared/widgets/selection.d.ts.map +1 -1
  168. package/package.json +1 -1
  169. package/src/core/api.ts +11 -2
  170. package/src/core/assets.ts +0 -7
  171. package/src/core/di.ts +13 -8
  172. package/src/core/pi_spi_custom_theme.ts +22 -15
  173. package/src/core/pi_spi_sdk_config.ts +27 -9
  174. package/src/core/theme.ts +381 -269
  175. package/src/index.ts +1 -1
  176. package/src/l10n/app_localizations.ts +44 -0
  177. package/src/l10n/app_localizations_en.ts +22 -0
  178. package/src/l10n/app_localizations_fr.ts +22 -0
  179. package/src/l10n/app_localizations_pt.ts +22 -0
  180. package/src/modules/categorie/presentation/pages/categorie_edit_icon_btn.tsx +25 -27
  181. package/src/modules/config/domain/models/config_keys.ts +3 -1
  182. package/src/modules/config/domain/services/config_service.ts +31 -2
  183. package/src/modules/home/presentation/pages/home_tab_compte.tsx +1 -1
  184. package/src/modules/home/presentation/pages/home_tab_compte_more_menu.tsx +34 -42
  185. package/src/modules/profile/presentation/pages/parametre/profile_parametre_page.tsx +2 -5
  186. package/src/modules/profile/presentation/pages/parametre/profile_parametre_page_qrcode.tsx +2 -2
  187. package/src/modules/profile/presentation/pages/parametre/profile_parametre_page_theme.tsx +105 -148
  188. package/src/modules/profile/presentation/pages/profile_menu.tsx +2 -2
  189. package/src/modules/profile/presentation/pages/profile_page_avatar.tsx +6 -12
  190. package/src/modules/profile/presentation/pages/profile_page_contacts.tsx +0 -1
  191. package/src/modules/profile/presentation/pages/profile_page_contacts_actions.tsx +111 -117
  192. package/src/modules/qrcode/presentation/pages/qrcode_alias_page.tsx +0 -1
  193. package/src/modules/qrcode/presentation/pages/qrcode_alias_page_share.tsx +32 -40
  194. package/src/modules/subscription/presentation/pages/subscription_details/subscription_details_page.tsx +0 -1
  195. package/src/modules/subscription/presentation/pages/subscription_details/subscription_details_page_actions.tsx +0 -1
  196. package/src/modules/subscription/presentation/pages/subscription_details/subscription_details_page_note_sheet.tsx +20 -59
  197. package/src/modules/subscription/presentation/pages/subscription_list/subscription_list_empty_widget.tsx +1 -1
  198. package/src/modules/subscription/presentation/pages/subscription_list/subscription_list_widget.tsx +1 -1
  199. package/src/modules/subscription/presentation/pages/subscription_menu_widget.tsx +25 -39
  200. package/src/modules/transactions/infra/transaction_output_remote.ts +6 -1
  201. package/src/modules/transactions/presentation/pages/transaction_details/transaction_details_page_actions.tsx +0 -1
  202. package/src/modules/transactions/presentation/pages/transaction_details/transaction_details_page_actions_cancel.tsx +39 -41
  203. package/src/modules/transactions/presentation/pages/transaction_details/transaction_details_page_actions_return.tsx +41 -46
  204. package/src/modules/transactions/presentation/pages/transaction_details/transaction_details_page_recu.tsx +3 -1
  205. package/src/modules/transactions/presentation/pages/transaction_details/transaction_details_page_ticket.tsx +46 -40
  206. package/src/modules/transactions/presentation/pages/transaction_form/transaction_form_input_pays.tsx +92 -0
  207. package/src/modules/transactions/presentation/pages/transaction_form/transaction_form_input_psp.tsx +48 -94
  208. package/src/modules/transactions/presentation/pages/transaction_form/transaction_form_page_othr.tsx +4 -17
  209. package/src/modules/transactions/presentation/pages/transaction_form/transaction_form_page_verification.tsx +0 -1
  210. package/src/modules/transactions/presentation/pages/transaction_recents/transaction_recents_nombre_widget.tsx +49 -42
  211. package/src/modules/transactions/presentation/pages/transaction_recents/transaction_recents_widget.tsx +1 -1
  212. package/src/modules/transactions/presentation/pages/transaction_rtp/transaction_rtp_page_actions.tsx +0 -1
  213. package/src/modules/transactions/presentation/pages/transaction_rtp/transaction_rtp_page_actions_reject.tsx +47 -48
  214. package/src/modules/transactions/presentation/pages/transaction_search/transaction_search_page_filters.tsx +4 -4
  215. package/src/modules/transactions/presentation/pages/transaction_split/transaction_split_page_repartition.tsx +2 -2
  216. package/src/pi_spi_sdk_entry.tsx +9 -2
  217. package/src/shared/widgets/confirm_action_sheet_widget.tsx +30 -34
  218. package/src/shared/widgets/custom_progressbar.tsx +3 -2
  219. package/src/shared/widgets/image_select_widget.tsx +46 -61
  220. package/src/shared/widgets/notification_dialog.tsx +66 -70
  221. package/src/shared/widgets/selection.tsx +293 -5
  222. package/assets/images/theme_light_blue.jpeg +0 -0
  223. package/assets/images/theme_light_green.jpeg +0 -0
  224. package/assets/images/theme_light_orange.jpeg +0 -0
  225. package/assets/images/theme_light_pink.jpeg +0 -0
  226. package/assets/images/theme_light_purple.jpeg +0 -0
  227. package/assets/images/theme_light_red.jpeg +0 -0
  228. package/assets/images/theme_light_yellow.jpeg +0 -0
  229. package/lib/module/modules/transactions/presentation/pages/transaction_details/sheet_box.js +0 -47
  230. package/lib/module/modules/transactions/presentation/pages/transaction_details/sheet_box.js.map +0 -1
  231. package/lib/typescript/src/modules/transactions/presentation/pages/transaction_details/sheet_box.d.ts +0 -10
  232. package/lib/typescript/src/modules/transactions/presentation/pages/transaction_details/sheet_box.d.ts.map +0 -1
  233. package/src/modules/transactions/presentation/pages/transaction_details/sheet_box.tsx +0 -30
@@ -1,11 +1,11 @@
1
1
  import { MaterialIcons } from '@expo/vector-icons';
2
2
  import { Image } from 'expo-image';
3
- import { useState, type ReactNode } from 'react';
3
+ import { useState } from 'react';
4
4
  import { Pressable, ScrollView, StyleSheet, Text, View } from 'react-native';
5
5
 
6
6
  import { Images } from '../../../../../core/assets';
7
7
  import { useBloc, useBlocBuilder } from '../../../../../core/bloc_react';
8
- import { Themer, Themes, useTheme, type ThemeData } from '../../../../../core/theme';
8
+ import { Accents, Themer, Themes, useTheme } from '../../../../../core/theme';
9
9
  import type { AppLocalizations } from '../../../../../l10n/app_localizations';
10
10
  import { useAppLocalizations } from '../../../../../l10n/localizations';
11
11
  import { Card } from '../../../../../shared/material/card';
@@ -24,20 +24,6 @@ function themeIcon(theme: Themes): number {
24
24
  return Images.imageThemeLight;
25
25
  case Themes.dark:
26
26
  return Images.imageThemeDark;
27
- case Themes.yellow:
28
- return Images.imageThemeLightYellow;
29
- case Themes.green:
30
- return Images.imageThemeLightGreen;
31
- case Themes.blue:
32
- return Images.imageThemeLightBlue;
33
- case Themes.red:
34
- return Images.imageThemeLightRed;
35
- case Themes.orange:
36
- return Images.imageThemeLightOrange;
37
- case Themes.purple:
38
- return Images.imageThemeLightPurple;
39
- case Themes.pink:
40
- return Images.imageThemeLightPink;
41
27
  default:
42
28
  return Images.imageThemeSystem;
43
29
  }
@@ -47,53 +33,119 @@ function themeTitle(traductions: AppLocalizations, theme: Themes): string {
47
33
  return theme === Themes.system ? traductions.appSettingPageMenuThemeDefault : Themes.label(theme, traductions);
48
34
  }
49
35
 
50
- /** Choix du thème de l'application (route `profileParametreTheme`). */
36
+ /** Choix du thème (système, clair, sombre) et de la couleur d'accentuation (route `profileParametreTheme`). */
51
37
  export function ProfileParametrePageTheme() {
52
38
  const traductions = useAppLocalizations();
39
+ const theme = useTheme();
53
40
  const configBloc = useBloc(ConfigBloc);
54
41
  const state = useBlocBuilder(
55
42
  configBloc,
56
- (_p, current) => current instanceof ConfigLoadedState && current.updatedKey === ConfigKey.preferedTheme,
43
+ (_p, current) =>
44
+ current instanceof ConfigLoadedState &&
45
+ (current.updatedKey === ConfigKey.preferedTheme || current.updatedKey === ConfigKey.preferedAccent),
57
46
  );
58
- const currentTheme = state.configParams.params[ConfigKey.preferedTheme];
59
-
47
+ const currentTheme = Themes.fromCode(state.configParams.params[ConfigKey.preferedTheme]);
48
+ const currentAccent = state.configParams.params[ConfigKey.preferedAccent] ?? Accents.parDefaut;
49
+ const sombre = theme.brightness === 'dark';
60
50
  const [largeurGrille, setLargeurGrille] = useState(0);
51
+
61
52
  // Trois aperçus par ligne
53
+ const espace = 12;
62
54
  // Arrondi vers le bas : sinon la troisième colonne peut passer à la ligne
63
- const largeur = Math.floor((largeurGrille - 2 * ESPACE) / 3);
55
+ const largeur = Math.floor((largeurGrille - 2 * espace) / 3);
64
56
 
65
57
  return (
66
58
  <Scaffold appBar={<ProfileAppBar titre={traductions.appSettingPageMenuThemePageTitle} />}>
67
59
  <MyPageContainer>
68
60
  <ScrollView contentContainerStyle={styles.contenu}>
69
- {/* Thème */}
70
- <ProfileSectionTitre titre={traductions.appSettingPageMenuThemeTitle} />
61
+ {/* Thème : système, clair ou sombre */}
62
+ <ProfileSectionTitre titre={traductions.appSettingPageThemeSection} />
71
63
  <Card style={styles.card}>
72
64
  <View style={styles.grille} onLayout={(e) => setLargeurGrille(e.nativeEvent.layout.width - 2 * 14)}>
73
- {largeurGrille > 0 && (
74
- <>
75
- {/* Thème personnalisé de l'hôte, en tête */}
76
- {Themer.customTheme != null && (
77
- <ThemeOption
78
- largeur={largeur}
79
- title={traductions.appSettingPageMenuThemeCustom}
80
- selected={currentTheme === Themer.customThemeCode}
81
- onSelect={() => configBloc.add(new ConfigChangeEvent(ConfigKey.preferedTheme, Themer.customThemeCode))}
82
- preview={<CustomThemePreview theme={Themer.customTheme} />}
83
- />
84
- )}
85
- {Themes.list().map((item) => (
86
- <ThemeOption
65
+ {largeurGrille > 0 &&
66
+ Themes.list().map((item) => {
67
+ const choisi = currentTheme === item;
68
+ return (
69
+ <Pressable
87
70
  key={item}
88
- largeur={largeur}
89
- title={themeTitle(traductions, item)}
90
- selected={currentTheme === item}
91
- onSelect={() => configBloc.add(new ConfigChangeEvent(ConfigKey.preferedTheme, item))}
92
- preview={<Image source={themeIcon(item)} style={styles.flex} contentFit="cover" />}
93
- />
94
- ))}
95
- </>
96
- )}
71
+ accessibilityRole="button"
72
+ accessibilityState={{ selected: choisi }}
73
+ disabled={choisi}
74
+ onPress={() => configBloc.add(new ConfigChangeEvent(ConfigKey.preferedTheme, item))}
75
+ style={[styles.item, { width: largeur }]}
76
+ >
77
+ {/* Aperçu, entouré quand il est choisi */}
78
+ <View style={[styles.cadre, { borderColor: choisi ? theme.colorScheme.primary : 'transparent' }]}>
79
+ <Image
80
+ source={themeIcon(item)}
81
+ style={[styles.apercu, { backgroundColor: theme.colorScheme.surface }]}
82
+ contentFit="cover"
83
+ />
84
+ </View>
85
+ {choisi && (
86
+ <View style={[styles.coche, { backgroundColor: theme.colorScheme.primary, borderColor: theme.colorScheme.surface }]}>
87
+ <MaterialIcons name="check" size={14} color={theme.colorScheme.onPrimary} />
88
+ </View>
89
+ )}
90
+ <Text
91
+ style={[
92
+ theme.textTheme.displayMedium,
93
+ styles.libelle,
94
+ { fontWeight: choisi ? '700' : '500' },
95
+ choisi ? null : { color: Themer.neural03Color },
96
+ ]}
97
+ >
98
+ {themeTitle(traductions, item)}
99
+ </Text>
100
+ </Pressable>
101
+ );
102
+ })}
103
+ </View>
104
+ </Card>
105
+
106
+ {/* Couleur d'accentuation */}
107
+ <View style={styles.espace} />
108
+ <ProfileSectionTitre titre={traductions.appSettingPageAccentSection} />
109
+ <Card style={styles.card}>
110
+ <View style={styles.pastilles}>
111
+ {[
112
+ // Couleur du thème personnalisé de l'hôte, en tête
113
+ ...(Themer.hasCustomTheme ? [Themer.customAccentCode] : []),
114
+ ...Accents.list(),
115
+ ].map((accent) => {
116
+ const apercu = Themer.get(sombre ? Themes.dark : Themes.light, accent).colorScheme;
117
+ const teintes = { accent: apercu.primary, surAccent: apercu.onPrimary };
118
+ const choisi = currentAccent === accent;
119
+ return (
120
+ <Pressable
121
+ key={accent}
122
+ accessibilityRole="button"
123
+ accessibilityLabel={Themer.accentLabel(traductions, accent)}
124
+ accessibilityState={{ selected: choisi }}
125
+ disabled={choisi}
126
+ onPress={() => configBloc.add(new ConfigChangeEvent(ConfigKey.preferedAccent, accent))}
127
+ style={styles.accent}
128
+ >
129
+ {/* Pastille, cochée quand elle est choisie */}
130
+ <View style={[styles.anneau, { borderColor: choisi ? theme.colorScheme.onSurface : 'transparent' }]}>
131
+ <View style={[styles.pastille, { backgroundColor: teintes.accent }]}>
132
+ {choisi && <MaterialIcons name="check" size={22} color={teintes.surAccent} />}
133
+ </View>
134
+ </View>
135
+ <Text
136
+ numberOfLines={1}
137
+ style={[
138
+ theme.textTheme.displaySmall,
139
+ styles.libelle,
140
+ { fontWeight: choisi ? '700' : '400' },
141
+ { color: choisi ? theme.colorScheme.onSurface : Themer.neural03Color },
142
+ ]}
143
+ >
144
+ {Themer.accentLabel(traductions, accent)}
145
+ </Text>
146
+ </Pressable>
147
+ );
148
+ })}
97
149
  </View>
98
150
  </Card>
99
151
  </ScrollView>
@@ -102,113 +154,18 @@ export function ProfileParametrePageTheme() {
102
154
  );
103
155
  }
104
156
 
105
- /** Une option de thème : aperçu, entouré et coché quand il est choisi, puis son nom */
106
- function ThemeOption({
107
- largeur,
108
- title,
109
- selected,
110
- onSelect,
111
- preview,
112
- }: {
113
- largeur: number;
114
- title: string;
115
- selected: boolean;
116
- onSelect: () => void;
117
- preview: ReactNode;
118
- }) {
119
- const theme = useTheme();
120
- return (
121
- <Pressable
122
- accessibilityRole="button"
123
- accessibilityState={{ selected }}
124
- disabled={selected}
125
- onPress={onSelect}
126
- style={[styles.item, { width: largeur }]}
127
- >
128
- {/* Aperçu, entouré quand il est choisi */}
129
- <View style={[styles.cadre, { borderColor: selected ? theme.colorScheme.primary : 'transparent' }]}>
130
- <View style={[styles.apercu, { backgroundColor: theme.colorScheme.surface }]}>{preview}</View>
131
- </View>
132
- {selected && (
133
- <View style={[styles.coche, { backgroundColor: theme.colorScheme.primary, borderColor: theme.colorScheme.surface }]}>
134
- <MaterialIcons name="check" size={14} color={theme.colorScheme.onPrimary} />
135
- </View>
136
- )}
137
- <Text
138
- style={[
139
- theme.textTheme.displayMedium,
140
- styles.libelle,
141
- { fontWeight: selected ? '700' : '500' },
142
- selected ? null : { color: Themer.neural03Color },
143
- ]}
144
- >
145
- {title}
146
- </Text>
147
- </Pressable>
148
- );
149
- }
150
-
151
- /**
152
- * Aperçu du thème personnalisé de l'hôte (pas d'image comme pour les
153
- * thèmes du SDK) : une miniature d'accueil dessinée avec ses couleurs.
154
- */
155
- function CustomThemePreview({ theme }: { theme: ThemeData }) {
156
- const primary = theme.colorScheme.primary;
157
- const secondary = theme.colorScheme.secondary;
158
- const bar = (width: number, color: string) => <View style={[styles.bar, { width, backgroundColor: color }]} />;
159
- return (
160
- <View style={[styles.flex, styles.mock, { backgroundColor: theme.scaffoldBackgroundColor }]}>
161
- {/* Avatar et titre */}
162
- <View style={styles.mockRow}>
163
- <View style={[styles.dot16, { backgroundColor: secondary }]} />
164
- {bar(40, Themer.neural02Color)}
165
- </View>
166
- <View style={styles.gap12} />
167
- {/* Carte du compte */}
168
- <View style={[styles.mockCard, { backgroundColor: theme.cardColor }]}>
169
- {bar(50, Themer.neural02Color)}
170
- {bar(30, primary)}
171
- </View>
172
- <View style={styles.gap12} />
173
- {/* Boutons d'action */}
174
- <View style={styles.mockActions}>
175
- {[0, 1, 2].map((i) => (
176
- <View key={i} style={[styles.mockButton, { backgroundColor: primary }]} />
177
- ))}
178
- </View>
179
- <View style={styles.gap14} />
180
- {/* Liste */}
181
- {[0, 1, 2].map((i) => (
182
- <View key={i} style={[styles.mockRow, styles.mockListRow]}>
183
- <View style={[styles.dot14, { backgroundColor: secondary }]} />
184
- {bar(46, Themer.neural02Color)}
185
- </View>
186
- ))}
187
- </View>
188
- );
189
- }
190
-
191
- const ESPACE = 12;
192
-
193
157
  const styles = StyleSheet.create({
194
- flex: { flex: 1 },
195
- mock: { padding: 10 },
196
- mockRow: { flexDirection: 'row', alignItems: 'center', gap: 6 },
197
- mockListRow: { marginBottom: 8 },
198
- mockCard: { height: 54, padding: 8, borderRadius: 8, justifyContent: 'space-between' },
199
- mockActions: { flexDirection: 'row', justifyContent: 'space-between' },
200
- mockButton: { width: 26, height: 26, borderRadius: 8 },
201
- bar: { height: 6, borderRadius: 3 },
202
- dot16: { width: 16, height: 16, borderRadius: 8 },
203
- dot14: { width: 14, height: 14, borderRadius: 7 },
204
- gap12: { height: 12 },
205
- gap14: { height: 14 },
206
158
  contenu: { paddingTop: 8, paddingBottom: 16 },
207
159
  card: { margin: 0 },
208
- grille: { padding: 14, flexDirection: 'row', flexWrap: 'wrap', columnGap: ESPACE, rowGap: 16 },
160
+ grille: { padding: 14, flexDirection: 'row', flexWrap: 'wrap', columnGap: 12, rowGap: 16 },
209
161
  item: { alignItems: 'center' },
210
162
  cadre: { alignSelf: 'stretch', padding: 3, borderWidth: 2, borderRadius: 14 },
211
- apercu: { width: '100%', aspectRatio: 0.6, borderRadius: 10, overflow: 'hidden' },
163
+ apercu: { width: '100%', aspectRatio: 0.6, borderRadius: 10 },
212
164
  coche: { position: 'absolute', top: 8, right: 8, borderRadius: 12, borderWidth: 2, padding: 1 },
213
165
  libelle: { marginTop: 8, textAlign: 'center' },
166
+ espace: { height: 24 },
167
+ pastilles: { paddingHorizontal: 10, paddingVertical: 16, flexDirection: 'row', flexWrap: 'wrap', justifyContent: 'space-evenly', rowGap: 16 },
168
+ accent: { width: 64, alignItems: 'center' },
169
+ anneau: { padding: 3, borderWidth: 2, borderRadius: 26 },
170
+ pastille: { width: 40, height: 40, borderRadius: 20, alignItems: 'center', justifyContent: 'center' },
214
171
  });
@@ -74,7 +74,7 @@ export function ProfilePageMenu({ items, titre }: { items: (ProfileItem | ReactE
74
74
  <Card style={styles.card}>
75
75
  {lignes.map((ligne, i) => (
76
76
  <Fragment key={i}>
77
- {i > 0 && <View style={styles.separateur} />}
77
+ {i > 0 && <View style={[styles.separateur, { backgroundColor: withAlpha(Themer.neural03Color, 0.25) }]} />}
78
78
  {ligne}
79
79
  </Fragment>
80
80
  ))}
@@ -160,5 +160,5 @@ const styles = StyleSheet.create({
160
160
  sousTitre: { marginTop: 2 },
161
161
  section: { fontSize: 12, letterSpacing: 0.8, fontWeight: '600', marginLeft: 4, marginBottom: 8 },
162
162
  // Trait aligné sur le texte (après la pastille)
163
- separateur: { height: StyleSheet.hairlineWidth, marginLeft: 68, backgroundColor: withAlpha(Themer.neural03Color, 0.25) },
163
+ separateur: { height: StyleSheet.hairlineWidth, marginLeft: 68 },
164
164
  });
@@ -15,6 +15,7 @@ import { withAlpha } from '../../../../shared/utils/color';
15
15
  import { AvatarWidget } from '../../../../shared/widgets/avatar_widget';
16
16
  import { ClipboardWidget } from '../../../../shared/widgets/clipboard_widget';
17
17
  import { ImageSelectWidget } from '../../../../shared/widgets/image_select_widget';
18
+ import { SbSelectionOption } from '../../../../shared/widgets/selection';
18
19
  import { AliasBloc } from '../../../alias/presentation/bloc/alias_bloc';
19
20
  import { AliasExistState } from '../../../alias/presentation/bloc/alias_state';
20
21
  import { ProfileAvatar } from '../../domain/profile_avatar';
@@ -45,21 +46,16 @@ export function ProfilePageAvatar() {
45
46
  otherActions={
46
47
  avatar != null
47
48
  ? [
48
- <Pressable
49
+ <SbSelectionOption
49
50
  key="delete"
50
- accessibilityRole="button"
51
- style={styles.deleteTile}
51
+ icone="delete-forever"
52
+ titre={traductions.btnTextDelete}
53
+ couleur={Themer.systemErrorColor}
52
54
  onPress={() => {
53
55
  AppRouter.pop(router);
54
56
  void ProfileAvatar.remove();
55
57
  }}
56
- >
57
- <MaterialIcons name="delete-forever" size={24} color={Themer.systemErrorColor} />
58
- <Text style={[theme.textTheme.bodyLarge, styles.deleteText, { color: Themer.systemErrorColor }]}>
59
- {traductions.btnTextDelete}
60
- </Text>
61
- <MaterialIcons name="arrow-forward-ios" size={16} color={Themer.systemErrorColor} />
62
- </Pressable>,
58
+ />,
63
59
  ]
64
60
  : []
65
61
  }
@@ -147,6 +143,4 @@ const styles = StyleSheet.create({
147
143
  maxWidth: '100%',
148
144
  },
149
145
  aliasTexte: { flexShrink: 1, marginHorizontal: 6 },
150
- deleteTile: { flexDirection: 'row', alignItems: 'center', paddingHorizontal: 16, minHeight: 56 },
151
- deleteText: { flex: 1, marginHorizontal: 16 },
152
146
  });
@@ -36,7 +36,6 @@ export function ProfilePageContacts({ contactPI }: { contactPI?: ContactPI | nul
36
36
 
37
37
  const onSelect = async (contact: PhoneContact | null, alias: string | null) => {
38
38
  const value = await showModalBottomSheet<boolean>(router, {
39
- themed: true,
40
39
  builder: () => <ProfilePageContactsActions alias={alias} contact={contact} contactPI={contactPI} />,
41
40
  });
42
41
  if (value != null && contactPI != null) AppRouter.pop(router);
@@ -1,8 +1,6 @@
1
- import { Image } from 'expo-image';
2
1
  import { MaterialIcons } from '@expo/vector-icons';
3
- import { useEffect, useRef, useState } from 'react';
4
- import { Animated, Easing, Keyboard, Platform, Pressable, ScrollView, StyleSheet, Text, useWindowDimensions, View } from 'react-native';
5
- import { useSafeAreaInsets } from 'react-native-safe-area-context';
2
+ import { useState } from 'react';
3
+ import { Keyboard, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native';
6
4
 
7
5
  import { Images } from '../../../../core/assets';
8
6
  import { useBloc, useBlocListener, useCreateBloc } from '../../../../core/bloc_react';
@@ -11,11 +9,12 @@ import { Themer, useTheme } from '../../../../core/theme';
11
9
  import { useAppLocalizations } from '../../../../l10n/localizations';
12
10
  import { ElevatedButton, FilledTonalButton } from '../../../../shared/material/buttons';
13
11
  import { AliasPI } from '../../../../shared/models/alias_pi';
14
- import { useKeyboardVisible } from '../../../../shared/utils/use_keyboard_visible';
12
+ import { withAlpha } from '../../../../shared/utils/color';
15
13
  import { ClipboardWidget } from '../../../../shared/widgets/clipboard_widget';
16
14
  import { InputAliasWidget } from '../../../../shared/widgets/input_alias_widget';
17
15
  import { CustomTextInput } from '../../../../shared/widgets/input_text';
18
16
  import { CustomLoadingDialog } from '../../../../shared/widgets/loading_page';
17
+ import { SelectionBoutons, SelectionSheet } from '../../../../shared/widgets/selection';
19
18
  import { ContactPI } from '../../../contacts/domain/contact_pi';
20
19
  import { contactIdOf, type PhoneContact } from '../../../contacts/domain/phone_contact';
21
20
  import { ContactBloc } from '../../../contacts/presentation/bloc/contact_bloc';
@@ -27,6 +26,7 @@ import {
27
26
  ContactCreateLoadingState,
28
27
  ContactCreateSuccessState,
29
28
  } from '../../../contacts/presentation/bloc/create/contact_create_state';
29
+ import { ProfileMenuTile, ProfilePageMenu } from './profile_menu';
30
30
 
31
31
  function fullName(contact: PhoneContact): string {
32
32
  return `${contact.firstName} ${contact.lastName}`.trim();
@@ -50,9 +50,6 @@ export function ProfilePageContactsActions({
50
50
  const traductions = useAppLocalizations();
51
51
  const theme = useTheme();
52
52
  const router = useAppRouter();
53
- const insets = useSafeAreaInsets();
54
- const { height } = useWindowDimensions();
55
- const isKeyboardVisible = useKeyboardVisible();
56
53
  const contactListBloc = useBloc(ContactBloc);
57
54
  const contactBloc = useCreateBloc(() => new ContactCreateBloc());
58
55
 
@@ -107,127 +104,124 @@ export function ProfilePageContactsActions({
107
104
  };
108
105
 
109
106
  const canSave = command.isValid() && command.value !== alias && name != null && name.length > 0;
110
- // Comme en Flutter, la feuille a une hauteur fixe (35 % ou 50 % de l'écran)
111
- // qui passe à 70 % ou 80 % quand le clavier est affiché, pour que le
112
- // formulaire reste au-dessus du clavier. Sur iOS, la feuille est déjà
113
- // remontée au-dessus du clavier par l'OverlayHost : elle garde sa hauteur.
114
- const keyboardOpen = isKeyboardVisible && Platform.OS !== 'ios';
115
- const ratio = !keyboardOpen ? (contact != null ? 0.35 : 0.5) : contact != null ? 0.7 : 0.8;
116
- const sheetHeight = useRef(new Animated.Value(height * ratio)).current;
117
- useEffect(() => {
118
- Animated.timing(sheetHeight, {
119
- toValue: height * ratio,
120
- duration: 300,
121
- easing: Easing.inOut(Easing.ease),
122
- useNativeDriver: false,
123
- }).start();
124
- }, [height, ratio, sheetHeight]);
107
+ const primaire = theme.colorScheme.primary;
108
+ const initiale = contact != null && name != null && name.trim().length > 0 ? name.trim()[0].toUpperCase() : null;
125
109
 
110
+ // La feuille remonte d'elle-même au-dessus du clavier
126
111
  return (
127
- <Animated.View style={[styles.sheet, { backgroundColor: theme.colorScheme.surface, height: sheetHeight, paddingBottom: insets.bottom }]}>
128
- <View style={styles.content}>
129
- <View style={styles.gap20} />
130
- {/* Titre */}
131
- <Text style={theme.textTheme.headlineMedium}>{name ?? traductions.contactCreateTitle}</Text>
132
- {alias != null && alias.length > 0 ? (
133
- <>
134
- <View style={styles.gap10} />
112
+ <SelectionSheet
113
+ hauteurMax={0.9}
114
+ contenu={
115
+ <>
116
+ <ScrollView keyboardShouldPersistTaps="handled" bounces={false} style={styles.defile} contentContainerStyle={styles.content}>
117
+ {/* Pastille, nom du contact (ou « Ajouter un contact ») et alias à copier (ou sous-titre de la création) */}
135
118
  <View style={styles.row}>
136
- <Text numberOfLines={1} style={[theme.textTheme.bodyLarge, styles.flex, { color: Themer.neural03Color }]}>
137
- {AliasPI.formatPhoneNumber(alias)}
138
- </Text>
139
- <Pressable accessibilityRole="button" hitSlop={8} onPress={() => void ClipboardWidget.setData(alias)}>
140
- <MaterialIcons name="content-copy" size={16} color={theme.colorScheme.onSurface} />
141
- </Pressable>
142
- </View>
143
- </>
144
- ) : contact == null ? (
145
- <>
146
- <View style={styles.gap10} />
147
- <Text numberOfLines={1} style={[theme.textTheme.bodyLarge, { color: Themer.neural03Color }]}>
148
- {traductions.contactCreateSubtitle}
149
- </Text>
150
- </>
151
- ) : null}
152
- <View style={styles.gap20} />
153
-
154
- {canEdit ? (
155
- <>
156
- {/* Formulaire */}
157
- <ScrollView style={styles.flex} keyboardShouldPersistTaps="handled">
158
- {contact == null && (
159
- <>
160
- <CustomTextInput
161
- defaultValue={name ?? ''}
162
- labelText={traductions.contactCreateNameLabel}
163
- messageError={name == null || name.length === 0 ? traductions.contactCreateNameErrorEmpty : null}
164
- onChange={setName}
165
- />
166
- <View style={styles.gap10} />
167
- </>
168
- )}
169
- <InputAliasWidget command={command} onChange={rebuild} />
170
- </ScrollView>
171
- <View style={styles.gap20} />
172
- {/* Annuler / Enregistrer */}
173
- <View style={styles.buttons}>
174
- <View style={styles.flex}>
175
- <FilledTonalButton onPress={cancel}>{traductions.btnTextCancel}</FilledTonalButton>
119
+ <View style={[styles.avatar, { backgroundColor: withAlpha(primaire, 0.12) }]}>
120
+ {initiale != null ? (
121
+ <Text style={[theme.textTheme.headlineMedium, styles.initiale, { color: primaire }]}>{initiale}</Text>
122
+ ) : (
123
+ <MaterialIcons name="person-add-alt-1" size={24} color={primaire} />
124
+ )}
176
125
  </View>
177
- <View style={styles.gap16} />
178
- <View style={styles.flex}>
179
- <ElevatedButton onPress={canSave ? () => saveAlias(command.value!) : undefined}>{traductions.btnTextSave}</ElevatedButton>
126
+ <View style={styles.entete}>
127
+ <Text numberOfLines={1} style={theme.textTheme.headlineMedium}>
128
+ {contact != null && name != null ? name : traductions.contactCreateTitle}
129
+ </Text>
130
+ <View style={styles.gap2} />
131
+ {alias != null && alias.length > 0 ? (
132
+ <View style={styles.row}>
133
+ <Text numberOfLines={1} style={[theme.textTheme.displayMedium, styles.flexShrink, { color: Themer.neural03Color }]}>
134
+ {AliasPI.formatPhoneNumber(alias)}
135
+ </Text>
136
+ <Pressable
137
+ accessibilityRole="button"
138
+ hitSlop={8}
139
+ style={styles.copier}
140
+ onPress={() => void ClipboardWidget.setData(alias)}
141
+ >
142
+ <MaterialIcons name="content-copy" size={16} color={primaire} />
143
+ </Pressable>
144
+ </View>
145
+ ) : contact == null ? (
146
+ <Text style={[theme.textTheme.displaySmall, { color: Themer.neural03Color }]}>{traductions.contactCreateSubtitle}</Text>
147
+ ) : null}
180
148
  </View>
181
149
  </View>
182
- </>
183
- ) : contact != null && alias != null ? (
184
- <>
185
- {/* Modifier */}
186
- <Action
187
- icon={Images.iconEdit}
188
- title={traductions.profileContactPageaActionEdit}
189
- onPress={() => {
190
- command.value = alias;
191
- setCanEdit(true);
192
- }}
193
- />
194
- {/* Supprimer */}
195
- <Action
196
- icon={Images.iconDelete}
197
- title={traductions.profileContactPageaActionDelete}
198
- onPress={() => contactBloc.add(new ContactDeleteSubmitEvent(contactIdOf(contact), alias))}
199
- />
200
- </>
201
- ) : null}
202
- </View>
203
- </Animated.View>
204
- );
205
- }
150
+ <View style={styles.gap20} />
206
151
 
207
- function Action({ icon, title, onPress }: { icon: number; title: string; onPress: () => void }) {
208
- const theme = useTheme();
209
- return (
210
- <Pressable accessibilityRole="button" onPress={onPress} style={styles.action}>
211
- <View style={[styles.actionIcon, { backgroundColor: theme.colorScheme.surface }]}>
212
- <Image source={icon} style={styles.icon} tintColor={theme.colorScheme.onSurface} />
213
- </View>
214
- <Text style={[theme.textTheme.headlineSmall, styles.actionText]}>{title}</Text>
215
- </Pressable>
152
+ {canEdit ? (
153
+ <>
154
+ {/* Champs nom et alias */}
155
+ {contact == null && (
156
+ <>
157
+ <CustomTextInput
158
+ defaultValue={name ?? ''}
159
+ labelText={traductions.contactCreateNameLabel}
160
+ messageError={name == null || name.length === 0 ? traductions.contactCreateNameErrorEmpty : null}
161
+ onChange={setName}
162
+ />
163
+ <View style={styles.gap12} />
164
+ </>
165
+ )}
166
+ <InputAliasWidget command={command} onChange={rebuild} />
167
+ </>
168
+ ) : contact != null && alias != null ? (
169
+ // Actions sur l'alias du contact
170
+ <ProfilePageMenu
171
+ items={[
172
+ // Modifier
173
+ <ProfileMenuTile
174
+ key="modifier"
175
+ image={Images.iconEdit}
176
+ titre={traductions.profileContactPageaActionEdit}
177
+ onPress={() => {
178
+ command.value = alias;
179
+ setCanEdit(true);
180
+ }}
181
+ />,
182
+ // Supprimer
183
+ <ProfileMenuTile
184
+ key="supprimer"
185
+ image={Images.iconDelete}
186
+ titre={traductions.profileContactPageaActionDelete}
187
+ couleur={theme.colorScheme.error}
188
+ trailing={<View />}
189
+ onPress={() => contactBloc.add(new ContactDeleteSubmitEvent(contactIdOf(contact), alias))}
190
+ />,
191
+ ]}
192
+ />
193
+ ) : null}
194
+ </ScrollView>
195
+
196
+ {/* Annuler / Enregistrer, fixés en bas */}
197
+ {canEdit && (
198
+ <SelectionBoutons
199
+ boutons={[
200
+ <FilledTonalButton key="annuler" onPress={cancel}>
201
+ {traductions.btnTextCancel}
202
+ </FilledTonalButton>,
203
+ <ElevatedButton key="enregistrer" onPress={canSave ? () => saveAlias(command.value!) : undefined}>
204
+ {traductions.btnTextSave}
205
+ </ElevatedButton>,
206
+ ]}
207
+ />
208
+ )}
209
+ </>
210
+ }
211
+ />
216
212
  );
217
213
  }
218
214
 
219
215
  const styles = StyleSheet.create({
220
- sheet: { borderTopLeftRadius: 20, borderTopRightRadius: 20, overflow: 'hidden' },
221
- content: { paddingHorizontal: 20, flex: 1 },
222
- flex: { flex: 1 },
216
+ defile: { flexShrink: 1 },
217
+ content: { paddingHorizontal: 20, paddingTop: 4, paddingBottom: 20 },
223
218
  flexShrink: { flexShrink: 1 },
224
219
  row: { flexDirection: 'row', alignItems: 'center' },
225
- buttons: { flexDirection: 'row', paddingVertical: 16 },
226
- action: { flexDirection: 'row', alignItems: 'center', minHeight: 64 },
227
- actionIcon: { width: 45, height: 45, borderRadius: 14, alignItems: 'center', justifyContent: 'center' },
228
- icon: { width: 20, height: 20 },
229
- actionText: { marginLeft: 16 },
230
- gap10: { height: 10 },
231
- gap16: { width: 16 },
220
+ avatar: { width: 52, height: 52, borderRadius: 26, alignItems: 'center', justifyContent: 'center' },
221
+ initiale: { fontWeight: '700' },
222
+ entete: { flex: 1, marginLeft: 14 },
223
+ copier: { padding: 4, marginLeft: 6 },
224
+ gap2: { height: 2 },
225
+ gap12: { height: 12 },
232
226
  gap20: { height: 20 },
233
227
  });
@@ -88,7 +88,6 @@ export function QrCodeAliasPage() {
88
88
  style={styles.icon}
89
89
  onPress={() =>
90
90
  void showModalBottomSheet(router, {
91
- themed: true,
92
91
  builder: () => <QrcodeAliasPageShare username={user.nomComplet()} alias={aliasCle} shareQrcode={() => void shareQRCode()} />,
93
92
  })
94
93
  }