Compare commits

...

517 Commits

Author SHA1 Message Date
Pfeil, Scott Robert
8212d7146c Merge branch 'bugfix/CXTDT-626224' into 'develop'
CXTDT-626224

### Summary
CXTDT-626224
MVA/iOS: Progress section has visual defects that need to be corrected.
Change :-  Number size should be: (font-size: 32px / line-height: 36px and “%” symbol size should be: font-size: 11px / line-height: 16px

### JIRA Ticket
https://onejira.verizon.com/browse/CXTDT-626224![Screenshot_2024-10-17_at_7.15.02_PM](/uploads/e89f367a09b23c230ab4f461320fc669/Screenshot_2024-10-17_at_7.15.02_PM.png)

![Screenshot_2024-10-17_at_7.15.33_PM](/uploads/a5055585223f4ab2697d1ce79f52d43b/Screenshot_2024-10-17_at_7.15.33_PM.png)

Co-authored-by: rajani kumari  Gupta <rajani.kumari.gupta@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1204
2024-10-21 13:10:53 +00:00
rajani kumari Gupta
5c280b7922 Fix comment 2024-10-21 14:28:34 +05:30
Pfeil, Scott Robert
1eed9ebb76 Merge branch 'feature/safe_area_insets' into 'develop'
Digital ACT192 story ONEAPP-11297 - Updating insets to allow for more...

### Summary
Updating insets to allow flexibility with the safe area

### JIRA Ticket
https://onejira.verizon.com/browse/ONEAPP-6673

Co-authored-by: Scott Pfeil <Scott.Pfeil3@verizonwireless.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1203
2024-10-17 15:30:33 +00:00
Scott Pfeil
a210b8da9b Remove Spacer 2024-10-17 09:34:50 -04:00
Scott Pfeil
44adc76dcb Digital ACT192 story ONEAPP-11297 - Updating insets to allow for more flexibility and edge using. Removing the status bar view because it is no longer used. 2024-10-17 09:04:31 -04:00
rajani kumari Gupta
eb4f741f1a CXTDT-626224
MVA/iOS: Progress section has visual defects that need to be corrected.
issue fixed :- Number size should be: (font-size: 32px / line-height: 36px and “%” symbol size should be: font-size: 11px / line-height: 16px
2024-10-17 17:47:24 +05:30
Bruce, Matt R
928c8c5b54 Merge branch 'bugfix/CXTDT-626309' into 'develop'
Digital ACT191 defect CXTDT-626309 - Updating fonts and spacing

### Summary
Fixes to the header component defaults.
https://docs.google.com/spreadsheets/d/1DqG_ZDxIseuVsEtRaQTVRC5mHME79Ksmhdj067jLNr4/edit?pli=1&gid=0#gid=0

### JIRA Ticket
https://onejira.verizon.com/browse/CXTDT-626309
https://onejira.verizon.com/browse/CXTDT-628092

Co-authored-by: Scott Pfeil <Scott.Pfeil3@verizonwireless.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1202
2024-10-16 16:34:13 +00:00
Scott Pfeil
2dd3a7dca8 Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui into bugfix/CXTDT-626309 2024-10-16 12:31:28 -04:00
Scott Pfeil
7bed914dca Digital ACT191 defect CXTDT-626309 - Updating fonts and spacing
Digital ACT191 defect CXTDT-628092 - Fixing accessibility trait header default.
2024-10-16 10:53:16 -04:00
Pfeil, Scott Robert
fe5bd4a9ac Merge branch 'feature/CXTDT-624895-Badge-Color-Updates' into 'develop'
refactored badge text/fill color

### Summary
Fixed bug in how fillColor is set.

Co-authored-by: Matt Bruce <matt.bruce@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1200
2024-10-16 01:25:12 +00:00
Matt Bruce
7eb1a4ff4b redid the values
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-10-15 16:57:37 -05:00
Matt Bruce
76b58ec88a using type now and not the old way.
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-10-14 15:57:25 -05:00
Matt Bruce
4487f9b03b refactored badge text/fill color
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-10-14 15:53:31 -05:00
Scott Pfeil
3a06f7b43e Digital ACT191 defect CXTDT-626309 - Update to default header h2 padding 2024-10-14 11:03:24 -04:00
Hedden, Kyle Matthew
f3e97ecfd4 Merge branch 'feature/CXTDT-624895-Badge-Color-Updates' into 'develop'
VDS - iOS Badge - Include ability to select custom color for Label and Background

### Summary
CXT - Defect TrackerCXTDT-624895
VDS - iOS Badge - Include ability to select custom color for Label and Background
### JIRA Ticket
https://onejira.verizon.com/browse/CXTDT-624895

Co-authored-by: Matt Bruce <matt.bruce@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1199
2024-10-09 13:04:36 +00:00
Matt Bruce
f66dc66818 undid comment
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-10-08 09:18:23 -05:00
Matt Bruce
bf2a3e7e5b removed isDark
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-10-08 09:10:04 -05:00
Matt Bruce
54b50bffd3 added fillColor codable
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-10-08 09:08:30 -05:00
Matt Bruce
3b2dc2d447 updated to use badgeModel
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-10-08 09:08:20 -05:00
Matt Bruce
c737ca1344 added textColor
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-10-08 09:08:05 -05:00
Pfeil, Scott Robert
d2e841c533 Merge branch 'bugfix/FontLabelAttribute-conversion' into 'develop'
added in model conversion to textStyle

### Summary
The size was not being used in the conversion along with the name. 

So now you either pass in a Style or a Name & Size.

Co-authored-by: Matt Bruce <matt.bruce@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1197
2024-10-04 17:57:09 +00:00
Matt Bruce
69d057c45a added in model conversion to textStyle
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-10-04 12:03:18 -05:00
Pfeil, Scott Robert
0510cded89 Merge branch 'feature/ONEAPP-11359' into 'develop'
Digital ACT192 story ONEAPP-11359: Lift the minimum supported iOS version number to 15.

### Summary
Lift the minimum supported iOS version number to 15.

### JIRA Ticket
https://onejira.verizon.com/browse/ONEAPP-11359

Co-authored-by: Hedden, Kyle Matthew <kyle.hedden@verizonwireless.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1196
2024-10-03 21:07:26 +00:00
Hedden, Kyle Matthew
03a8a2d925 Merge branch 'bugfix/missing_accessibility_identifiers' into 'develop'
Added missing accessibility identifier

### Summary
Added missing accessibilityIdentifiers

### JIRA Ticket
Awaiting

Co-authored-by: Scott Pfeil <Scott.Pfeil3@verizonwireless.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1195
2024-10-02 21:38:41 +00:00
Hedden, Kyle Matthew
65bf81830e Digital ACT192 story ONEAPP-11359: Lift the minimum supported iOS version number to 15. 2024-10-01 20:24:32 -04:00
Scott Pfeil
bb2fbe4bdd Added missing accessibility identifier 2024-09-27 12:13:09 -04:00
Pfeil, Scott Robert
ce038458dc Merge branch 'bugfix/atomic-vds-titleLockup-model-issue' into 'develop'
TitleLockup Model issue

### Summary
removed duplicate alignment property and updated the confluence to reference the correct textAlignment.

Co-authored-by: Matt Bruce <matt.bruce@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1194
2024-09-27 14:40:34 +00:00
Matt Bruce
de33f8ffa1 fixed migration issue in checkboxLabel to integrate the VDS.CheckboxItem
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-09-27 09:38:36 -05:00
Matt Bruce
4d4765ccec removed duplicate alignment property and updated the confluence to reference the correct textAlignment.
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-09-27 09:03:12 -05:00
Bruce, Matt R
464e36606e Merge branch 'bugfix/MVAPCT-271' into 'develop'
Digital PCT265 defect MVAPCT-271 - Ensure the app doesn't crash on invalid color hex.

### Summary
Ensure the app doesn't crash on invalid color hex. 

### JIRA Ticket
https://onejira.verizon.com/browse/MVAPCT-271

Co-authored-by: Scott Pfeil <Scott.Pfeil3@verizonwireless.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1192
2024-09-20 18:05:55 +00:00
Scott Pfeil
8a7c07ecf2 Digital PCT265 defect MVAPCT-271 - greater than or equal to length fix 2024-09-20 14:04:44 -04:00
Scott Pfeil
740c3eeb31 Digital PCT265 defect MVAPCT-271 - Ensure the app doesn't crash on invalid color hex. 2024-09-20 12:45:11 -04:00
Hedden, Kyle Matthew
00a11cd5dc Merge branch 'feature/atomic-vds-sept2024' into 'develop'
September Atomic/VDS Release

### Summary
Added Breadcrumbs and Pagination 

### JIRA Ticket
- https://onejira.verizon.com/browse/ONEAPP-6827
- https://onejira.verizon.com/browse/ONEAPP-6978

Co-authored-by: Matt Bruce <matt.bruce@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1185
2024-09-20 16:29:11 +00:00
Matt Bruce
03a1bd0920 made parentalmodelmolecule
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-09-20 08:30:51 -05:00
Matt Bruce
4f6b848e72 removed inits
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-09-20 08:30:37 -05:00
Matt Bruce
5043ff35a0 removed inits
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-09-20 08:30:27 -05:00
Bruce, Matt R
806ac9821a Merge branch 'bugfix/featured_products_defects' into 'develop'
Bugfix/featured products defects

### Summary
Fix for bold when the font isn't supported, and for bg image forcing full image size.

Co-authored-by: Scott Pfeil <Scott.Pfeil3@verizonwireless.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1191
2024-09-19 18:41:29 +00:00
Scott Pfeil
47e63e0c8b Digital ACT191 defect FeaturedProducts - Fix for bold when the font isn't supported, and for bg image forcing full image size. 2024-09-19 14:35:33 -04:00
Hedden, Kyle Matthew
2d7f8ae2ca Merge branch 'feature/MVAPCT-273' into 'develop'
MVAPCT-273

### Summary
Template Decoding Failed Error logs

### MVAPCT-273
https://onejira.verizon.com/browse/MVAPCT-273

Co-authored-by: Danish Phiroz <danish.phiroz@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1188
2024-09-19 12:27:47 +00:00
Phiroz, Danish
e708b97581 MVAPCT-273 2024-09-19 12:27:47 +00:00
Hedden, Kyle Matthew
1b5ca94988 Merge branch 'release/20_2_0' into 'develop'
release/20_2_0 hotfix merge

Co-authored-by: Pfeil, Scott Robert <scott.pfeil3@verizonwireless.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1182
2024-09-06 19:59:31 +00:00
Pfeil, Scott Robert
d7756b66b0 Merge branch 'bugfix/CXTDT-608227-2' into 'release/20_2_0'
Digital PCT032 defect CXTDT-608227: Set content compression resistance for RadioButton.

### Summary
Prevent the radio button from being crushed.

### JIRA Ticket
https://onejira.verizon.com/browse/CXTDT-608227

Co-authored-by: Hedden, Kyle Matthew <kyle.hedden@verizonwireless.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1187
2024-08-29 17:59:42 +00:00
Hedden, Kyle Matthew
89842ee443 Digital PCT032 defect CXTDT-608227: Set content compression resistance for RadioButton. 2024-08-29 13:39:41 -04:00
Matt Bruce
61f9fb9946 enforce an action
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-27 16:38:17 -05:00
Matt Bruce
484b578568 added Pagination
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-27 14:30:39 -05:00
Matt Bruce
1c723c31de registered in core
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-26 16:13:16 -05:00
Matt Bruce
e79c1d7637 added breadcrumbs/model
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-26 16:13:05 -05:00
Bruce, Matt R
02a2da7f0a Merge branch 'bugfix/CXTDT-601365' into 'develop'
Fix for CXTDT-601365, enabling option for Icon to be accessible from JSON.

### Summary
Enabling option for Icon to be accessible from JSON.

### JIRA Ticket
[CXTDT-601365](https://onejira.verizon.com/browse/CXTDT-601365)

Co-authored-by: Sumanth Nadigadda <sumanth.nadigadda@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1183
2024-08-26 18:49:05 +00:00
Sumanth Nadigadda
22c30de62f Fix for CXTDT-601365, enabling option for Icon to be accessible from JSON. 2024-08-26 23:40:29 +05:30
Hedden, Kyle Matthew
f6f3cd53fe Merge branch 'feature/atomic-vds-new-forms-atoms' into 'develop'
Revert code

### Summary
Removed code since this was a fix in VDS

Co-authored-by: Matt Bruce <matt.bruce@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1180
2024-08-23 17:29:19 +00:00
Matt Bruce
378c46facd removed this since it is no longer needed.
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-23 08:35:10 -05:00
Hedden, Kyle Matthew
c2e10582f8 Merge branch 'feature/atomic-vds-new-forms-atoms' into 'develop'
Last of the VDS FormFields

### Summary
Added in 
1. Checkboxes (VDS CheckboxGroup)
2. RadioButtons (VDS RadioButtonGroup)
3. CalendarView (VDS CalendarBase)
4. DatePickerEntryField (VDS DatePicker)

### JIRA Ticket
https://onejira.verizon.com/browse/ONEAPP-7001
https://onejira.verizon.com/browse/ONEAPP-7004
https://onejira.verizon.com/browse/ONEAPP-7016
https://onejira.verizon.com/browse/ONEAPP-7958

Co-authored-by: Matt Bruce <matt.bruce@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1176
2024-08-22 21:46:28 +00:00
Matt Bruce
8670fa3193 removed visualEquivalent
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-22 14:25:48 -05:00
Matt Bruce
9bbf325640 removed since this is not needed.
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-22 14:11:14 -05:00
Matt Bruce
59e762f52e added == and != for equality
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-22 14:10:44 -05:00
Matt Bruce
62c1aa6a8a removed isVisuallyEqual since this was the same as isEqual
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-22 14:10:26 -05:00
Matt Bruce
df1846c295 added parentMoleculeModelProtocol
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-22 14:09:48 -05:00
Matt Bruce
533bcd2dea added isEqual to CalendarView
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-22 13:30:13 -05:00
Matt Bruce
e211d4dc22 added isEqual to TextViewEntryFieldModel
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-22 13:21:52 -05:00
Matt Bruce
f9915dfacc update func
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-22 13:20:22 -05:00
Matt Bruce
68a72f6b2e added isEqual to ItemDropDown
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-22 13:20:10 -05:00
Matt Bruce
2a497082a0 added isEqual to TextEntry
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-22 13:19:50 -05:00
Matt Bruce
961a0546a8 added isEqual to base model
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-22 13:19:37 -05:00
Matt Bruce
86d49053a6 add isEqual to DatePicker
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-22 13:12:58 -05:00
Matt Bruce
db8ba63892 added isEqual to Toggle
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-22 13:12:00 -05:00
Matt Bruce
878fd11c8a added isEqual to RadioButton variations
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-22 13:11:48 -05:00
Matt Bruce
c40dc5e396 added isEqual to RadioBox variations
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-22 13:11:35 -05:00
Matt Bruce
f94ddbf866 added isEqual to Checkbox variations
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-22 13:11:14 -05:00
Matt Bruce
b70d2f8add added isEqual
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-22 13:10:49 -05:00
Matt Bruce
398bf94811 removed obj-c compatibility
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-22 11:41:28 -05:00
Bruce, Matt R
7f9ee10c5e Merge branch 'feature/tile_cont_upd_view' into 'develop'
added updateView for molecule in tile container

Added this change as updateView for the molecule was not getting called resulting in the molecule and its children always pinned to their respective superviews.

Co-authored-by: Arun Kumar Chintakrinda <arun.kumar.chintakrinda@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1179
2024-08-22 14:25:37 +00:00
Arun Kumar Chintakrinda
6354174857 Merge remote-tracking branch 'refs/remotes/origin/develop' 2024-08-22 19:46:40 +05:30
Arun Kumar Chintakrinda
3be3b11e39 added updateView for molecule in tile container 2024-08-22 19:41:43 +05:30
Bruce, Matt R
de30c5d286 Merge branch 'bugfix/molecule_replacement_module_id_validation' into 'develop'
Digital PCT265 defect: Missing moecule.id to moduleName validation for the replacement behavior.

### Summary
Data validation bug on notification_count_fios module return.

Co-authored-by: Hedden, Kyle Matthew <kyle.hedden@verizonwireless.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1178
2024-08-22 12:56:13 +00:00
Hedden, Kyle Matthew
472323f303 Digital PCT265 defect: Missing moecule.id to moduleName validation for the replacement behavior. 2024-08-21 19:59:46 -04:00
Matt Bruce
3b306a299a using enabled now
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-21 16:28:14 -05:00
Matt Bruce
de67fd7fb6 refactored
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-21 16:07:10 -05:00
Matt Bruce
60cefc57a6 pushed word change
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-21 15:47:27 -05:00
Matt Bruce
9185e185fd removed duplicate .
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-21 15:17:27 -05:00
Matt Bruce
3d5c188898 changed comment
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-21 15:16:26 -05:00
Matt Bruce
458f303972 fixed per comments
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-21 14:21:17 -05:00
Matt Bruce
ef08aa043e added other properties to encoder :D
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-21 14:14:01 -05:00
Matt Bruce
698f7b5520 subclass to formFieldModel
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-21 14:10:23 -05:00
Matt Bruce
3270f21951 used new isEnabled in model
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-21 14:10:09 -05:00
Matt Bruce
315eac1dac used new isEnabled in model
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-21 14:09:57 -05:00
Matt Bruce
c3290f83ba updated for change in RadioBoxModel
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-21 14:09:24 -05:00
Matt Bruce
c41cf3f18e converted to use FormFieldModel subclass
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-21 14:08:57 -05:00
Matt Bruce
56b4142c14 added isEnabled
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-21 14:07:59 -05:00
Matt Bruce
e7bcd32588 put the moleculeName in the base
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-21 13:07:51 -05:00
Bruce, Matt R
6c841c078a Merge branch 'release/20_1_1' into 'develop'
Digital PCT265 defect: VDS TabsTableViewCell delegate reset issue. Impacts UAD...

Co-authored-by: Subramaniam, Ramya <ramya.subramaniam@one.verizon.com>
Co-authored-by: Hedden, Kyle Matthew <kyle.hedden@verizonwireless.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1177
2024-08-21 13:17:32 +00:00
Matt Bruce
29b56bf63b updated field
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-20 15:41:53 -05:00
Matt Bruce
e030b460ce added final properties 2024-08-20 14:19:22 -05:00
Matt Bruce
25dce9e88c refactored naming of method
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-20 14:19:15 -05:00
Matt Bruce
7b0f4e4328 update only after the model sets the properties
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-20 13:59:52 -05:00
Matt Bruce
8829bd7457 added new mapping
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-20 13:59:27 -05:00
Matt Bruce
478f2b6083 added codable for VDS
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-20 13:59:19 -05:00
Matt Bruce
94ace3d49a added new models/views
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-20 13:59:07 -05:00
Matt Bruce
e3f22efb12 updated to convertTo
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-20 08:49:51 -05:00
Matt Bruce
b71a4c5b25 refactored to convertTo
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-20 08:49:36 -05:00
Matt Bruce
3fd10bf199 added registration
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-20 08:49:20 -05:00
Matt Bruce
aeabee2666 refactored to convertToXXXModel
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-20 08:49:12 -05:00
Matt Bruce
d8c83f9230 removed delegate that isn't used anywhere.
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-20 08:45:38 -05:00
Matt Bruce
6b608b4a8a added showError
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-20 08:45:23 -05:00
Matt Bruce
13f9776a4f new Checkboxes/RadioButtons
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-20 08:45:04 -05:00
Pfeil, Scott Robert
ffd5242cde Merge branch 'bugfix/atomic-buttonGroup' into 'develop'
Fix for the reset() issue with default properties being reset for buttonGroup

### Summary
There were buttongroup properties added in the setup() method, however they were getting removed in reset(). 

### JIRA Ticket
https://onejira.verizon.com/browse/CXTDT-602228

Co-authored-by: Matt Bruce <matt.bruce@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1175
2024-08-15 17:32:31 +00:00
Matt Bruce
e89272a3cd comments on the order of operations in reset()
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-15 12:31:50 -05:00
Matt Bruce
33dc411743 Fix for the reset() issue with default properties being reset for buttonGroup
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-15 11:08:25 -05:00
Pfeil, Scott Robert
558a3d7c55 Merge branch 'feature/negate_gone' into 'develop'
Digital PCT265 story VZWYZDG-1866 - Added action for negating the gone property on molecules.

### Summary
Action for negating the gone property on goneable molecules.
https://oneconfluence.verizon.com/x/AZT2UQ

### JIRA Ticket
https://onejira.verizon.com/browse/VZWYZDG-1866

![SuccessfulTest](/uploads/ac54fd745447ef52497843af641f24e4/SuccessfulTest.mp4)

Co-authored-by: Scott Pfeil <Scott.Pfeil3@verizonwireless.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1166
2024-08-14 18:56:12 +00:00
Scott Pfeil
17a94e2f04 Digital PCT265 story VZWYZDG-1866 - Ensure the footer stays at the bottom. 2024-08-14 12:32:50 -04:00
Scott Pfeil
4921d7d8db Digital PCT265 story VZWYZDG-1866 - Updating format per code review. 2024-08-14 11:33:40 -04:00
Subramaniam, Ramya
8c5a8776ab Merge branch 'bugfix/tabstableviewcell' into 'release/20_1_1'
Digital PCT265 defect: VDS TabsTableViewCell delegate reset issue. Impacts UAD.

### Summary
This issue is due to a change in the VDS tabs reset handling. The onTabSelect and onTabShouldSelect gets reset to nil. In the case of table cell reuse this reset gets called and our setup connection in the initializer is lost. Adding the delegate back in the model setter seems to resolve this immediate issue but we should expand out and see if there are other cases.

### JIRA Ticket
[CXTDT-601399](https://onejira.verizon.com/browse/CXTDT-601399)

Co-authored-by: Hedden, Kyle Matthew <kyle.hedden@verizonwireless.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1174
2024-08-14 05:34:05 +00:00
Hedden, Kyle Matthew
3867384307 Digital PCT265 defect: VDS TabsTableViewCell delegate reset issue. Impacts UAD account tab switcher. 2024-08-13 23:25:18 -04:00
Pfeil, Scott Robert
efccb312e8 Merge branch 'release/20_1_0' into 'develop'
ensure viewModel?. is used outside of the viewModelDidUpdate method

### Summary
Hotfix

Co-authored-by: Hedden, Kyle Matthew <kyle.hedden@verizonwireless.com>
Co-authored-by: Matt Bruce <matt.bruce@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1173
2024-08-13 20:43:30 +00:00
Hedden, Kyle Matthew
f437fbaea9 Merge branch 'hotfix/20_1-vds-update' into 'release/20_1_0'
ensure viewModel?. is used outside of the viewModelDidUpdate method

### Summary
Crash from not using optional ? for the viewModels.

Co-authored-by: Matt Bruce <matt.bruce@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1172
2024-08-12 14:47:10 +00:00
Matt Bruce
441525a610 ensure formModel exists
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-12 09:28:40 -05:00
Matt Bruce
07351c1a22 ensure viewModel?. is used outside of the viewModelDidUpdate method
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-12 09:28:31 -05:00
Hedden, Kyle Matthew
236a1969e9 Merge branch 'bugfix/vds-update' into 'develop'
Merge of release/20_1 and bugfix

### Summary
VDS Bugfix for new Generics plus all of the release/20_1 code that hasn't been merged down into develop.

Co-authored-by: Matt Bruce <matt.bruce@verizon.com>
Co-authored-by: Pfeil, Scott Robert <scott.pfeil3@verizonwireless.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1170
2024-08-12 13:21:53 +00:00
Matt Bruce
f96b750302 Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui.git into test 2024-08-10 11:31:02 -05:00
Matt Bruce
715a911ee4 fixed issue with vds refactor 2024-08-10 11:30:47 -05:00
Hedden, Kyle Matthew
696b6b99d0 Merge branch 'hotfix/checkbox-showError' into 'release/20_1_0'
CXTDT-599891 - taking out showError for now

### Summary
Checkboxes have never had an error state, so until we figure out the default state, we need to turn it off. 

### JIRA Ticket
https://onejira.verizon.com/browse/CXTDT-599891

Co-authored-by: Matt Bruce <matt.bruce@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1169
2024-08-09 22:52:31 +00:00
Matt Bruce
b41d2189bf taking out showError for now
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-09 17:48:05 -05:00
Matt Bruce
8c1577bb7f Merge branch 'release/20_1_0' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui into release/20_1_0 2024-08-09 09:17:13 -05:00
Pfeil, Scott Robert
21d1e957d0 Merge branch 'bugfix/proddef_26055_2' into 'release/20_1_0'
bugfix PRODDEF-26055 Issue #2

### Summary
added missing view to getAcessibilityElements func

### JIRA Ticket
https://onejira.verizon.com/browse/PRODDEF-26055

Co-authored-by: Hedden, Kyle Matthew <kyle.hedden@verizonwireless.com>
Co-authored-by: Arun Kumar Chintakrinda <arun.kumar.chintakrinda@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1168
2024-08-08 20:56:49 +00:00
Hedden, Kyle Matthew
c34a5c7661 Merge branch 'hotfix/radioButton' into 'release/20_1_0'
CXTDT-598142 - RadioButton fix

### Summary
Updated VDS RadioButton had more atomic setting than required. 

### JIRA Ticket
https://onejira.verizon.com/browse/CXTDT-598142

Co-authored-by: Matt Bruce <matt.bruce@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1167
2024-08-08 20:45:16 +00:00
Matt Bruce
d308bfc957 CXTDT-598142 - RadioButton fix
QA3||MVA||Prepay||IOS - 22053||Devices||From Add device screen

Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-08 15:38:53 -05:00
Matt Bruce
92b28d767b Merge branch 'release/20_1_0' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui into release/20_1_0 2024-08-08 14:32:35 -05:00
Scott Pfeil
a691f8d713 Digital PCT265 story VZWYZDG-1866 - Update name to proper jargon. 2024-08-08 14:14:03 -04:00
Scott Pfeil
f412fd70e1 Digital PCT265 story VZWYZDG-1866 - Added action for negating the gone property on molecules. 2024-08-08 14:02:21 -04:00
Pfeil, Scott Robert
50b0280ba4 Merge branch 'feature/MVAPCT-213' into 'develop'
Digital PCT265 story MVAPCT-213 - Allow for panels to override the supported...

### Summary
Allow for panels to override the supported orientation. Force chatbot panel to be full screen width on non tablet devices.

### JIRA Ticket
https://onejira.verizon.com/browse/MVAPCT-213

Co-authored-by: Scott Pfeil <Scott.Pfeil3@verizonwireless.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1165
2024-08-06 15:06:09 +00:00
Scott Pfeil
dfbb53f545 Digital PCT265 story MVAPCT-213 - Function name update 2024-08-06 10:31:18 -04:00
Scott Pfeil
1d2defeabb Digital PCT265 story MVAPCT-213 - Add Helper to update the orientation. 2024-08-06 09:53:59 -04:00
Hedden, Kyle Matthew
3d6d7c0cad Merge branch 'bugfix/proddef_26055_2' into 'develop'
bugfix PRODDEF-26055 Issue #2

### Summary
added missing view to getAcessibilityElements func

### JIRA Ticket
https://onejira.verizon.com/browse/PRODDEF-26055

Co-authored-by: Arun Kumar Chintakrinda <arun.kumar.chintakrinda@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1164
2024-08-06 13:38:57 +00:00
Arun Kumar Chintakrinda
2ce1b671bd added comment 2024-08-06 17:18:56 +05:30
Scott Pfeil
e13e8ca5ab Digital PCT265 story MVAPCT-213 - Allow for panels to override the supported orientation. Force chatbot panel to be full screen width on non tablet devices. 2024-08-05 13:59:59 -04:00
Arun Kumar Chintakrinda
100ede48fa added condition to check if view is available 2024-08-05 20:32:09 +05:30
Arun Kumar Chintakrinda
0d6fc3d15d bugfix PRODDEF-26055 Issue #2, added missing view to getAcessibilityElements func 2024-08-05 20:25:24 +05:30
Hedden, Kyle Matthew
5eca67fe0f Merge branch 'hotfix/checkbox-isSelected' into 'release/20_1_0'
HotFix Checkbox/CheckboxLabel

### Summary
reverted to old code so that if isSelected is set manually, the form will validate.

Co-authored-by: Matt Bruce <matt.bruce@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1163
2024-08-02 19:49:04 +00:00
Matt Bruce
1a48113b0d Merge branch 'hotfix/checkbox-isSelected' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui.git into release/20_1_0 2024-08-02 13:14:35 -05:00
Matt Bruce
37c6dfd6b3 optional viewModel
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-02 13:13:57 -05:00
Matt Bruce
0938328ea2 Merge branch 'hotfix/checkbox-isSelected' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui.git into release/20_1_0 2024-08-02 12:42:10 -05:00
Matt Bruce
5a3f04aa5f use super instead of var
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-02 08:53:15 -05:00
Matt Bruce
5e116e3c91 reverted code in case the isSelected is set directly
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-01 17:14:04 -05:00
Hedden, Kyle Matthew
941312dd08 Merge branch 'bugfix/dropDownSelect' into 'release/20_1_0'
DropDownSelect update

### Summary
fixed issue with EstimatedHeight and delegate callback.

### JIRA Ticket
https://onejira.verizon.com/browse/ONEAPP-7135

Co-authored-by: Matt Bruce <matt.bruce@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1162
2024-08-01 20:35:04 +00:00
Matt Bruce
c2cb8781d6 ensured all vds components have the estimated height implementation
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-01 15:18:33 -05:00
Matt Bruce
ab5a5a1e55 added placeholder in delegates so you can understand what is passed back
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-01 10:55:48 -05:00
Matt Bruce
3732f98d7c added override property to deal with oldvalue/newValue for the selected Item.
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-01 10:53:14 -05:00
Pfeil, Scott Robert
d69722c431 Merge branch 'bugfix/atomic-vds-selectorUpdate' into 'develop'
Updated Merged Selectors

### Summary
updated selectors for similar logic in valuechanged event 

### JIRA Ticket
https://onejira.verizon.com/browse/ONEAPP-7001

Co-authored-by: Matt Bruce <matt.bruce@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1159
2024-07-31 00:52:13 +00:00
Matt Bruce
9606b914cc removed code
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-30 17:02:17 -05:00
Matt Bruce
57bec1ecec moved formvalidation to publisher
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-30 17:02:09 -05:00
Matt Bruce
998ad97372 Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui.git into feature/atomic-vds-checkbox 2024-07-30 16:39:59 -05:00
Matt Bruce
d199389ff3 ensured isEnabled
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-30 16:38:30 -05:00
Pfeil, Scott Robert
b24094ea5b Merge branch 'feature/atomic-vds-checkbox' into 'develop'
VDS Brand 3.0 Checkbox

### Summary
VDS Brand 3.0 Checkbox, CheckboxItem for IOS
- CheckboxGroup will be a later integration since this is not in the app at this time.
 
### JIRA Ticket
https://onejira.verizon.com/browse/ONEAPP-7001

Co-authored-by: Matt Bruce <matt.bruce@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1152
2024-07-30 21:36:51 +00:00
Matt Bruce
ac23b0dc41 refactored checkbox action to didSet
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-30 16:35:46 -05:00
Matt Bruce
5a47b32789 Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui.git into feature/atomic-vds-checkbox 2024-07-30 16:34:17 -05:00
Pfeil, Scott Robert
f1087527d8 Merge branch 'feature/atomic-vds-toggle' into 'develop'
VDS Brand 3.0 Toggle Integration

### Summary
VDS Components - (iOS) VDS Brand 3.0 Toggle into Atomic

### JIRA Ticket
https://onejira.verizon.com/browse/ONEAPP-4827

Co-authored-by: Matt Bruce <matt.bruce@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1151
2024-07-30 21:18:56 +00:00
Matt Bruce
eb9ad769e5 Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui.git into feature/atomic-vds-toggle 2024-07-30 16:14:02 -05:00
Matt Bruce
fe66380d72 refactored setting of isON on viewModelDidUpdate
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-30 16:13:35 -05:00
Matt Bruce
eab6fb5f3b refactored model to remove default text
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-30 16:13:17 -05:00
Pfeil, Scott Robert
fa650bafb5 Merge branch 'feature/atomic-vds-radioButton' into 'develop'
VDS Brand 3.0 Radiobutton

### Summary
VDS Brand 3.0 Radiobutton, RadiobuttonItem for IOS
* RadiobuttonGroup will be a later integration since this is not in the app at this time.

### JIRA Ticket
https://onejira.verizon.com/browse/ONEAPP-7004

Co-authored-by: Matt Bruce <matt.bruce@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1153
2024-07-30 20:07:46 +00:00
Pfeil, Scott Robert
aca65b13d3 Merge branch 'feature/atomic-vds-radiobox' into 'develop'
VDS Brand 3.0 Radiobox

### Summary
VDS Brand 3.0 Radiobox and group for IOS

### JIRA Ticket
https://onejira.verizon.com/browse/ONEAPP-7007

Co-authored-by: Matt Bruce <matt.bruce@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1158
2024-07-30 19:52:42 +00:00
Matt Bruce
4b06a5ba1f ensured inverted is set
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-30 14:48:36 -05:00
Matt Bruce
ccf520f49e Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui.git into feature/atomic-vds-radiobox 2024-07-30 14:25:52 -05:00
Matt Bruce
2771808674 added inverted encoding
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-30 14:10:24 -05:00
Pfeil, Scott Robert
bf491e2341 Merge branch 'feature/atomic-vds-textArea' into 'develop'
VDS Brand 3.0 Text Area

### Summary
VDS Brand 3.0 Text Area for IOS

### JIRA Ticket
https://onejira.verizon.com/browse/ONEAPP-6682

Co-authored-by: Matt Bruce <matt.bruce@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1155
2024-07-30 18:51:43 +00:00
Matt Bruce
3e702ec0f5 removed properties that were pushed down
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-30 13:44:19 -05:00
Matt Bruce
c794add84d removed duplicate struct for view masking protocol
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-30 13:44:03 -05:00
Matt Bruce
344b2f18aa Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui.git into feature/atomic-vds-textArea 2024-07-30 13:36:09 -05:00
Pfeil, Scott Robert
d0a6bdda3d Merge branch 'feature/atomic-vds-inputField' into 'develop'
VDS Brand 3.0 Input Field

### Summary
VDS Brand 3.0 Input Field for IOS

### JIRA Ticket
https://onejira.verizon.com/browse/ONEAPP-7963

Co-authored-by: Matt Bruce <matt.bruce@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1156
2024-07-30 18:19:59 +00:00
Matt Bruce
68083819be change protocol to any
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-30 13:16:16 -05:00
Pfeil, Scott Robert
fbecc82d20 Merge branch 'feature/atomic-vds-dropDownSelect' into 'develop'
VDS Brand 3.0 Dropdown Select

### Summary
VDS Brand 3.0 Dropdown Select for IOS

### JIRA Ticket
https://onejira.verizon.com/browse/ONEAPP-7135

Co-authored-by: Matt Bruce <matt.bruce@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1157
2024-07-30 17:47:22 +00:00
Matt Bruce
8ec3f01e2c Merge branch 'feature/vds-form-controls' into feature/atomic-vds-textArea 2024-07-30 11:10:07 -05:00
Matt Bruce
bdaa4b5ea7 added extra check to ensure you aren't duplicating rules
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-30 11:09:40 -05:00
Matt Bruce
66464cebc3 comment
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-30 10:39:04 -05:00
Matt Bruce
b754b476a6 reverted code
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-30 08:29:07 -05:00
Matt Bruce
8215542ee7 removed method not needed
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-30 08:25:21 -05:00
Matt Bruce
192509feef remvoed inverted since this is now in subclass
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-30 08:24:05 -05:00
Matt Bruce
8a89b2b2a9 updated methods and comments
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-30 08:22:24 -05:00
Matt Bruce
35ab4c94d2 removed accessibility and rearranged methods/comments
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-30 08:17:51 -05:00
Matt Bruce
5ebdbd24f1 rearranged methods for commenting
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-30 08:15:17 -05:00
Matt Bruce
3d86b8fcf7 Merge branch 'feature/atomic-vds-toggle' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui.git into feature/atomic-vds-toggle 2024-07-30 08:10:01 -05:00
Matt Bruce
62a74e8c34 removed accessibility settings to use VDS and rearranged
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-30 08:09:44 -05:00
Matt Bruce
796215f64d rearranged methods and comments
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-30 08:07:34 -05:00
Matt Bruce
694f074d08 Merge branch 'feature/atomic-vds-checkbox' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui.git into feature/atomic-vds-checkbox 2024-07-30 08:03:34 -05:00
Matt Bruce
2675488ab3 removed accessibility so we can use the VDS version
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-30 08:03:26 -05:00
Matt Bruce
4ad3f7c078 Merge branch 'feature/atomic-vds-dropDownSelect' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui.git into feature/atomic-vds-dropDownSelect 2024-07-29 13:21:08 -05:00
Matt Bruce
e1755a3b32 Merge branch 'feature/vds-form-controls' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui.git into feature/atomic-vds-dropDownSelect 2024-07-29 13:09:31 -05:00
Bruce, Matt R
fa3c97cabe Merge branch 'bugfix/CXTDT-590886' into 'develop'
CXTDT-590886 Fix to make placeholder text visible.

### Summary
Placeholder text is getting hidden when text is empty for the first launch. Added a fix

### JIRA Ticket
https://onejira.verizon.com/browse/CXTDT-590886

Co-authored-by: Nandhini Rajendran <nandhini.rajendran@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1150
2024-07-26 19:05:42 +00:00
Matt Bruce
b8d6376e86 Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui.git into feature/atomic-vds-dropDownSelect 2024-07-25 19:26:29 -05:00
Nandhini Rajendran
6db3a58782 CXTDT-590886 Fix to make placeholder text visible. 2024-07-26 01:55:36 +05:30
Matt Bruce
226c23abae removed inverted
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-25 10:39:40 -05:00
Matt Bruce
3689b16339 refactored into VDS.Label extension
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-25 10:19:55 -05:00
Matt Bruce
c47d21bdf1 updated with open
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-19 16:32:46 -05:00
Matt Bruce
f82ef2e51c add open
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-19 16:12:12 -05:00
Matt Bruce
efd98cc887 removed un-needed properties
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-19 16:00:43 -05:00
Matt Bruce
c7d2dcd655 Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui.git into feature/atomic-vds-checkbox 2024-07-19 14:23:22 -05:00
Matt Bruce
2888eebb69 updated validity
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-19 14:16:55 -05:00
Hedden, Kyle Matthew
38ae12e91b Merge branch 'feature/VZWYZDG-1810-UpdatedProgressUI' into 'develop'
Set the default value of duration to 0 to disable the animation by default...

Set the default value of animation duration to 0 to disable the animation by default following confluence page.

JIRA Ticket
https://onejira.verizon.com/browse/VZWYZDG-2236

Co-authored-by: Xi Zhang <xi.zhang@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1149
2024-07-17 18:41:16 +00:00
Xi Zhang
0f4a97b49c Set the default value of duration to 0 to disable the animation by default following confluence page. 2024-07-17 14:35:55 -04:00
Hedden, Kyle Matthew
7f32af62cc Merge branch 'feature/VZWYZDG-1810-UpdatedProgressUI' into 'develop'
Fix the circular progress showing issue when percent is 100%.

Fix the circular progress showing issue when percent is 100%.

Jira Ticket:
https://onejira.verizon.com/browse/VZWYZDG-2236

Co-authored-by: Xi Zhang <xi.zhang@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1148
2024-07-17 15:49:12 +00:00
Xi Zhang
3b5b03a368 Fix the showing issue when percent is 100%. 2024-07-17 10:23:50 -04:00
Bruce, Matt R
a845f70b55 Merge branch 'feature/DE307-834' into 'develop'
Digital PCT265 story DE307-834: Prevent scroll reset on reconfigure.

### Summary
Prevent carousel reset on same data.

### JIRA Ticket
https://onejira.verizon.com/browse/DE307-834

Co-authored-by: Hedden, Kyle Matthew <kyle.hedden@verizonwireless.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1147
2024-07-17 12:32:44 +00:00
Hedden, Kyle Matthew
16c20507ce Digital PCT265 story DE307-834: Crash prevention on registered cells check for gone change. 2024-07-16 19:58:26 -04:00
Matt Bruce
018fe9a25e updated MDN Field to use new inputfield
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-16 16:16:39 -05:00
Matt Bruce
239af70710 fix initial updates
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-16 15:27:54 -05:00
Matt Bruce
36669b61cb used new input in mapping for now
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-16 15:27:42 -05:00
Matt Bruce
65be46c767 added inputentryfield
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-16 15:27:27 -05:00
Matt Bruce
273f45def0 updated model
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-16 15:27:14 -05:00
Hedden, Kyle Matthew
bc72d81396 Digital PCT265 story DE307-834: Prevent scroll reset on reconfigure. 2024-07-16 15:16:56 -04:00
Bruce, Matt R
c77f0c6837 Merge branch 'feature/DE307-834' into 'develop'
Digital PCT265 story DE307-834: Increase throttle time for collision safety....

### Summary
Badge isEqual implementation.

### JIRA Ticket
https://onejira.verizon.com/browse/DE307-834

Co-authored-by: Hedden, Kyle Matthew <kyle.hedden@verizonwireless.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1146
2024-07-16 18:38:37 +00:00
Hedden, Kyle Matthew
46d57733e4 Digital PCT265 story DE307-834: Increase throttle time for collision safety. As a throttle this is to space the updates at regular intervals. This should also help reduce some of the page stuttering as there will be bigger update batches. 2024-07-16 14:32:48 -04:00
Hedden, Kyle Matthew
f001f98d3a Digital PCT265 story DE307-834: Add missing BadgeModel isEqual(to:). 2024-07-16 14:20:37 -04:00
Hedden, Kyle Matthew
8e5e713c72 Merge branch 'feature/VZWYZDG-1810-UpdatedProgressUI' into 'develop'
Support for Circular Progress UI Component

add support for Circular progress UI Component

Jira Ticket:
https://onejira.verizon.com/browse/VZWYZDG-2236

Co-authored-by: Xi Zhang <xi.zhang@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1145
2024-07-16 13:17:13 +00:00
Xi Zhang
29466e4e33 Move GraphSize to a higher level for common use. 2024-07-15 17:02:28 -04:00
Xi Zhang
5cbd472a2d Make diameter default value to 64 consistent with the default small size diameter value. 2024-07-15 16:04:34 -04:00
Xi Zhang
53c4bd6c46 Revise codes following MR comments 2024-07-12 16:12:54 -04:00
Matt Bruce
022355a49f Merge branch 'feature/vds-form-controls' into feature/atomic-vds-textArea 2024-07-12 15:04:59 -05:00
Matt Bruce
c8496194f0 updated FormField
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-12 15:04:17 -05:00
Matt Bruce
d2eae79f47 bug in rule
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-12 15:04:12 -05:00
Matt Bruce
1a23c97a73 updated FormField
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-12 15:03:46 -05:00
Matt Bruce
b5f61953df updated textViewEntry
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-12 14:58:05 -05:00
Matt Bruce
c8d817948b bug in rule
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-12 14:57:56 -05:00
Matt Bruce
80edb943b2 Merge branch 'feature/vds-form-controls' into feature/atomic-vds-textArea 2024-07-12 14:49:47 -05:00
Matt Bruce
05e2967131 add to validator
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-12 14:48:56 -05:00
Matt Bruce
c925323347 implemented new protocol
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-12 14:48:48 -05:00
Matt Bruce
716550bf23 added new rule
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-12 14:48:36 -05:00
Matt Bruce
1b391272c5 updated model
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-12 14:45:20 -05:00
Matt Bruce
fedf1760ec made public/open
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-12 09:33:21 -05:00
Xi Zhang
de60fdfaf9 Make animation duration configurable. 2024-07-11 17:22:11 -04:00
Matt Bruce
73893d36d7 Merge branch 'feature/vds-form-controls' into feature/vds-radiobox 2024-07-11 12:53:59 -05:00
Matt Bruce
cb30a58db6 Merge branch 'feature/vds-form-controls' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui.git into feature/vds-radioButton 2024-07-11 12:53:16 -05:00
Matt Bruce
0abc903793 turn off required
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-11 12:52:53 -05:00
Matt Bruce
675ba3eaff Merge branch 'feature/vds-form-controls' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui.git into feature/vds-checkbox 2024-07-11 12:51:55 -05:00
Matt Bruce
c7d5cac1af Merge branch 'feature/vds-form-controls' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui.git into feature/vds-toggle
# Conflicts:
#	MVMCoreUI/Atomic/Extensions/VDS-Enums+Codable.swift

Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-11 12:51:01 -05:00
Matt Bruce
4c28312191 updated helper text placement
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-11 12:47:31 -05:00
Matt Bruce
d76d7c0974 Merge branch 'feature/vds-form-controls' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui.git into feature/atomic-vds-dropDownSelect 2024-07-11 12:42:34 -05:00
Matt Bruce
be5a691365 added more properties
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-11 12:41:45 -05:00
Matt Bruce
7ec685136b added more properties
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-11 12:22:28 -05:00
Xi Zhang
021f4184a6 Merge branch 'develop' into feature/VZWYZDG-1810-UpdatedProgressUI 2024-07-11 13:14:08 -04:00
Xi Zhang
20d818b2c2 Refactor codes for circular progress UI. 2024-07-11 13:12:29 -04:00
Matt Bruce
bd4c7780b0 Merge branch 'feature/vds-form-controls' into feature/vds-textArea 2024-07-11 12:11:45 -05:00
Matt Bruce
cadded3217 added more enums
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-11 12:09:52 -05:00
Matt Bruce
c7a4bf72c3 added more propeties
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-11 12:00:54 -05:00
Matt Bruce
9e9a1ab853 added properties from model
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-11 11:23:14 -05:00
Matt Bruce
b1c59124a7 fixed bugs in validation to match textViewentryfield
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-11 11:20:17 -05:00
Matt Bruce
a4b550cf03 first cut of textEntry
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-11 10:19:01 -05:00
Matt Bruce
0ab9ad37a8 added extension
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-10 14:51:49 -05:00
Matt Bruce
797d044913 added inverted
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-10 14:51:36 -05:00
Matt Bruce
79d5529991 added delegates
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-10 14:51:10 -05:00
Matt Bruce
981bdac292 refactored to use VDS Dropdown Select
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-10 14:37:04 -05:00
Matt Bruce
8bf4a28b0f added extension
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-10 14:36:47 -05:00
Matt Bruce
144efea342 added inverted
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-10 12:54:50 -05:00
Matt Bruce
4eba94f413 refactored to use formfieldmodel
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-10 12:05:07 -05:00
Xi Zhang
1b0197ed2c Add support for circular progress bar part 2 2024-07-09 18:49:10 -04:00
Pfeil, Scott Robert
82fe0e13de Merge branch 'bugfix/CXTDT-579050' into 'develop'
Digital PCT265 defect CXTDT-579049: Fix indexing safety to mocules to add....

### Summary
A new attempt at synchronizing data + UI updates.

### JIRA Ticket
https://onejira.verizon.com/browse/CXTDT-579050

Co-authored-by: Hedden, Kyle Matthew <kyle.hedden@verizonwireless.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1142
2024-07-09 18:40:06 +00:00
Matt Bruce
8c5840fba3 views updated for model changes
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-09 10:23:05 -05:00
Matt Bruce
8a12bf12c2 refactored models
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-09 10:21:55 -05:00
Hedden, Kyle Matthew
6e88ae0b62 Merge branch 'release/20_0_3' into 'develop'
release/20_0_3 hotfix merge


See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1139
2024-07-09 14:53:22 +00:00
Xi Zhang
7fec6f540e Add support for circular progress bar. 2024-07-05 15:10:34 -04:00
Hedden, Kyle Matthew
cae92360a2 Digital PCT265 defect CXTDT-579050: Carousel cell registration check break early. 2024-07-03 18:45:29 -04:00
Hedden, Kyle Matthew
b2ad684f00 Digital PCT265 defect CXTDT-579050: Carousel cell registration check. 2024-07-03 18:40:43 -04:00
Hedden, Kyle Matthew
90f9a0bcf5 Digital PCT265 defect CXTDT-579050: Code simplification and fixes of combine pipeline for page updates. 2024-07-03 18:39:28 -04:00
Matt Bruce
04f228ea48 refactored to remove old properties
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-03 15:58:35 -05:00
Matt Bruce
724130a827 converted to vds
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-03 15:58:22 -05:00
Matt Bruce
10c55b12be converted to VDS
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-03 15:58:15 -05:00
Matt Bruce
fa52fa8c12 added protocol/refactored to deal with RadiobuttonLabel
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-03 15:58:01 -05:00
Matt Bruce
fcd4f4e0ec refactored name to subTitle
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-03 15:57:22 -05:00
Hedden, Kyle Matthew
4cbf15a3a7 Digital PCT265 defect CXTDT-579050: Change batching to the UI. 2024-07-03 15:42:12 -04:00
Matt Bruce
1d048f9389 Merge branch 'feature/vds-form-controls' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui.git into feature/vds-checkbox 2024-07-03 11:43:42 -05:00
Matt Bruce
aa773dc8f5 added base FormField model class
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-03 11:42:08 -05:00
Pfeil, Scott Robert
fdab57200d Merge branch 'bugfix/tilecontainer-refactor' into 'develop'
fixes for VDS TileContainer update

### Summary
TileContainer/Tilelet for VDS still hasn't been fully VDS Tested, however the automatic fill is in fact a part of the requirement. This was resolved as well as the height/width issue.

This change in Atomic is to default to leading for Tilelet so it won't automatically be pinned to all edges. These components shouldn't be pinned to the trailing/right or bottom if they are to be resized by ratio or having width/height values.

Also by default, the Tilelet's aspectRatio should be set to .none

### JIRA
https://onejira.verizon.com/browse/VZWYZDG-2117

Co-authored-by: Matt Bruce <matt.bruce@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1141
2024-07-03 14:44:37 +00:00
Matt Bruce
a84f502a0e updated checkbox/label
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-03 09:37:00 -05:00
Hedden, Kyle Matthew
3cdd3a95a0 Merge branch 'bugfix/CXTDT-578423' into 'develop'
Digital ACT191 defect CXTDT-578423 - Fix to missing navigation line when the...

### Summary
The hide navigation bar line logic has been updated to include if the sub navigation is manually hidden.

### JIRA Ticket
https://onejira.verizon.com/browse/CXTDT-578423

Co-authored-by: Scott Pfeil <Scott.Pfeil3@verizonwireless.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1143
2024-07-03 13:46:04 +00:00
Scott Pfeil
9e712aa213 Digital ACT191 defect CXTDT-578423 - Fix to missing navigation line when the subnav tabs are manually hidden. 2024-07-03 09:33:57 -04:00
Hedden, Kyle Matthew
d8d4b37d1d Digital PCT265 defect CXTDT-579050: Rewire asynchronous response JSON parsing to filter, queue, and delay drop UI changes. 2024-07-02 19:05:53 -04:00
Matt Bruce
568ab2e5e5 added surface
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-02 10:56:40 -05:00
Matt Bruce
847daee32f - refactored more code
- CheckboxLabel to VDS.CheckboxItem

Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-01 14:55:25 -05:00
Matt Bruce
dee11d7732 aspectRatio set to .none
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-01 11:13:18 -05:00
Matt Bruce
f3efb91fee remove horizontalAlignment
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-01 11:12:57 -05:00
Matt Bruce
7357a199d2 fixes for VDS TileContainer update
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-06-29 09:48:18 -05:00
Hedden, Kyle Matthew
12bbe5d9a2 Merge branch 'bugfix/CXTDT-579050' into 'release/20_0_3'
Digital PCT265 defect CXTDT-579050: Prevent updateViews from triggering...

### Summary
UAD thread state crash fix.

### JIRA Ticket
https://onejira.verizon.com/browse/CXTDT-579050

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1140
2024-06-28 20:02:36 +00:00
Hedden, Kyle Matthew
3092804f7c Merge branch 'bugfix/CXTDT-579049' into 'release/20_0_3'
Digital PCT265 defect CXTDT-579049: Index out of bounds crash fixes.

### Summary
Array indexing safety for mid property updates.

### JIRA Ticket
https://onejira.verizon.com/browse/CXTDT-579049

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1138
2024-06-28 19:58:59 +00:00
Matt Bruce
11a023d92a initial cut for the checkbox
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-06-28 14:57:15 -05:00
Matt Bruce
04e11ee1fb a few updates
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-06-28 14:54:47 -05:00
Hedden, Kyle Matthew
91eb4fa87a Digital PCT265 defect CXTDT-579050: Prevent updateViews from triggering tableView(_:cellForRowAt:) through visibleCells. 2024-06-28 15:23:17 -04:00
Hedden, Kyle Matthew
080f77581f Digital PCT265 defect CXTDT-579049: Fix indexing safety to mocules to add. (Another crash in App Store reports.) 2024-06-28 09:18:13 -04:00
Hedden, Kyle Matthew
525f0f8f0a Digital PCT265 defect CXTDT-579049: Add indexing safety to track action call. 2024-06-28 09:13:49 -04:00
Matt Bruce
66255d9dc5 implemented initial vds toggle
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-06-27 15:49:06 -05:00
Pfeil, Scott Robert
eb78d507d6 Merge branch 'release/20_0_0' into 'develop'
release/20_0_0 hotfix merge

Co-authored-by: Hedden, Kyle Matthew <kyle.hedden@verizonwireless.com>
Co-authored-by: Matt Bruce <matt.bruce@verizon.com>
Co-authored-by: Subramaniam, Ramya <ramya.subramaniam@one.verizon.com>
Co-authored-by: Bruce, Matt R <matt.bruce@one.verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1128
2024-06-26 14:42:50 +00:00
Hedden, Kyle Matthew
3cdd74f097 Merge branch 'hotfix/vds-label-actions' into 'release/20_0_0'
refactored out code that is now in VDS.Label

### Summary
Code refactored down in to VDS Label, therefor this needed to be removed. 

### JIRA Ticket
https://onejira.verizon.com/browse/CXTDT-576006

Co-authored-by: Matt Bruce <matt.bruce@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1136
2024-06-21 19:18:31 +00:00
Matt Bruce
3108dcdafc refactored out code that is now in VDS.Label
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-06-21 14:11:20 -05:00
Hedden, Kyle Matthew
626b8082df Merge branch 'bugfix/CXTDT-531317' into 'release/20_0_0'
Digital PCT265 defect CXTDT-531317: Give the default page type for those that send an empty string.

### Summary
Allow openURL to send an empty string pageType.

### JIRA Ticket
https://onejira.verizon.com/browse/CXTDT-531317

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1134
2024-06-21 15:18:53 +00:00
Pfeil, Scott Robert
e9106e955f Merge branch 'bugfix/account_crash_fix' into 'release/20_0_0'
Making the view nil to prevent dangling contrainst

### Summary
Account landing crash fix.
### JIRA Ticket
(ticket URL here or remove the section)

Co-authored-by: Subramaniam, Ramya <ramya.subramaniam@one.verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1135
2024-06-21 13:32:21 +00:00
Subramaniam, Ramya
adb415f72c Making the view nil to prevent dangling contrainst 2024-06-21 12:17:48 +05:30
Hedden, Kyle Matthew
41548b8434 Digital PCT265 defect CXTDT-531317: Give the default page type for those that send an empty string. 2024-06-20 16:44:58 -04:00
Pfeil, Scott Robert
18aca32b43 Merge branch 'bugfix/CXTDT-574791' into 'release/20_0_0'
Digital PCT265 defect CXTDT-574791: Restore table reload to ensure table is synced to model.

### Summary
Table data not synced properly causing table crashes in some scenarios.

### JIRA Ticket
https://onejira.verizon.com/browse/CXTDT-574791

Co-authored-by: Hedden, Kyle Matthew <kyle.hedden@verizonwireless.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1133
2024-06-19 19:31:07 +00:00
Hedden, Kyle Matthew
efa99033e9 Digital PCT265 story CXTDT-574791: Prevent additional reload tables in updateView. 2024-06-19 15:30:03 -04:00
Hedden, Kyle Matthew
451758f96d Restore table reload to ensure table is synced to model. 2024-06-19 14:52:33 -04:00
Hedden, Kyle Matthew
1d2098c44c Merge branch 'bugfix/DE307-687' into 'release/20_0_0'
Digital PCT265 defect DE307-687: Replacement module reporting on page visibility restore.

### Summary
Fire the trackState page section updates again when the page becomes visible.

### JIRA Ticket
https://onejira.verizon.com/browse/DE307-687

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1132
2024-06-18 16:35:15 +00:00
Hedden, Kyle Matthew
10c63a52b9 Digital PCT265 defect DE307-687: Slightly better logging clarity, making sure the base page is logged before the module counterparts. 2024-06-17 19:43:47 -04:00
Hedden, Kyle Matthew
be797aaee2 Digital PCT265 defect DE307-687: Re-log all analytics on page state return. 2024-06-17 19:21:19 -04:00
Bruce, Matt R
1fcd8854f5 Merge branch 'bugfix/CXTDT-573370' into 'release/20_0_0'
Digital PCT265 defect CXTDT-573370: Expose VDS bundle helper in MVMCoreUI.

### Summary
Fix webview local font loading.

### JIRA Ticket
https://onejira.verizon.com/browse/CXTDT-573370

Co-authored-by: Hedden, Kyle Matthew <kyle.hedden@verizonwireless.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1131
2024-06-14 18:16:19 +00:00
Hedden, Kyle Matthew
19f08dca79 Digital PCT265 defect CXTDT-573370: Code review. Matt's genious. 2024-06-14 14:15:00 -04:00
Hedden, Kyle Matthew
725d4e3cd7 Digital PCT265 defect CXTDT-573370: Expose VDS bundle helper in MVMCoreUI. 2024-06-14 13:49:18 -04:00
Bruce, Matt R
a608ae294c Merge branch 'develop' into 'release/20_0_0'
Develop

### Summary
Monarch merge.

Co-authored-by: Hedden, Kyle Matthew <kyle.hedden@verizonwireless.com>
Co-authored-by: Matt Bruce <matt.bruce@verizon.com>
Co-authored-by: Scott Pfeil <Scott.Pfeil3@verizonwireless.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1130
2024-06-13 19:56:10 +00:00
Hedden, Kyle Matthew
18a60437d4 Merge branch 'feature/monarch' into 'develop'
Feature/monarch

### Summary
(a brief description of the change)

### JIRA Ticket
(ticket URL here or remove the section)

Co-authored-by: Matt Bruce <matt.bruce@verizon.com>
Co-authored-by: Scott Pfeil <Scott.Pfeil3@verizonwireless.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1107
2024-06-13 19:50:17 +00:00
Hedden, Kyle Matthew
2e36423fae Merge remote-tracking branch 'origin/develop' into feature/monarch 2024-06-13 12:24:41 -04:00
Bruce, Matt R
8844fd7fb3 Merge branch 'feature/DE307-731' into 'develop'
Digital PCT265 story DE307-731: Support 'gone' configuration for carousel cells.

### Summary
Support 'gone' configuration for carousel cells.

### JIRA Ticket
https://onejira.verizon.com/browse/DE307-731

Co-authored-by: Hedden, Kyle Matthew <kyle.hedden@verizonwireless.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1126
2024-06-13 16:21:43 +00:00
Matt Bruce
ef8a95f7c9 Merge branch 'develop' into feature/monarch 2024-06-13 10:57:32 -05:00
Hedden, Kyle Matthew
2ce7a7dbc6 Digital PCT265 story DE307-731: Earlier behavior application. Sumanth catch. 2024-06-13 10:19:13 -04:00
Hedden, Kyle Matthew
7a4984f2d8 Digital PCT265 story DE307-731: Restore missing support for deep replacemenr by moving the template extension to ParentMoleculeModelProtocol. 2024-06-12 23:14:10 -04:00
Hedden, Kyle Matthew
89fbcc7149 Merge remote-tracking branch 'origin/develop' into feature/DE307-731 2024-06-12 16:49:54 -04:00
Hedden, Kyle Matthew
759517f8fd Merge branch 'bugfix/vds-buttonIcon-update' into 'develop'
refactored to vds buttonIcon breaking change

### Summary
ButtonIcon had 3 properties missing from the original requirements.

Co-authored-by: Matt Bruce <matt.bruce@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1127
2024-06-12 20:45:09 +00:00
Matt Bruce
b635ec7d95 refactored to vds buttonIcon breaking change
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-06-12 15:37:52 -05:00
Hedden, Kyle Matthew
750e50d476 Digital PCT265 story DE307-731: Support 'gone' configuration for carousel cells. 2024-06-12 15:59:43 -04:00
Bruce, Matt R
d0bf8a1573 Merge branch 'bugfix/CXTDT-569436' into 'develop'
Digital PCT265 defect CXTDT-569436: Restore render dispatch in handleNewData....

### Summary
Fix first time rendering.

### JIRA Ticket
https://onejira.verizon.com/browse/CXTDT-569436

Co-authored-by: Hedden, Kyle Matthew <kyle.hedden@verizonwireless.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1125
2024-06-12 13:18:25 +00:00
Hedden, Kyle Matthew
b1dc3e13ee Merge remote-tracking branch 'origin/bugfix/CXTDT-569436' into feature/monarch 2024-06-11 19:22:00 -04:00
Hedden, Kyle Matthew
2dcbc9d41b Digital PCT265 defect CXTDT-569436: Restore render dispatch in handleNewData. Add optional flag to disable in situations where we want to handle it ourselves. 2024-06-11 19:06:46 -04:00
Scott Pfeil
1637682cae Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui into feature/monarch 2024-06-10 14:58:18 -04:00
Bruce, Matt R
e3b6591ee4 Merge branch 'bugfix/referenced_removed_frameworks' into 'develop'
removing dead references

removing dead references

Co-authored-by: Scott Pfeil <Scott.Pfeil3@verizonwireless.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1123
2024-06-06 12:48:53 +00:00
Bruce, Matt R
a3fdaca3f5 Merge branch 'bugfix/vds-tilelet-titlelockup-color-update' into 'develop'
fixed the vds color breaking changes for monarch

Updated models for Monarch color changes.

Co-authored-by: Matt Bruce <matt.bruce@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1124
2024-06-05 18:56:17 +00:00
Matt Bruce
037a52d379 fixed the vds color breaking changes for monarch
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-06-05 13:40:01 -05:00
Scott Pfeil
4aba3335d1 Merge branch 'develop' into feature/monarch 2024-06-05 12:44:25 -04:00
Scott Pfeil
7acd9e1b77 removing dead references 2024-06-05 12:30:08 -04:00
Pfeil, Scott Robert
fb584f6a03 Merge branch 'bugfix/font-file-removal' into 'develop'
remove the duplication of the same fonts that are available within the VDS Framework Library.

Per Kyle, we want to shrink the framework sizes, we are removing font file duplication which can impact the size of this framework file.

Co-authored-by: Matt Bruce <matt.bruce@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1122
2024-06-05 14:06:11 +00:00
Matt Bruce
f6a46eed00 updated to static method
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-06-05 08:28:09 -05:00
Matt Bruce
30b2eb150a remove the duplication of the same fonts that are available within the VDS Framework Library.
we are now calling the registration() funtion in VDS on the launch of MVMCoreUI

Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-06-04 14:25:56 -05:00
Scott Pfeil
eb990b7321 Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui into feature/monarch 2024-06-04 10:50:34 -04:00
Scott Pfeil
df02a46c62 Tableview and collection view optimizations 2024-06-04 10:48:47 -04:00
Bruce, Matt R
f3e2263048 Merge branch 'bugfix/prospect_ui_defects' into 'develop'
Removing bars indicator animation

### Summary
Bugfixes for bugs found during monarch testing

Co-authored-by: Scott Pfeil <Scott.Pfeil3@verizonwireless.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1120
2024-06-03 18:35:36 +00:00
Scott Pfeil
4a829eea7c remove test code 2024-06-03 14:31:35 -04:00
Scott Pfeil
5e9f33efa8 warning fix 2024-06-03 14:25:06 -04:00
Scott Pfeil
32d3a20232 navigation line dark fix 2024-06-03 14:24:11 -04:00
Scott Pfeil
012d677b0f Removing bars indicator animation
Removing dispatch to main thread during initial template load
2024-06-03 13:19:01 -04:00
Scott Pfeil
25b7af0a07 Merge branch 'develop' into feature/monarch 2024-05-30 10:09:40 -04:00
Hedden, Kyle Matthew
e0caceaf61 Merge branch 'feature/ONEAPP-7249' into 'develop'
Digital PCT265 story ONEAPP-7249 - Enhancement for allowing background polling.

### Summary
1. Fix card double layout from half width to full width.
2. Optimizations to reduce scrolling stagger on refresh.
3. Reduce layout row tearing.

### JIRA Ticket
https://onejira.verizon.com/browse/ONEAPP-7249

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1106
2024-05-29 23:51:18 +00:00
Hedden, Kyle Matthew
4313041ae0 Digital PCT265 story PCT-135: Code reivew. Comments misspellings. 2024-05-29 18:00:32 -04:00
Hedden, Kyle Matthew
b3d1bd02b0 Digital PCT265 story PCT-135: Code reivew. NavigationItemModel missing property checks. 2024-05-29 17:59:34 -04:00
Hedden, Kyle Matthew
9fdc5c5b69 Digital PCT265 story PCT-135: Code reivew. Missing unSelectedColor check in TabBarModel. 2024-05-29 17:39:09 -04:00
Hedden, Kyle Matthew
79972fc262 Digital PCT265 story PCT-135: Code review. Missing properties in TitleLockup equality check. 2024-05-29 17:33:34 -04:00
Hedden, Kyle Matthew
5660a3273f Digital PCT265 story PCT-135: Code review of headerH2TwoRows double body2 replace check. 2024-05-29 17:28:51 -04:00
Hedden, Kyle Matthew
6d8f8bd298 Digital PCT265 story PCT-135: Code review fix in AlertModel equality check. 2024-05-29 17:25:43 -04:00
Scott Pfeil
3566dd19fa Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui into feature/monarch 2024-05-24 09:26:46 -04:00
Hedden, Kyle Matthew
0a3186ad2e Merge remote-tracking branch 'origin/develop' into feature/ONEAPP-7249 2024-05-23 17:06:57 -04:00
Hedden, Kyle Matthew
54c697dd9d Digital PCT265 story PCT-135: Carousel item clipping VDS conditional approach. 2024-05-23 16:18:46 -04:00
Pfeil, Scott Robert
ab27a96538 Merge branch 'bugfix/disable_gitlab_runner' into 'develop'
remove gitlab stages to disable

### Summary
(a brief description of the change)

### JIRA Ticket
(ticket URL here or remove the section)

Co-authored-by: Hedden, Kyle Matthew <kyle.hedden@verizonwireless.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1027
2024-05-23 16:39:25 +00:00
Hedden, Kyle Matthew
a3334ee607 Merge branch 'bugfix/vds-tilelet-decode' into 'develop'
fixed issue with decoding

### Summary
Broke decoding with Tilelet Icon Change

Co-authored-by: Matt Bruce <matt.bruce@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1118
2024-05-23 16:27:32 +00:00
Matt Bruce
d8f642258f encodeIfPresent
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-05-23 11:25:52 -05:00
Matt Bruce
062a1cfe64 accessibleText not required
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-05-23 11:24:39 -05:00
Matt Bruce
97d7e1dba1 fixed issue with decoding
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-05-23 11:18:23 -05:00
Hedden, Kyle Matthew
756b464cf6 Merge branch 'bugfix/CXTDT-561854' into 'develop'
Digital ACT191 defect CXTDT-561854 - Update font of navigation bar label button to BoldBodySmall

### Summary
Navigation Bar Button Font

### JIRA Ticket
https://onejira.verizon.com/browse/CXTDT-561854

Co-authored-by: Scott Pfeil <Scott.Pfeil3@verizonwireless.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1117
2024-05-23 16:03:06 +00:00
Scott Pfeil
7956a643cb Digital ACT191 defect CXTDT-561854 - Update font of navigation bar label button to BoldBodySmall 2024-05-23 12:00:28 -04:00
Hedden, Kyle Matthew
c48402a638 Merge remote-tracking branch 'refs/remotes/origin/develop' 2024-05-22 18:03:23 -04:00
Hedden, Kyle Matthew
cb659b63e9 Digital PCT265 story PCT-135: ContainerModel ModelComparisonProtocol conformance. 2024-05-22 18:00:59 -04:00
Hedden, Kyle Matthew
9ff5b58eb5 Digital PCT265 story PCT-135: Carousel item clips to bounds restore. 2024-05-22 18:00:17 -04:00
Scott Pfeil
eb1fbb8732 Merge branch 'develop' into feature/monarch 2024-05-22 09:49:08 -04:00
Bruce, Matt R
3ee3644b6d Merge branch 'bugfix/navigation_title_offset' into 'develop'
Digital ACT191 defect ONEAPP-7459 - Fix missing title adjustment commit

### Summary
Fix missing title adjustment commit

### JIRA Ticket
https://onejira.verizon.com/browse/ONEAPP-7459

Co-authored-by: Scott Pfeil <Scott.Pfeil3@verizonwireless.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1116
2024-05-22 13:42:32 +00:00
Scott Pfeil
f940026bf1 Digital ACT191 defect ONEAPP-7459 - Fix missing title adjustment commit 2024-05-22 09:36:20 -04:00
Hedden, Kyle Matthew
6421c53f75 Digital PCT265 story PCT-135: Resovle merge conflicts & updates. 2024-05-21 20:28:51 -04:00
Hedden, Kyle Matthew
ab8b457772 Merge remote-tracking branch 'origin/develop' into feature/ONEAPP-7249 2024-05-21 20:12:21 -04:00
Hedden, Kyle Matthew
0efbb231c3 Merge branch 'feature/navigation_patterns' into 'develop'
Digital ACT191 story ONEAPP-7459 - Navigation Patterns

### Summary
Changes to allow for setting navigation items by pattern.

### JIRA Ticket
https://onejira.verizon.com/browse/ONEAPP-7459

Co-authored-by: Scott Pfeil <Scott.Pfeil3@verizonwireless.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1115
2024-05-22 00:11:56 +00:00
Hedden, Kyle Matthew
fbb582d2b7 Merge remote-tracking branch 'origin/develop' into feature/ONEAPP-7249 2024-05-21 20:04:10 -04:00
Hedden, Kyle Matthew
d79ec8dc6a Digital PCT265 story PCT-135: Extract running the behavior transformations for method clarity. 2024-05-21 17:11:15 -04:00
Hedden, Kyle Matthew
042cc20859 Digital PCT265 story PCT-135: Cleanup. 2024-05-21 17:00:39 -04:00
Hedden, Kyle Matthew
f403e34d7d Digital PCT265 story PCT-135: Change filtering fix, disable partial page updates, move manager newDataReceived. 2024-05-21 14:00:07 -04:00
Hedden, Kyle Matthew
8135a126ed Digital PCT265 story PCT-135: Remove subnav from listening to page updates. 2024-05-21 13:57:04 -04:00
Hedden, Kyle Matthew
3ed40e52be Digital PCT265 story PCT-135: Deep equals check for replacement changes. 2024-05-21 13:56:02 -04:00
Hedden, Kyle Matthew
75104dbe4d Digital PCT265 story PCT-135: Revert onPageNew signature change. 2024-05-20 23:16:16 -04:00
Hedden, Kyle Matthew
d377ec84b7 Digital PCT265 story PCT-135: Rewire to allow the page transformation behavior to list all changes performed to the model tree. 2024-05-20 21:36:26 -04:00
Scott Pfeil
0c28c8dc42 Merge branch 'feature/navigation_patterns' into feature/monarch 2024-05-20 14:56:36 -04:00
Scott Pfeil
7cddd8ef6f Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui into feature/monarch 2024-05-20 14:56:29 -04:00
Scott Pfeil
4a8ac3f9f0 Digital ACT191 story ONEAPP-7459 - Update to allow separate models in the pattern navigation 2024-05-20 14:55:01 -04:00
Pfeil, Scott Robert
1e557e23e7 Merge branch 'bugfix/CXTDT-546581' into 'develop'
Digital PCT265 defect CXTDT-546581: Tabs page state tracking.

### Summary
Add analyticsData map handling at the tabs level. 

### Atomic Docs
https://oneconfluence.verizon.com/display/MFD/Tabs

### JIRA Ticket
https://onejira.verizon.com/browse/CXTDT-546581

Co-authored-by: Hedden, Kyle Matthew <kyle.hedden@verizonwireless.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1114
2024-05-20 16:53:41 +00:00
Hedden, Kyle Matthew
8e70aba157 Digital PCT265 defect CXTDT-54658: Code review. 2024-05-20 11:54:01 -04:00
Hedden, Kyle Matthew
f74bea64c2 Digital PCT265 story PCT-135: Switch to shallow equals with deep compare on parent in order to pinpoint midmatched models. Unit testing setup. 2024-05-17 21:24:58 -04:00
Hedden, Kyle Matthew
7557e913a2 Digital PCT265 defect CXTDT-546581: Tabs page state tracking. 2024-05-17 14:42:35 -04:00
Hedden, Kyle Matthew
52e8ce7621 Digital PCT265 story PCT-135: Prevent registering table cells on ListViewTemplate handleNewData when the page is not changing. 2024-05-16 10:20:31 -04:00
Hedden, Kyle Matthew
eac64ec506 Digital PCT265 story PCT-135: handleNewData logic fix for orginalModel comparison. 2024-05-15 22:25:44 -04:00
Hedden, Kyle Matthew
ffc36c309f Digital PCT265 story PCT-135: More isEquals. Fix replaceChildMolecule signature for TabsListItemModel. 2024-05-15 22:24:03 -04:00
Hedden, Kyle Matthew
cd5d9b0c4a Digital PCT265 story PCT-135: Pager fix. TwoButtonViewModel isEqual. 2024-05-14 20:30:11 -04:00
Hedden, Kyle Matthew
32deda3d3d Digital PCT265 story PCT-135: Code review comments, cleanups and isEquals expansion. 2024-05-13 21:23:00 -04:00
Hedden, Kyle Matthew
f37e7abcb1 Digital PCT265 story PCT-135: Inline replacement updates with the core render loop. 2024-05-13 14:46:35 -04:00
Bruce, Matt R
ee3fccd708 Merge branch 'bugfix/CXTDT-552665' into 'develop'
CXTDT-552665 Fixing top notification close button

### Summary
Fixed dismiss action for "noop" in topNotification.

### JIRA Ticket
https://onejira.verizon.com/browse/CXTDT-552665

Co-authored-by: Nandhini Rajendran <nandhini.rajendran@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1113
2024-05-13 13:25:10 +00:00
Hedden, Kyle Matthew
9de1437edc Digital PCT265 story ONEAPP-7249 - Prevent SplitViewController forced layouts on every newDataBuildScreen update. 2024-05-08 20:36:17 -04:00
Hedden, Kyle Matthew
04581558e3 Digital PCT265 story ONEAPP-7249 - isVisuallyEquivalent build out to work with stabilizing carousel refreshes. 2024-05-08 20:34:08 -04:00
Hedden, Kyle Matthew
067f63e6de Digital PCT265 story ONEAPP-7249 - Fix notification retain cycle. 2024-05-08 17:49:33 -04:00
Scott Pfeil
7e4b2a781d Digital ACT191 story ONEAPP-7847 - neonYellow and monarchRed 2024-05-08 15:28:43 -04:00
Nandhini Rajendran
b6ac373e0f Addressing review comments. 2024-05-08 21:01:07 +05:30
Hedden, Kyle Matthew
658850400f Merge remote-tracking branch 'refs/remotes/origin/develop' 2024-05-08 10:12:25 -04:00
Scott Pfeil
2bf63fcb1a Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui into feature/monarch 2024-05-08 09:56:58 -04:00
Hedden, Kyle Matthew
283fc2c17f Digital PCT265 story ONEAPP-7249 - Relax over aggressive polling on model updates. 2024-05-07 23:29:25 -04:00
Hedden, Kyle Matthew
31096a15a5 Digital PCT265 story ONEAPP-7249 - Prevent UI updates when there are no model changes. 2024-05-07 23:28:53 -04:00
Nandhini Rajendran
c628616e4a Remove NotificationXButton class 2024-05-08 08:25:54 +05:30
Nandhini Rajendran
91cee993b3 CXTDT-552665 Fixing top notification close button 2024-05-08 08:01:14 +05:30
Bruce, Matt R
758a7f686b Merge branch 'bugfix/atomic_headers_deprecated' into 'develop'
Digital ACT191 story ONEAPP-7718 - Bugfix for headlineBody legacy mapping to...

### Summary
Bugfix for headlineBody legacy mapping to titleLockup. Remove clipsToBounds to allow shadows.

### JIRA Ticket
https://onejira.verizon.com/browse/ONEAPP-7718

Co-authored-by: Scott Pfeil <Scott.Pfeil3@verizonwireless.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1112
2024-05-07 23:05:45 +00:00
Scott Pfeil
861c6fd4d4 Digital ACT191 story ONEAPP-7718 - Bugfix for headlineBody legacy mapping to titleLockup. Remove clipsToBounds to allow shadows. 2024-05-07 18:52:33 -04:00
Matt Bruce
7e722c07d4 Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui.git into feature/monarch 2024-05-07 16:48:58 -05:00
Pfeil, Scott Robert
07db477416 Merge branch 'feature/vds-titleLockup-update' into 'develop'
TextColor enums for TitleLockup/Tilelet

### Summary
For TitleLockup there are enum values that pertain to what color palette is used.

### JIRA Ticket
https://onejira.verizon.com/browse/ONEAPP-7847

Co-authored-by: Matt Bruce <matt.bruce@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1111
2024-05-07 21:38:46 +00:00
Matt Bruce
e7576ab19b removed old comments
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-05-07 16:37:06 -05:00
Matt Bruce
d07825c753 added back the TextColor enums for TitleLockup/Tilelet
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-05-07 16:32:48 -05:00
Matt Bruce
f71d991b9d Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui.git into feature/monarch 2024-05-07 14:28:12 -05:00
Pfeil, Scott Robert
208fbd4824 Merge branch 'feature/vds-titleLockup-update' into 'develop'
Updated against new TitleLockup

### Summary
Updated to fix issues with the VDS TitleLockup text color changes.

### JIRA Ticket

Co-authored-by: Matt Bruce <matt.bruce@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1110
2024-05-07 18:51:34 +00:00
Matt Bruce
c0d0e6f627 added to look at the Color(name: after VDS
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-05-07 13:29:47 -05:00
Matt Bruce
ddc1d5002c removed subtitleColor since this is now textColor for the label
added textColor into the API for the model to read textColor of label

Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-05-07 13:29:26 -05:00
Matt Bruce
3e8c53ecdf updated enums
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-05-07 13:28:17 -05:00
Matt Bruce
d7fd6f4465 added eyebrowModel
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-05-07 13:26:39 -05:00
Scott Pfeil
ef26c27452 Digital ACT191 story ONEAPP-7847 - Updating to use the vds core tokens library for monarch colors 2024-05-07 12:04:13 -04:00
Scott Pfeil
866f213dd8 Merge branch 'feature/monarch' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui into feature/monarch 2024-05-07 10:50:47 -04:00
Scott Pfeil
272465008f Digital ACT191 story ONEAPP-7847 - Updating the VDS tokens library 2024-05-07 10:46:05 -04:00
Scott Pfeil
7162c3b996 Merge branch 'feature/monarch' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui into feature/monarch 2024-05-06 17:38:45 -04:00
Scott Pfeil
0c338b7ce6 Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui into feature/monarch 2024-05-03 15:21:11 -04:00
Hedden, Kyle Matthew
4cd43dcfbe Merge branch 'bugfix/carousel_indicator_missing' into 'develop'
Digital ACT191 defect - Carousel indicator disappearing fix.

### Summary
Missing carousel indicator.

Co-authored-by: Scott Pfeil <Scott.Pfeil3@verizonwireless.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1109
2024-05-03 19:19:22 +00:00
Scott Pfeil
1c953bcccb Digital ACT191 defect - fix logic flip 2024-05-03 15:02:06 -04:00
Hedden, Kyle Matthew
7a948b3556 Merge branch 'feature/tile_container_colors' into 'develop'
Digital PCT265 story ONEAPP-7592 - Updates to tile container to allow custom colors.

### Summary
Updating tile container to allow any color

### JIRA Ticket
https://onejira.verizon.com/browse/ONEAPP-7592

Co-authored-by: Scott Pfeil <Scott.Pfeil3@verizonwireless.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1108
2024-05-03 16:55:40 +00:00
Scott Pfeil
6f92282a1d Digital ACT191 defect - Carousel indicator disappearing fix. 2024-05-03 12:54:17 -04:00
Hedden, Kyle Matthew
fd296b9623 Digital PCT265 story ONEAPP-7249 - Reduce full cell reloads on updates. 2024-05-02 19:21:29 -04:00
Scott Pfeil
55050bf084 merge 2024-05-02 11:53:00 -04:00
Scott Pfeil
16cd1601ba Digital ACT191 story ONEAPP-7459 - Update back to Vivid Red 2024-05-01 14:47:37 -04:00
Hedden, Kyle Matthew
3f77a261bc Digital PCT265 story ONEAPP-7249 - Polling behavior fixes and logging for clarity. 2024-04-30 20:36:49 -04:00
Scott Pfeil
a0168d6e38 Digital PCT265 story ONEAPP-7592 - Warning fixes 2024-04-30 16:13:25 -04:00
Scott Pfeil
895f0181ec Digital PCT265 story ONEAPP-7592 - Updates to tile container to allow custom colors. 2024-04-30 16:03:48 -04:00
Scott Pfeil
c5fa1a2515 Digital ACT191 story ONEAPP-7592 - icon updates 2024-04-30 13:11:39 -04:00
Scott Pfeil
b0c2a301eb Digital ACT191 story ONEAPP-7592 - Color Updates to allow strings or hash 2024-04-30 12:32:15 -04:00
Scott Pfeil
58c462c15e Merge branch 'feature/monarch' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui into feature/monarch 2024-04-30 11:03:33 -04:00
Scott Pfeil
f635cd4e84 Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui into feature/monarch 2024-04-30 11:03:06 -04:00
Scott Pfeil
efa90aaa10 Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui into feature/monarch 2024-04-30 09:29:53 -04:00
Scott Pfeil
7eb0d64237 Digital ACT191 story ONEAPP-7592 - Monarch testing 2024-04-29 19:26:49 -04:00
Hedden, Kyle Matthew
0ab05f4206 Merge remote-tracking branch 'refs/remotes/origin/develop' 2024-04-26 15:43:56 -04:00
Hedden, Kyle Matthew
5bfd2ed85c Merge branch 'bugfix/CXTDT-531317' into 'develop'
Digital PCT265 defect CXTDT-531317 - Throw error during decode when pageType is empty.

### Summary
Error logging updates.

### JIRA Ticket
https://onejira.verizon.com/browse/CXTDT-531317

Co-authored-by: Pfeil, Scott Robert <scott.pfeil3@verizonwireless.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1104
2024-04-26 14:30:13 +00:00
Hedden, Kyle Matthew
c5dd5ed4e7 Digital PCT265 story ONEAPP-7249 - Prevent forcing immediate layouts on cell changes which causes scroll stagger and carousel width double layouts. 2024-04-25 19:34:36 -04:00
Scott Pfeil
b2cfc810cf Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui into feature/monarch 2024-04-25 16:36:18 -04:00
Pfeil, Scott Robert
9518e34d5d Merge branch 'feature/atomic_vds_badgeIndicator_buttonIcon_tileContainer' into 'develop'
Property Updates that were missing

### Summary 
VDS Integration for new Atomic Components for BadgeIndicator, ButtonIcon, TileContainer

### JIRA Ticket

- BadgeIndicator - https://onejira.verizon.com/browse/ONEAPP-6305
- ButtonIcon - https://onejira.verizon.com/browse/ONEAPP-6315 
- TileContainer - https://onejira.verizon.com/browse/ONEAPP-6679

Co-authored-by: Matt Bruce <matt.bruce@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1105
2024-04-25 20:25:19 +00:00
Matt Bruce
6e0b135f30 forgot to add the action
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-04-25 15:14:55 -05:00
Hedden, Kyle Matthew
9d801e7028 Digital PCT265 defect CXTDT-531317 - Adjust logging to capture webview errors. 2024-04-25 15:58:27 -04:00
Matt Bruce
ce8b5b85cb sync properties
also ensured same properties were in

Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-04-25 14:56:00 -05:00
Hedden, Kyle Matthew
e06788ca66 Digital PCT265 defect CXTDT-531317 - Throw error during decode when pageType is empty. 2024-04-25 15:51:35 -04:00
Scott Pfeil
0033009bb9 Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui into feature/monarch 2024-04-25 12:48:41 -04:00
Pfeil, Scott Robert
4c371b1875 Merge branch 'feature/atomic_vds_badgeIndicator_buttonIcon_tileContainer' into 'develop'
Batch for BadgeIndicator, ButtonIcon, TileContainer

### Summary
VDS Integration for new Atomic Components for BadgeIndicator, ButtonIcon, TileContainer

### JIRA Ticket
BadgeIndicator - https://onejira.verizon.com/browse/ONEAPP-6305
ButtonIcon - https://onejira.verizon.com/browse/ONEAPP-6315
TileContainer - https://onejira.verizon.com/browse/ONEAPP-6679

Co-authored-by: Matt Bruce <matt.bruce@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1096
2024-04-25 15:02:40 +00:00
Matt Bruce
e25a0cadc1 updated nameforreuse
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-04-25 09:55:50 -05:00
Matt Bruce
9292e6a8d0 set the molecule to the moleculeView found
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-04-25 09:18:49 -05:00
Matt Bruce
0f3d7c1320 removed setting the molecule to nil
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-04-25 09:13:25 -05:00
Matt Bruce
50099b1cd6 Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui.git into feature/atomic_vds_badgeIndicator_buttonIcon_tileContainer 2024-04-25 09:10:58 -05:00
Matt Bruce
dac8711258 ensure molecule is removed from parent
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-04-25 09:07:40 -05:00
Matt Bruce
725d80b5ce added praentmoleculemodel protocol
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-04-24 17:24:20 -05:00
Matt Bruce
980ffaee67 removed carriage return
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-04-24 17:15:36 -05:00
Matt Bruce
c9589e9b94 added nameforReuse
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-04-24 17:15:11 -05:00
Scott Pfeil
1a417300d2 Merge branch 'develop' into feature/monarch 2024-04-24 11:43:03 -04:00
Scott Pfeil
01371a320a Digital ACT191 story ONV9720_MVAPP - Updated colors and icons for Monarch MVP 2024-04-24 11:37:31 -04:00
Pfeil, Scott Robert
35088ae446 Merge branch 'develop' into 'release/11_6_0'
Develop merge

Co-authored-by: Hedden, Kyle Matthew <kyle.hedden@verizonwireless.com>
Co-authored-by: Xi Zhang <xi.zhang@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1103
2024-04-23 23:19:35 +00:00
Hedden, Kyle Matthew
3f93f1654b Merge branch 'feature/MVAPCT-1-Offline-Network-Feedback' into 'develop'
Provide an API for checking selected date is today.

Provide an API for checking if selected date is today.

JIRA Ticket
https://onejira.verizon.com/browse/MVAPCT-1

Co-authored-by: Xi Zhang <xi.zhang@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1101
2024-04-23 23:15:32 +00:00
Pfeil, Scott Robert
8db7a3f696 Merge branch 'bugfix/PRODDEF-28200' into 'release/11_6_0'
Digital PCT265 defect PRODDEF-28200 - Prevent navigation to the same selected...

### Summary
Prevent navigation to the same selected index fixing hang ups.

### JIRA Ticket
https://onejira.verizon.com/browse/PRODDEF-28200

Co-authored-by: Hedden, Kyle Matthew <kyle.hedden@verizonwireless.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1102
2024-04-23 23:09:35 +00:00
Hedden, Kyle Matthew
f3f779f702 Digital PCT265 defect PRODDEF-28200 - Prevent navigation to the same selected index fixing hang ups. 2024-04-23 19:00:27 -04:00
Xi Zhang
5698f1f5c1 Provide an API for checking selected date is today. 2024-04-23 17:18:59 -04:00
Scott Pfeil
b8526ac8e1 Monarch colors 2024-04-23 17:00:22 -04:00
Scott Pfeil
056e56c15d Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui into feature/monarch 2024-04-23 11:27:07 -04:00
Hedden, Kyle Matthew
7488ba3bcb Merge branch 'bugfix/CXTDT-546577' into 'develop'
Digital PCT265 defect CXTDT-546577 - Remove transcendsPageUpdates to prevent replace duplication.

### Summary
Remove transcendsPageUpdates to prevent replace duplication.

### JIRA Ticket
https://onejira.verizon.com/browse/CXTDT-546577

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1099
2024-04-23 14:14:49 +00:00
Hedden, Kyle Matthew
adda10efb0 Digital PCT265 defect CXTDT-546577 - Logging for clarity. 2024-04-23 09:41:35 -04:00
Hedden, Kyle Matthew
652fcddcda Digital PCT265 defect CXTDT-546577 - Remove transcendsPageUpdates to prevent multiple replaces from muliple ReplaceMoleculeBehaviors listening and replacing. 2024-04-23 09:40:22 -04:00
Pfeil, Scott Robert
061959a7eb Merge branch 'bugfix/CXTDT-546577' into 'develop'
Digital PCT265 defect CXTDT-546577 - Track UI updates from module changes.

### Summary
Create feedback loop for module UI changes.

### JIRA Ticket
https://onejira.verizon.com/browse/CXTDT-546577

Co-authored-by: Hedden, Kyle Matthew <kyle.hedden@verizonwireless.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1098
2024-04-19 17:36:51 +00:00
Hedden, Kyle Matthew
94c66488ee Merge remote-tracking branch 'refs/remotes/origin/develop' 2024-04-18 14:23:26 -04:00
Hedden, Kyle Matthew
c48eab03ec Digital PCT265 defect CXTDT-546577 - Track UI updates from module changes. 2024-04-17 19:23:45 -04:00
Scott Pfeil
f660eeb9b8 Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui into feature/monarch 2024-04-17 17:26:38 -04:00
Pfeil, Scott Robert
76a50b1fda Merge branch 'bugfix/vds-tilecontainer-padding' into 'develop'
VDS Team removed 2x and replaced with 3x in the spec.

### Summary
Figma Spec update

### JIRA Ticket
CXTDT-544383 - TileContainer - Removed spacing2x and replaced with spacing3x

Co-authored-by: Matt Bruce <matt.bruce@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1097
2024-04-17 21:25:43 +00:00
Matt Bruce
185912467e VDS Team removed 2x and replaced with 3x in the spec.
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-04-17 16:24:03 -05:00
Scott Pfeil
16d9f59142 Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui into feature/monarch 2024-04-17 17:06:45 -04:00
Matt Bruce
c87bbb3a78 refdactored to use better codable for the BackgroundEffect Enum
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-04-17 09:43:50 -05:00
Matt Bruce
0ddf76b576 refactored out base enums into base model
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-04-16 15:15:02 -05:00
Matt Bruce
08a2079654 rearranged
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-04-16 14:35:56 -05:00
Matt Bruce
03318e863f refactored backgroundEffect
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-04-16 14:27:17 -05:00
Matt Bruce
eccf721447 Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui.git into feature/atomic_vds_badgeIndicator_buttonIcon_tileContainer 2024-04-16 11:57:08 -05:00
Matt Bruce
f5d9423b1b removed code not nedded
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-04-16 11:47:08 -05:00
Matt Bruce
300047fdbe updated the loadImage
made ViewModelMolecule optional

Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-04-16 10:45:47 -05:00
Matt Bruce
44cbeeb695 refactored the Tilelet with missing tilecontainer properties
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-04-15 15:16:28 -05:00
Matt Bruce
61a5f4d7d1 registered tilecontainer
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-04-15 15:16:12 -05:00
Matt Bruce
6e5abcc912 added tileContainer view/model
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-04-15 15:14:56 -05:00
Matt Bruce
122f5b6c97 added ButtonIcon
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-04-15 13:12:15 -05:00
Matt Bruce
02973badbd refactor
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-04-15 13:12:04 -05:00
Hedden, Kyle Matthew
70bc766c41 Merge branch 'bugfix/PRODDEF-24073' into 'develop'
Added missing code

### Summary
Checkbox label accessibility changes

### JIRA Ticket
https://onejira.verizon.com/browse/PRODDEF-24073

Co-authored-by: Krishna Kishore Bandaru <krishna.kishore.bandaru@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1092
2024-04-15 17:35:00 +00:00
Pfeil, Scott Robert
f6b73712fb Merge branch 'feature/atomic_vds_notification' into 'develop'
Atomic VDS Notification Integration

### Summary
Atomic VDS Notification Integration

### JIRA Ticket
https://onejira.verizon.com/browse/ONEAPP-6358

Co-authored-by: Matt Bruce <matt.bruce@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1095
2024-04-15 15:12:32 +00:00
Matt Bruce
0c474a2764 Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui.git into feature/atomic_vds_badgeIndicator_buttonIcon_tileContainer 2024-04-12 13:11:01 -05:00
Matt Bruce
c6fccb014a initial button icon
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-04-12 13:10:51 -05:00
Matt Bruce
a74362cc0c fixed issue with taking out ContainerModel
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-04-12 13:06:15 -05:00
Matt Bruce
1376752c8a Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui.git into feature/atomic_vds_notification 2024-04-12 12:46:06 -05:00
Hedden, Kyle Matthew
44fc093b7d Merge branch 'bugfix/vds-tokens-update' into 'develop'
Removed old frameworks to add the 1 primary VDSTokens

### Summary
Removed the old 3 frameworks to use the now 1 merge of 6 frameworks that contain the Tokens/Contants.

Co-authored-by: Matt Bruce <matt.bruce@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1091
2024-04-12 17:27:14 +00:00
Matt Bruce
c50e6adfd6 removed embed
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-04-12 12:22:59 -05:00
Matt Bruce
59a5c6a3e7 added BadgeIndicator Atom
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-04-12 10:22:12 -05:00
Matt Bruce
1edffd8e24 added encoding for inverted
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-04-12 08:39:28 -05:00
Hedden, Kyle Matthew
0cb04e3700 Merge branch 'release/11_5_0' into 'develop'
release/11_5_0 hotfix merge

Co-authored-by: Scott Pfeil <Scott.Pfeil3@verizonwireless.com>
Co-authored-by: Bruce, Matt R <matt.bruce@one.verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1093
2024-04-12 13:39:00 +00:00
Matt Bruce
79cccbb471 removed ContainerModel
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-04-12 08:38:02 -05:00
Matt Bruce
8fd6a2e7c4 removed background color coding
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-04-11 14:08:21 -05:00
Matt Bruce
473c98cca4 removed color since now this is driven by vds
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-04-11 14:04:12 -05:00
Matt Bruce
1048a29891 added rbg helper to UIColor extension
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-04-11 13:06:39 -05:00
Matt Bruce
7d6591a394 default implementation for model in protocol used for vds component integration
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-04-11 12:29:28 -05:00
Matt Bruce
ae8f19ba51 set default color to black
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-04-11 12:28:31 -05:00
Matt Bruce
277f54599e omit text color
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-04-11 12:28:18 -05:00
Matt Bruce
bd93cfdfe8 map notification label to topLabel
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-04-11 12:28:02 -05:00
Matt Bruce
b23351386b using helper now
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-04-10 16:56:59 -05:00
Matt Bruce
89e6ea43d0 put back to NotificationXBUttonModel
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-04-10 16:56:51 -05:00
Matt Bruce
2e1bb7358f added executeAction helper method
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-04-10 16:55:58 -05:00
Matt Bruce
f6a29a734c updated collapsablenotification view/model
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-04-10 14:01:26 -05:00
Matt Bruce
5fbf076aa7 refactored NotificationMoleculeView/Model
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-04-10 13:40:09 -05:00
Matt Bruce
077ee85dc0 removed ternary
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-04-10 13:39:45 -05:00
Scott Pfeil
9446899ca7 Digital ACT191 story - Monarch Testing 2024-04-09 17:07:14 -04:00
Hedden, Kyle Matthew
206395ea85 Merge branch 'bugfix/missing_deprecated_headlinebody_decode' into 'release/11_5_0'
Bugfix/missing deprecated headlinebody decode

### Summary
Bugfix for missing deprecated decodes for headers

Co-authored-by: Scott Pfeil <Scott.Pfeil3@verizonwireless.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1094
2024-04-09 15:06:56 +00:00
Scott Pfeil
c4dad0bddd Digital PCT265 bugfix - Added missing deprecated decodes for headers. 2024-04-09 11:00:15 -04:00
Bruce, Matt R
f40c0b8b9e Merge branch 'feature/feed_cache' into 'release/11_5_0'
Feature/feed cache

### Summary
Persistently Cached Discover

### JIRA Ticket
https://onejira.verizon.com/browse/MVAPCT-48

Co-authored-by: Scott Pfeil <Scott.Pfeil3@verizonwireless.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1086
2024-04-05 20:17:43 +00:00
Pfeil, Scott Robert
add7eee2f7 Merge branch 'bugfix/CXTDT-537495' into 'develop'
Digital PCT265 defect CXTDT-537495

### Summary
Retail store locator crash fix.

### JIRA Ticket
https://onejira.verizon.com/browse/CXTDT-537495

Co-authored-by: Hedden, Kyle Matthew <kyle.hedden@verizonwireless.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1085
2024-04-03 16:36:51 +00:00
Pfeil, Scott Robert
52f93e86cc Merge branch 'bugfix/CXTDT-538262' into 'develop'
Digital ACT191 defect CXTDT-538262 - 'Fix tab selection flicker.'

### Summary
Update the tab selection logic to occur in a single table transaction to animate smoothly.

### JIRA Ticket
https://onejira.verizon.com/browse/CXTDT-538262

Co-authored-by: Hedden, Kyle Matthew <kyle.hedden@verizonwireless.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1089
2024-04-03 13:51:17 +00:00
Krishna Kishore Bandaru
da701bac23 Added missing code 2024-04-03 18:18:54 +05:30
Matt Bruce
494a729658 update to point to the new VDSTokens framework
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-04-02 15:02:39 -05:00
Scott Pfeil
36eaaf97df Digital PCT265 story MVAPCT-48 - Remove animating of navigation bar shown 2024-03-28 13:36:28 -04:00
Hedden, Kyle Matthew
6a3bbc2a45 Digital ACT191 defect CXTDT-538262 - Switch tab selection over to a single transaction action to blend the animation. 2024-03-27 23:48:40 -04:00
Scott Pfeil
efbeadf809 Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui into feature/feed_cache 2024-03-27 09:14:48 -04:00
Scott Pfeil
a913c744c3 Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui into feature/feed_cache 2024-03-26 11:17:18 -04:00
Hedden, Kyle Matthew
6b2ac01028 Open heightForRowAt delegate method. Add index safety fetch to getMoleculeInfo given optional return. 2024-03-26 10:06:51 -04:00
Scott Pfeil
314f2e91cb Manager updates for navigating to controller. 2024-03-25 13:29:36 -04:00
Hedden, Kyle Matthew
fca60ace66 switch to manual runner 2023-11-15 18:10:24 -05:00
Hedden, Kyle Matthew
47050e3c03 remove gitlab stages to disable 2023-11-15 18:02:50 -05:00
296 changed files with 10911 additions and 3518 deletions

View File

@ -12,6 +12,7 @@ stages:
# - xcode_12_2
download_artifacts:
when: manual
stage: download
script:
- ./Scripts/download_dependencies.sh
@ -27,6 +28,7 @@ download_artifacts:
ARTIFACTORY_URL: https://oneartifactoryci.verizon.com/artifactory
build_project:
when: manual
stage: build
script:
- ./Scripts/build_aggregate.sh
@ -37,6 +39,7 @@ build_project:
- xcode_12_2
deploy_snapshot:
when: manual
stage: deploy
script:
- cd Scripts && ./upload_core_ui_frameworks.sh

View File

@ -126,7 +126,6 @@
0AE98BB523FF18D2004C5109 /* Arrow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE98BB423FF18D2004C5109 /* Arrow.swift */; };
0AE98BB723FF18E9004C5109 /* ArrowModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE98BB623FF18E9004C5109 /* ArrowModel.swift */; };
0AF60F0926B3316E00AC3DB4 /* MVMCoreUIUtility+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AF60F0826B3316E00AC3DB4 /* MVMCoreUIUtility+Extension.swift */; };
187FEB2A2844D2A600BF29C2 /* VDSFormControlsTokens.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 187FEB292844D2A600BF29C2 /* VDSFormControlsTokens.xcframework */; };
1D6D258826899B0C00DEBB08 /* ImageButtonModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D6D258626899B0B00DEBB08 /* ImageButtonModel.swift */; };
1D6D258926899B0C00DEBB08 /* ImageButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D6D258726899B0B00DEBB08 /* ImageButton.swift */; };
22B678F929E7944E00CF4196 /* GetNotificationAuthStatusBehavior.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22B678F829E7944E00CF4196 /* GetNotificationAuthStatusBehavior.swift */; };
@ -153,6 +152,10 @@
444FB7C12821B73200DFE692 /* TitleLockup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 444FB7C02821B73200DFE692 /* TitleLockup.swift */; };
444FB7C32821B76B00DFE692 /* TitleLockupModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 444FB7C22821B76B00DFE692 /* TitleLockupModel.swift */; };
4457904E27ECE989002B1E1E /* UIImageRenderingMode+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4457904D27ECE989002B1E1E /* UIImageRenderingMode+Extension.swift */; };
4B002ACA2BD855EC009BC9C1 /* DateDropdownEntryFieldModel+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B002AC92BD855EC009BC9C1 /* DateDropdownEntryFieldModel+Extension.swift */; };
4B3408A22C3873B0003BFABF /* CircularProgressBarModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B3408A12C3873B0003BFABF /* CircularProgressBarModel.swift */; };
4B3408A42C3873E8003BFABF /* CircularProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B3408A32C3873E8003BFABF /* CircularProgressBar.swift */; };
4B53AF7B2C45BBBA00274685 /* GraphSizeProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B53AF7A2C45BBBA00274685 /* GraphSizeProtocol.swift */; };
522679C123FE886900906CBA /* ListLeftVariableCheckboxAllTextAndLinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 522679BF23FE886900906CBA /* ListLeftVariableCheckboxAllTextAndLinks.swift */; };
522679C223FE886900906CBA /* ListLeftVariableCheckboxAllTextAndLinksModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 522679C023FE886900906CBA /* ListLeftVariableCheckboxAllTextAndLinksModel.swift */; };
52267A0723FFE25000906CBA /* ListOneColumnFullWidthTextAllTextAndLinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52267A0623FFE25000906CBA /* ListOneColumnFullWidthTextAllTextAndLinks.swift */; };
@ -170,12 +173,16 @@
52B201D324081CFB00D2011E /* ListLeftVariableRadioButtonAndPaymentMethodModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52B201D124081CFB00D2011E /* ListLeftVariableRadioButtonAndPaymentMethodModel.swift */; };
5822720B2B1FC55F00F75BAE /* AccessibilityHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 582272092B1FC55F00F75BAE /* AccessibilityHandler.swift */; };
5822720C2B1FC55F00F75BAE /* RotorHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5822720A2B1FC55F00F75BAE /* RotorHandler.swift */; };
583335592BF64E77001D90D7 /* MVMCoreUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 583335582BF64E77001D90D7 /* MVMCoreUITests.swift */; };
5833355A2BF64E77001D90D7 /* MVMCoreUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D29DF0CC21E404D4003B2FB9 /* MVMCoreUI.framework */; };
583335632BF6509C001D90D7 /* UAD_page_model.json in Resources */ = {isa = PBXBuildFile; fileRef = 583335622BF6509C001D90D7 /* UAD_page_model.json */; };
583335652BF6A5C3001D90D7 /* TestUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 583335642BF6A5C3001D90D7 /* TestUtils.swift */; };
583335672BF6DCD0001D90D7 /* UAD_page_model_2.json in Resources */ = {isa = PBXBuildFile; fileRef = 583335662BF6DCD0001D90D7 /* UAD_page_model_2.json */; };
5833356D2BFBF51C001D90D7 /* UAD_page_model_3.json in Resources */ = {isa = PBXBuildFile; fileRef = 5833356C2BFBF51C001D90D7 /* UAD_page_model_3.json */; };
5846ABF62B4762A600FA6C76 /* PollingBehaviorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5846ABF52B4762A600FA6C76 /* PollingBehaviorModel.swift */; };
5870636F2ACF238E00CA18D5 /* ReadableDecodingErrors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5870636E2ACF238E00CA18D5 /* ReadableDecodingErrors.swift */; };
58A9DD7D2AC2103300F5E0B0 /* ReplaceableMoleculeBehaviorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58A9DD7C2AC2103300F5E0B0 /* ReplaceableMoleculeBehaviorModel.swift */; };
58E7561D2BE04C320088BB5D /* MoleculeComparisonProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58E7561C2BE04C320088BB5D /* MoleculeComparisonProtocol.swift */; };
608211282AC6B57E00C3FC39 /* MVMCoreUILoggingHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 608211262AC6AF8200C3FC39 /* MVMCoreUILoggingHandler.swift */; };
7199C8162A4F3A64001568B7 /* AccessibilityHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7199C8152A4F3A64001568B7 /* AccessibilityHandler.swift */; };
71BE969E2AD96BE6000B5DB7 /* RotorHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71BE969D2AD96BE6000B5DB7 /* RotorHandler.swift */; };
8D070BB0241B56530099AC56 /* ListRightVariableTotalDataModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D070BAF241B56530099AC56 /* ListRightVariableTotalDataModel.swift */; };
8D070BB2241B56AD0099AC56 /* ListRightVariableTotalData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D070BB1241B56AD0099AC56 /* ListRightVariableTotalData.swift */; };
8D084AD02410BF4800951227 /* ListOneColumnFullWidthTextBodyTextModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D084ACF2410BF4800951227 /* ListOneColumnFullWidthTextBodyTextModel.swift */; };
@ -222,9 +229,6 @@
94C2D9AB23872EB50006CF46 /* LabelAttributeActionModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94C2D9AA23872EB50006CF46 /* LabelAttributeActionModel.swift */; };
94C661D923CCF4B400D9FE5B /* LeftRightLabelModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9402C34F23A2CEA3004B974C /* LeftRightLabelModel.swift */; };
94C661DA23CCF4FB00D9FE5B /* UIColor+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AA33B33239813C50067DD0F /* UIColor+Extension.swift */; };
94CA227C24058534002D6750 /* VerizonNHGeTX-Bold.otf in Resources */ = {isa = PBXBuildFile; fileRef = 94CA227824058533002D6750 /* VerizonNHGeTX-Bold.otf */; };
94CA227D24058534002D6750 /* VerizonNHGeDS-Regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = 94CA227924058533002D6750 /* VerizonNHGeDS-Regular.otf */; };
94CA227E24058534002D6750 /* VerizonNHGeDS-Bold.otf in Resources */ = {isa = PBXBuildFile; fileRef = 94CA227A24058533002D6750 /* VerizonNHGeDS-Bold.otf */; };
94F6516D2437954100631BF9 /* Tabs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94F6516C2437954100631BF9 /* Tabs.swift */; };
AA07EA912510A442009A2AE3 /* StarModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA07EA902510A442009A2AE3 /* StarModel.swift */; };
AA07EA932510A451009A2AE3 /* Star.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA07EA922510A451009A2AE3 /* Star.swift */; };
@ -292,6 +296,7 @@
AF1C336F2885A16A006B1001 /* ActionCollapseNotificationHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF1C336E2885A16A006B1001 /* ActionCollapseNotificationHandler.swift */; };
AF1C33712885AE76006B1001 /* MVMCoreUIActionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF1C33702885AE76006B1001 /* MVMCoreUIActionHandler.swift */; };
AF1C33732885D481006B1001 /* MVMCoreUIActionOpenPageHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF1C33722885D481006B1001 /* MVMCoreUIActionOpenPageHandler.swift */; };
AF1CEFE82BEA73890001F9A5 /* VDSCoreTokens.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = AF1CEFE72BEA73890001F9A5 /* VDSCoreTokens.xcframework */; };
AF60A7F62892D2E300919EEB /* ActionDismissNotificationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF60A7F52892D2E300919EEB /* ActionDismissNotificationModel.swift */; };
AF60A7F82892D34D00919EEB /* ActionDismissNotificationHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF60A7F72892D34D00919EEB /* ActionDismissNotificationHandler.swift */; };
AF766D262A3CD4C600749099 /* UIAccessibilityTraits+Codable.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF766D252A3CD4C600749099 /* UIAccessibilityTraits+Codable.swift */; };
@ -302,7 +307,9 @@
AFA4932229E5EF2E001A9663 /* NotificationHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFA4932129E5EF2E001A9663 /* NotificationHandler.swift */; };
AFA4933F29E874F0001A9663 /* MVMCoreUILoggingDelegateProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFA4933E29E874F0001A9663 /* MVMCoreUILoggingDelegateProtocol.swift */; };
AFA4935729EE3DCC001A9663 /* AlertDelegateProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFA4935629EE3DCC001A9663 /* AlertDelegateProtocol.swift */; };
AFE4A1D127DFB5EE00C458D0 /* VDSColorTokens.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = AFE4A1D027DFB5EE00C458D0 /* VDSColorTokens.xcframework */; };
AFB6336E2C65166E00791221 /* GoneableProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFB6336D2C65166E00791221 /* GoneableProtocol.swift */; };
AFB633702C65175800791221 /* ActionUpdateVisibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFB6336F2C65175800791221 /* ActionUpdateVisibility.swift */; };
AFB633722C653C0900791221 /* ActionUpdateVisibilityModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFB633712C653C0900791221 /* ActionUpdateVisibilityModel.swift */; };
AFE4A1D627DFBB6F00C458D0 /* UINavigationController+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFE4A1D527DFBB6F00C458D0 /* UINavigationController+Extension.swift */; };
B4CC8FBD29DF34680005D28B /* Badge.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4CC8FBC29DF34680005D28B /* Badge.swift */; };
B4CC8FBF29DF34730005D28B /* BadgeModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4CC8FBE29DF34730005D28B /* BadgeModel.swift */; };
@ -438,7 +445,6 @@
D28764AC245898A400CB882D /* ThreeLayerFillMiddleTemplateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D28764AB245898A400CB882D /* ThreeLayerFillMiddleTemplateModel.swift */; };
D28764F9245A327200CB882D /* TwoLinkView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D28764F8245A327200CB882D /* TwoLinkView.swift */; };
D28764FB245A33A500CB882D /* TwoLinkViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D28764FA245A33A500CB882D /* TwoLinkViewModel.swift */; };
D287651A245B338E00CB882D /* VerizonNHGeTX-Regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = 94CA227B24058533002D6750 /* VerizonNHGeTX-Regular.otf */; };
D28A837923C7D5BC00DFE4FC /* PageModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D28A837823C7D5BC00DFE4FC /* PageModelProtocol.swift */; };
D28A837B23C928DA00DFE4FC /* MoleculeListCellProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D28A837A23C928DA00DFE4FC /* MoleculeListCellProtocol.swift */; };
D28A837D23CCA86A00DFE4FC /* TabsListItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D28A837C23CCA86A00DFE4FC /* TabsListItemModel.swift */; };
@ -562,7 +568,6 @@
D2ED27EE254B0CE700A1C293 /* ActionAlertModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2ED27E9254B0CE600A1C293 /* ActionAlertModel.swift */; };
D2ED27EF254B0CE700A1C293 /* AlertModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2ED27EA254B0CE700A1C293 /* AlertModel.swift */; };
D2ED27FC254B0E0300A1C293 /* AlertObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2ED27F3254B0E0200A1C293 /* AlertObject.swift */; };
D2FA83D22513EA6900564112 /* NotificationXButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2FA83D12513EA6900564112 /* NotificationXButton.swift */; };
D2FA83D42514F80C00564112 /* CollapsableNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2FA83D32514F80C00564112 /* CollapsableNotification.swift */; };
D2FA83D62515021F00564112 /* CollapsableNotificationTopView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2FA83D52515021F00564112 /* CollapsableNotificationTopView.swift */; };
D2FB151B23A2B65B00C20E10 /* MoleculeContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2FB151A23A2B65B00C20E10 /* MoleculeContainer.swift */; };
@ -575,11 +580,32 @@
DBEFFA04225A829700230692 /* Label.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB891E822253FA8500022516 /* Label.swift */; };
EA05EFA9278DDE2C00828819 /* ClearFormFieldEffectModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA05EFA8278DDE2C00828819 /* ClearFormFieldEffectModel.swift */; };
EA05EFAB278DE53600828819 /* ClearableModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA05EFAA278DE53600828819 /* ClearableModelProtocol.swift */; };
EA1758482BC97ED800A5C0D9 /* BadgeIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA1758472BC97ED800A5C0D9 /* BadgeIndicator.swift */; };
EA17584A2BC97EF100A5C0D9 /* BadgeIndicatorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA1758492BC97EF100A5C0D9 /* BadgeIndicatorModel.swift */; };
EA17584C2BC9894800A5C0D9 /* ButtonIconModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA17584B2BC9894800A5C0D9 /* ButtonIconModel.swift */; };
EA17584E2BC9895A00A5C0D9 /* ButtonIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA17584D2BC9895A00A5C0D9 /* ButtonIcon.swift */; };
EA1B02DE2C41BFD200F0758B /* RuleVDSModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA1B02DD2C41BFD200F0758B /* RuleVDSModel.swift */; };
EA1B02E02C470AFD00F0758B /* InputEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA1B02DF2C470AFD00F0758B /* InputEntryField.swift */; };
EA41F4AC2787927100F5B377 /* DynamicRuleFormFieldEffectModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA41F4AB2787927100F5B377 /* DynamicRuleFormFieldEffectModel.swift */; };
EA5124FD243601600051A3A4 /* BGImageHeadlineBodyButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA5124FC243601600051A3A4 /* BGImageHeadlineBodyButton.swift */; };
EA5124FF2436018E0051A3A4 /* BGImageHeadlineBodyButtonModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA5124FE2436018E0051A3A4 /* BGImageHeadlineBodyButtonModel.swift */; };
EA5DBDAB2C35B6C500290DF8 /* FormFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA5DBDAA2C35B6C500290DF8 /* FormFieldModel.swift */; };
EA6642912BCDA97300D81DC4 /* TileContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA6642902BCDA97300D81DC4 /* TileContainer.swift */; };
EA6642932BCDA97D00D81DC4 /* TileContainerModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA6642922BCDA97D00D81DC4 /* TileContainerModel.swift */; };
EA6E8B952B504A43000139B4 /* ButtonGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA6E8B942B504A43000139B4 /* ButtonGroup.swift */; };
EA6E8B972B504A4D000139B4 /* ButtonGroupModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA6E8B962B504A4D000139B4 /* ButtonGroupModel.swift */; };
EA7AE5472C73C01A00107C74 /* CheckboxesModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA7AE5462C73C01A00107C74 /* CheckboxesModel.swift */; };
EA7AE5492C7403DC00107C74 /* Checkboxes.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA7AE5482C7403DC00107C74 /* Checkboxes.swift */; };
EA7AE54B2C74CACA00107C74 /* RadioButtons.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA7AE54A2C74CACA00107C74 /* RadioButtons.swift */; };
EA7AE54D2C74CAD700107C74 /* RadioButtonsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA7AE54C2C74CAD700107C74 /* RadioButtonsModel.swift */; };
EA7AE54F2C74EB3700107C74 /* CalendarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA7AE54E2C74EB3700107C74 /* CalendarView.swift */; };
EA7AE5512C74EB4500107C74 /* CalendarViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA7AE5502C74EB4500107C74 /* CalendarViewModel.swift */; };
EA7AE5532C74F1F600107C74 /* DatePickerEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA7AE5522C74F1F600107C74 /* DatePickerEntryField.swift */; };
EA7AE5552C74F20600107C74 /* DatePickerEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA7AE5542C74F20600107C74 /* DatePickerEntryFieldModel.swift */; };
EA7AE55C2C7D18A100107C74 /* BreadcrumbsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA7AE55B2C7D18A100107C74 /* BreadcrumbsModel.swift */; };
EA7AE55E2C7D234500107C74 /* Breadcrumbs.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA7AE55D2C7D234500107C74 /* Breadcrumbs.swift */; };
EA7AE5602C7E554700107C74 /* PaginationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA7AE55F2C7E554700107C74 /* PaginationModel.swift */; };
EA7AE5622C7E555D00107C74 /* Pagination.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA7AE5612C7E555D00107C74 /* Pagination.swift */; };
EA7D81602B2B6E6800D29F9E /* Icon.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA7D815F2B2B6E6800D29F9E /* Icon.swift */; };
EA7D81622B2B6E7F00D29F9E /* IconModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA7D81612B2B6E7F00D29F9E /* IconModel.swift */; };
EA7D81642B2BABCB00D29F9E /* TooltipModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA7D81632B2BABCB00D29F9E /* TooltipModel.swift */; };
@ -589,7 +615,6 @@
EA985C3E2970938F00F2FF2E /* Tilelet.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA985C3D2970938F00F2FF2E /* Tilelet.swift */; };
EA985C402970939A00F2FF2E /* TileletModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA985C3F2970939A00F2FF2E /* TileletModel.swift */; };
EA985C602970A3F000F2FF2E /* VDS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EA985C5F2970A3F000F2FF2E /* VDS.framework */; };
EA985C642970A40E00F2FF2E /* VDSTypographyTokens.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = EA985C632970A40E00F2FF2E /* VDSTypographyTokens.xcframework */; };
EA985C852981AA9C00F2FF2E /* VDS-Enums+Codable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA985C842981AA9C00F2FF2E /* VDS-Enums+Codable.swift */; };
EA985C872981AB0F00F2FF2E /* VDS-Tilelet+Codable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA985C862981AB0F00F2FF2E /* VDS-Tilelet+Codable.swift */; };
EA985C892981AB7100F2FF2E /* VDS-TextStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA985C882981AB7100F2FF2E /* VDS-TextStyle.swift */; };
@ -607,6 +632,16 @@
FD99130028E21E4900542CC3 /* RuleNotEqualsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD9912FF28E21E4900542CC3 /* RuleNotEqualsModel.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
5833355B2BF64E77001D90D7 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = D29DF0C321E404D4003B2FB9 /* Project object */;
proxyType = 1;
remoteGlobalIDString = D29DF0CB21E404D4003B2FB9;
remoteInfo = MVMCoreUI;
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
01004F2F22721C3800991ECC /* RadioButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioButton.swift; sourceTree = "<group>"; };
0103B84D23D7E33A009C315C /* HeadlineBodyToggleModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadlineBodyToggleModel.swift; sourceTree = "<group>"; };
@ -729,7 +764,6 @@
0AE98BB423FF18D2004C5109 /* Arrow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Arrow.swift; sourceTree = "<group>"; };
0AE98BB623FF18E9004C5109 /* ArrowModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArrowModel.swift; sourceTree = "<group>"; };
0AF60F0826B3316E00AC3DB4 /* MVMCoreUIUtility+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MVMCoreUIUtility+Extension.swift"; sourceTree = "<group>"; };
187FEB292844D2A600BF29C2 /* VDSFormControlsTokens.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = VDSFormControlsTokens.xcframework; path = ../SharedFrameworks/VDSFormControlsTokens.xcframework; sourceTree = "<group>"; };
1D6D258626899B0B00DEBB08 /* ImageButtonModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageButtonModel.swift; path = MVMCoreUI/Atomic/Atoms/Buttons/ImageButtonModel.swift; sourceTree = SOURCE_ROOT; };
1D6D258726899B0B00DEBB08 /* ImageButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageButton.swift; path = MVMCoreUI/Atomic/Atoms/Buttons/ImageButton.swift; sourceTree = SOURCE_ROOT; };
22B678F829E7944E00CF4196 /* GetNotificationAuthStatusBehavior.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetNotificationAuthStatusBehavior.swift; sourceTree = "<group>"; };
@ -756,6 +790,10 @@
444FB7C02821B73200DFE692 /* TitleLockup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TitleLockup.swift; sourceTree = "<group>"; };
444FB7C22821B76B00DFE692 /* TitleLockupModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TitleLockupModel.swift; sourceTree = "<group>"; };
4457904D27ECE989002B1E1E /* UIImageRenderingMode+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImageRenderingMode+Extension.swift"; sourceTree = "<group>"; };
4B002AC92BD855EC009BC9C1 /* DateDropdownEntryFieldModel+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DateDropdownEntryFieldModel+Extension.swift"; sourceTree = "<group>"; };
4B3408A12C3873B0003BFABF /* CircularProgressBarModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CircularProgressBarModel.swift; sourceTree = "<group>"; };
4B3408A32C3873E8003BFABF /* CircularProgressBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CircularProgressBar.swift; sourceTree = "<group>"; };
4B53AF7A2C45BBBA00274685 /* GraphSizeProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GraphSizeProtocol.swift; sourceTree = "<group>"; };
522679BF23FE886900906CBA /* ListLeftVariableCheckboxAllTextAndLinks.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListLeftVariableCheckboxAllTextAndLinks.swift; sourceTree = "<group>"; };
522679C023FE886900906CBA /* ListLeftVariableCheckboxAllTextAndLinksModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListLeftVariableCheckboxAllTextAndLinksModel.swift; sourceTree = "<group>"; };
52267A0623FFE25000906CBA /* ListOneColumnFullWidthTextAllTextAndLinks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListOneColumnFullWidthTextAllTextAndLinks.swift; sourceTree = "<group>"; };
@ -773,12 +811,18 @@
52B201D124081CFB00D2011E /* ListLeftVariableRadioButtonAndPaymentMethodModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListLeftVariableRadioButtonAndPaymentMethodModel.swift; sourceTree = "<group>"; };
582272092B1FC55F00F75BAE /* AccessibilityHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccessibilityHandler.swift; sourceTree = "<group>"; };
5822720A2B1FC55F00F75BAE /* RotorHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RotorHandler.swift; sourceTree = "<group>"; };
583335562BF64E77001D90D7 /* MVMCoreUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MVMCoreUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
583335582BF64E77001D90D7 /* MVMCoreUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MVMCoreUITests.swift; sourceTree = "<group>"; };
583335622BF6509C001D90D7 /* UAD_page_model.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = UAD_page_model.json; sourceTree = "<group>"; };
583335642BF6A5C3001D90D7 /* TestUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestUtils.swift; sourceTree = "<group>"; };
583335662BF6DCD0001D90D7 /* UAD_page_model_2.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = UAD_page_model_2.json; sourceTree = "<group>"; };
5833356C2BFBF51C001D90D7 /* UAD_page_model_3.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = UAD_page_model_3.json; sourceTree = "<group>"; };
5846ABF52B4762A600FA6C76 /* PollingBehaviorModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PollingBehaviorModel.swift; sourceTree = "<group>"; };
5870636E2ACF238E00CA18D5 /* ReadableDecodingErrors.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadableDecodingErrors.swift; sourceTree = "<group>"; };
5878F0A42BD7E68800ADE23D /* mvmcoreui.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = mvmcoreui.xcconfig; sourceTree = "<group>"; };
5878F0A52BD7E6BE00ADE23D /* mvmcoreui_dev.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = mvmcoreui_dev.xcconfig; sourceTree = "<group>"; };
58A9DD7C2AC2103300F5E0B0 /* ReplaceableMoleculeBehaviorModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReplaceableMoleculeBehaviorModel.swift; sourceTree = "<group>"; };
58E7561C2BE04C320088BB5D /* MoleculeComparisonProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeComparisonProtocol.swift; sourceTree = "<group>"; };
608211262AC6AF8200C3FC39 /* MVMCoreUILoggingHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MVMCoreUILoggingHandler.swift; sourceTree = "<group>"; };
7199C8152A4F3A64001568B7 /* AccessibilityHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccessibilityHandler.swift; sourceTree = "<group>"; };
71BE969D2AD96BE6000B5DB7 /* RotorHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RotorHandler.swift; sourceTree = "<group>"; };
8D070BAF241B56530099AC56 /* ListRightVariableTotalDataModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListRightVariableTotalDataModel.swift; sourceTree = "<group>"; };
8D070BB1241B56AD0099AC56 /* ListRightVariableTotalData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListRightVariableTotalData.swift; sourceTree = "<group>"; };
8D084ACF2410BF4800951227 /* ListOneColumnFullWidthTextBodyTextModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListOneColumnFullWidthTextBodyTextModel.swift; sourceTree = "<group>"; };
@ -824,10 +868,6 @@
94C2D9A623872DA90006CF46 /* LabelAttributeColorModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelAttributeColorModel.swift; sourceTree = "<group>"; };
94C2D9A823872E5E0006CF46 /* LabelAttributeImageModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelAttributeImageModel.swift; sourceTree = "<group>"; };
94C2D9AA23872EB50006CF46 /* LabelAttributeActionModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelAttributeActionModel.swift; sourceTree = "<group>"; };
94CA227824058533002D6750 /* VerizonNHGeTX-Bold.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "VerizonNHGeTX-Bold.otf"; sourceTree = "<group>"; };
94CA227924058533002D6750 /* VerizonNHGeDS-Regular.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "VerizonNHGeDS-Regular.otf"; sourceTree = "<group>"; };
94CA227A24058533002D6750 /* VerizonNHGeDS-Bold.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "VerizonNHGeDS-Bold.otf"; sourceTree = "<group>"; };
94CA227B24058533002D6750 /* VerizonNHGeTX-Regular.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "VerizonNHGeTX-Regular.otf"; sourceTree = "<group>"; };
94F6516C2437954100631BF9 /* Tabs.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Tabs.swift; sourceTree = "<group>"; };
AA07EA902510A442009A2AE3 /* StarModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StarModel.swift; sourceTree = "<group>"; };
AA07EA922510A451009A2AE3 /* Star.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Star.swift; sourceTree = "<group>"; };
@ -895,6 +935,7 @@
AF1C336E2885A16A006B1001 /* ActionCollapseNotificationHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionCollapseNotificationHandler.swift; sourceTree = "<group>"; };
AF1C33702885AE76006B1001 /* MVMCoreUIActionHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MVMCoreUIActionHandler.swift; sourceTree = "<group>"; };
AF1C33722885D481006B1001 /* MVMCoreUIActionOpenPageHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MVMCoreUIActionOpenPageHandler.swift; sourceTree = "<group>"; };
AF1CEFE72BEA73890001F9A5 /* VDSCoreTokens.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = VDSCoreTokens.xcframework; path = ../SharedFrameworks/VDSCoreTokens.xcframework; sourceTree = "<group>"; };
AF60A7F52892D2E300919EEB /* ActionDismissNotificationModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionDismissNotificationModel.swift; sourceTree = "<group>"; };
AF60A7F72892D34D00919EEB /* ActionDismissNotificationHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionDismissNotificationHandler.swift; sourceTree = "<group>"; };
AF766D252A3CD4C600749099 /* UIAccessibilityTraits+Codable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIAccessibilityTraits+Codable.swift"; sourceTree = "<group>"; };
@ -905,7 +946,9 @@
AFA4932129E5EF2E001A9663 /* NotificationHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationHandler.swift; sourceTree = "<group>"; };
AFA4933E29E874F0001A9663 /* MVMCoreUILoggingDelegateProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MVMCoreUILoggingDelegateProtocol.swift; sourceTree = "<group>"; };
AFA4935629EE3DCC001A9663 /* AlertDelegateProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertDelegateProtocol.swift; sourceTree = "<group>"; };
AFE4A1D027DFB5EE00C458D0 /* VDSColorTokens.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = VDSColorTokens.xcframework; path = ../SharedFrameworks/VDSColorTokens.xcframework; sourceTree = "<group>"; };
AFB6336D2C65166E00791221 /* GoneableProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GoneableProtocol.swift; sourceTree = "<group>"; };
AFB6336F2C65175800791221 /* ActionUpdateVisibility.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionUpdateVisibility.swift; sourceTree = "<group>"; };
AFB633712C653C0900791221 /* ActionUpdateVisibilityModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionUpdateVisibilityModel.swift; sourceTree = "<group>"; };
AFE4A1D527DFBB6F00C458D0 /* UINavigationController+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UINavigationController+Extension.swift"; sourceTree = "<group>"; };
B4CC8FBC29DF34680005D28B /* Badge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Badge.swift; sourceTree = "<group>"; };
B4CC8FBE29DF34730005D28B /* BadgeModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BadgeModel.swift; sourceTree = "<group>"; };
@ -1166,7 +1209,6 @@
D2ED27E9254B0CE600A1C293 /* ActionAlertModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionAlertModel.swift; sourceTree = "<group>"; };
D2ED27EA254B0CE700A1C293 /* AlertModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlertModel.swift; sourceTree = "<group>"; };
D2ED27F3254B0E0200A1C293 /* AlertObject.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlertObject.swift; sourceTree = "<group>"; };
D2FA83D12513EA6900564112 /* NotificationXButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationXButton.swift; sourceTree = "<group>"; };
D2FA83D32514F80C00564112 /* CollapsableNotification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollapsableNotification.swift; sourceTree = "<group>"; };
D2FA83D52515021F00564112 /* CollapsableNotificationTopView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollapsableNotificationTopView.swift; sourceTree = "<group>"; };
D2FB151A23A2B65B00C20E10 /* MoleculeContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeContainer.swift; sourceTree = "<group>"; };
@ -1179,11 +1221,32 @@
DBC4391A224421A0001AB423 /* CaretLink.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CaretLink.swift; sourceTree = "<group>"; };
EA05EFA8278DDE2C00828819 /* ClearFormFieldEffectModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClearFormFieldEffectModel.swift; sourceTree = "<group>"; };
EA05EFAA278DE53600828819 /* ClearableModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClearableModelProtocol.swift; sourceTree = "<group>"; };
EA1758472BC97ED800A5C0D9 /* BadgeIndicator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BadgeIndicator.swift; sourceTree = "<group>"; };
EA1758492BC97EF100A5C0D9 /* BadgeIndicatorModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BadgeIndicatorModel.swift; sourceTree = "<group>"; };
EA17584B2BC9894800A5C0D9 /* ButtonIconModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonIconModel.swift; sourceTree = "<group>"; };
EA17584D2BC9895A00A5C0D9 /* ButtonIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonIcon.swift; sourceTree = "<group>"; };
EA1B02DD2C41BFD200F0758B /* RuleVDSModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuleVDSModel.swift; sourceTree = "<group>"; };
EA1B02DF2C470AFD00F0758B /* InputEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InputEntryField.swift; sourceTree = "<group>"; };
EA41F4AB2787927100F5B377 /* DynamicRuleFormFieldEffectModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DynamicRuleFormFieldEffectModel.swift; sourceTree = "<group>"; };
EA5124FC243601600051A3A4 /* BGImageHeadlineBodyButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BGImageHeadlineBodyButton.swift; sourceTree = "<group>"; };
EA5124FE2436018E0051A3A4 /* BGImageHeadlineBodyButtonModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BGImageHeadlineBodyButtonModel.swift; sourceTree = "<group>"; };
EA5DBDAA2C35B6C500290DF8 /* FormFieldModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormFieldModel.swift; sourceTree = "<group>"; };
EA6642902BCDA97300D81DC4 /* TileContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TileContainer.swift; sourceTree = "<group>"; };
EA6642922BCDA97D00D81DC4 /* TileContainerModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TileContainerModel.swift; sourceTree = "<group>"; };
EA6E8B942B504A43000139B4 /* ButtonGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonGroup.swift; sourceTree = "<group>"; };
EA6E8B962B504A4D000139B4 /* ButtonGroupModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonGroupModel.swift; sourceTree = "<group>"; };
EA7AE5462C73C01A00107C74 /* CheckboxesModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckboxesModel.swift; sourceTree = "<group>"; };
EA7AE5482C7403DC00107C74 /* Checkboxes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Checkboxes.swift; sourceTree = "<group>"; };
EA7AE54A2C74CACA00107C74 /* RadioButtons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioButtons.swift; sourceTree = "<group>"; };
EA7AE54C2C74CAD700107C74 /* RadioButtonsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioButtonsModel.swift; sourceTree = "<group>"; };
EA7AE54E2C74EB3700107C74 /* CalendarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarView.swift; sourceTree = "<group>"; };
EA7AE5502C74EB4500107C74 /* CalendarViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarViewModel.swift; sourceTree = "<group>"; };
EA7AE5522C74F1F600107C74 /* DatePickerEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DatePickerEntryField.swift; sourceTree = "<group>"; };
EA7AE5542C74F20600107C74 /* DatePickerEntryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DatePickerEntryFieldModel.swift; sourceTree = "<group>"; };
EA7AE55B2C7D18A100107C74 /* BreadcrumbsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BreadcrumbsModel.swift; sourceTree = "<group>"; };
EA7AE55D2C7D234500107C74 /* Breadcrumbs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Breadcrumbs.swift; sourceTree = "<group>"; };
EA7AE55F2C7E554700107C74 /* PaginationModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaginationModel.swift; sourceTree = "<group>"; };
EA7AE5612C7E555D00107C74 /* Pagination.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Pagination.swift; sourceTree = "<group>"; };
EA7D815F2B2B6E6800D29F9E /* Icon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Icon.swift; sourceTree = "<group>"; };
EA7D81612B2B6E7F00D29F9E /* IconModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IconModel.swift; sourceTree = "<group>"; };
EA7D81632B2BABCB00D29F9E /* TooltipModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TooltipModel.swift; sourceTree = "<group>"; };
@ -1193,7 +1256,6 @@
EA985C3D2970938F00F2FF2E /* Tilelet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tilelet.swift; sourceTree = "<group>"; };
EA985C3F2970939A00F2FF2E /* TileletModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TileletModel.swift; sourceTree = "<group>"; };
EA985C5F2970A3F000F2FF2E /* VDS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = VDS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
EA985C632970A40E00F2FF2E /* VDSTypographyTokens.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = VDSTypographyTokens.xcframework; path = ../SharedFrameworks/VDSTypographyTokens.xcframework; sourceTree = "<group>"; };
EA985C842981AA9C00F2FF2E /* VDS-Enums+Codable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VDS-Enums+Codable.swift"; sourceTree = "<group>"; };
EA985C862981AB0F00F2FF2E /* VDS-Tilelet+Codable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VDS-Tilelet+Codable.swift"; sourceTree = "<group>"; };
EA985C882981AB7100F2FF2E /* VDS-TextStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VDS-TextStyle.swift"; sourceTree = "<group>"; };
@ -1208,19 +1270,26 @@
EABFC1402763BB8D00E78B40 /* FormLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormLabel.swift; sourceTree = "<group>"; };
EABFC151276913E800E78B40 /* FormLabelModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormLabelModel.swift; sourceTree = "<group>"; };
EACCF38B2ABB346700E0F104 /* VDS-Interpreters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VDS-Interpreters.swift"; sourceTree = "<group>"; };
EAD715A92BBC8FAF00DEDA6A /* VDSTokens.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = VDSTokens.xcframework; path = ../SharedFrameworks/VDSTokens.xcframework; sourceTree = "<group>"; };
FD9912FF28E21E4900542CC3 /* RuleNotEqualsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuleNotEqualsModel.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
583335532BF64E77001D90D7 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
5833355A2BF64E77001D90D7 /* MVMCoreUI.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
D29DF0C921E404D4003B2FB9 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
AF1CEFE82BEA73890001F9A5 /* VDSCoreTokens.xcframework in Frameworks */,
D29DF0E621E4F3C7003B2FB9 /* MVMCore.framework in Frameworks */,
AFE4A1D127DFB5EE00C458D0 /* VDSColorTokens.xcframework in Frameworks */,
EA985C602970A3F000F2FF2E /* VDS.framework in Frameworks */,
187FEB2A2844D2A600BF29C2 /* VDSFormControlsTokens.xcframework in Frameworks */,
EA985C642970A40E00F2FF2E /* VDSTypographyTokens.xcframework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -1247,6 +1316,8 @@
D28BA74C248589C800B75CB8 /* TabPageModelProtocol.swift */,
27F6B08B26052AFF008529AA /* ParentMoleculeModelProtocol.swift */,
27577DCC286CA959001EC47E /* MoleculeMaskingProtocol.swift */,
58E7561C2BE04C320088BB5D /* MoleculeComparisonProtocol.swift */,
AFB6336D2C65166E00791221 /* GoneableProtocol.swift */,
);
path = ModelProtocols;
sourceTree = "<group>";
@ -1266,6 +1337,7 @@
011D95A0240453D0000E3791 /* RuleEqualsModel.swift */,
0A849EFD246F1775009F277F /* RuleEqualsIgnoreCaseModel.swift */,
FD9912FF28E21E4900542CC3 /* RuleNotEqualsModel.swift */,
EA1B02DD2C41BFD200F0758B /* RuleVDSModel.swift */,
);
name = Rules;
path = Rules/Rules;
@ -1344,6 +1416,7 @@
children = (
0A7EF86623D8B0AE00B2AAD1 /* DateDropdownEntryFieldModel.swift */,
0ABD136C237CAD1E0081388D /* DateDropdownEntryField.swift */,
4B002AC92BD855EC009BC9C1 /* DateDropdownEntryFieldModel+Extension.swift */,
);
path = "Date Dropdown";
sourceTree = "<group>";
@ -1496,6 +1569,34 @@
path = Accessibility;
sourceTree = "<group>";
};
583335572BF64E77001D90D7 /* MVMCoreUITests */ = {
isa = PBXGroup;
children = (
583335602BF65063001D90D7 /* JSON */,
583335582BF64E77001D90D7 /* MVMCoreUITests.swift */,
583335642BF6A5C3001D90D7 /* TestUtils.swift */,
);
path = MVMCoreUITests;
sourceTree = "<group>";
};
583335602BF65063001D90D7 /* JSON */ = {
isa = PBXGroup;
children = (
583335612BF6506C001D90D7 /* Modelling */,
);
path = JSON;
sourceTree = "<group>";
};
583335612BF6506C001D90D7 /* Modelling */ = {
isa = PBXGroup;
children = (
583335662BF6DCD0001D90D7 /* UAD_page_model_2.json */,
583335622BF6509C001D90D7 /* UAD_page_model.json */,
5833356C2BFBF51C001D90D7 /* UAD_page_model_3.json */,
);
path = Modelling;
sourceTree = "<group>";
};
8DD1E36C243B3CD900D8F2DF /* ThreeColumn */ = {
isa = PBXGroup;
children = (
@ -1528,6 +1629,8 @@
AF1C33722885D481006B1001 /* MVMCoreUIActionOpenPageHandler.swift */,
AF60A7F52892D2E300919EEB /* ActionDismissNotificationModel.swift */,
AF60A7F72892D34D00919EEB /* ActionDismissNotificationHandler.swift */,
AFB633712C653C0900791221 /* ActionUpdateVisibilityModel.swift */,
AFB6336F2C65175800791221 /* ActionUpdateVisibility.swift */,
);
path = Actions;
sourceTree = "<group>";
@ -1608,7 +1711,6 @@
D202AFE2242A5F1400E5BEDF /* Extensions */ = {
isa = PBXGroup;
children = (
5870636E2ACF238E00CA18D5 /* ReadableDecodingErrors.swift */,
D202AFE3242A5F5E00E5BEDF /* NSTextAlignment+Extension.swift */,
0A209CD223A7E2810068F8B0 /* UIStackViewAlignment+Extension.swift */,
D21EE53B23AD3AD4003D1A30 /* NSLayoutConstraintAxis+Extension.swift */,
@ -1953,8 +2055,12 @@
BBAA4F00243D8E3B005AAD5F /* RadioBoxModel.swift */,
D264FAA6243FE13B00D98315 /* RadioBox.swift */,
0116A4E4228B19640094F3ED /* RadioButtonSelectionHelper.swift */,
EA7AE54C2C74CAD700107C74 /* RadioButtonsModel.swift */,
EA7AE54A2C74CACA00107C74 /* RadioButtons.swift */,
011D95AE2407266E000E3791 /* RadioButtonModel.swift */,
01004F2F22721C3800991ECC /* RadioButton.swift */,
EA7AE5462C73C01A00107C74 /* CheckboxesModel.swift */,
EA7AE5482C7403DC00107C74 /* Checkboxes.swift */,
31BE15CA23D8924C00452370 /* CheckboxModel.swift */,
0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */,
AAC6F166243332E400F295C1 /* RadioSwatchesModel.swift */,
@ -2006,6 +2112,7 @@
isa = PBXGroup;
children = (
D29DF0CE21E404D4003B2FB9 /* MVMCoreUI */,
583335572BF64E77001D90D7 /* MVMCoreUITests */,
D29DF0CD21E404D4003B2FB9 /* Products */,
D29DF0E421E4F3C7003B2FB9 /* Frameworks */,
);
@ -2015,6 +2122,7 @@
isa = PBXGroup;
children = (
D29DF0CC21E404D4003B2FB9 /* MVMCoreUI.framework */,
583335562BF64E77001D90D7 /* MVMCoreUITests.xctest */,
);
name = Products;
sourceTree = "<group>";
@ -2081,10 +2189,9 @@
D29DF0E421E4F3C7003B2FB9 /* Frameworks */ = {
isa = PBXGroup;
children = (
EA985C632970A40E00F2FF2E /* VDSTypographyTokens.xcframework */,
AF1CEFE72BEA73890001F9A5 /* VDSCoreTokens.xcframework */,
EAD715A92BBC8FAF00DEDA6A /* VDSTokens.xcframework */,
EA985C5F2970A3F000F2FF2E /* VDS.framework */,
187FEB292844D2A600BF29C2 /* VDSFormControlsTokens.xcframework */,
AFE4A1D027DFB5EE00C458D0 /* VDSColorTokens.xcframework */,
D29DF0E521E4F3C7003B2FB9 /* MVMCore.framework */,
);
name = Frameworks;
@ -2104,6 +2211,7 @@
D29DF10E21E67A77003B2FB9 /* Molecules */ = {
isa = PBXGroup;
children = (
EA7AE55A2C7D188900107C74 /* Breadcrumbs */,
D2EC7BD22527A1E400F540AF /* HeadersAndFooters */,
D2CAC7C9251104CB00C75681 /* TopNotification */,
D2509ED42472EE0B001BFB9D /* NavigationBar */,
@ -2252,8 +2360,11 @@
94C2D9822386F3E30006CF46 /* Label */,
31BE15C923D8924C00452370 /* CheckboxLabelModel.swift */,
0A7BAFA2232BE63400FB8E22 /* CheckboxLabel.swift */,
4B53AF7A2C45BBBA00274685 /* GraphSizeProtocol.swift */,
D28A838223CCBD3F00DFE4FC /* WheelModel.swift */,
943784F3236B77BB006A1E82 /* Wheel.swift */,
4B3408A12C3873B0003BFABF /* CircularProgressBarModel.swift */,
4B3408A32C3873E8003BFABF /* CircularProgressBar.swift */,
943784F4236B77BB006A1E82 /* WheelAnimationHandler.swift */,
0AE98BB623FF18E9004C5109 /* ArrowModel.swift */,
0AE98BB423FF18D2004C5109 /* Arrow.swift */,
@ -2262,18 +2373,28 @@
D20492A524329CE200A5EED6 /* LoadImageView.swift */,
0A51F3E02475CB73002E08B6 /* LoadingSpinnerModel.swift */,
0A51F3E12475CB73002E08B6 /* LoadingSpinner.swift */,
EA7AE55F2C7E554700107C74 /* PaginationModel.swift */,
EA7AE5612C7E555D00107C74 /* Pagination.swift */,
AA37CBD2251907200027344C /* StarsModel.swift */,
AA37CBD42519072F0027344C /* Stars.swift */,
AA07EA902510A442009A2AE3 /* StarModel.swift */,
AA07EA922510A451009A2AE3 /* Star.swift */,
B4CC8FBE29DF34730005D28B /* BadgeModel.swift */,
B4CC8FBC29DF34680005D28B /* Badge.swift */,
EA1758492BC97EF100A5C0D9 /* BadgeIndicatorModel.swift */,
EA1758472BC97ED800A5C0D9 /* BadgeIndicator.swift */,
EA17584B2BC9894800A5C0D9 /* ButtonIconModel.swift */,
EA17584D2BC9895A00A5C0D9 /* ButtonIcon.swift */,
EA6642922BCDA97D00D81DC4 /* TileContainerModel.swift */,
EA6642902BCDA97300D81DC4 /* TileContainer.swift */,
EA985C3F2970939A00F2FF2E /* TileletModel.swift */,
EA985C3D2970938F00F2FF2E /* Tilelet.swift */,
EA7D81612B2B6E7F00D29F9E /* IconModel.swift */,
EA7D815F2B2B6E6800D29F9E /* Icon.swift */,
EA7D81632B2BABCB00D29F9E /* TooltipModel.swift */,
EA7D81652B2BABD200D29F9E /* Tooltip.swift */,
EA7AE5502C74EB4500107C74 /* CalendarViewModel.swift */,
EA7AE54E2C74EB3700107C74 /* CalendarView.swift */,
);
path = Views;
sourceTree = "<group>";
@ -2283,6 +2404,7 @@
children = (
0A7EF85A23D8A52800B2AAD1 /* EntryFieldModel.swift */,
0A21DB7E235DECC500C160A2 /* EntryField.swift */,
EA1B02DF2C470AFD00F0758B /* InputEntryField.swift */,
0A7EF85C23D8A95600B2AAD1 /* TextEntryFieldModel.swift */,
0A41BA7E23453A6400D4C0BC /* TextEntryField.swift */,
0A7EF85E23D8ABC500B2AAD1 /* MdnEntryFieldModel.swift */,
@ -2351,6 +2473,8 @@
D29DF31421ECECA7003B2FB9 /* SupportingFiles */ = {
isa = PBXGroup;
children = (
5878F0A52BD7E6BE00ADE23D /* mvmcoreui_dev.xcconfig */,
5878F0A42BD7E68800ADE23D /* mvmcoreui.xcconfig */,
D29DF32721EE8736003B2FB9 /* Strings */,
D29DF26621E6A9E4003B2FB9 /* ThirdParty */,
D29DF31521ECECC0003B2FB9 /* Fonts */,
@ -2363,10 +2487,6 @@
D29DF31521ECECC0003B2FB9 /* Fonts */ = {
isa = PBXGroup;
children = (
94CA227A24058533002D6750 /* VerizonNHGeDS-Bold.otf */,
94CA227924058533002D6750 /* VerizonNHGeDS-Regular.otf */,
94CA227824058533002D6750 /* VerizonNHGeTX-Bold.otf */,
94CA227B24058533002D6750 /* VerizonNHGeTX-Regular.otf */,
D29DF31721ECECC0003B2FB9 /* OCRAExtended.ttf */,
);
path = Fonts;
@ -2426,6 +2546,9 @@
D2BEFEF5248A954C00FAB3A9 /* FormFields */ = {
isa = PBXGroup;
children = (
EA7AE5542C74F20600107C74 /* DatePickerEntryFieldModel.swift */,
EA7AE5522C74F1F600107C74 /* DatePickerEntryField.swift */,
EA5DBDAA2C35B6C500290DF8 /* FormFieldModel.swift */,
D2BEFEF6248A957A00FAB3A9 /* Tags */,
D29DF22B21E6A0FA003B2FB9 /* TextFields */,
);
@ -2480,7 +2603,6 @@
isa = PBXGroup;
children = (
D2CAC7CA251104E100C75681 /* NotificationXButtonModel.swift */,
D2FA83D12513EA6900564112 /* NotificationXButton.swift */,
D2CAC7CC251104FE00C75681 /* NotificationMoleculeModel.swift */,
D23118B225124E18001C8440 /* NotificationMoleculeView.swift */,
D2CAC7CE2511052300C75681 /* CollapsableNotificationModel.swift */,
@ -2530,6 +2652,15 @@
path = Alerts;
sourceTree = "<group>";
};
EA7AE55A2C7D188900107C74 /* Breadcrumbs */ = {
isa = PBXGroup;
children = (
EA7AE55B2C7D18A100107C74 /* BreadcrumbsModel.swift */,
EA7AE55D2C7D234500107C74 /* Breadcrumbs.swift */,
);
path = Breadcrumbs;
sourceTree = "<group>";
};
EAA0CFAD275E7D5A00D65EB0 /* FormFieldEffect */ = {
isa = PBXGroup;
children = (
@ -2582,6 +2713,24 @@
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
583335552BF64E77001D90D7 /* MVMCoreUITests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 5833355F2BF64E77001D90D7 /* Build configuration list for PBXNativeTarget "MVMCoreUITests" */;
buildPhases = (
583335522BF64E77001D90D7 /* Sources */,
583335532BF64E77001D90D7 /* Frameworks */,
583335542BF64E77001D90D7 /* Resources */,
);
buildRules = (
);
dependencies = (
5833355C2BF64E77001D90D7 /* PBXTargetDependency */,
);
name = MVMCoreUITests;
productName = MVMCoreUITests;
productReference = 583335562BF64E77001D90D7 /* MVMCoreUITests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
D29DF0CB21E404D4003B2FB9 /* MVMCoreUI */ = {
isa = PBXNativeTarget;
buildConfigurationList = D29DF0D421E404D4003B2FB9 /* Build configuration list for PBXNativeTarget "MVMCoreUI" */;
@ -2606,9 +2755,13 @@
D29DF0C321E404D4003B2FB9 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 1540;
LastUpgradeCheck = 1320;
ORGANIZATIONNAME = "Verizon Wireless";
TargetAttributes = {
583335552BF64E77001D90D7 = {
CreatedOnToolsVersion = 15.4;
};
D29DF0CB21E404D4003B2FB9 = {
CreatedOnToolsVersion = 10.1;
LastSwiftMigration = 1010;
@ -2631,22 +2784,29 @@
projectRoot = "";
targets = (
D29DF0CB21E404D4003B2FB9 /* MVMCoreUI */,
583335552BF64E77001D90D7 /* MVMCoreUITests */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
583335542BF64E77001D90D7 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
583335672BF6DCD0001D90D7 /* UAD_page_model_2.json in Resources */,
5833356D2BFBF51C001D90D7 /* UAD_page_model_3.json in Resources */,
583335632BF6509C001D90D7 /* UAD_page_model.json in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
D29DF0CA21E404D4003B2FB9 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
94CA227C24058534002D6750 /* VerizonNHGeTX-Bold.otf in Resources */,
D29DF32C21EE8736003B2FB9 /* Localizable.strings in Resources */,
0A6C1FC324927E2E00E64B52 /* colors.xcassets in Resources */,
94CA227D24058534002D6750 /* VerizonNHGeDS-Regular.otf in Resources */,
D29DF32E21EE8C3D003B2FB9 /* Media.xcassets in Resources */,
94CA227E24058534002D6750 /* VerizonNHGeDS-Bold.otf in Resources */,
D287651A245B338E00CB882D /* VerizonNHGeTX-Regular.otf in Resources */,
D29DF31B21ECECC0003B2FB9 /* OCRAExtended.ttf in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
@ -2654,6 +2814,15 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
583335522BF64E77001D90D7 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
583335592BF64E77001D90D7 /* MVMCoreUITests.swift in Sources */,
583335652BF6A5C3001D90D7 /* TestUtils.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
D29DF0C821E404D4003B2FB9 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@ -2684,6 +2853,7 @@
D29B771022C281F400D6ACE0 /* ModuleMolecule.swift in Sources */,
AAE96FA225341F6A0037A989 /* ListStoreLocatorModel.swift in Sources */,
D28A838923CCCFCB00DFE4FC /* LinkModel.swift in Sources */,
EA17584A2BC97EF100A5C0D9 /* BadgeIndicatorModel.swift in Sources */,
AA56A20F243C5EE900303286 /* ListTwoColumnSubsectionDividerModel.swift in Sources */,
AAB9C10824346F4B00151545 /* RadioSwatches.swift in Sources */,
94C2D9A923872E5E0006CF46 /* LabelAttributeImageModel.swift in Sources */,
@ -2722,11 +2892,13 @@
AA7F32AD246C0F8C00C965BA /* ListLeftVariableRadioButtonAllTextAndLinks.swift in Sources */,
EAA482CE2B45F2F300978105 /* MFLoadingSpinner+VDS.swift in Sources */,
D272F5F92473163100BD1A8F /* BarButtonItem.swift in Sources */,
EA7AE54D2C74CAD700107C74 /* RadioButtonsModel.swift in Sources */,
D2D2FCF3252B72CF0033EAAA /* MoleculeSectionFooter.swift in Sources */,
0A9D09202433796500D2E6C0 /* BarsIndicatorView.swift in Sources */,
D2E2A99423D8CCBC000B42E6 /* HeadlineBodyLinkModel.swift in Sources */,
01004F3022721C3800991ECC /* RadioButton.swift in Sources */,
D268C70E238C22D7007F2C1C /* DropDownFilterTableViewCell.swift in Sources */,
AFB633702C65175800791221 /* ActionUpdateVisibility.swift in Sources */,
D236E5B7242007C500C38625 /* MVMControllerModelProtocol.swift in Sources */,
AA71AD4024A32FE700ACA76F /* HeadersH2Link.swift in Sources */,
D29DF11721E6805F003B2FB9 /* UIColor+MFConvenience.m in Sources */,
@ -2734,6 +2906,8 @@
D253BB8A24574CC5002DE544 /* StackModel.swift in Sources */,
EAB14BC127D935F00012AB2C /* RuleCompareModelProtocol.swift in Sources */,
011D95A924057AC7000E3791 /* FormGroupWatcherFieldProtocol.swift in Sources */,
EA1B02DE2C41BFD200F0758B /* RuleVDSModel.swift in Sources */,
EA7AE5532C74F1F600107C74 /* DatePickerEntryField.swift in Sources */,
EA985C892981AB7100F2FF2E /* VDS-TextStyle.swift in Sources */,
BB2BF0EA2452A9BB001D0FC2 /* ListDeviceComplexButtonSmall.swift in Sources */,
D20C700B250BFDE40095B21C /* NotificationContainerView.swift in Sources */,
@ -2775,6 +2949,7 @@
D2E2A99D23DA3217000B42E6 /* UIStackViewAlignment+Extension.swift in Sources */,
01EB369423609801006832FA /* HeadlineBodyModel.swift in Sources */,
D2A92884241ACB25004E01C6 /* ProgrammaticScrollViewController.swift in Sources */,
AFB633722C653C0900791221 /* ActionUpdateVisibilityModel.swift in Sources */,
EA985C3E2970938F00F2FF2E /* Tilelet.swift in Sources */,
D23A90002612347A007E14CE /* PageBehaviorContainerModelProtocol.swift in Sources */,
EAA78020290081320057DFDF /* VDSMoleculeViewProtocol.swift in Sources */,
@ -2788,6 +2963,7 @@
D29DF2CF21E7C104003B2FB9 /* MFLoadingViewController.m in Sources */,
D28A837B23C928DA00DFE4FC /* MoleculeListCellProtocol.swift in Sources */,
D28BA74D248589C800B75CB8 /* TabPageModelProtocol.swift in Sources */,
EA7AE5602C7E554700107C74 /* PaginationModel.swift in Sources */,
608211282AC6B57E00C3FC39 /* MVMCoreUILoggingHandler.swift in Sources */,
014AA72F23C5059B006F3E93 /* ThreeLayerPageTemplateModel.swift in Sources */,
0A21DB91235E0EDB00C160A2 /* DigitBox.swift in Sources */,
@ -2813,8 +2989,10 @@
525239C02407BCFF00454969 /* ListTwoColumnPriceDetailsModel.swift in Sources */,
D2E2A99A23D8D6B4000B42E6 /* HeadlineBodyButtonModel.swift in Sources */,
D202AFE6242A6A9C00E5BEDF /* UICollectionViewScrollPosition+Extension.swift in Sources */,
EA7AE55C2C7D18A100107C74 /* BreadcrumbsModel.swift in Sources */,
D20F3B44252E00E4004B3F56 /* PageProtocol.swift in Sources */,
AA37CBD3251907200027344C /* StarsModel.swift in Sources */,
EA7AE5622C7E555D00107C74 /* Pagination.swift in Sources */,
8D084AD22410BF7600951227 /* ListOneColumnFullWidthTextBodyText.swift in Sources */,
94C0150C2421564A005811A9 /* ActionCollapseNotificationModel.swift in Sources */,
D2CAC7CB251104E100C75681 /* NotificationXButtonModel.swift in Sources */,
@ -2823,7 +3001,6 @@
0A0FEC7425D42A5E00AF2548 /* BaseItemPickerEntryField.swift in Sources */,
D29DF2A221E7AF4E003B2FB9 /* MVMCoreUIUtility.m in Sources */,
D23A8FF82612308D007E14CE /* PageBehaviorProtocolRequirer.swift in Sources */,
5870636F2ACF238E00CA18D5 /* ReadableDecodingErrors.swift in Sources */,
94C2D9A723872DA90006CF46 /* LabelAttributeColorModel.swift in Sources */,
943820842432382400B43AF3 /* WebView.swift in Sources */,
0103B84E23D7E33A009C315C /* HeadlineBodyToggleModel.swift in Sources */,
@ -2842,6 +3019,7 @@
AAE96FA525341F7D0037A989 /* ListStoreLocator.swift in Sources */,
D282AABA224131D100C46919 /* MFTransparentGIFView.swift in Sources */,
944589232385DA9600DE9FD4 /* ImageViewModel.swift in Sources */,
EA7AE55E2C7D234500107C74 /* Breadcrumbs.swift in Sources */,
D213347723843825008E41B3 /* Line.swift in Sources */,
D2E2A99C23D8D975000B42E6 /* ImageHeadlineBodyModel.swift in Sources */,
BB3BC1302550094500297977 /* ListLeftVariableIconWithRightCaretAllTextLinksModel.swift in Sources */,
@ -2907,7 +3085,9 @@
D29DF2EF21ECEAE1003B2FB9 /* MFFonts.m in Sources */,
D22479942316AE5E003FCCF9 /* NSLayoutConstraintExtension.swift in Sources */,
D2B18B94236214AD00A9AEDC /* NavigationController.swift in Sources */,
4B3408A42C3873E8003BFABF /* CircularProgressBar.swift in Sources */,
0A9D09222433796500D2E6C0 /* CarouselIndicator.swift in Sources */,
EA17584E2BC9895A00A5C0D9 /* ButtonIcon.swift in Sources */,
D29E28DA23D21AFA00ACEA85 /* StringAndMoleculeModel.swift in Sources */,
D260105D23D0BCD400764D80 /* Stack.swift in Sources */,
0A7EF85D23D8A95600B2AAD1 /* TextEntryFieldModel.swift in Sources */,
@ -2926,6 +3106,7 @@
AA1EC59924373994003D6F50 /* ListThreeColumnSpeedTestDivider.swift in Sources */,
AA37CBD52519072F0027344C /* Stars.swift in Sources */,
942C378E2412F5B60066E45E /* ModalMoleculeStackTemplate.swift in Sources */,
4B3408A22C3873B0003BFABF /* CircularProgressBarModel.swift in Sources */,
8D8067D32444473A00203BE8 /* ListRightVariablePriceChangeAllTextAndLinks.swift in Sources */,
8D4687E4242E2DF300802879 /* ListFourColumnDataUsageListItem.swift in Sources */,
D2874024249BA6F300BE950A /* MVMCoreUISplitViewController+Extension.swift in Sources */,
@ -2935,6 +3116,7 @@
D22479962316AF6E003FCCF9 /* HeadlineBodyLink.swift in Sources */,
8DE5BECD2456F7A200772E76 /* ListTwoColumnDropdownSelectorsModel.swift in Sources */,
AA7F47732541AD560015A2C1 /* ListStarRatingModel.swift in Sources */,
EA17584C2BC9894800A5C0D9 /* ButtonIconModel.swift in Sources */,
AA7F47762541AD6A0015A2C1 /* ListStarRating.swift in Sources */,
0A41BA7F23453A6400D4C0BC /* TextEntryField.swift in Sources */,
AF7E509829E477C1009DC2AD /* AlertHandler.swift in Sources */,
@ -2976,7 +3158,9 @@
AA69AAF62445BF5700AF3D3B /* ListLeftVariableCheckboxBodyText.swift in Sources */,
AFA4935729EE3DCC001A9663 /* AlertDelegateProtocol.swift in Sources */,
58A9DD7D2AC2103300F5E0B0 /* ReplaceableMoleculeBehaviorModel.swift in Sources */,
EA7AE54B2C74CACA00107C74 /* RadioButtons.swift in Sources */,
D264FAA3243E632F00D98315 /* ProgrammaticCollectionViewController.swift in Sources */,
EA7AE5552C74F20600107C74 /* DatePickerEntryFieldModel.swift in Sources */,
D29DF27A21E7A533003B2FB9 /* MVMCoreUISession.m in Sources */,
27F9736A246750BE00CAB5C5 /* ScreenBrightnessModifierBehavior.swift in Sources */,
EA6E8B972B504A4D000139B4 /* ButtonGroupModel.swift in Sources */,
@ -2989,8 +3173,10 @@
D264FAAC2441009400D98315 /* RadioBoxCollectionViewCell.swift in Sources */,
BB2C969224330F73006FF80C /* ListRightVariableTextLinkAllTextAndLinks.swift in Sources */,
D2D90B42240463E100DD6EC9 /* MoleculeHeaderModel.swift in Sources */,
EA1758482BC97ED800A5C0D9 /* BadgeIndicator.swift in Sources */,
012A88B1238C880100FE3DA1 /* CarouselPagingModelProtocol.swift in Sources */,
0A9D091E2433796500D2E6C0 /* NumericCarouselIndicatorModel.swift in Sources */,
58E7561D2BE04C320088BB5D /* MoleculeComparisonProtocol.swift in Sources */,
D29DF2C921E7BFC6003B2FB9 /* MFSizeObject.m in Sources */,
AF1C336928859778006B1001 /* ActionAlertHandler.swift in Sources */,
9445890E2385C3F800DE9FD4 /* MultiProgressModel.swift in Sources */,
@ -2999,6 +3185,7 @@
D2A6390522CBCE160052ED1F /* MoleculeCollectionViewCell.swift in Sources */,
D2A6390122CBB1820052ED1F /* Carousel.swift in Sources */,
C7F8012123E8303200396FBD /* ListRVWheel.swift in Sources */,
4B53AF7B2C45BBBA00274685 /* GraphSizeProtocol.swift in Sources */,
BB2C968F24330EA7006FF80C /* ListRightVariableTextLinkAllTextAndLinksModel.swift in Sources */,
D2FB151B23A2B65B00C20E10 /* MoleculeContainer.swift in Sources */,
EA7D81622B2B6E7F00D29F9E /* IconModel.swift in Sources */,
@ -3031,6 +3218,7 @@
323AC96A24C837F000F8E4C4 /* ListThreeColumnBillChangesModel.swift in Sources */,
D2E1FAE12268E81D00AEFD8C /* MoleculeListTemplate.swift in Sources */,
525019E72406853600EED91C /* ListFourColumnDataUsageDivider.swift in Sources */,
EA1B02E02C470AFD00F0758B /* InputEntryField.swift in Sources */,
D28BA730247EC2EB00B75CB8 /* NavigationButtonModelProtocol.swift in Sources */,
0AE98BB323FF0934004C5109 /* ExternalLinkModel.swift in Sources */,
D20FB165241A5D75004AFC3A /* NavigationItemModel.swift in Sources */,
@ -3044,7 +3232,6 @@
EACCF38C2ABB346700E0F104 /* VDS-Interpreters.swift in Sources */,
C695A67F23C9830600BFB94E /* UnOrderedListModel.swift in Sources */,
0AE98BB523FF18D2004C5109 /* Arrow.swift in Sources */,
D2FA83D22513EA6900564112 /* NotificationXButton.swift in Sources */,
D2D90B442404789000DD6EC9 /* MoleculeContainerProtocol.swift in Sources */,
0A7ECC5F243CEB1200C828E8 /* ColorViewWithLabel.swift in Sources */,
BB3BC12F2550094500297977 /* ListLeftVariableIconWithRightCaretAllTextLinks.swift in Sources */,
@ -3052,7 +3239,9 @@
D2092355244FA0FD0044AD09 /* ThreeLayerTemplateModelProtocol.swift in Sources */,
0AE14F64238315D2005417F8 /* TextField.swift in Sources */,
0A51F3E22475CB73002E08B6 /* LoadingSpinnerModel.swift in Sources */,
AFB6336E2C65166E00791221 /* GoneableProtocol.swift in Sources */,
D2169303251E53D9002A6324 /* SectionListTemplateModel.swift in Sources */,
EA6642932BCDA97D00D81DC4 /* TileContainerModel.swift in Sources */,
AF7E509929E477C1009DC2AD /* AlertController.swift in Sources */,
0AB764D124460F6300E7FE72 /* UIDatePicker+Extension.swift in Sources */,
BB105859248DEFF70069D008 /* UICollectionViewLeftAlignedLayout.swift in Sources */,
@ -3086,6 +3275,7 @@
8DE5BECF2456F7B100772E76 /* ListTwoColumnDropdownSelectors.swift in Sources */,
D2E1FADF2268B8E700AEFD8C /* ThreeLayerTableViewController.swift in Sources */,
0A21DB83235DFBC500C160A2 /* MdnEntryField.swift in Sources */,
4B002ACA2BD855EC009BC9C1 /* DateDropdownEntryFieldModel+Extension.swift in Sources */,
0AE98BB723FF18E9004C5109 /* ArrowModel.swift in Sources */,
01F2C20427C81F9700DC3D36 /* SubNavInteractor.swift.swift in Sources */,
D28A837D23CCA86A00DFE4FC /* TabsListItemModel.swift in Sources */,
@ -3127,6 +3317,7 @@
01F2C20327C81F9700DC3D36 /* SubNavManagerNavigationController.swift in Sources */,
EABFC1412763BB8D00E78B40 /* FormLabel.swift in Sources */,
AA997252247530B100FC7472 /* ListLeftVariableIconAllTextLinks.swift in Sources */,
EA7AE5492C7403DC00107C74 /* Checkboxes.swift in Sources */,
D2A5146122121FBF00345BFB /* MoleculeStackTemplate.swift in Sources */,
D23EA7FB2475F09800D60C34 /* CarouselItemProtocol.swift in Sources */,
D2E2A9A323E096B1000B42E6 /* DisableableModelProtocol.swift in Sources */,
@ -3157,6 +3348,7 @@
BB6C6AC824225290005F7224 /* ListOneColumnTextWithWhitespaceDividerShort.swift in Sources */,
0A41BA6E2344FCD400D4C0BC /* CATransaction+Extension.swift in Sources */,
D21B7F73243BAC6800051ABF /* CollectionItemModelProtocol.swift in Sources */,
EA7AE5512C74EB4500107C74 /* CalendarViewModel.swift in Sources */,
AA104B1A24474A66004D2810 /* HeadersH2Buttons.swift in Sources */,
C7192E7D23C301750050C2A0 /* HeadLineBodyCaretLinkImage.swift in Sources */,
D2D2FCF0252B72AF0033EAAA /* MoleculeSectionFooterModel.swift in Sources */,
@ -3177,8 +3369,10 @@
D2D3957D252FDBCD00047B11 /* ModalSectionListTemplateModel.swift in Sources */,
D2B9D0E4265EEE9D0084735C /* MoleculeListProtocol.swift in Sources */,
D29C559625C099630082E7D6 /* VideoDataManager.swift in Sources */,
EA7AE5472C73C01A00107C74 /* CheckboxesModel.swift in Sources */,
8D4687E2242E2DE400802879 /* ListFourColumnDataUsageListItemModel.swift in Sources */,
D29E28DD23D7404C00ACEA85 /* ContainerHelper.swift in Sources */,
EA6642912BCDA97300D81DC4 /* TileContainer.swift in Sources */,
012A88C2238D7BCA00FE3DA1 /* CarouselItemModel.swift in Sources */,
27F6B08C26052AFF008529AA /* ParentMoleculeModelProtocol.swift in Sources */,
EA985C402970939A00F2FF2E /* TileletModel.swift in Sources */,
@ -3188,6 +3382,7 @@
D28BA7432480284E00B75CB8 /* TabBar.swift in Sources */,
AA3561AE24C96B9000452EB1 /* ListRightVariableRightCaretAllTextAndLinks.swift in Sources */,
AA26850C244840AE00CE34CC /* HeadersH2TinyButton.swift in Sources */,
EA5DBDAB2C35B6C500290DF8 /* FormFieldModel.swift in Sources */,
011D95AB2405C553000E3791 /* FormItemProtocol.swift in Sources */,
D21EE53C23AD3AD4003D1A30 /* NSLayoutConstraintAxis+Extension.swift in Sources */,
0A25209824645B76000FA9F6 /* TextViewEntryFieldModel.swift in Sources */,
@ -3215,11 +3410,20 @@
D2169301251E51E7002A6324 /* SectionListTemplate.swift in Sources */,
0A6682AA2435125F00AD3CA1 /* Styler.swift in Sources */,
D264FAA7243FE13B00D98315 /* RadioBox.swift in Sources */,
EA7AE54F2C74EB3700107C74 /* CalendarView.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
5833355C2BF64E77001D90D7 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = D29DF0CB21E404D4003B2FB9 /* MVMCoreUI */;
targetProxy = 5833355B2BF64E77001D90D7 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
D29DF32821EE8736003B2FB9 /* Localizable.strings */ = {
isa = PBXVariantGroup;
@ -3234,8 +3438,52 @@
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
5833355D2BF64E77001D90D7 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
GENERATE_INFOPLIST_FILE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 17.5;
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.vzw.MVMCoreUITests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
SWIFT_EMIT_LOC_STRINGS = NO;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
5833355E2BF64E77001D90D7 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
GENERATE_INFOPLIST_FILE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 17.5;
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.vzw.MVMCoreUITests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = NO;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};
D29DF0D221E404D4003B2FB9 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 5878F0A52BD7E6BE00ADE23D /* mvmcoreui_dev.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
@ -3294,7 +3542,7 @@
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
@ -3303,6 +3551,7 @@
};
D29DF0D321E404D4003B2FB9 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 5878F0A42BD7E68800ADE23D /* mvmcoreui.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
@ -3376,7 +3625,7 @@
FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/../SharedFrameworks";
INFOPLIST_FILE = MVMCoreUI/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@ -3406,7 +3655,7 @@
FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/../SharedFrameworks";
INFOPLIST_FILE = MVMCoreUI/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@ -3424,6 +3673,15 @@
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
5833355F2BF64E77001D90D7 /* Build configuration list for PBXNativeTarget "MVMCoreUITests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
5833355D2BF64E77001D90D7 /* Debug */,
5833355E2BF64E77001D90D7 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
D29DF0C621E404D4003B2FB9 /* Build configuration list for PBXProject "MVMCoreUI" */ = {
isa = XCConfigurationList;
buildConfigurations = (

View File

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1540"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
buildArchitectures = "Automatic">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D29DF0CB21E404D4003B2FB9"
BuildableName = "MVMCoreUI.framework"
BlueprintName = "MVMCoreUI"
ReferencedContainer = "container:MVMCoreUI.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D29DF0CB21E404D4003B2FB9"
BuildableName = "MVMCoreUI.framework"
BlueprintName = "MVMCoreUI"
ReferencedContainer = "container:MVMCoreUI.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -25,4 +25,11 @@ public struct ActionAlertModel: ActionModelProtocol {
public init(alert: AlertModel) {
self.alert = alert
}
public func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false }
return model.extraParameters == extraParameters
&& model.analyticsData == analyticsData
&& model.alert == alert
}
}

View File

@ -20,4 +20,12 @@ public struct ActionCollapseNotificationModel: ActionModelProtocol {
self.extraParameters = extraParameters
self.analyticsData = analyticsData
}
// Default
//public func isEqual(to model: any ModelComparisonProtocol) -> Bool {
// guard let model = model as? Self else { return false }
// return model.actionType == actionType
// && model.extraParameters == extraParameters
// && model.analyticsData == analyticsData
//}
}

View File

@ -20,4 +20,12 @@ public struct ActionDismissNotificationModel: ActionModelProtocol {
self.extraParameters = extraParameters
self.analyticsData = analyticsData
}
// Default
// public func isEqual(to model: any ModelComparisonProtocol) -> Bool {
// guard let model = model as? Self else { return false }
// return model.actionType == actionType
// && model.extraParameters == extraParameters
// && model.analyticsData == analyticsData
//}
}

View File

@ -29,4 +29,12 @@ public struct ActionOpenPanelModel: ActionModelProtocol {
self.extraParameters = extraParameters
self.analyticsData = analyticsData
}
// Default
public func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false }
return model.extraParameters == extraParameters
&& model.analyticsData == analyticsData
&& model.panel == panel
}
}

View File

@ -22,4 +22,11 @@ public struct ActionTopNotificationModel: ActionModelProtocol {
self.extraParameters = extraParameters
self.analyticsData = analyticsData
}
public func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false }
return model.extraParameters == extraParameters
&& model.analyticsData == analyticsData
&& model.topNotification == topNotification
}
}

View File

@ -0,0 +1,47 @@
//
// ActionToggleGone.swift
// MVMCoreUI
//
// Created by Scott Pfeil on 8/8/24.
// Copyright © 2024 Verizon Wireless. All rights reserved.
//
import Foundation
import MVMCore
public struct ActionUpdateVisibility: MVMCoreActionHandlerProtocol {
public init() {}
public func execute(with model: any MVMCore.ActionModelProtocol, delegateObject: MVMCore.DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {
guard let model = model as? ActionUpdateVisibilityModel,
let delegate = (delegateObject as? MVMCoreUIDelegateObject)?.moleculeDelegate else { return }
let stateMap = model.targets.reduce(into: [String: ActionUpdateVisibilityModel.VisibilityTarget.VisibilityState]()) {
$0[$1.id] = $1.state
}
let updatedModels: [MoleculeModelProtocol] = delegate.getRootMolecules().reduceDepthFirstTraverse(options: .parentFirst, depth: 0, initialResult: [], nextPartialResult: { accumulator, model, depth in
guard var model = model as? (GoneableProtocol & MoleculeModelProtocol),
let state = stateMap[model.id] else { return accumulator }
model.updateVisibility(state)
return accumulator + [model]
})
guard updatedModels.count > 0 else { return }
await delegate.updateUI(for: updatedModels)
}
}
extension GoneableProtocol {
mutating func updateVisibility(_ state: ActionUpdateVisibilityModel.VisibilityTarget.VisibilityState) {
switch state {
case .true:
gone = false
case .false:
gone = true
case .inverted:
gone = !gone
}
}
}

View File

@ -0,0 +1,42 @@
//
// ActionToggleGoneModel.swift
// MVMCoreUI
//
// Created by Scott Pfeil on 8/8/24.
// Copyright © 2024 Verizon Wireless. All rights reserved.
//
import Foundation
import MVMCore
public struct ActionUpdateVisibilityModel: ActionModelProtocol {
public static var identifier: String = "updateVisibility"
public var actionType: String = ActionUpdateVisibilityModel.identifier
public var extraParameters: JSONValueDictionary?
public var analyticsData: JSONValueDictionary?
public var targets: [VisibilityTarget]
public struct VisibilityTarget: Codable {
public enum VisibilityState: String, Codable {
case `true`
case `false`
case inverted
}
public var id: String
public var state: VisibilityState
public init(id: String, state: VisibilityState) {
self.id = id
self.state = state
}
}
public init(targets: [VisibilityTarget], extraParameters: JSONValueDictionary? = nil, analyticsData: JSONValueDictionary? = nil) {
self.targets = targets
self.extraParameters = extraParameters
self.analyticsData = analyticsData
}
}

View File

@ -9,7 +9,8 @@
import UIKit
import MVMCore
public struct AlertButtonModel: Codable {
public struct AlertButtonModel: Codable, Equatable {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
@ -62,14 +63,21 @@ public struct AlertButtonModel: Codable {
try container.encodeModel(action, forKey: .action)
try container.encodeIfPresent(preferred, forKey: .preferred)
}
public static func == (lhs: AlertButtonModel, rhs: AlertButtonModel) -> Bool {
lhs.title == rhs.title
&& lhs.preferred == rhs.preferred
&& lhs.style == rhs.style
&& lhs.action.isEqual(to: rhs.action)
}
}
public struct AlertModel: Codable, Identifiable, AlertModelProtocol {
public struct AlertModel: Codable, Identifiable, Equatable, AlertModelProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public var title: String?
public var message: String?
public var preferredStyle: UIAlertController.Style = .alert
@ -78,7 +86,7 @@ public struct AlertModel: Codable, Identifiable, AlertModelProtocol {
public var id: String
public var delegateObject: DelegateObject?
public var actions: [UIAlertAction] {
get {
buttonModels.map({ alertButtonModel in
@ -94,8 +102,7 @@ public struct AlertModel: Codable, Identifiable, AlertModelProtocol {
})
}
}
//--------------------------------------------------
// MARK: - Init
//--------------------------------------------------
@ -149,6 +156,14 @@ public struct AlertModel: Codable, Identifiable, AlertModelProtocol {
try container.encodeIfPresent(analyticsData, forKey: .analyticsData)
try container.encode(id, forKey: .id)
}
public static func == (lhs: AlertModel, rhs: AlertModel) -> Bool {
lhs.title == rhs.title
&& lhs.message == rhs.message
&& lhs.preferredStyle == rhs.preferredStyle
&& lhs.buttonModels == rhs.buttonModels
&& lhs.analyticsData == rhs.analyticsData
}
}
public extension AlertButtonModel {

View File

@ -38,7 +38,10 @@ open class ButtonGroup: VDS.ButtonGroup, VDSMoleculeViewProtocol {
return PillButton.estimatedHeight(with: buttonModel, delegateObject)
}
public func viewModelDidUpdate() {
public func viewModelDidUpdate() {
if let accessibilityIdentifier = viewModel.accessibilityIdentifier {
self.accessibilityIdentifier = accessibilityIdentifier
}
surface = viewModel.surface
isEnabled = viewModel.enabled
alignment = viewModel.alignment

View File

@ -7,6 +7,7 @@
//
import Foundation
import MVMCore
import VDS
public class ButtonGroupModel: ParentMoleculeModelProtocol {
@ -17,6 +18,7 @@ public class ButtonGroupModel: ParentMoleculeModelProtocol {
public static var identifier: String = "buttonGroup"
public var id: String = UUID().uuidString
public var accessibilityIdentifier: String?
public var backgroundColor: Color?
public var children: [MoleculeModelProtocol] { buttons }
@ -38,6 +40,7 @@ public class ButtonGroupModel: ParentMoleculeModelProtocol {
private enum CodingKeys: String, CodingKey {
case id
case moleculeName
case accessibilityIdentifier
case backgroundColor
case buttons
case alignment
@ -56,6 +59,7 @@ public class ButtonGroupModel: ParentMoleculeModelProtocol {
required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
id = try typeContainer.decodeIfPresent(String.self, forKey: .id) ?? UUID().uuidString
accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
surface = try typeContainer.decodeIfPresent(Surface.self, forKey: .surface) ?? .light
enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) ?? true
buttons = try typeContainer.decodeModels(codingKey: .buttons)
@ -70,6 +74,7 @@ public class ButtonGroupModel: ParentMoleculeModelProtocol {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encode(moleculeName, forKey: .moleculeName)
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
try container.encode(surface, forKey: .surface)
try container.encode(enabled, forKey: .enabled)
try container.encodeModels(buttons, forKey: .buttons)
@ -79,4 +84,16 @@ public class ButtonGroupModel: ParentMoleculeModelProtocol {
try container.encodeIfPresent(childWidthValue, forKey: .childWidthValue)
try container.encodeIfPresent(childWidthPercentage, forKey: .childWidthPercentage)
}
public func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false }
return buttons.count == model.buttons.count
&& surface == model.surface
&& enabled == model.enabled
&& alignment == model.alignment
&& rowQuantityPhone == model.rowQuantityPhone
&& rowQuantityTablet == model.rowQuantityTablet
&& childWidthValue == model.childWidthValue
&& childWidthPercentage == model.childWidthPercentage
}
}

View File

@ -7,7 +7,7 @@
//
import UIKit
import VDSColorTokens
import VDSCoreTokens
import VDS
import MVMCore
@ -186,4 +186,34 @@ open class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupWat
try container.encodeIfPresent(accessibilityTraits, forKey: .accessibilityTraits)
try container.encodeIfPresent(disabledAccessibilityTraits, forKey: .disabledAccessibilityTraits)
}
public func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false }
return title == model.title
&& enabled == model.enabled
&& inverted == model.inverted
&& accessibilityText == model.accessibilityText
&& accessibilityIdentifier == model.accessibilityIdentifier
&& accessibilityTraits == model.accessibilityTraits
&& disabledAccessibilityTraits == model.disabledAccessibilityTraits
&& style == model.style
&& size == model.size
&& groupName == model.groupName
&& width == model.width
&& action.isEqual(to: model.action)
}
public func isVisuallyEquivalent(to model: any MoleculeModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false }
return title == model.title
&& enabled == model.enabled
&& inverted == model.inverted
&& accessibilityText == model.accessibilityText
&& accessibilityIdentifier == model.accessibilityIdentifier
&& accessibilityTraits == model.accessibilityTraits
&& disabledAccessibilityTraits == model.disabledAccessibilityTraits
&& style == model.style
&& size == model.size
&& width == model.width
}
}

View File

@ -15,7 +15,8 @@ open class ImageButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGro
public static var identifier: String = "imageButton"
public var id: String = UUID().uuidString
public var accessibilityIdentifier: String?
public var backgroundColor: Color?
public var image: ImageViewModel?
@ -33,7 +34,7 @@ open class ImageButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGro
[image].compactMap({$0})
}
public func replaceChildMolecule(with molecule: MoleculeModelProtocol) throws -> Bool {
public func replaceChildMolecule(with molecule: MoleculeModelProtocol) throws -> MoleculeModelProtocol? {
return try replaceChildMolecule(at: &image, with: molecule)
}
@ -45,6 +46,7 @@ open class ImageButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGro
private enum CodingKeys: String, CodingKey {
case id
case moleculeName
case accessibilityIdentifier
case image
case backgroundColor
case accessibilityText
@ -64,6 +66,7 @@ open class ImageButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGro
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
id = try typeContainer.decodeIfPresent(String.self, forKey: .id) ?? UUID().uuidString
accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
image = try typeContainer.decodeIfPresent(ImageViewModel.self, forKey: .image)
accessibilityText = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityText)
@ -91,6 +94,7 @@ open class ImageButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGro
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encode(moleculeName, forKey: .moleculeName)
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
try container.encodeIfPresent(image, forKey: .image)
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
try container.encodeIfPresent(accessibilityText, forKey: .accessibilityText)

View File

@ -7,7 +7,7 @@
//
import UIKit
import VDSColorTokens
import VDSCoreTokens
import VDS
open class Link: VDS.TextLink, VDSMoleculeViewProtocol {

View File

@ -99,6 +99,30 @@ open class LinkModel: ButtonModelProtocol, MoleculeModelProtocol, EnableableMode
try container.encodeIfPresent(size, forKey: .size)
try container.encode(shouldMaskRecordedView, forKey: .shouldMaskRecordedView)
}
public func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false }
return backgroundColor == model.backgroundColor
&& title == model.title
&& accessibilityText == model.accessibilityText
&& accessibilityIdentifier == model.accessibilityIdentifier
&& inverted == model.inverted
&& enabled == model.enabled
&& size == model.size
&& shouldMaskRecordedView == model.shouldMaskRecordedView
&& action.isEqual(to: model.action)
}
public func isVisuallyEquivalent(to model: any MoleculeModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false }
return backgroundColor == model.backgroundColor
&& title == model.title
&& accessibilityText == model.accessibilityText
&& accessibilityIdentifier == model.accessibilityIdentifier
&& inverted == model.inverted
&& enabled == model.enabled
&& size == model.size
}
}
extension LinkModel {

View File

@ -7,7 +7,7 @@
//
import UIKit
import VDSColorTokens
import VDSCoreTokens
import VDS
import MVMCore
import Combine
@ -36,7 +36,7 @@ open class PillButton: VDS.Button, MVMCoreUIViewConstrainingProtocol, MFButtonPr
text = viewModel.title
isEnabled = viewModel.enabled
size = viewModel.size
use = viewModel.style ?? .primary
use = viewModel.style
surface = viewModel.inverted ? .dark : .light
if let accessibilityText = viewModel.accessibilityText {
accessibilityLabel = accessibilityText

View File

@ -0,0 +1,51 @@
//
// DatePickerEntryField.swift
// MVMCoreUI
//
// Created by Matt Bruce on 8/20/24.
// Copyright © 2024 Verizon Wireless. All rights reserved.
//
import Foundation
import VDS
open class DatePickerEntryField: VDS.DatePicker, VDSMoleculeViewProtocol {
//--------------------------------------------------
// MARK: - Public Properties
//--------------------------------------------------
public var viewModel: DatePickerEntryFieldModel!
public var delegateObject: MVMCoreUIDelegateObject?
public var additionalData: [AnyHashable : Any]?
//--------------------------------------------------
// MARK: - Public Methods
//--------------------------------------------------
open override func setup() {
super.setup()
//turn off internal required rule
useRequiredRule = false
publisher(for: .valueChanged)
.sink { [weak self] control in
guard let self, let viewModel, isEnabled else { return }
viewModel.selectedDate = control.selectedDate
_ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate)
}.store(in: &subscribers)
}
public func viewModelDidUpdate() {
surface = viewModel.surface
labelText = viewModel.title
helperText = viewModel.feedback
helperTextPlacement = viewModel.feedbackTextPlacement
tooltipModel = viewModel.tooltip?.convertToVDSTooltipModel()
transparentBackground = viewModel.transparentBackground
width = viewModel.width
selectedDate = viewModel.selectedDate
calendarModel = viewModel.calendar.convertToVDSCalendarModel()
FormValidator.setupValidation(for: viewModel, delegate: delegateObject?.formHolderDelegate)
}
public func updateView(_ size: CGFloat) {}
}

View File

@ -0,0 +1,121 @@
//
// DatePickerEntryFieldModel.swift
// MVMCoreUI
//
// Created by Matt Bruce on 8/20/24.
// Copyright © 2024 Verizon Wireless. All rights reserved.
//
import Foundation
import VDS
open class DatePickerEntryFieldModel: FormFieldModel {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public override static var identifier: String { "datePicker" }
public var dateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateStyle = .medium
formatter.timeZone = NSTimeZone.system
formatter.locale = .current
formatter.formatterBehavior = .default
return formatter
}()
/// Update the property value to alter the format of how the date is presented.
public var dateFormat: String = "MMM d, y" {
didSet { dateFormatter.dateFormat = dateFormat }
}
public var selectedDate: Date?
public var calendar: CalendarViewModel = .init()
public var title: String?
public var feedback: String?
public var feedbackTextPlacement: VDS.DatePicker.HelperTextPlacement = .bottom
public var tooltip: TooltipModel?
public var transparentBackground: Bool = false
public var width: CGFloat?
//--------------------------------------------------
// MARK: - Keys
//--------------------------------------------------
private enum CodingKeys: String, CodingKey {
case dateFormat
case selectedDate
case calendar
case title
case feedback
case feedbackTextPlacement
case tooltip
case transparentBackground
case width
}
//--------------------------------------------------
// MARK: - Form Validation
//--------------------------------------------------
/// Returns the fieldValue of the selectedDate.
public override func formFieldValue() -> AnyHashable? {
guard let selectedDate, enabled else { return nil }
return dateFormatter.string(from: selectedDate)
}
//--------------------------------------------------
// MARK: - Codec
//--------------------------------------------------
required public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
if let dateFormat = try container.decodeIfPresent(String.self, forKey: .dateFormat) {
self.dateFormat = dateFormat
dateFormatter.dateFormat = dateFormat
}
if let date = try container.decodeIfPresent(String.self, forKey: .selectedDate) {
selectedDate = calendar.dateFormatter.date(from: date)
}
if let calendar = try container.decodeIfPresent(CalendarViewModel.self, forKey: .calendar) {
self.calendar = calendar
}
title = try container.decodeIfPresent(String.self, forKey: .title)
feedback = try container.decodeIfPresent(String.self, forKey: .feedback)
feedbackTextPlacement = try container.decodeIfPresent(VDS.EntryFieldBase.HelperTextPlacement.self, forKey: .feedbackTextPlacement) ?? .bottom
tooltip = try container.decodeIfPresent(TooltipModel.self, forKey: .tooltip)
transparentBackground = try container.decodeIfPresent(Bool.self, forKey: .transparentBackground) ?? false
width = try container.decodeIfPresent(CGFloat.self, forKey: .width)
try super.init(from: decoder)
}
public override func encode(to encoder: Encoder) throws {
try super.encode(to: encoder)
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encodeIfPresent(selectedDate, forKey: .selectedDate)
try container.encode(calendar, forKey: .calendar)
try container.encodeIfPresent(title, forKey: .title)
try container.encodeIfPresent(feedback, forKey: .feedback)
try container.encode(feedbackTextPlacement, forKey: .feedbackTextPlacement)
try container.encodeIfPresent(tooltip, forKey: .tooltip)
try container.encode(transparentBackground, forKey: .transparentBackground)
try container.encodeIfPresent(width, forKey: .width)
}
open override func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard super.isEqual(to: model), let model = model as? Self else { return false }
return dateFormat == model.dateFormat
&& selectedDate == model.selectedDate
&& calendar == model.calendar
&& title == model.title
&& feedback == model.feedback
&& feedbackTextPlacement == model.feedbackTextPlacement
&& tooltip == model.tooltip
&& transparentBackground == model.transparentBackground
&& width == model.width
}
}

View File

@ -0,0 +1,159 @@
//
// FormFieldModel.swift
// MVMCoreUI
//
// Created by Matt Bruce on 7/3/24.
// Copyright © 2024 Verizon Wireless. All rights reserved.
//
import Foundation
import VDS
@objcMembers open class FormFieldModel: MoleculeModelProtocol, FormFieldProtocol, FormRuleWatcherFieldProtocol, UIUpdatableModelProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public class var identifier: String { "" }
public var moleculeName: String { Self.identifier }
public var id: String = UUID().uuidString
public var backgroundColor: Color?
public var accessibilityIdentifier: String?
public var enabled: Bool = true
public var required: Bool = true
public var readOnly: Bool = false
public var showError: Bool = false
public var errorMessage: String?
public var initialErrorMessage: String?
public var fieldKey: String?
public var groupName: String = FormValidator.defaultGroupName
public var baseValue: AnyHashable?
public var inverted: Bool = false
public var surface: Surface { inverted ? .dark : .light }
public var dynamicErrorMessage: String? {
didSet {
isValid = dynamicErrorMessage?.isEmpty ?? true
updateUIDynamicError?()
}
}
public var isValid: Bool? = true {
didSet { updateUI?() }
}
/// Temporary binding mechanism for the view to update on enable changes.
public var updateUI: ActionBlock?
// TODO: Remove once updateUI is fixed with isSelected
public var updateUIDynamicError: ActionBlock?
//--------------------------------------------------
// MARK: - Initializer
//--------------------------------------------------
public init() {}
//--------------------------------------------------
// MARK: - Keys
//--------------------------------------------------
private enum CodingKeys: String, CodingKey {
case id
case moleculeName
case accessibilityIdentifier
case errorMessage
case showError
case enabled
case readOnly
case required
case fieldKey
case groupName
case inverted
}
//--------------------------------------------------
// MARK: - Validation Methods
//--------------------------------------------------
open func formFieldValue() -> AnyHashable? {
fatalError("developer must implement")
}
open func formFieldServerValue() -> AnyHashable? {
return formFieldValue()
}
public func setValidity(_ valid: Bool, errorMessage: String?) {
if let ruleErrorMessage = errorMessage, fieldKey != nil {
self.errorMessage = ruleErrorMessage
} else {
self.errorMessage = initialErrorMessage
}
isValid = valid
updateUI?()
}
//--------------------------------------------------
// MARK: - Codable
//--------------------------------------------------
required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
id = try typeContainer.decodeIfPresent(String.self, forKey: .id) ?? UUID().uuidString
accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
errorMessage = try typeContainer.decodeIfPresent(String.self, forKey: .errorMessage)
initialErrorMessage = errorMessage
showError = try typeContainer.decodeIfPresent(Bool.self, forKey: .showError) ?? false
enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) ?? true
required = try typeContainer.decodeIfPresent(Bool.self, forKey: .required) ?? true
readOnly = try typeContainer.decodeIfPresent(Bool.self, forKey: .readOnly) ?? false
fieldKey = try typeContainer.decodeIfPresent(String.self, forKey: .fieldKey)
groupName = try typeContainer.decodeIfPresent(String.self, forKey: .groupName) ?? FormValidator.defaultGroupName
if let inverted = try typeContainer.decodeIfPresent(Bool.self, forKey: .inverted) {
self.inverted = inverted
}
}
open func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encodeIfPresent(moleculeName, forKey: .moleculeName)
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
try container.encodeIfPresent(errorMessage, forKey: .errorMessage)
try container.encodeIfPresent(fieldKey, forKey: .fieldKey)
try container.encodeIfPresent(groupName, forKey: .groupName)
try container.encode(showError, forKey: .showError)
try container.encode(readOnly, forKey: .readOnly)
try container.encode(enabled, forKey: .enabled)
try container.encode(required, forKey: .required)
try container.encode(inverted, forKey: .inverted)
}
open func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false }
return moleculeName == model.moleculeName
&& enabled == model.enabled
&& showError == model.showError
&& errorMessage == model.errorMessage
&& readOnly == model.readOnly
&& required == model.required
&& inverted == model.inverted
&& fieldKey == model.fieldKey
&& groupName == model.groupName
&& accessibilityText == model.accessibilityText
&& accessibilityIdentifier == model.accessibilityIdentifier
&& accessibilityTraits == model.accessibilityTraits
}
}
extension FormFieldModel {
public var isEnabled: Bool { enabled && !readOnly }
}

View File

@ -12,13 +12,15 @@ import MVMCore
@objcMembers public class TagModel: MoleculeModelProtocol {
public static var identifier: String = "tag"
public var id: String = UUID().uuidString
public var accessibilityIdentifier: String?
public var label: LabelModel
public var action: ActionModelProtocol?
public var backgroundColor: Color?
private enum CodingKeys: String, CodingKey {
case id
case accessibilityIdentifier
case moleculeName
case label
case action
@ -42,6 +44,7 @@ import MVMCore
required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
id = try typeContainer.decodeIfPresent(String.self, forKey: .id) ?? UUID().uuidString
accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
label = try typeContainer.decode(LabelModel.self, forKey: .label)
action = try typeContainer.decodeModelIfPresent(codingKey: .action)
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
@ -50,6 +53,7 @@ import MVMCore
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
try container.encode(moleculeName, forKey: .moleculeName)
try container.encode(label, forKey: .label)
try container.encodeModelIfPresent(action, forKey: .action)

View File

@ -12,12 +12,14 @@ import MVMCore
@objcMembers public class TagsModel: MoleculeModelProtocol {
public static var identifier: String = "tags"
public var id: String = UUID().uuidString
public var accessibilityIdentifier: String?
public var backgroundColor: Color?
public var tags: [TagModel]
private enum CodingKeys: String, CodingKey {
case id
case accessibilityIdentifier
case moleculeName
case backgroundColor
case tags
@ -34,6 +36,7 @@ import MVMCore
required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
id = try typeContainer.decodeIfPresent(String.self, forKey: .id) ?? UUID().uuidString
accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
tags = try typeContainer.decode([TagModel].self, forKey: .tags)
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
}
@ -41,6 +44,7 @@ import MVMCore
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
try container.encode(moleculeName, forKey: .moleculeName)
try container.encode(tags, forKey: .tags)
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)

View File

@ -345,9 +345,8 @@ import UIKit
numberOfDigits = model.digits
if let entryType = model.type {
setAsSecureTextEntry(entryType == .secure || entryType == .password)
}
let entryType = model.type
setAsSecureTextEntry(entryType == .secure || entryType == .password)
let observingDelegate = delegateObject?.observingTextFieldDelegate ?? self

View File

@ -16,12 +16,6 @@ import UIKit
public weak var datePicker: UIDatePicker?
private var calendar: Calendar = {
var calendar: Calendar = .current
calendar.timeZone = NSTimeZone.system
return calendar
}()
public var dateFormat: String? {
get { dateDropdownModel?.dateFormat }
set {
@ -97,7 +91,7 @@ import UIKit
dateDropdownModel?.date = date
if calendar.isDate(date, inSameDayAs: Date()) {
if let isToday = dateDropdownModel?.isSelectedToday(), isToday {
text = MVMCoreUIUtility.hardcodedString(withKey: "textfield_today_string")
} else {
text = dateDropdownModel?.dateFormatter.string(from: date)

View File

@ -0,0 +1,21 @@
//
// DateDropdownEntryFieldModel+Extension.swift
// MVMCoreUI
//
// Created by Xi Zhang on 4/23/24.
// Copyright © 2024 Verizon Wireless. All rights reserved.
//
import Foundation
extension DateDropdownEntryFieldModel {
public func isSelectedToday() -> Bool {
guard let date = date else {
return false
}
return calendar.isDate(date, inSameDayAs: Date())
}
}

View File

@ -31,6 +31,12 @@
public var minDate: Date?
public var maxDate: Date?
var calendar: Calendar = {
var calendar: Calendar = .current
calendar.timeZone = NSTimeZone.system
return calendar
}()
//--------------------------------------------------
// MARK: - Keys
//--------------------------------------------------

View File

@ -74,7 +74,7 @@ extension BaseItemPickerEntryField {
@objc open override func setAccessibilityString(_ accessibilityString: String?) {
var accessibilityString = accessibilityString ?? ""
let accessibilityString = accessibilityString ?? ""
textField.accessibilityTraits = .staticText
textField.accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "textfield_picker_item")
textField.accessibilityLabel = "\(accessibilityString) \(textField.isEnabled ? "" : MVMCoreUIUtility.hardcodedString(withKey: "textfield_disabled_state") ?? "")"

View File

@ -7,19 +7,79 @@
//
import UIKit
import VDS
open class ItemDropdownEntryField: VDS.DropdownSelect, VDSMoleculeViewProtocol, ObservingTextFieldDelegate {
//------------------------------------------------------
// MARK: - Properties
//------------------------------------------------------
open var viewModel: ItemDropdownEntryFieldModel!
open var delegateObject: MVMCoreUIDelegateObject?
open var additionalData: [AnyHashable : Any]?
open class ItemDropdownEntryField: BaseItemPickerEntryField {
// Form Validation
var fieldKey: String?
var fieldValue: JSONValue?
var groupName: String?
open var pickerData: [String] = [] {
didSet {
options = pickerData.compactMap({ DropdownOptionModel(text: $0) })
}
}
private var isEditting: Bool = false
//override for to deal with getting the
//old selectedItem to pass down to the observeDropdownChange
open override var selectId: Int? {
didSet {
guard let observeDropdownChange, let selectedItem else { return }
var oldSelectedItem: DropdownOptionModel?
if let oldValue {
oldSelectedItem = options[oldValue]
}
observeDropdownChange(oldSelectedItem?.text, selectedItem.text)
}
}
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public var isValid: Bool = true
/// Closure passed here will run as picker changes items.
public var observeDropdownChange: ((_ oldValue: String?, _ newValue: String) -> ())?
open var pickerData: [String] = []
/// Closure passed here will run upon dismissing the selection picker.
public var observeDropdownSelection: ((_ newValue: String) -> ())?
public var itemDropdownEntryFieldModel: ItemDropdownEntryFieldModel? {
model as? ItemDropdownEntryFieldModel
/// When selecting for first responder, allow initial selected value to appear in empty text field.
public var setInitialValueInTextField = true
open override var errorText: String? {
get {
viewModel.dynamicErrorMessage ?? viewModel.errorMessage
}
set {}
}
//--------------------------------------------------
// MARK: - Delegate Properties
//--------------------------------------------------
/// The delegate and block for validation. Validates if the text that the user has entered.
public weak var observingTextFieldDelegate: ObservingTextFieldDelegate?
/// If you're using a ViewController, you must set this to it
open weak var uiTextFieldDelegate: UITextFieldDelegate? {
get { dropdownField.delegate }
set { dropdownField.delegate = newValue }
}
@objc public func dismissFieldInput(_ sender: Any?) {
_ = resignFirstResponder()
}
//--------------------------------------------------
// MARK: - Initializers
//--------------------------------------------------
@ -28,7 +88,7 @@ open class ItemDropdownEntryField: BaseItemPickerEntryField {
super.init(frame: frame)
}
@objc public convenience init() {
@objc public convenience required init() {
self.init(frame: .zero)
}
@ -40,76 +100,133 @@ open class ItemDropdownEntryField: BaseItemPickerEntryField {
@objc required public init?(coder: NSCoder) {
fatalError("ItemDropdownEntryField init(coder:) has not been implemented")
}
required public init(model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
super.init(model: model, delegateObject, additionalData)
}
//--------------------------------------------------
// MARK: - Methods
//--------------------------------------------------
open override func setup() {
super.setup()
useRequiredRule = false
publisher(for: .valueChanged)
.sink { [weak self] control in
guard let self, let selectedItem, let viewModel else { return }
viewModel.selectedIndex = control.selectId
observeDropdownSelection?(selectedItem.text)
_ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate)
}.store(in: &subscribers)
dropdownField
.publisher(for: .editingDidBegin)
.sink { [weak self] textField in
guard let self else { return }
isEditting = true
setInitialValueFromPicker()
}.store(in: &subscribers)
dropdownField
.publisher(for: .editingDidEnd)
.sink { [weak self] textField in
guard let self else { return }
isEditting = false
_ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate)
if let viewModel, let valid = viewModel.isValid {
updateValidation(valid)
}
performDropdownAction()
}.store(in: &subscribers)
}
public func viewModelDidUpdate() {
pickerData = viewModel.options
showInlineLabel = viewModel.showInlineLabel
helperTextPlacement = viewModel.feedbackTextPlacement
labelText = viewModel.title
helperText = viewModel.feedback
isEnabled = viewModel.enabled
isReadOnly = viewModel.readOnly
isRequired = viewModel.required
tooltipModel = viewModel.tooltip?.convertToVDSTooltipModel()
width = viewModel.width
transparentBackground = viewModel.transparentBackground
if let index = viewModel.selectedIndex {
selectId = index
optionsPicker.selectRow(index, inComponent: 0, animated: false)
pickerView(optionsPicker, didSelectRow: index, inComponent: 0)
}
if (viewModel.selected ?? false) && !viewModel.wasInitiallySelected {
viewModel.wasInitiallySelected = true
isEditting = true
}
FormValidator.setupValidation(for: viewModel, delegate: delegateObject?.formHolderDelegate)
if isEditting {
DispatchQueue.main.async {
_ = self.becomeFirstResponder()
}
}
viewModel.updateUI = {
MVMCoreDispatchUtility.performBlock(onMainThread: { [weak self] in
guard let self = self else { return }
if isEditting {
updateValidation(viewModel.isValid ?? true)
} else if viewModel.isValid ?? true && showError {
showError = false
}
isEnabled = viewModel.enabled
})
}
viewModel.updateUIDynamicError = {
MVMCoreDispatchUtility.performBlock(onMainThread: { [weak self] in
guard let self = self else { return }
let validState = viewModel.isValid ?? false
if !validState && viewModel.shouldClearText {
selectId = nil
viewModel.shouldClearText = false
}
updateValidation(validState)
})
}
}
public func updateView(_ size: CGFloat) { }
/// Sets the textField with the first value of the available picker data.
@objc private func setInitialValueFromPicker() {
private func setInitialValueFromPicker() {
guard !pickerData.isEmpty else { return }
if setInitialValueInTextField {
let pickerIndex = pickerView.selectedRow(inComponent: 0)
itemDropdownEntryFieldModel?.selectedIndex = pickerIndex
observeDropdownChange?(text, pickerData[pickerIndex])
text = pickerData[pickerIndex]
let pickerIndex = optionsPicker.selectedRow(inComponent: 0)
viewModel?.selectedIndex = pickerIndex
selectId = pickerIndex
}
}
@objc override func startEditing() {
super.startEditing()
setInitialValueFromPicker()
private func performDropdownAction() {
guard let actionModel = viewModel.action,
!dropdownField.isFirstResponder
else { return }
MVMCoreUIActionHandler.performActionUnstructured(with: actionModel, sourceModel: viewModel, additionalData: additionalData, delegateObject: delegateObject)
}
@objc override func endInputing() {
super.endInputing()
private func updateValidation(_ isValid: Bool) {
let previousValidity = self.isValid
self.isValid = isValid
guard !pickerData.isEmpty else { return }
observeDropdownSelection?(pickerData[pickerView.selectedRow(inComponent: 0)])
}
public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
super.set(with: model, delegateObject, additionalData)
guard let model = model as? ItemDropdownEntryFieldModel else { return }
pickerData = model.options
if let index = model.selectedIndex {
self.pickerView.selectRow(index, inComponent: 0, animated: false)
self.pickerView(pickerView, didSelectRow: index, inComponent: 0)
if previousValidity && !isValid {
showError = true
} else if (!previousValidity && isValid) {
showError = false
}
}
//--------------------------------------------------
// MARK: - Picker Delegate
//--------------------------------------------------
@objc public override func numberOfComponents(in pickerView: UIPickerView) -> Int { 1 }
@objc public override func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
pickerData.count
}
@objc public func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
guard !pickerData.isEmpty else { return nil }
return pickerData[row]
}
@objc public func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
guard !pickerData.isEmpty else { return }
itemDropdownEntryFieldModel?.selectedIndex = row
observeDropdownChange?(text, pickerData[row])
text = pickerData[row]
}
}

View File

@ -5,16 +5,19 @@
// Created by Kevin Christiano on 1/22/20.
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import VDS
@objcMembers open class ItemDropdownEntryFieldModel: BaseItemPickerEntryFieldModel {
@objcMembers open class ItemDropdownEntryFieldModel: TextEntryFieldModel {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public override class var identifier: String { "dropDown" }
public var action: ActionModelProtocol?
public var options: [String] = []
public var selectedIndex: Int?
public var showInlineLabel: Bool = false
public var feedbackTextPlacement: VDS.DropdownSelect.HelperTextPlacement = .bottom
public init(with options: [String], selectedIndex: Int? = nil) {
self.options = options
@ -42,6 +45,9 @@
private enum CodingKeys: String, CodingKey {
case options
case selectedIndex
case action
case showInlineLabel
case feedbackTextPlacement
}
//--------------------------------------------------
@ -58,6 +64,9 @@
self.selectedIndex = selectedIndex
baseValue = options.indices.contains(selectedIndex) ? options[selectedIndex] : nil
}
showInlineLabel = try typeContainer.decodeIfPresent(Bool.self, forKey: .showInlineLabel) ?? false
feedbackTextPlacement = try typeContainer.decodeIfPresent(VDS.EntryFieldBase.HelperTextPlacement.self, forKey: .feedbackTextPlacement) ?? .bottom
action = try typeContainer.decodeModelIfPresent(codingKey: .action)
}
public override func encode(to encoder: Encoder) throws {
@ -65,5 +74,17 @@
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(options, forKey: .options)
try container.encodeIfPresent(selectedIndex, forKey: .selectedIndex)
try container.encode(showInlineLabel, forKey: .showInlineLabel)
try container.encode(feedbackTextPlacement, forKey: .feedbackTextPlacement)
try container.encodeModelIfPresent(action, forKey: .action)
}
open override func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard super.isEqual(to: model), let model = model as? Self else { return false }
return options == model.options
&& selectedIndex == model.selectedIndex
&& showInlineLabel == model.showInlineLabel
&& feedbackTextPlacement == model.feedbackTextPlacement
&& action.isEqual(to: model.action)
}
}

View File

@ -315,7 +315,9 @@ import UIKit
self.showError = false
}
self.isEnabled = model.enabled
self.text = model.text
if let text = model.text, !text.isEmpty {
self.text = model.text
}
})
}

View File

@ -9,79 +9,38 @@
import Foundation
@objcMembers open class EntryFieldModel: MoleculeModelProtocol, FormFieldProtocol, FormRuleWatcherFieldProtocol, UIUpdatableModelProtocol, ClearableModelProtocol {
@objcMembers open class EntryFieldModel: FormFieldModel, ClearableModelProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public class var identifier: String { "" }
public var id: String = UUID().uuidString
public var backgroundColor: Color?
public var accessibilityIdentifier: String?
public var shouldClearText: Bool = false
public var dynamicErrorMessage: String? {
didSet {
isValid = dynamicErrorMessage?.isEmpty ?? true
updateUIDynamicError?()
}
}
public var errorMessage: String?
public var errorTextColor: Color?
public var enabled: Bool = true
public var required: Bool = true
public var readOnly: Bool = false
public var showError: Bool?
public var hideBorders = false
public var locked: Bool?
public var selected: Bool?
public var text: String?
public var fieldKey: String?
public var groupName: String = FormValidator.defaultGroupName
public var baseValue: AnyHashable?
public var wasInitiallySelected: Bool = false
public var text: String?
public var title: String?
public var feedback: String?
public var shouldMaskRecordedView: Bool? = true
//used to drive the EntryFieldView UI
public var titleStateLabel: FormLabelModel
public var feedbackStateLabel: FormLabelModel
public var isValid: Bool? = true {
didSet { updateUI?() }
}
/// Temporary binding mechanism for the view to update on enable changes.
public var updateUI: ActionBlock?
// TODO: Remove once updateUI is fixed with isSelected
public var updateUIDynamicError: ActionBlock?
public var titleStateLabel = FormLabelModel(text: "")
public var feedbackStateLabel = FormLabelModel(text: "")
//--------------------------------------------------
// MARK: - Keys
//--------------------------------------------------
private enum CodingKeys: String, CodingKey {
case id
case moleculeName
case backgroundColor
case accessibilityIdentifier
case title
case enabled
case readOnly
case feedback
case errorMessage
case errorTextColor
case locked
case selected
case showError
case hideBorders
case text
case fieldKey
case groupName
case required
case shouldMaskRecordedView
}
@ -92,7 +51,7 @@ import Foundation
// MARK: - Validation Methods
//--------------------------------------------------
public func formFieldValue() -> AnyHashable? {
open override func formFieldValue() -> AnyHashable? {
guard enabled else { return nil }
if dynamicErrorMessage != nil {
@ -100,30 +59,15 @@ import Foundation
}
return text
}
open func formFieldServerValue() -> AnyHashable? {
return formFieldValue()
}
public func setValidity(_ valid: Bool, errorMessage: String?) {
if let ruleErrorMessage = errorMessage, fieldKey != nil {
self.errorMessage = ruleErrorMessage
}
self.isValid = valid
updateUI?()
}
//--------------------------------------------------
// MARK: - Initializers
//--------------------------------------------------
public init(with text: String) {
super.init()
self.text = text
baseValue = text
self.titleStateLabel = FormLabelModel(text: "")
self.feedbackStateLabel = FormLabelModel(text: "")
setDefaults()
}
@ -131,7 +75,7 @@ import Foundation
// MARK: - Initializers
//--------------------------------------------------
public func clear() {
self.text = ""
text = ""
}
//--------------------------------------------------
@ -139,55 +83,46 @@ import Foundation
//--------------------------------------------------
required public init(from decoder: Decoder) throws {
try super.init(from: decoder)
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
id = try typeContainer.decodeIfPresent(String.self, forKey: .id) ?? UUID().uuidString
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
title = try typeContainer.decodeIfPresent(String.self, forKey: .title)
feedback = try typeContainer.decodeIfPresent(String.self, forKey: .feedback)
errorMessage = try typeContainer.decodeIfPresent(String.self, forKey: .errorMessage)
errorTextColor = try typeContainer.decodeIfPresent(Color.self, forKey: .errorTextColor)
enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) ?? true
required = try typeContainer.decodeIfPresent(Bool.self, forKey: .required) ?? true
readOnly = try typeContainer.decodeIfPresent(Bool.self, forKey: .readOnly) ?? false
locked = try typeContainer.decodeIfPresent(Bool.self, forKey: .locked)
selected = try typeContainer.decodeIfPresent(Bool.self, forKey: .selected)
text = try typeContainer.decodeIfPresent(String.self, forKey: .text)
hideBorders = try typeContainer.decodeIfPresent(Bool.self, forKey: .hideBorders) ?? false
baseValue = text
fieldKey = try typeContainer.decodeIfPresent(String.self, forKey: .fieldKey)
shouldMaskRecordedView = try typeContainer.decodeIfPresent(Bool.self, forKey: .shouldMaskRecordedView) ?? shouldMaskRecordedView
if let groupName = try typeContainer.decodeIfPresent(String.self, forKey: .groupName) {
self.groupName = groupName
}
self.titleStateLabel = FormLabelModel(text: title ?? "")
self.feedbackStateLabel = FormLabelModel(model: LabelModel(text: feedback ?? "",
titleStateLabel = FormLabelModel(text: title ?? "")
feedbackStateLabel = FormLabelModel(model: LabelModel(text: feedback ?? "",
fontStyle: FormLabelModel.defaultFontStyle,
textColor: Color(uiColor: .mvmCoolGray6)))
setDefaults()
}
public func encode(to encoder: Encoder) throws {
open override func encode(to encoder: Encoder) throws {
try super.encode(to: encoder)
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encodeIfPresent(moleculeName, forKey: .moleculeName)
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
try container.encodeIfPresent(title, forKey: .title)
try container.encodeIfPresent(feedback, forKey: .feedback)
try container.encodeIfPresent(text, forKey: .text)
try container.encodeIfPresent(locked, forKey: .locked)
try container.encodeIfPresent(showError, forKey: .showError)
try container.encodeIfPresent(selected, forKey: .selected)
try container.encodeIfPresent(errorTextColor, forKey: .errorTextColor)
try container.encodeIfPresent(errorMessage, forKey: .errorMessage)
try container.encodeIfPresent(fieldKey, forKey: .fieldKey)
try container.encodeIfPresent(groupName, forKey: .groupName)
try container.encode(readOnly, forKey: .readOnly)
try container.encode(enabled, forKey: .enabled)
try container.encode(required, forKey: .required)
try container.encode(hideBorders, forKey: .hideBorders)
try container.encode(shouldMaskRecordedView, forKey: .shouldMaskRecordedView)
}
open override func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard super.isEqual(to: model), let model = model as? Self else { return false }
return selected == model.selected
&& title == model.title
&& feedback == model.feedback
&& errorTextColor == model.errorTextColor
&& locked == model.locked
&& hideBorders == model.hideBorders
&& text == model.text
&& shouldMaskRecordedView == model.shouldMaskRecordedView
}
}

View File

@ -0,0 +1,347 @@
//
// InputEntryField.swift
// MVMCoreUI
//
// Created by Matt Bruce on 7/16/24.
// Copyright © 2024 Verizon Wireless. All rights reserved.
//
import Foundation
import VDS
@objcMembers open class InputEntryField: VDS.InputField, VDSMoleculeViewProtocol, ObservingTextFieldDelegate, ViewMaskingProtocol {
//------------------------------------------------------
// MARK: - Properties
//------------------------------------------------------
open var viewModel: TextEntryFieldModel!
open var delegateObject: MVMCoreUIDelegateObject?
open var additionalData: [AnyHashable : Any]?
// Form Validation
var fieldKey: String?
var fieldValue: JSONValue?
var groupName: String?
//--------------------------------------------------
// MARK: - Stored Properties
//--------------------------------------------------
public var isValid: Bool = true
/// Holds a reference to the delegating class so this class can internally influence the TextField behavior as well.
private weak var proprietorTextDelegate: UITextFieldDelegate?
private var isEditting: Bool = false {
didSet {
viewModel?.selected = isEditting
}
}
//--------------------------------------------------
// MARK: - Stored Properties
//--------------------------------------------------
private var observingForChange: Bool = false
/// Validate when user resigns editing. Default: true
open var validateWhenDoneEditing: Bool = true
open var shouldMaskWhileRecording: Bool {
return viewModel?.shouldMaskRecordedView ?? false
}
//--------------------------------------------------
// MARK: - Computed Properties
//--------------------------------------------------
/// The text of this TextField.
open override var text: String? {
didSet {
viewModel?.text = text
}
}
open override var errorText: String? {
get {
viewModel.dynamicErrorMessage ?? viewModel.errorMessage
}
set {}
}
/// Placeholder access for the TextField.
public var placeholder: String? {
get { textField.placeholder }
set { textField.placeholder = newValue }
}
//--------------------------------------------------
// MARK: - Delegate Properties
//--------------------------------------------------
/// The delegate and block for validation. Validates if the text that the user has entered.
public weak var observingTextFieldDelegate: ObservingTextFieldDelegate?
/// If you're using a ViewController, you must set this to it
open weak var uiTextFieldDelegate: UITextFieldDelegate?
{
get { textField.delegate }
set {
textField.delegate = self
proprietorTextDelegate = newValue
}
}
//--------------------------------------------------
// MARK: - Lifecycle
//--------------------------------------------------
open override func setup() {
super.setup()
//turn off internal required rule
useRequiredRule = false
publisher(for: .valueChanged)
.sink { [weak self] control in
guard let self, let viewModel else { return }
_ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate)
if (viewModel.type == .email) {
// remove spaces (either user entered Or auto-correct suggestion) for the email field
text = textField.text?.replacingOccurrences(of: " ", with: "")
}
}.store(in: &subscribers)
textField
.publisher(for: .editingDidBegin)
.sink { [weak self] textView in
guard let self else { return }
isEditting = true
if let viewModel, viewModel.clearTextOnTap {
text = ""
}
}.store(in: &subscribers)
textField
.publisher(for: .editingDidEnd)
.sink { [weak self] textView in
guard let self else { return }
isEditting = false
if let viewModel, validateWhenDoneEditing, let valid = viewModel.isValid {
updateValidation(valid)
}
regexTextFieldOutputIfAvailable()
}.store(in: &subscribers)
}
open override func updateView() {
super.updateView()
if let viewModel {
switch viewModel.type {
case .secure:
textField.isSecureTextEntry = true
textField.shouldMaskWhileRecording = true
case .numberSecure:
textField.isSecureTextEntry = true
textField.shouldMaskWhileRecording = true
textField.keyboardType = .numberPad
case .email:
textField.keyboardType = .emailAddress
case .securityCode, .creditCard, .password:
textField.shouldMaskWhileRecording = true
default:
break;
}
// Override the preset keyboard set in type.
if let keyboardType = viewModel.assignKeyboardType() {
textField.keyboardType = keyboardType
}
}
}
open func viewModelDidUpdate() {
fieldType = viewModel.type.toVDSFieldType()
text = viewModel.text
placeholder = viewModel.placeholder
labelText = viewModel.title
helperText = viewModel.feedback
isEnabled = viewModel.enabled
isReadOnly = viewModel.readOnly
isRequired = viewModel.required
tooltipModel = viewModel.tooltip?.convertToVDSTooltipModel()
width = viewModel.width
transparentBackground = viewModel.transparentBackground
containerView.accessibilityIdentifier = model.accessibilityIdentifier
textField.textAlignment = viewModel.textAlignment
textField.enableClipboardActions = viewModel.enableClipboardActions
textField.placeholder = viewModel.placeholder ?? ""
uiTextFieldDelegate = delegateObject?.uiTextFieldDelegate
observingTextFieldDelegate = delegateObject?.observingTextFieldDelegate
if (viewModel.selected ?? false) && !viewModel.wasInitiallySelected {
viewModel.wasInitiallySelected = true
isEditting = true
}
viewModel.rules = rules
FormValidator.setupValidation(for: viewModel, delegate: delegateObject?.formHolderDelegate)
if isEditting {
DispatchQueue.main.async {
_ = self.becomeFirstResponder()
}
}
viewModel.updateUI = {
MVMCoreDispatchUtility.performBlock(onMainThread: { [weak self] in
guard let self = self else { return }
if isEditting {
updateValidation(viewModel.isValid ?? true)
} else if viewModel.isValid ?? true && showError {
showError = false
}
isEnabled = viewModel.enabled
})
}
viewModel.updateUIDynamicError = {
MVMCoreDispatchUtility.performBlock(onMainThread: { [weak self] in
guard let self = self else { return }
let validState = viewModel.isValid ?? false
if !validState && viewModel.shouldClearText {
text = ""
viewModel.shouldClearText = false
}
updateValidation(validState)
})
}
//Added to override text when view is reloaded.
if let text = viewModel.text, !text.isEmpty {
regexTextFieldOutputIfAvailable()
}
}
//--------------------------------------------------
// MARK: - Observing for Change (TextFieldDelegate)
//--------------------------------------------------
@objc public func setBothTextDelegates(to delegate: (UITextFieldDelegate & ObservingTextFieldDelegate)?) {
observingTextFieldDelegate = delegate
uiTextFieldDelegate = delegate
}
func regexTextFieldOutputIfAvailable() {
if let regex = viewModel?.displayFormat,
let mask = viewModel?.displayMask,
let finalText = text {
let range = NSRange(finalText.startIndex..., in: finalText)
if let regex = try? NSRegularExpression(pattern: regex) {
let maskedText = regex.stringByReplacingMatches(in: finalText,
range: range,
withTemplate: mask)
textField.text = maskedText
}
}
}
@objc public func dismissFieldInput(_ sender: Any?) {
_ = resignFirstResponder()
}
private func updateValidation(_ isValid: Bool) {
let previousValidity = self.isValid
self.isValid = isValid
if previousValidity && !isValid {
showError = true
observingTextFieldDelegate?.isValid?(textfield: self)
} else if (!previousValidity && isValid) {
showError = false
observingTextFieldDelegate?.isInvalid?(textfield: self)
}
}
//--------------------------------------------------
// MARK: - MoleculeViewProtocol
//--------------------------------------------------
@objc open func updateView(_ size: CGFloat) {}
}
extension InputEntryField {
//--------------------------------------------------
// MARK: - Implemented TextField Delegate
//--------------------------------------------------
@discardableResult
@objc public func textFieldShouldReturn(_ textField: UITextField) -> Bool {
proprietorTextDelegate?.textFieldShouldReturn?(textField) ?? true
}
@objc public override func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
proprietorTextDelegate?.textField?(textField, shouldChangeCharactersIn: range, replacementString: string)
??
super.textField(textField, shouldChangeCharactersIn: range, replacementString: string)
}
@objc public override func textFieldDidBeginEditing(_ textField: UITextField) {
proprietorTextDelegate?.textFieldDidBeginEditing?(textField) ?? super.textFieldDidBeginEditing(textField)
}
@objc public override func textFieldDidEndEditing(_ textField: UITextField) {
proprietorTextDelegate?.textFieldDidEndEditing?(textField) ?? super.textFieldDidEndEditing(textField)
}
@objc public func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
proprietorTextDelegate?.textFieldShouldBeginEditing?(textField) ?? true
}
@objc public func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
proprietorTextDelegate?.textFieldShouldEndEditing?(textField) ?? true
}
@objc public func textFieldShouldClear(_ textField: UITextField) -> Bool {
proprietorTextDelegate?.textFieldShouldClear?(textField) ?? true
}
}
// MARK: - Accessibility
extension InputEntryField {
@objc open func pushAccessibilityNotification() {
DispatchQueue.main.async { [weak self] in
guard let self = self else { return }
UIAccessibility.post(notification: .layoutChanged, argument: containerView)
}
}
}
internal struct ViewMasking {
static var shouldMaskWhileRecording: UInt8 = 0
}
extension VDS.TextField: ViewMaskingProtocol {
public var shouldMaskWhileRecording: Bool {
get {
return (objc_getAssociatedObject(self, &ViewMasking.shouldMaskWhileRecording) as? Bool) ?? false
}
set {
objc_setAssociatedObject(self, &ViewMasking.shouldMaskWhileRecording, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
}

View File

@ -14,7 +14,7 @@ import MVMCore
/**
This class provides the convenience of formatting the MDN entered/displayer for the user.
*/
@objcMembers open class MdnEntryField: TextEntryField, ABPeoplePickerNavigationControllerDelegate, CNContactPickerDelegate {
@objcMembers open class MdnEntryField: InputEntryField, ABPeoplePickerNavigationControllerDelegate, CNContactPickerDelegate {
//--------------------------------------------------
// MARK: - Stored Properties
//--------------------------------------------------
@ -47,52 +47,17 @@ import MVMCore
get { MVMCoreUIUtility.removeMdnFormat(text) }
set { text = MVMCoreUIUtility.formatMdn(newValue) }
}
/// Toggles selected or original (unselected) UI.
public override var isSelected: Bool {
get { return entryFieldContainer.isSelected }
set (selected) {
if selected && showError {
showError = false
}
super.isSelected = selected
}
}
//--------------------------------------------------
// MARK: - Initializers
//--------------------------------------------------
@objc public override init(frame: CGRect) {
super.init(frame: .zero)
}
@objc public convenience init() {
self.init(frame: .zero)
}
@objc required public init?(coder: NSCoder) {
super.init(coder: coder)
fatalError("MdnEntryField xib not supported.")
}
required public init(model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
super.init(model: model, delegateObject, additionalData)
}
//--------------------------------------------------
// MARK: - Setup
//--------------------------------------------------
@objc public override func setupFieldContainerContent(_ container: UIView) {
super.setupFieldContainerContent(container)
textField.keyboardType = .numberPad
open override func setup() {
super.setup()
setupTextFieldToolbar()
}
open override func setupTextFieldToolbar() {
open func setupTextFieldToolbar() {
let toolbar = UIToolbar.createEmptyToolbar()
let space = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
let contacts = UIBarButtonItem(title: MVMCoreUIUtility.hardcodedString(withKey: "textfield_contacts_barbutton"), style: .plain, target: self, action: #selector(getContacts))
@ -103,40 +68,7 @@ import MVMCore
//--------------------------------------------------
// MARK: - Methods
//--------------------------------------------------
@objc public func hasValidMDN() -> Bool {
guard let MDN = mdn, !MDN.isEmpty else { return false }
if isNationalMDN {
return MVMCoreUIUtility.validateMDNString(MDN)
}
return MVMCoreUIUtility.validateInternationalMDNString(MDN)
}
@objc public func validateMDNTextField() -> Bool {
guard !shouldValidateMDN, let MDN = mdn, !MDN.isEmpty else {
isValid = true
return true
}
isValid = hasValidMDN()
if self.isValid {
showError = false
} else {
entryFieldModel?.errorMessage = entryFieldModel?.errorMessage ?? MVMCoreUIUtility.hardcodedString(withKey: "textfield_phone_format_error_message")
showError = true
UIAccessibility.post(notification: .layoutChanged, argument: textField)
}
return isValid
}
//--------------------------------------------------
@objc public func getContacts(_ sender: Any?) {
let picker = CNContactPickerViewController()
@ -152,11 +84,12 @@ import MVMCore
//--------------------------------------------------
// MARK: - MoleculeViewProtocol
//--------------------------------------------------
public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
super.set(with: model, delegateObject, additionalData)
textField.keyboardType = .phonePad
public override func viewModelDidUpdate() {
viewModel.type = .phone
super.viewModelDidUpdate()
if let phoneNumber = viewModel.text {
text = phoneNumber.formatUSNumber()
}
}
//--------------------------------------------------
@ -179,62 +112,47 @@ import MVMCore
let startIndex = unformedMDN.index(unformedMDN.startIndex, offsetBy: 1)
unformattedMDN = String(unformedMDN[startIndex...])
}
text = unformattedMDN
textFieldShouldReturn(textField)
textFieldDidEndEditing(textField)
}
}
//--------------------------------------------------
// MARK: - Implemented TextField Delegate
//--------------------------------------------------
@discardableResult
@objc public func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return proprietorTextDelegate?.textFieldShouldReturn?(textField) ?? true
@objc public override func textFieldShouldReturn(_ textField: UITextField) -> Bool {
_ = resignFirstResponder()
let superValue = super.textFieldShouldReturn(textField)
return proprietorTextDelegate?.textFieldShouldReturn?(textField) ?? superValue
}
@objc public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if !MVMCoreUIUtility.validate(string, withRegularExpression: RegularExpressionDigitOnly) {
return false
}
return proprietorTextDelegate?.textField?(textField, shouldChangeCharactersIn: range, replacementString: string) ?? true
@objc public override func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let superValue = super.textField(textField, shouldChangeCharactersIn: range, replacementString: string)
return proprietorTextDelegate?.textField?(textField, shouldChangeCharactersIn: range, replacementString: string) ?? superValue
}
@objc public func textFieldDidBeginEditing(_ textField: UITextField) {
textField.text = MVMCoreUIUtility.removeMdnFormat(textField.text)
@objc public override func textFieldDidBeginEditing(_ textField: UITextField) {
super.textFieldDidBeginEditing(textField)
proprietorTextDelegate?.textFieldDidBeginEditing?(textField)
}
@objc public func textFieldDidEndEditing(_ textField: UITextField) {
@objc public override func textFieldDidEndEditing(_ textField: UITextField) {
proprietorTextDelegate?.textFieldDidEndEditing?(textField)
if validateMDNTextField() {
if isNationalMDN {
textField.text = MVMCoreUIUtility.formatMdn(textField.text)
}
// Validate the base input field along with triggering form field validation rules.
validateText()
}
super.textFieldDidEndEditing(textField)
}
@objc public func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
@objc public override func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
proprietorTextDelegate?.textFieldShouldBeginEditing?(textField) ?? true
}
@objc public func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
@objc public override func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
proprietorTextDelegate?.textFieldShouldEndEditing?(textField) ?? true
}
@objc public func textFieldShouldClear(_ textField: UITextField) -> Bool {
@objc public override func textFieldShouldClear(_ textField: UITextField) -> Bool {
proprietorTextDelegate?.textFieldShouldClear?(textField) ?? true
}
}

View File

@ -12,4 +12,9 @@
//--------------------------------------------------
public override class var identifier: String { "mdnEntryField" }
open override func formFieldServerValue() -> AnyHashable? {
guard let value = formFieldValue() as? String else { return nil }
return value.filter { $0.isNumber }
}
}

View File

@ -11,9 +11,9 @@ import UIKit
@objc public protocol ObservingTextFieldDelegate {
/// Called when the entered text becomes valid based on the validation block
@objc optional func isValid(textfield: TextEntryField?)
@objc optional func isValid(textfield: Any?)
/// Called when the entered text becomes invalid based on the validation block
@objc optional func isInvalid(textfield: TextEntryField?)
@objc optional func isInvalid(textfield: Any?)
/// Dismisses the keyboard.
@objc optional func dismissFieldInput(_ sender: Any?)
}
@ -317,9 +317,9 @@ import UIKit
super.shouldShowError(showError)
if showError {
observingTextFieldDelegate?.isValid?(textfield: self)
} else {
observingTextFieldDelegate?.isInvalid?(textfield: self)
} else {
observingTextFieldDelegate?.isValid?(textfield: self)
}
}
@ -397,7 +397,7 @@ extension TextEntryField {
@objc open override func setAccessibilityString(_ accessibilityString: String?) {
var accessibilityString = accessibilityString ?? ""
let accessibilityString = accessibilityString ?? ""
textField.accessibilityLabel = "\(accessibilityString) \(textField.isEnabled ? "" : MVMCoreUIUtility.hardcodedString(withKey: "textfield_disabled_state") ?? "")"
}

View File

@ -5,9 +5,10 @@
// Created by Kevin Christiano on 1/22/20.
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import VDS
@objcMembers open class TextEntryFieldModel: EntryFieldModel {
@objcMembers open class TextEntryFieldModel: EntryFieldModel, FormFieldInternalValidatableProtocol {
//--------------------------------------------------
// MARK: - Types
//--------------------------------------------------
@ -20,6 +21,39 @@
case email
case text
case phone
//additional
case inlineAction
case creditCard
case date
case securityCode
public func toVDSFieldType() -> VDS.InputField.FieldType {
switch self {
case .password:
.password
case .secure:
.text
case .number:
.number
case .numberSecure:
.number
case .email:
.text
case .text:
.text
case .phone:
.telephone
case .inlineAction:
.inlineAction
case .creditCard:
.creditCard
case .date:
.date
case .securityCode:
.securityCode
}
}
}
//--------------------------------------------------
@ -33,12 +67,21 @@
public var disabledTextColor: Color = Color(uiColor: .mvmCoolGray3)
public var textAlignment: NSTextAlignment = .left
public var keyboardOverride: String?
public var type: EntryType?
public var type: EntryType = .text
public var clearTextOnTap: Bool = false
public var displayFormat: String?
public var displayMask: String?
public var enableClipboardActions: Bool = true
public var tooltip: TooltipModel?
public var transparentBackground: Bool = false
public var width: CGFloat?
//--------------------------------------------------
// MARK: - FormFieldInternalValidatableProtocol
//--------------------------------------------------
open var rules: [AnyRule<String>]?
//--------------------------------------------------
// MARK: - Initializers
//--------------------------------------------------
@ -114,6 +157,9 @@
case displayFormat
case displayMask
case enableClipboardActions
case tooltip
case transparentBackground
case width
}
//--------------------------------------------------
@ -128,7 +174,7 @@
displayFormat = try typeContainer.decodeIfPresent(String.self, forKey: .displayFormat)
keyboardOverride = try typeContainer.decodeIfPresent(String.self, forKey: .keyboardOverride)
displayMask = try typeContainer.decodeIfPresent(String.self, forKey: .displayMask)
type = try typeContainer.decodeIfPresent(EntryType.self, forKey: .type)
type = try typeContainer.decodeIfPresent(EntryType.self, forKey: .type) ?? .text
if let clearTextOnTap = try typeContainer.decodeIfPresent(Bool.self, forKey: .clearTextOnTap) {
self.clearTextOnTap = clearTextOnTap
@ -149,6 +195,10 @@
if let enableClipboardActions = try typeContainer.decodeIfPresent(Bool.self, forKey: .enableClipboardActions) {
self.enableClipboardActions = enableClipboardActions
}
tooltip = try typeContainer.decodeIfPresent(TooltipModel.self, forKey: .tooltip)
transparentBackground = try typeContainer.decodeIfPresent(Bool.self, forKey: .transparentBackground) ?? false
width = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .width)
}
open override func encode(to encoder: Encoder) throws {
@ -164,5 +214,25 @@
try container.encode(disabledTextColor, forKey: .disabledTextColor)
try container.encode(clearTextOnTap, forKey: .clearTextOnTap)
try container.encode(enableClipboardActions, forKey: .enableClipboardActions)
try container.encodeIfPresent(tooltip, forKey: .tooltip)
try container.encode(transparentBackground, forKey: .transparentBackground)
try container.encodeIfPresent(width, forKey: .width)
}
open override func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard super.isEqual(to: model), let model = model as? Self else { return false }
return placeholder == model.placeholder
&& textAlignment == model.textAlignment
&& enabledTextColor == model.enabledTextColor
&& disabledTextColor == model.disabledTextColor
&& keyboardOverride == model.keyboardOverride
&& type == model.type
&& clearTextOnTap == model.clearTextOnTap
&& displayFormat == model.displayFormat
&& displayMask == model.displayMask
&& enableClipboardActions == model.enableClipboardActions
&& tooltip == model.tooltip
&& transparentBackground == model.transparentBackground
&& width == model.width
}
}

View File

@ -7,100 +7,60 @@
//
import UIKit
import VDS
class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDelegate {
//--------------------------------------------------
// MARK: - Outlets
//--------------------------------------------------
open private(set) var textView: TextView = {
let textView = TextView()
textView.setContentCompressionResistancePriority(.required, for: .vertical)
return textView
}()
//--------------------------------------------------
open class TextViewEntryField: VDS.TextArea, VDSMoleculeViewProtocol, ObservingTextFieldDelegate, ViewMaskingProtocol {
//------------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
//------------------------------------------------------
open var viewModel: TextViewEntryFieldModel!
open var delegateObject: MVMCoreUIDelegateObject?
open var additionalData: [AnyHashable : Any]?
// Form Validation
open var fieldKey: String?
open var fieldValue: JSONValue?
open var groupName: String?
private var observingForChange: Bool = false
//--------------------------------------------------
// MARK: - Stored Properties
//--------------------------------------------------
public var isValid: Bool = true
private var isEditting: Bool = false {
didSet {
viewModel?.selected = isEditting
}
}
//--------------------------------------------------
// MARK: - Computed Properties
//--------------------------------------------------
public var textViewEntryFieldModel: TextViewEntryFieldModel? {
model as? TextViewEntryFieldModel
open var shouldMaskWhileRecording: Bool {
return viewModel?.shouldMaskRecordedView ?? false
}
public override var isEnabled: Bool {
get { super.isEnabled }
set (enabled) {
super.isEnabled = enabled
DispatchQueue.main.async { [weak self] in
guard let self = self else { return }
self.textView.isEnabled = enabled
if self.textView.isShowingPlaceholder {
self.textView.textColor = self.textView.placeholderTextColor
} else {
self.textView.textColor = (self.textView.isEnabled ? self.textViewEntryFieldModel?.enabledTextColor : self.textViewEntryFieldModel?.disabledTextColor)?.uiColor
}
}
}
}
public override var showError: Bool {
get { super.showError }
set (error) {
if error {
textView.accessibilityValue = String(format: MVMCoreUIUtility.hardcodedString(withKey: "textView_error_message") ?? "", textView.text ?? "", entryFieldModel?.errorMessage ?? "")
} else {
textView.accessibilityValue = nil
}
super.showError = error
/// Placeholder access for the textView.
open var placeholder: String? {
get { viewModel?.placeholder }
set {
textView.placeholder = newValue ?? ""
viewModel?.placeholder = newValue
}
}
/// The text of this textView.
open override var text: String? {
get { textViewEntryFieldModel?.text }
set {
textView.text = newValue
textViewEntryFieldModel?.text = newValue
didSet {
viewModel?.text = text
}
}
/// Placeholder access for the textView.
public var placeholder: String? {
get { textViewEntryFieldModel?.placeholder }
set {
textView.placeholder = newValue ?? ""
textViewEntryFieldModel?.placeholder = newValue
textView.setPlaceholderIfAvailable()
open override var errorText: String? {
get {
viewModel.dynamicErrorMessage ?? viewModel.errorMessage
}
}
//--------------------------------------------------
// MARK: - Constraint
//--------------------------------------------------
public var heightConstraint: NSLayoutConstraint?
private var topConstraint: NSLayoutConstraint?
private var leadingConstraint: NSLayoutConstraint?
private var trailingConstraint: NSLayoutConstraint?
private var bottomConstraint: NSLayoutConstraint?
private func adjustMarginConstraints(constant: CGFloat) {
topConstraint?.constant = constant
leadingConstraint?.constant = constant
trailingConstraint?.constant = constant
bottomConstraint?.constant = constant
set {}
}
//--------------------------------------------------
@ -108,198 +68,178 @@ class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDele
//--------------------------------------------------
/// The delegate and block for validation. Validates if the text that the user has entered.
public weak var observingTextViewDelegate: ObservingTextFieldDelegate? {
didSet {
if observingTextViewDelegate != nil && !observingForChange {
observingForChange = true
NotificationCenter.default.addObserver(self, selector: #selector(valueChanged), name: UITextView.textDidChangeNotification, object: textView)
NotificationCenter.default.addObserver(self, selector: #selector(endInputing), name: UITextView.textDidEndEditingNotification, object: textView)
NotificationCenter.default.addObserver(self, selector: #selector(startEditing), name: UITextView.textDidBeginEditingNotification, object: textView)
} else if observingTextViewDelegate == nil && observingForChange {
observingForChange = false
NotificationCenter.default.removeObserver(self, name: UITextView.textDidChangeNotification, object: textView)
NotificationCenter.default.removeObserver(self, name: UITextView.textDidEndEditingNotification, object: textView)
NotificationCenter.default.removeObserver(self, name: UITextView.textDidBeginEditingNotification, object: textView)
}
}
}
open weak var observingTextViewDelegate: ObservingTextFieldDelegate?
/// If you're using a ViewController, you must set this to it
public weak var uiTextViewDelegate: UITextViewDelegate? {
open weak var uiTextViewDelegate: UITextViewDelegate? {
get { textView.delegate }
set { textView.delegate = newValue }
}
@objc public func setBothTextDelegates(to delegate: (UITextViewDelegate & ObservingTextFieldDelegate)?) {
@objc open func setBothTextDelegates(to delegate: (UITextViewDelegate & ObservingTextFieldDelegate)?) {
observingTextViewDelegate = delegate
uiTextViewDelegate = delegate
}
open func setupTextViewToolbar() {
let observingDelegate = observingTextViewDelegate ?? self
textView.inputAccessoryView = UIToolbar.getToolbarWithDoneButton(delegate: observingDelegate,
action: #selector(observingDelegate.dismissFieldInput))
}
//--------------------------------------------------
// MARK: - Lifecycle
//--------------------------------------------------
@objc open override func setupFieldContainerContent(_ container: UIView) {
open override func setup() {
super.setup()
//turn off internal required rule
useRequiredRule = false
container.addSubview(textView)
publisher(for: .valueChanged)
.sink { [weak self] control in
guard let self, let viewModel else { return }
_ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate)
}.store(in: &subscribers)
topConstraint = textView.topAnchor.constraint(equalTo: container.topAnchor, constant: Padding.Three)
leadingConstraint = textView.leadingAnchor.constraint(equalTo: container.leadingAnchor, constant: Padding.Three)
trailingConstraint = container.trailingAnchor.constraint(equalTo: textView.trailingAnchor, constant: Padding.Three)
bottomConstraint = container.bottomAnchor.constraint(equalTo: textView.bottomAnchor, constant: Padding.Three)
textView
.publisher(for: .editingDidBegin)
.sink { [weak self] textView in
guard let self else { return }
isEditting = true
}.store(in: &subscribers)
topConstraint?.isActive = true
leadingConstraint?.isActive = true
trailingConstraint?.isActive = true
bottomConstraint?.isActive = true
heightConstraint = textView.heightAnchor.constraint(equalToConstant: 0)
accessibilityElements = [textView]
textView
.publisher(for: .editingDidEnd)
.sink { [weak self] textView in
guard let self else { return }
isEditting = false
if let viewModel, let valid = viewModel.isValid {
updateValidation(valid)
}
}.store(in: &subscribers)
}
open override func updateView(_ size: CGFloat) {
super.updateView(size)
textView.updateView(size)
}
open override func reset() {
super.reset()
textView.reset()
adjustMarginConstraints(constant: Padding.Three)
heightConstraint?.constant = 0
heightConstraint?.isActive = false
}
open func viewModelDidUpdate() {
//--------------------------------------------------
// MARK: - Methods
//--------------------------------------------------
/// Validates the text of the entry field.
@objc public override func validateText() {
text = textView.text
super.validateText()
}
/// Executes on UITextView.textDidBeginEditingNotification
@objc override func startEditing() {
super.startEditing()
_ = textView.becomeFirstResponder()
}
/// Executes on UITextView.textDidChangeNotification (each character entry)
@objc override func valueChanged() {
super.valueChanged()
validateText()
}
/// Executes on UITextView.textDidEndEditingNotification
@objc override func endInputing() {
super.endInputing()
text = viewModel.text
minHeight = viewModel.minHeight
maxLength = viewModel.maxLength
// Don't show error till user starts typing.
guard text?.count ?? 0 != 0 else {
showError = false
return
}
if let isValid = textViewEntryFieldModel?.isValid {
self.isValid = isValid
}
showError = !isValid
}
//--------------------------------------------------
// MARK: - MoleculeViewProtocol
//--------------------------------------------------
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
super.set(with: model, delegateObject, additionalData)
guard let model = model as? TextViewEntryFieldModel else { return }
if let height = model.height {
heightConstraint?.constant = height
heightConstraint?.isActive = true
}
text = model.text
labelText = viewModel.title
helperText = viewModel.feedback
isEnabled = viewModel.enabled
isReadOnly = viewModel.readOnly
isRequired = viewModel.required
tooltipModel = viewModel.tooltip?.convertToVDSTooltipModel()
width = viewModel.width
transparentBackground = viewModel.transparentBackground
uiTextViewDelegate = delegateObject?.uiTextViewDelegate
observingTextViewDelegate = delegateObject?.observingTextFieldDelegate
if let accessibilityText = model.accessibilityText {
if let accessibilityText = viewModel.accessibilityText {
accessibilityLabel = accessibilityText
}
containerView.accessibilityIdentifier = viewModel.accessibilityIdentifier
textView.isEditable = viewModel.editable
textView.textAlignment = viewModel.textAlignment
textView.placeholder = viewModel.placeholder ?? ""
if (viewModel.selected ?? false) && !viewModel.wasInitiallySelected {
viewModel.wasInitiallySelected = true
isEditting = true
}
textView.isEditable = model.editable
textView.textAlignment = model.textAlignment
textView.accessibilityIdentifier = model.accessibilityIdentifier
textView.textColor = model.enabled ? model.enabledTextColor.uiColor : model.disabledTextColor.uiColor
textView.font = model.fontStyle.getFont()
textView.placeholder = model.placeholder ?? ""
textView.placeholderFontStyle = model.placeholderFontStyle
textView.placeholderTextColor = model.placeholderTextColor.uiColor
textView.setPlaceholderIfAvailable()
switch model.type {
case .secure, .password:
switch viewModel.type {
case .secure:
textView.isSecureTextEntry = true
textView.shouldMaskWhileRecording = true
case .numberSecure:
textView.isSecureTextEntry = true
textView.keyboardType = .numberPad
case .number:
textView.shouldMaskWhileRecording = true
textView.keyboardType = .numberPad
case .email:
textView.keyboardType = .emailAddress
default: break
case .securityCode, .creditCard, .password:
textView.shouldMaskWhileRecording = true
default:
break;
}
// Override the preset keyboard set in type.
if let keyboardType = viewModel.assignKeyboardType() {
textView.keyboardType = keyboardType
}
/// append any internal rules:
viewModel.rules = rules
/// No point in configuring if the TextView is Read-only.
if textView.isEditable {
FormValidator.setupValidation(for: model, delegate: delegateObject?.formHolderDelegate)
setupTextViewToolbar()
FormValidator.setupValidation(for: viewModel, delegate: delegateObject?.formHolderDelegate)
if isSelected {
if isEditting {
DispatchQueue.main.async {
_ = self.textView.becomeFirstResponder()
_ = self.becomeFirstResponder()
}
}
}
if model.hideBorders {
adjustMarginConstraints(constant: 0)
viewModel.updateUI = {
MVMCoreDispatchUtility.performBlock(onMainThread: { [weak self] in
guard let self = self else { return }
if isEditting {
updateValidation(viewModel.isValid ?? true)
} else if viewModel.isValid ?? true && showError {
showError = false
}
isEnabled = viewModel.enabled
})
}
updateAccessibility(model: model)
viewModel.updateUIDynamicError = {
MVMCoreDispatchUtility.performBlock(onMainThread: { [weak self] in
guard let self = self else { return }
let validState = viewModel.isValid ?? false
if !validState && viewModel.shouldClearText {
text = ""
viewModel.shouldClearText = false
}
updateValidation(validState)
})
}
}
func updateAccessibility(model: TextViewEntryFieldModel) {
private func updateValidation(_ isValid: Bool) {
let previousValidity = self.isValid
self.isValid = isValid
var message = ""
if let titleText = model.accessibilityText ?? model.title {
message += "\(titleText) \( model.enabled ? String(format: (MVMCoreUIUtility.hardcodedString(withKey: "textfield_optional")) ?? "") : "" ) \(self.textView.isEnabled ? "" : MVMCoreUIUtility.hardcodedString(withKey: "textfield_disabled_state") ?? "")"
if previousValidity && !isValid {
showError = true
} else if (!previousValidity && isValid) {
showError = false
}
if let feedback = model.feedback {
message += ", " + feedback
}
//--------------------------------------------------
// MARK: - MoleculeViewProtocol
//--------------------------------------------------
open func updateView(_ size: CGFloat) {}
}
extension VDS.TextView: ViewMaskingProtocol {
public var shouldMaskWhileRecording: Bool {
get {
return (objc_getAssociatedObject(self, &ViewMasking.shouldMaskWhileRecording) as? Bool) ?? false
}
if let errorMessage = errorLabel.text {
message += ", " + errorMessage
set {
objc_setAssociatedObject(self, &ViewMasking.shouldMaskWhileRecording, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
textView.accessibilityLabel = message
}
}

View File

@ -7,9 +7,9 @@
//
import UIKit
import VDS
class TextViewEntryFieldModel: TextEntryFieldModel {
public class TextViewEntryFieldModel: TextEntryFieldModel {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
@ -17,12 +17,10 @@ class TextViewEntryFieldModel: TextEntryFieldModel {
public override class var identifier: String { "textView" }
public var accessibilityText: String?
public var fontStyle: Styler.Font = Styler.Font.RegularBodyLarge
public var height: CGFloat?
public var placeholderTextColor: Color = Color(uiColor: .mvmCoolGray3)
public var placeholderFontStyle: Styler.Font = Styler.Font.RegularMicro
public var editable: Bool = true
public var showsPlaceholder: Bool = false
public var minHeight: VDS.TextArea.Height = .twoX
public var maxLength: Int?
//--------------------------------------------------
// MARK: - Keys
@ -30,11 +28,9 @@ class TextViewEntryFieldModel: TextEntryFieldModel {
private enum CodingKeys: String, CodingKey {
case accessibilityText
case fontStyle
case height
case placeholderFontStyle
case placeholderTextColor
case editable
case minHeight
case maxLength
}
//--------------------------------------------------
@ -45,34 +41,27 @@ class TextViewEntryFieldModel: TextEntryFieldModel {
try super.init(from: decoder)
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
if let placeholderFontStyle = try typeContainer.decodeIfPresent(Styler.Font.self, forKey: .placeholderFontStyle) {
self.placeholderFontStyle = placeholderFontStyle
}
if let placeholderTextColor = try typeContainer.decodeIfPresent(Color.self, forKey: .placeholderTextColor) {
self.placeholderTextColor = placeholderTextColor
}
if let fontStyle = try typeContainer.decodeIfPresent(Styler.Font.self, forKey: .fontStyle) {
self.fontStyle = fontStyle
}
if let editable = try typeContainer.decodeIfPresent(Bool.self, forKey: .editable) {
self.editable = editable
}
editable = try typeContainer.decodeIfPresent(Bool.self, forKey: .editable) ?? true
minHeight = try typeContainer.decodeIfPresent(VDS.TextArea.Height.self, forKey: .minHeight) ?? .twoX
maxLength = try typeContainer.decodeIfPresent(Int.self, forKey: .maxLength)
accessibilityText = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityText)
height = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .height)
}
public override func encode(to encoder: Encoder) throws {
try super.encode(to: encoder)
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encodeIfPresent(accessibilityText, forKey: .accessibilityText)
try container.encodeIfPresent(height, forKey: .height)
try container.encode(fontStyle, forKey: .fontStyle)
try container.encode(editable, forKey: .editable)
try container.encode(placeholderFontStyle, forKey: .placeholderFontStyle)
try container.encode(placeholderTextColor, forKey: .placeholderTextColor)
try container.encode(minHeight, forKey: .minHeight)
try container.encodeIfPresent(maxLength, forKey: .maxLength)
}
open override func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard super.isEqual(to: model), let model = model as? Self else { return false }
return accessibilityText == model.accessibilityText
&& editable == model.editable
&& minHeight == model.minHeight
&& maxLength == model.maxLength
}
}

View File

@ -7,144 +7,41 @@
//
import MVMCore
import VDS
/**
This class expects its height and width to be equal.
*/
@objcMembers open class Checkbox: Control, MVMCoreUIViewConstrainingProtocol {
//--------------------------------------------------
@objcMembers open class Checkbox: VDS.Checkbox, VDSMoleculeViewProtocol, MVMCoreUIViewConstrainingProtocol {
//------------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public var sizeObject: MFSizeObject? = MFSizeObject(standardSize: Checkbox.defaultHeightWidth, standardiPadPortraitSize: Checkbox.defaultHeightWidth + 6.0)
//------------------------------------------------------
open var viewModel: CheckboxModel!
open var delegateObject: MVMCoreUIDelegateObject?
open var additionalData: [AnyHashable : Any]?
// Form Validation
var fieldKey: String?
var fieldValue: JSONValue?
var groupName: String?
var delegateObject: MVMCoreUIDelegateObject?
public var checkboxModel: CheckboxModel? {
model as? CheckboxModel
}
public static let defaultHeightWidth: CGFloat = 18.0
/// If true the border of this checkbox will be circular.
public var isRound: Bool = false
/// Determined if the checkbox's UI should animated when selected.
public var isAnimated: Bool = true
/// Disables all selection logic when setting the value of isSelected, reducing it to a stored property.
public var updateSelectionOnly: Bool = false
/// The color of the background when checked.
public var checkedBackgroundColor: UIColor = .clear {
didSet {
if isSelected {
backgroundColor = checkedBackgroundColor
}
}
}
/// The color of the background when unChecked.
public var unCheckedBackgroundColor: UIColor = .clear {
didSet {
if !isSelected {
backgroundColor = unCheckedBackgroundColor
}
}
}
/// Retrieves ideeal radius value to curve square into a circle.
public var cornerRadiusValue: CGFloat {
bounds.size.height / 2
}
/// Action Block called when the switch is selected.
public var actionBlock: ActionBlock?
/// Manages the appearance of the checkbox.
private var shapeLayer: CAShapeLayer?
/// Width of the check mark.
public var checkWidth: CGFloat = 2 {
open var actionBlock: ActionBlock? {
didSet {
if let shapeLayer = shapeLayer {
CATransaction.withDisabledAnimations {
shapeLayer.lineWidth = checkWidth
if let actionBlock {
onChange = { _ in
actionBlock()
}
}
}
}
open override var isEnabled: Bool {
didSet {
isUserInteractionEnabled = isEnabled
if isEnabled {
layer.borderColor = borderColor.cgColor
backgroundColor = isSelected ? checkedBackgroundColor : unCheckedBackgroundColor
setShapeLayerStrokeColor(checkColor)
} else {
layer.borderColor = disabledBorderColor.cgColor
backgroundColor = disabledBackgroundColor
setShapeLayerStrokeColor(disabledCheckColor)
onChange = nil
}
}
}
public var disabledBackgroundColor: UIColor = .clear
public var disabledBorderColor: UIColor = .mvmCoolGray3
public var disabledCheckColor: UIColor = .mvmCoolGray3
/// Color of the check mark.
public var checkColor: UIColor = .mvmBlack {
didSet { setShapeLayerStrokeColor(checkColor) }
}
/// Border width of the checkbox
public var borderWidth: CGFloat = 1 {
didSet { layer.borderWidth = borderWidth }
}
/// border color of the Checkbox
public var borderColor: UIColor = .mvmBlack {
didSet { layer.borderColor = borderColor.cgColor }
}
/**
The represented state of the Checkbox.
Setting updateSelectionOnly to true bypasses the animation logic inherent with setting this property.
*/
override open var isSelected: Bool {
didSet {
if !updateSelectionOnly {
layoutIfNeeded()
(model as? CheckboxModel)?.selected = isSelected
shapeLayer?.removeAllAnimations()
updateCheckboxUI(isSelected: isSelected, isAnimated: isAnimated)
_ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate)
updateAccessibilityLabel()
}
}
}
//--------------------------------------------------
// MARK: - Constraints
//--------------------------------------------------
public var heightConstraint: NSLayoutConstraint?
public var widthConstraint: NSLayoutConstraint?
/// Updates the height and width anchors of the Checkbox with the assigned value.
public var heigthWidthConstant: CGFloat = Checkbox.defaultHeightWidth {
didSet {
heightConstraint?.constant = heigthWidthConstant
widthConstraint?.constant = heigthWidthConstant
viewModel?.selected = isSelected
_ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate)
}
}
@ -154,11 +51,6 @@ import MVMCore
override public init(frame: CGRect) {
super.init(frame: frame)
isAccessibilityElement = true
accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "checkbox_action_hint")
accessibilityTraits = .button
updateAccessibilityLabel()
}
/// There is currently no intention on using xib files.
@ -167,278 +59,110 @@ import MVMCore
fatalError("xib file is not implemented for Checkbox.")
}
public convenience override init() {
public convenience required init() {
self.init(frame:.zero)
}
public convenience init(isChecked: Bool) {
self.init(frame: .zero)
checkAndBypassAnimations(selected: isChecked)
isSelected = isChecked
}
public convenience init(checkedBackgroundColor: UIColor, unCheckedBackgroundColor: UIColor, isChecked: Bool = false) {
self.init(frame: .zero)
checkAndBypassAnimations(selected: isChecked)
self.checkedBackgroundColor = checkedBackgroundColor
self.unCheckedBackgroundColor = unCheckedBackgroundColor
}
//--------------------------------------------------
// MARK: - Lifecycle
//--------------------------------------------------
override open func layoutSubviews() {
super.layoutSubviews()
drawShapeLayer()
layer.cornerRadius = isRound ? cornerRadiusValue : 0
}
open override func setupView() {
super.setupView()
isUserInteractionEnabled = true
translatesAutoresizingMaskIntoConstraints = false
backgroundColor = .clear
widthConstraint = widthAnchor.constraint(equalToConstant: Checkbox.defaultHeightWidth)
heightConstraint = heightAnchor.constraint(equalToConstant: Checkbox.defaultHeightWidth)
heightWidthIsActive(true)
isSelected = isChecked
}
//--------------------------------------------------
// MARK: - Actions
//--------------------------------------------------
open override func sendAction(_ action: Selector, to target: Any?, for event: UIEvent?) {
super.sendAction(action, to: target, for: event)
toggleAndAction()
}
open override func sendActions(for controlEvents: UIControl.Event) {
super.sendActions(for: controlEvents)
toggleAndAction()
}
/// This will toggle the state of the Checkbox and execute the actionBlock if provided.
public func toggleAndAction() {
isSelected.toggle()
actionBlock?()
open func toggleAndAction() {
toggle()
}
//--------------------------------------------------
// MARK: - Methods
//--------------------------------------------------
/// Creates the check mark layer.
private func drawShapeLayer() {
if shapeLayer == nil {
let shapeLayer = CAShapeLayer()
self.shapeLayer = shapeLayer
shapeLayer.frame = bounds
layer.addSublayer(shapeLayer)
shapeLayer.strokeColor = isEnabled ? checkColor.cgColor : disabledCheckColor.cgColor
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.path = checkMarkPath()
shapeLayer.lineJoin = .miter
shapeLayer.lineWidth = checkWidth
CATransaction.withDisabledAnimations {
shapeLayer.strokeEnd = isSelected ? 1 : 0
}
}
}
/// - returns: The CGPath of a UIBezierPath detailing the path of a checkmark
func checkMarkPath() -> CGPath {
let length = max(bounds.size.height, bounds.size.width)
let xInsetLeft = length * 0.25
let yInsetTop = length * 0.3
let innerWidth = length - (xInsetLeft + length * 0.25) // + Right X Inset
let innerHeight = length - (yInsetTop + length * 0.35) // + Bottom Y Inset
let startPoint = CGPoint(x: xInsetLeft, y: yInsetTop + (innerHeight / 2))
let pivotOffSet = CGPoint(x: xInsetLeft + (innerWidth * 0.33), y: yInsetTop + innerHeight)
let endOffset = CGPoint(x: xInsetLeft + innerWidth, y: yInsetTop)
let bezierPath = UIBezierPath()
bezierPath.move(to: startPoint)
bezierPath.addLine(to: pivotOffSet)
bezierPath.addLine(to: endOffset)
return bezierPath.cgPath
}
/// Programmatic means to check/uncheck the box.
/// - parameter selected: state of the check box: true = checked OR false = unchecked.
/// - parameter animated: allows the state of the checkbox to change with or without animation.
public func updateSelection(to selected: Bool, animated: Bool) {
open func updateSelection(to selected: Bool, animated: Bool) {
DispatchQueue.main.async {
self.checkAndBypassAnimations(selected: selected)
self.drawShapeLayer()
self.shapeLayer?.removeAllAnimations()
self.updateCheckboxUI(isSelected: selected, isAnimated: animated)
self.isAnimated = animated
self.isSelected = selected
}
}
/// updates the visuals of the check mark and background.
/// - parameter isSelected: the check state of the checkbox.
/// - parameter isAnimated: determines of the changes should animate or immediately refelect.
public func updateCheckboxUI(isSelected: Bool, isAnimated: Bool) {
open func updateCheckboxUI(isSelected: Bool, isAnimated: Bool) {
if isAnimated {
let animateStrokeEnd = CABasicAnimation(keyPath: "strokeEnd")
animateStrokeEnd.timingFunction = CAMediaTimingFunction(name: .linear)
animateStrokeEnd.duration = 0.3
animateStrokeEnd.fillMode = .both
animateStrokeEnd.isRemovedOnCompletion = false
animateStrokeEnd.fromValue = !isSelected ? 1 : 0
animateStrokeEnd.toValue = isSelected ? 1 : 0
self.shapeLayer?.add(animateStrokeEnd, forKey: "strokeEnd")
UIView.animate(withDuration: 0.2, delay: 0.1, options: .curveEaseOut, animations: {
self.backgroundColor = isSelected ? self.checkedBackgroundColor : self.unCheckedBackgroundColor
})
} else {
CATransaction.withDisabledAnimations {
self.shapeLayer?.strokeEnd = isSelected ? 1 : 0
}
backgroundColor = isSelected ? checkedBackgroundColor : unCheckedBackgroundColor
DispatchQueue.main.async {
self.isAnimated = isAnimated
self.isSelected = isSelected
}
}
/// Adjust accessibility label based on state of Checkbox.
public func updateAccessibilityLabel() {
// Attention: This needs to be addressed with the accessibility team.
// NOTE: Currently emptying description part of MVMCoreUICheckBox accessibility label to avoid crashing!
if let state = MVMCoreUIUtility.hardcodedString(withKey: isSelected ? "checkbox_checked_state" : "checkbox_unchecked_state") {
accessibilityLabel = String(format: MVMCoreUIUtility.hardcodedString(withKey: "checkbox_desc_state") ?? "%@%@", "", state)
}
}
private func setShapeLayerStrokeColor(_ color: UIColor) {
if let shapeLayer = shapeLayer {
CATransaction.withDisabledAnimations {
shapeLayer.strokeColor = color.cgColor
}
}
}
public func heightWidthIsActive(_ isActive: Bool) {
heightConstraint?.isActive = isActive
widthConstraint?.isActive = isActive
}
private func checkAndBypassAnimations(selected: Bool) {
updateSelectionOnly = true
isSelected = selected
updateSelectionOnly = false
}
//--------------------------------------------------
// MARK: - UITouch
//--------------------------------------------------
open override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
sendActions(for: .touchUpInside)
}
override open func accessibilityActivate() -> Bool {
guard isEnabled else { return false }
sendActions(for: .touchUpInside)
return true
}
//--------------------------------------------------
// MARK: - Molecular
//--------------------------------------------------
open func needsToBeConstrained() -> Bool { true }
open override func reset() {
super.reset()
isEnabled = true
shapeLayer?.removeAllAnimations()
shapeLayer?.removeFromSuperlayer()
shapeLayer = nil
backgroundColor = .clear
borderColor = .mvmBlack
borderWidth = 1
checkColor = .mvmBlack
checkWidth = 2
checkAndBypassAnimations(selected: false)
}
public override func updateView(_ size: CGFloat) {
super.updateView(size)
if let dimension = sizeObject?.getValueBased(onSize: size) {
widthConstraint?.constant = dimension
heightConstraint?.constant = dimension
}
}
open func horizontalAlignment() -> UIStackView.Alignment { .leading }
open func updateView(_ size: CGFloat) {}
private func performCheckboxAction(with actionModel: ActionModelProtocol, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
MVMCoreUIActionHandler.performActionUnstructured(with: actionModel, sourceModel: checkboxModel, additionalData: additionalData, delegateObject: delegateObject)
MVMCoreUIActionHandler.performActionUnstructured(with: actionModel, sourceModel: viewModel, additionalData: additionalData, delegateObject: delegateObject)
}
public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
super.set(with: model, delegateObject, additionalData)
self.delegateObject = delegateObject
guard let model = model as? CheckboxModel else { return }
FormValidator.setupValidation(for: model, delegate: delegateObject?.formHolderDelegate)
if let fieldKey = model.fieldKey {
public func viewModelDidUpdate() {
if let accessibilityIdentifier = viewModel.accessibilityIdentifier {
self.accessibilityIdentifier = accessibilityIdentifier
}
//forms
FormValidator.setupValidation(for: viewModel, delegate: delegateObject?.formHolderDelegate)
groupName = viewModel.groupName
if let fieldKey = viewModel.fieldKey {
self.fieldKey = fieldKey
}
borderColor = (model.inverted ? model.invertedColor : model.borderColor).uiColor
borderWidth = model.borderWidth
checkColor = (model.inverted ? model.invertedColor : model.checkColor).uiColor
unCheckedBackgroundColor = (model.inverted ? model.invertedBackgroundColor : model.unCheckedBackgroundColor).uiColor
checkedBackgroundColor = (model.inverted ? model.invertedBackgroundColor : model.checkedBackgroundColor).uiColor
disabledCheckColor = (model.inverted ? model.invertedColor : model.disabledCheckColor).uiColor
disabledBorderColor = (model.inverted ? model.invertedColor : model.disabledBorderColor).uiColor
disabledBackgroundColor = (model.inverted ? model.invertedColor : model.disabledBackgroundColor).uiColor
isAnimated = model.animated
isRound = model.round
if model.selected {
checkAndBypassAnimations(selected: model.selected)
}
model.updateUI = { [weak self] in
MVMCoreDispatchUtility.performBlock(onMainThread: {
//properties
isEnabled = viewModel.isEnabled
isAnimated = viewModel.animated
//call super here to go around the didSet
//in this class
super.isSelected = viewModel.selected
//events
viewModel.updateUI = {
MVMCoreDispatchUtility.performBlock(onMainThread: { [weak self] in
guard let self = self else { return }
self.isEnabled = model.enabled
//let isValid = viewModel.isValid ?? true
//TODO: Fix issue with default state
//showError = !isValid
isEnabled = viewModel.enabled
})
}
isEnabled = model.enabled && !model.readOnly
if (model.action != nil || model.offAction != nil) {
//onChange
if (viewModel.action != nil || viewModel.offAction != nil) {
actionBlock = { [weak self] in
guard let self = self else { return }
if let offAction = model.offAction, !self.isSelected {
self.performCheckboxAction(with: offAction, delegateObject: delegateObject, additionalData: additionalData)
if let offAction = viewModel.offAction, !isSelected {
performCheckboxAction(with: offAction, delegateObject: delegateObject, additionalData: additionalData)
} else if let action = model.action {
self.performCheckboxAction(with: action, delegateObject: delegateObject, additionalData: additionalData)
} else if let action = viewModel.action {
performCheckboxAction(with: action, delegateObject: delegateObject, additionalData: additionalData)
}
}
}

View File

@ -5,6 +5,7 @@
// Created by Chintakrinda, Arun Kumar (Arun) on 21/01/20.
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import VDS
/// Protocol to apply to any model of a UI Control with a binary on/off nature.
///
@ -13,67 +14,25 @@
var selected: Bool { get set }
}
@objcMembers public class CheckboxModel: MoleculeModelProtocol, SelectableMoleculeModelProtocol, FormFieldProtocol, UIUpdatableModelProtocol {
@objcMembers public class CheckboxModel: FormFieldModel, SelectableMoleculeModelProtocol{
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public static var identifier: String = "checkbox"
public var id: String = UUID().uuidString
public var backgroundColor: Color?
public var accessibilityIdentifier: String?
public static override var identifier: String { "checkbox" }
public var selected: Bool = false
public var enabled: Bool = true
public var readOnly: Bool = false
public var animated: Bool = true
public var inverted: Bool = false
public var round: Bool = false
public var borderWidth: CGFloat = 1
public var borderColor: Color = Color(uiColor: .mvmBlack)
public var checkColor: Color = Color(uiColor: .mvmBlack)
public var unCheckedBackgroundColor: Color = Color(uiColor: .clear)
public var checkedBackgroundColor: Color = Color(uiColor: .clear)
public var disabledBackgroundColor: Color = Color(uiColor: .clear)
public var disabledBorderColor: Color = Color(uiColor: .mvmCoolGray3)
public var disabledCheckColor: Color = Color(uiColor: .mvmCoolGray3)
public var invertedColor: Color = Color(uiColor: .mvmWhite)
public var invertedBackgroundColor: Color = Color(uiColor: .mvmBlack)
public var action: ActionModelProtocol?
public var offAction: ActionModelProtocol?
public var fieldKey: String?
public var groupName: String = FormValidator.defaultGroupName
public var baseValue: AnyHashable?
public var updateUI: ActionBlock?
//--------------------------------------------------
// MARK: - Keys
//--------------------------------------------------
private enum CodingKeys: String, CodingKey {
case id
case moleculeName
case accessibilityIdentifier
case checked
case enabled
case readOnly
case inverted
case animated
case round
case borderWidth
case borderColor
case checkColor
case invertedColor
case invertedBackgroundColor
case unCheckedBackgroundColor
case checkedBackgroundColor
case disabledBackgroundColor
case disabledCheckColor
case disabledBorderColor
case action
case fieldKey
case groupName
case offAction
}
@ -81,16 +40,17 @@
// MARK: - Form Validation
//--------------------------------------------------
public func formFieldValue() -> AnyHashable? {
open override func formFieldValue() -> AnyHashable? {
guard enabled else { return nil }
return selected
}
//--------------------------------------------------
// MARK: - Server Value
//--------------------------------------------------
open func formFieldServerValue() -> AnyHashable? {
return formFieldValue()
open override func setValidity(_ valid: Bool, errorMessage: String?) {
if let ruleErrorMessage = errorMessage, fieldKey != nil {
self.errorMessage = ruleErrorMessage
}
isValid = valid
updateUI?()
}
//--------------------------------------------------
@ -98,7 +58,8 @@
//--------------------------------------------------
public init(isChecked: Bool = false) {
self.selected = isChecked
super.init()
selected = isChecked
baseValue = isChecked
}
@ -107,52 +68,9 @@
//--------------------------------------------------
required public init(from decoder: Decoder) throws {
try super.init(from: decoder)
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
id = try typeContainer.decodeIfPresent(String.self, forKey: .id) ?? UUID().uuidString
accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
if let borderWidth = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .borderWidth) {
self.borderWidth = borderWidth
}
if let borderColor = try typeContainer.decodeIfPresent(Color.self, forKey: .borderColor) {
self.borderColor = borderColor
}
if let checkColor = try typeContainer.decodeIfPresent(Color.self, forKey: .checkColor) {
self.checkColor = checkColor
}
if let unCheckedBackgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .unCheckedBackgroundColor) {
self.unCheckedBackgroundColor = unCheckedBackgroundColor
}
if let checkedBackgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .checkedBackgroundColor) {
self.checkedBackgroundColor = checkedBackgroundColor
}
if let disabledBackgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .disabledBackgroundColor) {
self.disabledBackgroundColor = disabledBackgroundColor
}
if let disabledBorderColor = try typeContainer.decodeIfPresent(Color.self, forKey: .disabledBorderColor) {
self.disabledBorderColor = disabledBorderColor
}
if let disabledCheckColor = try typeContainer.decodeIfPresent(Color.self, forKey: .disabledCheckColor) {
self.disabledCheckColor = disabledCheckColor
}
if let invertedColor = try typeContainer.decodeIfPresent(Color.self, forKey: .invertedColor) {
self.invertedColor = invertedColor
}
if let invertedBackgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .invertedBackgroundColor) {
self.invertedBackgroundColor = invertedBackgroundColor
}
if let checked = try typeContainer.decodeIfPresent(Bool.self, forKey: .checked) {
self.selected = checked
}
@ -162,51 +80,26 @@
if let animated = try typeContainer.decodeIfPresent(Bool.self, forKey: .animated) {
self.animated = animated
}
if let round = try typeContainer.decodeIfPresent(Bool.self, forKey: .round) {
self.round = round
}
if let inverted = try typeContainer.decodeIfPresent(Bool.self, forKey: .inverted) {
self.inverted = inverted
}
enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) ?? true
readOnly = try typeContainer.decodeIfPresent(Bool.self, forKey: .readOnly) ?? false
action = try typeContainer.decodeModelIfPresent(codingKey: .action)
fieldKey = try typeContainer.decodeIfPresent(String.self, forKey: .fieldKey)
if let groupName = try typeContainer.decodeIfPresent(String.self, forKey: .groupName) {
self.groupName = groupName
}
offAction = try typeContainer.decodeModelIfPresent(codingKey: .offAction)
}
public func encode(to encoder: Encoder) throws {
public override func encode(to encoder: Encoder) throws {
try super.encode(to: encoder)
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encode(moleculeName, forKey: .moleculeName)
try container.encodeIfPresent(groupName, forKey: .groupName)
try container.encodeIfPresent(fieldKey, forKey: .fieldKey)
try container.encodeIfPresent(borderColor, forKey: .borderColor)
try container.encode(borderWidth, forKey: .borderWidth)
try container.encode(selected, forKey: .checked)
try container.encode(inverted, forKey: .inverted)
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
try container.encodeIfPresent(checkColor, forKey: .checkColor)
try container.encodeIfPresent(invertedColor, forKey: .invertedColor)
try container.encodeIfPresent(invertedBackgroundColor, forKey: .invertedBackgroundColor)
try container.encodeIfPresent(unCheckedBackgroundColor, forKey: .unCheckedBackgroundColor)
try container.encodeIfPresent(checkedBackgroundColor, forKey: .checkedBackgroundColor)
try container.encodeIfPresent(disabledBorderColor, forKey: .disabledBorderColor)
try container.encodeIfPresent(disabledBackgroundColor, forKey: .disabledBackgroundColor)
try container.encodeIfPresent(disabledCheckColor, forKey: .disabledCheckColor)
try container.encodeIfPresent(animated, forKey: .animated)
try container.encodeIfPresent(round, forKey: .round)
try container.encode(enabled, forKey: .enabled)
try container.encode(readOnly, forKey: .readOnly)
try container.encodeModelIfPresent(action, forKey: .action)
try container.encodeIfPresent(groupName, forKey: .groupName)
try container.encodeModelIfPresent(offAction, forKey: .offAction)
}
open override func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard super.isEqual(to: model), let model = model as? Self else { return false }
return selected == model.selected
&& animated == model.animated
&& offAction.isEqual(to: model.offAction)
&& action.isEqual(to: model.action)
}
}

View File

@ -0,0 +1,58 @@
//
// Checkboxes.swift
// MVMCoreUI
//
// Created by Matt Bruce on 8/19/24.
// Copyright © 2024 Verizon Wireless. All rights reserved.
//
import Foundation
import VDS
open class Checkboxes: VDS.CheckboxGroup, VDSMoleculeViewProtocol {
//------------------------------------------------------
// MARK: - Properties
//------------------------------------------------------
open var viewModel: CheckboxesModel!
open var delegateObject: MVMCoreUIDelegateObject?
open var additionalData: [AnyHashable : Any]?
// Form Validation
var fieldKey: String?
var fieldValue: JSONValue?
var groupName: String?
/// The models for the molecules.
public var checkboxes: [CheckboxLabelModel]?
// MARK: - MoleculeViewProtocol
public func viewModelDidUpdate() {
if let accessibilityIdentifier = viewModel.accessibilityIdentifier {
self.accessibilityIdentifier = accessibilityIdentifier
}
surface = viewModel.surface
showError = viewModel.showError
isEnabled = viewModel.enabled && !viewModel.readOnly
checkboxes = viewModel.checkboxes
checkboxes?.forEach {
FormValidator.setupValidation(for: $0.checkbox, delegate: delegateObject?.formHolderDelegate)
}
selectorModels = viewModel.checkboxes.convertToVDSCheckboxItemModel(surface: surface,
delegateObject: delegateObject,
additionalData: additionalData)
}
open func updateView(_ size: CGFloat) {}
open override func didSelect(_ selectedControl: CheckboxItem) {
super.didSelect(selectedControl)
// since the checkboxes has the state being tracked, we need to update the values here.
if let index = items.firstIndex(where: {$0 === selectedControl}), let selected = checkboxes?[index] {
selected.checkbox.selected = true
}
_ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate)
}
}

View File

@ -0,0 +1,101 @@
//
// CheckboxesModel.swift
// MVMCoreUI
//
// Created by Matt Bruce on 8/19/24.
// Copyright © 2024 Verizon Wireless. All rights reserved.
//
import Foundation
import MVMCore
import VDS
public class CheckboxesModel: MoleculeModelProtocol, ParentMoleculeModelProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public static var identifier: String { "checkboxes" }
public var id: String = UUID().uuidString
public var backgroundColor: Color?
public var accessibilityIdentifier: String?
public var enabled: Bool = true
public var required: Bool = true
public var readOnly: Bool = false
public var showError: Bool = false
public var inverted: Bool = false
public var surface: Surface { inverted ? .dark : .light }
public var checkboxes: [CheckboxLabelModel]
public var children: [any MoleculeModelProtocol] { checkboxes }
//--------------------------------------------------
// MARK: - Keys
//--------------------------------------------------
private enum CodingKeys: String, CodingKey {
case id
case moleculeName
case accessibilityIdentifier
case inverted
case enabled
case readOnly
case showError
case checkboxes
}
//--------------------------------------------------
// MARK: - Initializer
//--------------------------------------------------
public init(with checkboxes: [CheckboxLabelModel]){
self.checkboxes = checkboxes
}
//--------------------------------------------------
// MARK: - Codec
//--------------------------------------------------
required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
id = try typeContainer.decodeIfPresent(String.self, forKey: .id) ?? UUID().uuidString
accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
showError = try typeContainer.decodeIfPresent(Bool.self, forKey: .showError) ?? false
enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) ?? true
readOnly = try typeContainer.decodeIfPresent(Bool.self, forKey: .readOnly) ?? false
if let inverted = try typeContainer.decodeIfPresent(Bool.self, forKey: .inverted) {
self.inverted = inverted
}
checkboxes = try typeContainer.decode([CheckboxLabelModel].self, forKey: .checkboxes)
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encodeIfPresent(moleculeName, forKey: .moleculeName)
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
try container.encode(readOnly, forKey: .readOnly)
try container.encode(enabled, forKey: .enabled)
try container.encode(inverted, forKey: .inverted)
try container.encode(checkboxes, forKey: .checkboxes)
}
open func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false }
return moleculeName == model.moleculeName
&& enabled == model.enabled
&& showError == model.showError
&& readOnly == model.readOnly
&& required == model.required
&& inverted == model.inverted
&& accessibilityText == model.accessibilityText
&& accessibilityIdentifier == model.accessibilityIdentifier
&& accessibilityTraits == model.accessibilityTraits
}
}

View File

@ -5,243 +5,66 @@
// Created by Scott Pfeil on 4/9/20.
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import VDS
open class RadioBox: Control, MFButtonProtocol {
//--------------------------------------------------
@objcMembers open class RadioBox: VDS.RadioBoxItem, VDSMoleculeViewProtocol, MFButtonProtocol {
//------------------------------------------------------
// MARK: - Properties
//------------------------------------------------------
open var viewModel: RadioBoxModel!
open var delegateObject: MVMCoreUIDelegateObject?
open var additionalData: [AnyHashable : Any]?
open var isOutOfStock: Bool {
get { strikethrough }
set {
strikethrough = newValue
viewModel?.strikethrough = newValue
}
}
//--------------------------------------------------
// MARK: - Lifecycle
//--------------------------------------------------
public let label = Label(fontStyle: .RegularBodySmall)
public let subTextLabel = Label(fontStyle: .RegularMicro)
public var isOutOfStock = false
public var accentColor = UIColor.mvmRed
public let innerPadding: CGFloat = 12.0
private var borderLayer: CALayer?
private var strikeLayer: CALayer?
private var maskLayer: CALayer?
public var subTextLabelHeightConstraint: NSLayoutConstraint?
private var delegateObject: MVMCoreUIDelegateObject?
var additionalData: [AnyHashable: Any]?
public var radioBoxModel: RadioBoxModel? {
model as? RadioBoxModel
}
public override var isSelected: Bool {
didSet { updateAccessibility() }
}
public override var isEnabled: Bool {
didSet { updateAccessibility() }
}
public func viewModelDidUpdate() {
if let accessibilityIdentifier = viewModel.accessibilityIdentifier {
self.accessibilityIdentifier = accessibilityIdentifier
}
text = viewModel.text
subText = viewModel.subText
subTextRight = viewModel.subTextRight
strikethrough = viewModel.strikethrough
isSelected = viewModel.selected
isEnabled = viewModel.enabled && !viewModel.readOnly
onChange = { [weak self] _ in
if let radioBoxModel = self?.viewModel, let actionModel = radioBoxModel.action {
Task(priority: .userInitiated) { [weak self] in
guard let self else { return }
try await Button.performButtonAction(with: actionModel, button: self, delegateObject: delegateObject, additionalData: additionalData, sourceModel: radioBoxModel)
}
}
}
}
//--------------------------------------------------
// MARK: - Functions
//--------------------------------------------------
@objc open func selectBox() {
toggle()
}
@objc open func deselectBox() {
toggle()
}
//--------------------------------------------------
// MARK: - MVMCoreViewProtocol
//--------------------------------------------------
open override func updateView(_ size: CGFloat) {
super.updateView(size)
label.updateView(size)
subTextLabel.updateView(size)
layer.setNeedsDisplay()
}
open override func setupView() {
super.setupView()
layer.delegate = self
layer.borderColor = UIColor.mvmCoolGray6.cgColor
layer.borderWidth = 1
open func updateView(_ size: CGFloat) {}
label.numberOfLines = 1
addSubview(label)
NSLayoutConstraint.constraintPinSubview(label, pinTop: true, topConstant: innerPadding, pinBottom: false, bottomConstant: 0, pinLeft: true, leftConstant: innerPadding, pinRight: true, rightConstant: innerPadding)
subTextLabel.textColor = .mvmCoolGray6
subTextLabel.numberOfLines = 1
addSubview(subTextLabel)
NSLayoutConstraint.constraintPinSubview(subTextLabel, pinTop: false, topConstant:0, pinBottom: false, bottomConstant: 0, pinLeft: true, leftConstant: innerPadding, pinRight: true, rightConstant: innerPadding)
bottomAnchor.constraint(greaterThanOrEqualTo: subTextLabel.bottomAnchor, constant: innerPadding).isActive = true
subTextLabel.topAnchor.constraint(equalTo: label.bottomAnchor, constant: 2).isActive = true
subTextLabelHeightConstraint = subTextLabel.heightAnchor.constraint(equalToConstant: 0)
subTextLabelHeightConstraint?.isActive = true
addTarget(self, action: #selector(selectBox), for: .touchUpInside)
isAccessibilityElement = true
}
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
super.set(with: model, delegateObject, additionalData)
guard let model = model as? RadioBoxModel else { return }
self.delegateObject = delegateObject
self.additionalData = additionalData
label.text = model.text
subTextLabel.text = model.subText
isOutOfStock = model.strikethrough
subTextLabelHeightConstraint?.isActive = (subTextLabel.text?.count ?? 0) == 0
if let color = model.selectedAccentColor?.uiColor {
accentColor = color
}
isSelected = model.selected
isEnabled = model.enabled && !model.readOnly
}
open override func reset() {
super.reset()
backgroundColor = .white
accentColor = .mvmRed
}
//--------------------------------------------------
// MARK: - State Handling
//--------------------------------------------------
open override func draw(_ layer: CALayer, in ctx: CGContext) {
// Draw the strikethrough
strikeLayer?.removeFromSuperlayer()
if isOutOfStock {
let line = getStrikeThrough(color: isSelected ? .black : .mvmCoolGray6, thickness: 1)
layer.addSublayer(line)
strikeLayer = line
}
// Draw the border
borderLayer?.removeFromSuperlayer()
if isSelected {
layer.borderWidth = 0
let border = getSelectedBorder()
layer.addSublayer(border)
borderLayer = border
} else {
layer.borderWidth = 1
}
// Handle Mask
maskLayer?.removeFromSuperlayer()
if !isEnabled {
let mask = getMaskLayer()
layer.mask = mask
maskLayer = mask
}
}
open override func layoutSubviews() {
super.layoutSubviews()
// Accounts for any size changes
layer.setNeedsDisplay()
}
@objc open func selectBox() {
guard isEnabled, !isSelected else { return }
isSelected = true
radioBoxModel?.selected = isSelected
if let radioBoxModel = radioBoxModel, let actionModel = radioBoxModel.action {
Task(priority: .userInitiated) {
try await Button.performButtonAction(with: actionModel, button: self, delegateObject: delegateObject, additionalData: additionalData, sourceModel: radioBoxModel)
}
}
layer.setNeedsDisplay()
}
@objc open func deselectBox() {
isSelected = false
radioBoxModel?.selected = isSelected
layer.setNeedsDisplay()
}
/// Gets the selected state border
func getSelectedBorder() -> CAShapeLayer {
let layer = CAShapeLayer()
let topLineWidth: CGFloat = 4
let topLinePath = UIBezierPath()
topLinePath.lineWidth = topLineWidth
topLinePath.move(to: CGPoint(x: 0, y: topLineWidth / 2.0))
topLinePath.addLine(to: CGPoint(x: bounds.width, y: topLineWidth / 2.0))
let topLineLayer = CAShapeLayer()
topLineLayer.fillColor = nil
topLineLayer.strokeColor = accentColor.cgColor
topLineLayer.lineWidth = 4
topLineLayer.path = topLinePath.cgPath
layer.addSublayer(topLineLayer)
let lineWidth: CGFloat = 1
let halfLineWidth: CGFloat = 0.5
let linePath = UIBezierPath()
linePath.move(to: CGPoint(x: halfLineWidth, y: topLineWidth))
linePath.addLine(to: CGPoint(x: halfLineWidth, y: bounds.height))
linePath.move(to: CGPoint(x: 0, y: bounds.height - halfLineWidth))
linePath.addLine(to: CGPoint(x: bounds.width, y: bounds.height - halfLineWidth))
linePath.move(to: CGPoint(x: bounds.width - halfLineWidth, y: bounds.height))
linePath.addLine(to: CGPoint(x: bounds.width - halfLineWidth, y: topLineWidth))
let borderLayer = CAShapeLayer()
borderLayer.fillColor = nil
borderLayer.strokeColor = UIColor.black.cgColor
borderLayer.lineWidth = lineWidth
borderLayer.path = linePath.cgPath
layer.addSublayer(borderLayer)
return layer
}
/// Adds a border to edge
func getStrikeThrough(color: UIColor, thickness: CGFloat) -> CAShapeLayer {
let border = CAShapeLayer()
border.name = "strikethrough"
border.fillColor = nil
border.opacity = 1.0
border.lineWidth = thickness
border.strokeColor = color.cgColor
let linePath = UIBezierPath()
linePath.move(to: CGPoint(x: 0, y: bounds.height))
linePath.addLine(to: CGPoint(x: bounds.width, y: 0))
border.path = linePath.cgPath
return border
}
func getMaskLayer() -> CALayer {
let mask = CALayer()
mask.backgroundColor = UIColor.white.cgColor
mask.opacity = 0.3
mask.frame = bounds
return mask
}
//--------------------------------------------------
// MARK: - Accessibility
//--------------------------------------------------
public func updateAccessibility() {
var message = ""
if let labelText = label.text, label.hasText {
message += labelText + ", "
}
if let subLabelText = subTextLabel.text, subTextLabel.hasText {
message += subLabelText + ", "
}
accessibilityLabel = message
accessibilityTraits = .button
if isSelected {
accessibilityTraits.insert(.selected)
}
if !isEnabled {
accessibilityTraits.insert(.notEnabled)
}
}
}

View File

@ -6,45 +6,35 @@
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import MVMCore
import VDS
@objcMembers public class RadioBoxModel: MoleculeModelProtocol, EnableableModelProtocol {
public class RadioBoxModel: FormFieldModel {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public static var identifier: String = "radioBox"
public var id: String = UUID().uuidString
public override static var identifier: String { "radioBox" }
public var text: String
public var subText: String?
public var backgroundColor: Color?
public var accessibilityIdentifier: String?
public var selectedAccentColor: Color?
public var subTextRight: String?
public var selected: Bool = false
public var enabled: Bool = true
public var readOnly: Bool = false
public var strikethrough: Bool = false
public var fieldValue: String?
public var action: ActionModelProtocol?
public var fieldValue: String?
//--------------------------------------------------
// MARK: - Keys
//--------------------------------------------------
private enum CodingKeys: String, CodingKey {
case id
case moleculeName
case text
case subText
case selectedAccentColor
case backgroundColor
case accessibilityIdentifier
case subTextRight
case selected
case enabled
case strikethrough
case fieldValue
case action
case readOnly
case fieldValue
}
//--------------------------------------------------
@ -53,8 +43,19 @@ import MVMCore
public init(text: String) {
self.text = text
super.init()
}
//--------------------------------------------------
// MARK: - Form Validation
//--------------------------------------------------
/// Returns the fieldValue of the selected box, otherwise the text of the selected box.
public override func formFieldValue() -> AnyHashable? {
guard enabled else { return nil }
return fieldValue
}
//--------------------------------------------------
// MARK: - Codec
//--------------------------------------------------
@ -62,42 +63,42 @@ import MVMCore
required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
id = try typeContainer.decodeIfPresent(String.self, forKey: .id) ?? UUID().uuidString
text = try typeContainer.decode(String.self, forKey: .text)
subText = try typeContainer.decodeIfPresent(String.self, forKey: .subText)
selectedAccentColor = try typeContainer.decodeIfPresent(Color.self, forKey: .selectedAccentColor)
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
subTextRight = try typeContainer.decodeIfPresent(String.self, forKey: .subTextRight)
if let isSelected = try typeContainer.decodeIfPresent(Bool.self, forKey: .selected) {
selected = isSelected
}
enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) ?? true
readOnly = try typeContainer.decodeIfPresent(Bool.self, forKey: .readOnly) ?? false
if let isStrikeTrough = try typeContainer.decodeIfPresent(Bool.self, forKey: .strikethrough) {
strikethrough = isStrikeTrough
}
fieldValue = try typeContainer.decodeIfPresent(String.self, forKey: .fieldValue)
action = try typeContainer.decodeModelIfPresent(codingKey: .action)
try super.init(from: decoder)
}
public func encode(to encoder: Encoder) throws {
public override func encode(to encoder: Encoder) throws {
try super.encode(to: encoder)
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encode(moleculeName, forKey: .moleculeName)
try container.encode(text, forKey: .text)
try container.encodeIfPresent(subText, forKey: .subText)
try container.encodeIfPresent(selectedAccentColor, forKey: .selectedAccentColor)
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
try container.encodeIfPresent(subTextRight, forKey: .subTextRight)
try container.encode(selected, forKey: .selected)
try container.encode(enabled, forKey: .enabled)
try container.encode(readOnly, forKey: .readOnly)
try container.encode(strikethrough, forKey: .strikethrough)
try container.encodeIfPresent(fieldValue, forKey: .fieldValue)
try container.encodeModelIfPresent(action, forKey: .action)
}
open override func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard super.isEqual(to: model), let model = model as? Self else { return false }
return text == model.text
&& subText == model.subText
&& subTextRight == model.subTextRight
&& selected == model.selected
&& strikethrough == model.strikethrough
&& fieldValue == model.fieldValue
&& action.isEqual(to: model.action)
}
}

View File

@ -7,172 +7,49 @@
//
import Foundation
import VDS
public protocol RadioBoxSelectionDelegate: AnyObject {
func selected(radioBox: RadioBoxModel)
}
open class RadioBoxes: VDS.RadioBoxGroup, VDSMoleculeViewProtocol {
//------------------------------------------------------
// MARK: - Properties
//------------------------------------------------------
open var viewModel: RadioBoxesModel!
open var delegateObject: MVMCoreUIDelegateObject?
open var additionalData: [AnyHashable : Any]?
// Form Validation
var fieldKey: String?
var fieldValue: JSONValue?
var groupName: String?
open class RadioBoxes: View {
public var collectionView: CollectionView!
public var collectionViewHeight: NSLayoutConstraint!
private let boxWidth: CGFloat = 151.0
private let boxHeight: CGFloat = 64.0
private var itemSpacing: CGFloat = 12.0
private var numberOfColumns: CGFloat = 2.0
private var radioBoxesModel: RadioBoxesModel? {
return model as? RadioBoxesModel
}
public weak var radioDelegate: RadioBoxSelectionDelegate?
private var delegateObject: MVMCoreUIDelegateObject?
/// The models for the molecules.
public var boxes: [RadioBoxModel]?
private var size: CGFloat?
open override func layoutSubviews() {
super.layoutSubviews()
// Accounts for any collection size changes
DispatchQueue.main.async {
self.collectionView.collectionViewLayout.invalidateLayout()
}
}
open func updateAccessibilityValue(collectionView: UICollectionView, cell: RadioBoxCollectionViewCell, indexPath: IndexPath) {
guard let format = MVMCoreUIUtility.hardcodedString(withKey: "index_string_of_total"),
let indexString = MVMCoreUIUtility.getOrdinalString(forIndex: NSNumber(value: indexPath.row + 1)) else { return }
let total = self.collectionView(collectionView, numberOfItemsInSection: indexPath.section)
cell.accessibilityValue = String(format: format, indexString, total)
}
// MARK: - MVMCoreViewProtocol
open override func setupView() {
super.setupView()
collectionView = createCollectionView()
addSubview(collectionView)
NSLayoutConstraint.constraintPinSubview(toSuperview: collectionView)
collectionViewHeight = collectionView.heightAnchor.constraint(equalToConstant: 300)
collectionViewHeight?.isActive = true
}
// MARK: - MoleculeViewProtocol
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
super.set(with: model, delegateObject, additionalData)
self.delegateObject = delegateObject
guard let model = model as? RadioBoxesModel else { return }
boxes = model.boxes
FormValidator.setupValidation(for: model, delegate: delegateObject?.formHolderDelegate)
backgroundColor = model.backgroundColor?.uiColor
registerCells()
setHeight()
collectionView.reloadData()
}
@objc override open func updateView(_ size: CGFloat) {
super.updateView(size)
self.size = size
itemSpacing = Padding.Component.gutterFor(size: size)
collectionView.updateView(size)
}
// MARK: - Creation
/// Creates the layout for the collection.
open func createCollectionViewLayout() -> UICollectionViewLayout {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .vertical
layout.minimumLineSpacing = itemSpacing
layout.minimumInteritemSpacing = itemSpacing
return layout
}
/// Creates the collection view.
open func createCollectionView() -> CollectionView {
let collection = CollectionView(frame: .zero, collectionViewLayout: createCollectionViewLayout())
collection.dataSource = self
collection.delegate = self
return collection
}
/// Registers the cells with the collection view
open func registerCells() {
collectionView.register(RadioBoxCollectionViewCell.self, forCellWithReuseIdentifier: "RadioBoxCollectionViewCell")
}
// MARK: - JSON Setters
open func setHeight() {
guard let boxes = boxes, boxes.count > 0 else {
collectionViewHeight.constant = 0
return
public func viewModelDidUpdate() {
if let accessibilityIdentifier = viewModel.accessibilityIdentifier {
self.accessibilityIdentifier = accessibilityIdentifier
}
boxes = viewModel.boxes
surface = viewModel.surface
selectorModels = viewModel.boxes.convertToVDSRadioBoxModel(surface: surface)
FormValidator.setupValidation(for: viewModel, delegate: delegateObject?.formHolderDelegate)
// Calculate the height
let rows = ceil(CGFloat(boxes.count) / numberOfColumns)
let height = (rows * boxHeight) + ((rows - 1) * itemSpacing)
collectionViewHeight?.constant = height
}
open func updateView(_ size: CGFloat) {}
open override func didSelect(_ selectedControl: RadioBoxItem) {
super.didSelect(selectedControl)
// since the boxes has the state being tracked, we need to update the values here.
if let index = items.firstIndex(where: {$0 === selectedControl}), let selectedBox = boxes?[index] {
boxes?.forEach { $0.selected = false }
selectedBox.selected = true
_ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate)
}
}
}
extension RadioBoxes: UICollectionViewDelegateFlowLayout {
open func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let itemWidth: CGFloat = (collectionView.bounds.width - itemSpacing) / numberOfColumns
return CGSize(width: itemWidth, height: boxHeight)
}
}
extension RadioBoxes: UICollectionViewDataSource {
open func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return boxes?.count ?? 0
}
open func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let molecule = boxes?[indexPath.row],
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "RadioBoxCollectionViewCell", for: indexPath) as? RadioBoxCollectionViewCell else {
fatalError()
}
cell.reset()
cell.radioBox.isUserInteractionEnabled = false
if let color = radioBoxesModel?.boxesColor {
cell.radioBox.backgroundColor = color.uiColor
}
if let color = radioBoxesModel?.selectedAccentColor {
cell.radioBox.accentColor = color.uiColor
}
cell.set(with: molecule, delegateObject, nil)
cell.updateView(size ?? collectionView.bounds.width)
if molecule.selected {
collectionView.selectItem(at: indexPath, animated: false, scrollPosition: .centeredVertically)
}
updateAccessibilityValue(collectionView: collectionView, cell: cell, indexPath: indexPath)
cell.layoutIfNeeded()
return cell
}
}
extension RadioBoxes: UICollectionViewDelegate {
open func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool {
guard let molecule = boxes?[indexPath.row] else { return false }
return molecule.enabled
}
open func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
guard let cell = collectionView.cellForItem(at: indexPath) as? RadioBoxCollectionViewCell else { return }
cell.radioBox.selectBox()
_ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate)
cell.updateAccessibility()
guard let radioBox = boxes?[indexPath.row] else { return }
radioDelegate?.selected(radioBox: radioBox)
}
open func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
guard let cell = collectionView.cellForItem(at: indexPath) as? RadioBoxCollectionViewCell else { return }
cell.radioBox.deselectBox()
cell.updateAccessibility()
}
}

View File

@ -6,43 +6,37 @@
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import MVMCore
import VDS
@objcMembers public class RadioBoxesModel: MoleculeModelProtocol, FormFieldProtocol {
public class RadioBoxesModel: FormFieldModel, ParentMoleculeModelProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public static var identifier: String = "radioBoxes"
public var id: String = UUID().uuidString
public override static var identifier: String { "radioBoxes" }
public var boxes: [RadioBoxModel]
public var backgroundColor: Color?
public var accessibilityIdentifier: String?
public var selectedAccentColor: Color?
public var boxesColor: Color?
public var fieldKey: String?
public var groupName: String = FormValidator.defaultGroupName
public var baseValue: AnyHashable?
public var enabled: Bool = true
public var readOnly: Bool = false
public var children: [any MoleculeModelProtocol] { boxes }
//--------------------------------------------------
// MARK: - Form Validation
//--------------------------------------------------
/// Returns the fieldValue of the selected box, otherwise the text of the selected box.
public func formFieldValue() -> AnyHashable? {
public override func formFieldValue() -> AnyHashable? {
guard enabled else { return nil }
let selectedBox = boxes.first { (box) -> Bool in
return box.selected
}
return selectedBox?.fieldValue ?? selectedBox?.text
return selectedBox?.formFieldValue() ?? selectedBox?.text
}
//--------------------------------------------------
// MARK: - Server Value
//--------------------------------------------------
open func formFieldServerValue() -> AnyHashable? {
open override func formFieldServerValue() -> AnyHashable? {
return formFieldValue()
}
@ -51,17 +45,7 @@ import MVMCore
//--------------------------------------------------
private enum CodingKeys: String, CodingKey {
case id
case moleculeName
case enabled
case readOnly
case selectedAccentColor
case backgroundColor
case accessibilityIdentifier
case boxesColor
case boxes
case fieldKey
case groupName
}
//--------------------------------------------------
@ -69,7 +53,8 @@ import MVMCore
//--------------------------------------------------
public init(with boxes: [RadioBoxModel]){
self.boxes = boxes
self.boxes = boxes
super.init()
}
//--------------------------------------------------
@ -78,32 +63,29 @@ import MVMCore
required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
id = try typeContainer.decodeIfPresent(String.self, forKey: .id) ?? UUID().uuidString
selectedAccentColor = try typeContainer.decodeIfPresent(Color.self, forKey: .selectedAccentColor)
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
boxesColor = try typeContainer.decodeIfPresent(Color.self, forKey: .boxesColor)
boxes = try typeContainer.decode([RadioBoxModel].self, forKey: .boxes)
fieldKey = try typeContainer.decodeIfPresent(String.self, forKey: .fieldKey)
if let groupName = try typeContainer.decodeIfPresent(String.self, forKey: .groupName) {
self.groupName = groupName
}
enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) ?? true
readOnly = try typeContainer.decodeIfPresent(Bool.self, forKey: .readOnly) ?? false
baseValue = formFieldValue()
try super.init(from: decoder)
}
public func encode(to encoder: Encoder) throws {
public override func encode(to encoder: Encoder) throws {
try super.encode(to: encoder)
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encode(moleculeName, forKey: .moleculeName)
try container.encode(boxes, forKey: .boxes)
try container.encodeIfPresent(selectedAccentColor, forKey: .selectedAccentColor)
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
try container.encodeIfPresent(fieldKey, forKey: .fieldKey)
try container.encode(groupName, forKey: .groupName)
try container.encode(enabled, forKey: .enabled)
try container.encode(readOnly, forKey: .readOnly)
}
}
extension Array where Element == RadioBoxModel {
internal func convertToVDSRadioBoxModel(surface: Surface) -> [RadioBoxGroup.RadioBoxItemModel] {
compactMap({ item in
var radioBox = RadioBoxGroup.RadioBoxItemModel()
radioBox.text = item.text
radioBox.subText = item.subText
radioBox.subTextRight = item.subTextRight
radioBox.surface = surface
radioBox.selected = item.selected
radioBox.strikethrough = item.strikethrough
radioBox.enabled = item.isEnabled
return radioBox
})
}
}

View File

@ -7,38 +7,26 @@
//
import UIKit
import VDSColorTokens
import VDSFormControlsTokens
import VDS
@objcMembers open class RadioButton: Control, MFButtonProtocol {
//--------------------------------------------------
@objcMembers open class RadioButton: VDS.RadioButton, RadioButtonSelectionHelperProtocol, VDSMoleculeViewProtocol, MFButtonProtocol, MVMCoreUIViewConstrainingProtocol {
//------------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public var diameter: CGFloat = 20 {
didSet { widthConstraint?.constant = diameter }
//------------------------------------------------------
open var viewModel: RadioButtonModel!
open var delegateObject: MVMCoreUIDelegateObject?
open var additionalData: [AnyHashable : Any]?
open var radioButtonModel: RadioButtonModel {
viewModel
}
@objc public override var isSelected: Bool {
didSet {
radioModel?.state = isSelected
updateAccessibilityLabel()
}
}
public var enabledColor: UIColor {
return radioModel?.inverted ?? false ? VDSColor.elementsPrimaryOndark : VDSColor.elementsPrimaryOnlight
}
public var disabledColor: UIColor {
return radioModel?.inverted ?? false ? VDSColor.interactiveDisabledOndark : VDSColor.interactiveDisabledOnlight
}
public var delegateObject: MVMCoreUIDelegateObject?
var additionalData: [AnyHashable: Any]?
public var radioModel: RadioButtonModel? {
model as? RadioButtonModel
}
lazy public var radioGroupName: String? = { radioModel?.fieldKey }()
// Form Validation
open var fieldKey: String?
open var fieldValue: JSONValue?
open var groupName: String?
lazy public var radioGroupName: String? = { viewModel.fieldKey }()
lazy public var radioButtonSelectionHelper: RadioButtonSelectionHelper? = {
@ -49,132 +37,120 @@ import VDSFormControlsTokens
return radioButtonModel
}()
public override var isEnabled: Bool {
didSet {
isUserInteractionEnabled = isEnabled
setNeedsDisplay()
}
//--------------------------------------------------
// MARK: - Initializers
//--------------------------------------------------
override public init(frame: CGRect) {
super.init(frame: frame)
}
//--------------------------------------------------
// MARK: - Constraints
//--------------------------------------------------
public var widthConstraint: NSLayoutConstraint?
public var heightConstraint: NSLayoutConstraint?
//--------------------------------------------------
// MARK: - Lifecycle
//--------------------------------------------------
open override func draw(_ rect: CGRect) {
guard let context = UIGraphicsGetCurrentContext() else { return }
let color = isEnabled == false ? disabledColor.cgColor : enabledColor.cgColor
layer.cornerRadius = bounds.width * 0.5
layer.borderColor = color
layer.borderWidth = bounds.width * 0.0333
if isSelected {
// Space around inner circle is 1/5 the size
context.addEllipse(in: CGRect(x: bounds.width * 0.2,
y: bounds.height * 0.2,
width: bounds.width * 0.6,
height: bounds.height * 0.6))
context.setFillColor(color)
context.fillPath()
}
/// There is currently no intention on using xib files.
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
fatalError("xib file is not implemented for Checkbox.")
}
public convenience required init() {
self.init(frame:.zero)
}
//--------------------------------------------------
// MARK: - Validation
//--------------------------------------------------
/// The action performed when tapped.
func tapAction() {
if !isEnabled {
return
}
let wasPreviouslySelected = isSelected
if let radioButtonModel = radioButtonSelectionHelper {
radioButtonModel.selected(self)
} else {
isSelected = !isSelected
}
if let radioModel = radioModel, let actionModel = radioModel.action, isSelected, !wasPreviouslySelected {
Task(priority: .userInitiated) {
try await Button.performButtonAction(with: actionModel, button: self, delegateObject: delegateObject, additionalData: additionalData, sourceModel: radioModel)
}
}
_ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate)
setNeedsDisplay()
}
public func isValidField() -> Bool { isSelected }
public func formFieldName() -> String? {
radioModel?.fieldKey
viewModel.fieldKey
}
public func formFieldGroupName() -> String? {
radioModel?.fieldKey
viewModel.fieldKey
}
public func formFieldValue() -> AnyHashable? {
guard let radioModel = radioModel, radioModel.enabled else { return nil }
guard let radioModel = viewModel, radioModel.enabled else { return nil }
return radioModel.fieldValue
}
//--------------------------------------------------
// MARK: - Methods
//--------------------------------------------------
/// Adjust accessibility label based on state of RadioButton.
func updateAccessibilityLabel() {
if let message = MVMCoreUIUtility.hardcodedString(withKey: "radio_button"),
let selectedState = MVMCoreUIUtility.hardcodedString(withKey: isSelected ? "radio_selected_state" : "radio_not_selected_state") {
accessibilityLabel = message + selectedState
// MARK: - Lifecycle
//--------------------------------------------------
open override func setup() {
super.setup()
// Radio button should never be smaller that its content size.
setContentCompressionResistancePriority(.required, for: .vertical)
setContentCompressionResistancePriority(.required, for: .horizontal)
publisher(for: .valueChanged)
.sink { [weak self] control in
guard let self, isEnabled else { return }
viewModel?.state = isSelected
_ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate)
}.store(in: &subscribers)
}
open func viewModelDidUpdate() {
if let accessibilityIdentifier = viewModel.accessibilityIdentifier {
self.accessibilityIdentifier = accessibilityIdentifier
}
//events
viewModel.updateUI = {
MVMCoreDispatchUtility.performBlock(onMainThread: { [weak self] in
guard let self = self else { return }
let isValid = viewModel.isValid ?? true
showError = !isValid
isEnabled = viewModel.enabled
})
}
isSelected = viewModel.state
isEnabled = viewModel.isEnabled
RadioButtonSelectionHelper.setupForRadioButtonGroup(viewModel, self, delegateObject: delegateObject)
}
//--------------------------------------------------
// MARK: - Overrides
//--------------------------------------------------
open override func toggle() {
guard !isSelected, isEnabled else { return }
//removed error
if showError && isSelected == false {
showError.toggle()
}
let wasPreviouslySelected = isSelected
if let radioButtonSelectionHelper {
radioButtonSelectionHelper.selected(self)
} else {
isSelected.toggle()
}
if let actionModel = viewModel.action, isSelected, !wasPreviouslySelected {
Task(priority: .userInitiated) {
try await Button.performButtonAction(with: actionModel, button: self, delegateObject: delegateObject, additionalData: additionalData, sourceModel: viewModel)
}
}
sendActions(for: .valueChanged)
setNeedsUpdate()
}
//--------------------------------------------------
// MARK: - MVMViewProtocol
// MARK: - Actions
//--------------------------------------------------
open override func setupView() {
super.setupView()
backgroundColor = .clear
clipsToBounds = true
widthConstraint = widthAnchor.constraint(equalToConstant: 20)
widthConstraint?.isActive = true
heightConstraint = heightAnchor.constraint(equalTo: widthAnchor, multiplier: 1)
heightConstraint?.isActive = true
addTarget(self, action: #selector(tapAction), for: .touchUpInside)
isAccessibilityElement = true
accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "radio_action_hint")
accessibilityTraits = .button
updateAccessibilityLabel()
/// This will toggle the state of the Checkbox and execute the actionBlock if provided.
public func tapAction() {
toggle()
}
//--------------------------------------------------
// MARK: - MoleculeViewProtocol
//--------------------------------------------------
public func updateView(_ size: CGFloat) {}
public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
super.set(with: model, delegateObject, additionalData)
self.delegateObject = delegateObject
self.additionalData = additionalData
guard let model = model as? RadioButtonModel else { return }
isSelected = model.state
isEnabled = model.enabled && !model.readOnly
RadioButtonSelectionHelper.setupForRadioButtonGroup(model, self, delegateObject: delegateObject)
}
public override func reset() {
super.reset()
backgroundColor = .clear
}
}

View File

@ -7,48 +7,29 @@
//
import MVMCore
import VDS
open class RadioButtonModel: MoleculeModelProtocol, FormFieldProtocol {
open class RadioButtonModel: FormFieldModel {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public static var identifier: String = "radioButton"
public var id: String = UUID().uuidString
public var backgroundColor: Color?
public var accessibilityIdentifier: String?
public static override var identifier: String { "radioButton" }
public var state: Bool = false
public var enabled: Bool = true
public var readOnly: Bool = false
/// The specific value to send to server. TODO: update this to be more generic.
public var fieldValue: String?
public var baseValue: AnyHashable?
public var groupName: String = FormValidator.defaultGroupName
public var fieldKey: String?
public var action: ActionModelProtocol?
public var inverted: Bool = false
//--------------------------------------------------
// MARK: - Keys
//--------------------------------------------------
private enum CodingKeys: String, CodingKey {
case id
case moleculeName
case backgroundColor
case accessibilityIdentifier
case state
case enabled
case fieldValue
case fieldKey
case groupName
case action
case readOnly
case inverted
}
//--------------------------------------------------
@ -56,69 +37,57 @@ open class RadioButtonModel: MoleculeModelProtocol, FormFieldProtocol {
//--------------------------------------------------
public init(_ state: Bool) {
super.init()
self.state = state
baseValue = state
self.baseValue = state
}
//--------------------------------------------------
// MARK: - Validation
//--------------------------------------------------
public func formFieldValue() -> AnyHashable? {
public override func formFieldValue() -> AnyHashable? {
guard enabled else { return nil }
return fieldValue
}
//--------------------------------------------------
// MARK: - Server Value
//--------------------------------------------------
open func formFieldServerValue() -> AnyHashable? {
return formFieldValue()
open override func setValidity(_ valid: Bool, errorMessage: String?) {
if let ruleErrorMessage = errorMessage, fieldKey != nil {
self.errorMessage = ruleErrorMessage
}
isValid = valid
updateUI?()
}
//--------------------------------------------------
// MARK: - Codec
//--------------------------------------------------
required public init(from decoder: Decoder) throws {
try super.init(from: decoder)
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
id = try typeContainer.decodeIfPresent(String.self, forKey: .id) ?? UUID().uuidString
if let state = try typeContainer.decodeIfPresent(Bool.self, forKey: .state) {
self.state = state
}
enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) ?? true
readOnly = try typeContainer.decodeIfPresent(Bool.self, forKey: .readOnly) ?? false
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
baseValue = state
fieldKey = try typeContainer.decodeIfPresent(String.self, forKey: .fieldKey)
if let groupName = try typeContainer.decodeIfPresent(String.self, forKey: .groupName) {
self.groupName = groupName
}
fieldValue = try typeContainer.decodeIfPresent(String.self, forKey: .fieldValue)
action = try typeContainer.decodeModelIfPresent(codingKey: .action)
if let inverted = try typeContainer.decodeIfPresent(Bool.self, forKey: .inverted) {
self.inverted = inverted
}
}
public func encode(to encoder: Encoder) throws {
public override func encode(to encoder: Encoder) throws {
try super.encode(to: encoder)
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
try container.encode(id, forKey: .id)
try container.encode(moleculeName, forKey: .moleculeName)
try container.encode(state, forKey: .state)
try container.encode(enabled, forKey: .enabled)
try container.encode(readOnly, forKey: .readOnly)
try container.encodeIfPresent(fieldKey, forKey: .fieldKey)
try container.encodeIfPresent(groupName, forKey: .groupName)
try container.encodeIfPresent(fieldValue, forKey: .fieldValue)
try container.encodeModelIfPresent(action, forKey: .action)
try container.encodeIfPresent(inverted, forKey: .inverted)
}
open override func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard super.isEqual(to: model), let model = model as? Self else { return false }
return state == model.state
&& fieldValue == model.fieldValue
&& action.isEqual(to: model.action)
}
}

View File

@ -6,6 +6,10 @@
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
public protocol RadioButtonSelectionHelperProtocol: AnyObject {
var isSelected: Bool { get set }
var radioButtonModel: RadioButtonModel { get }
}
@objcMembers public class RadioButtonSelectionHelper: FormFieldProtocol {
//--------------------------------------------------
@ -14,7 +18,7 @@
public var fieldKey: String?
public var groupName: String = FormValidator.defaultGroupName
private var selectedRadioButton: RadioButton?
private var selectedRadioButton: RadioButtonSelectionHelperProtocol?
private var selectedRadioButtonModel: RadioButtonModel?
public var baseValue: AnyHashable?
public var enabled: Bool = true
@ -24,7 +28,7 @@
// MARK: - Initializer
//--------------------------------------------------
public func set(_ radioButtonModel: RadioButtonModel, _ radioButton: RadioButton) {
public func set(_ radioButtonModel: RadioButtonModel, _ radioButton: RadioButtonSelectionHelperProtocol) {
self.fieldKey = radioButtonModel.fieldKey
self.groupName = radioButtonModel.groupName
@ -49,7 +53,7 @@
// MARK: - Functions
//--------------------------------------------------
public static func setupForRadioButtonGroup(_ radioButtonModel: RadioButtonModel, _ radioButton: RadioButton, delegateObject: MVMCoreUIDelegateObject?) {
public static func setupForRadioButtonGroup(_ radioButtonModel: RadioButtonModel, _ radioButton: RadioButtonSelectionHelperProtocol, delegateObject: MVMCoreUIDelegateObject?) {
guard let groupName = radioButtonModel.fieldKey,
let formValidator = delegateObject?.formHolderDelegate?.formValidator
@ -61,10 +65,10 @@
FormValidator.setupValidation(for: radioButtonSelectionHelper, delegate: delegateObject?.formHolderDelegate)
}
public func selected(_ radioButton: RadioButton) {
public func selected(_ radioButton: RadioButtonSelectionHelperProtocol) {
// Checks because the view could be reused
if selectedRadioButton?.radioModel === selectedRadioButtonModel {
if selectedRadioButton?.radioButtonModel === selectedRadioButtonModel {
selectedRadioButton?.isSelected = false
} else {
selectedRadioButtonModel?.state = false
@ -72,7 +76,7 @@
selectedRadioButton = radioButton
selectedRadioButton?.isSelected = true
selectedRadioButtonModel = selectedRadioButton?.radioModel
selectedRadioButtonModel = selectedRadioButton?.radioButtonModel
}
}

View File

@ -0,0 +1,57 @@
//
// RadioButtons.swift
// MVMCoreUI
//
// Created by Matt Bruce on 8/20/24.
// Copyright © 2024 Verizon Wireless. All rights reserved.
//
import Foundation
import VDS
open class RadioButtons: VDS.RadioButtonGroup, VDSMoleculeViewProtocol {
//------------------------------------------------------
// MARK: - Properties
//------------------------------------------------------
open var viewModel: RadioButtonsModel!
open var delegateObject: MVMCoreUIDelegateObject?
open var additionalData: [AnyHashable : Any]?
// Form Validation
var fieldKey: String?
var fieldValue: JSONValue?
var groupName: String?
/// The models for the molecules.
public var radioButtons: [RadioButtonLabelModel]?
// MARK: - MoleculeViewProtocol
public func viewModelDidUpdate() {
if let accessibilityIdentifier = viewModel.accessibilityIdentifier {
self.accessibilityIdentifier = accessibilityIdentifier
}
showError = viewModel.showError
isEnabled = viewModel.isEnabled
surface = viewModel.surface
radioButtons = viewModel.radioButtons
selectorModels = viewModel.radioButtons.convertToVDSRadioButtonItemModel(surface: surface,
delegateObject: delegateObject,
additionalData: additionalData)
FormValidator.setupValidation(for: viewModel, delegate: delegateObject?.formHolderDelegate)
}
open func updateView(_ size: CGFloat) {}
open override func didSelect(_ selectedControl: RadioButtonItem) {
super.didSelect(selectedControl)
// since the radiobutton has the state being tracked, we need to update the values here.
if let index = items.firstIndex(where: {$0 === selectedControl}), let selected = radioButtons?[index] {
radioButtons?.forEach { $0.radioButton.state = false }
selected.radioButton.state = true
}
_ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate)
}
}

View File

@ -0,0 +1,74 @@
//
// RadioButtonsModel.swift
// MVMCoreUI
//
// Created by Matt Bruce on 8/20/24.
// Copyright © 2024 Verizon Wireless. All rights reserved.
//
import Foundation
import MVMCore
import VDS
public class RadioButtonsModel: FormFieldModel, ParentMoleculeModelProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public override static var identifier: String { "radioButtons" }
public var radioButtons: [RadioButtonLabelModel]
public var children: [any MoleculeModelProtocol] { radioButtons }
//--------------------------------------------------
// MARK: - Form Validation
//--------------------------------------------------
/// Returns the fieldValue of the selected RadioButton.
public override func formFieldValue() -> AnyHashable? {
guard enabled else { return nil }
let selected = radioButtons.first { $0.radioButton.state }
return selected?.radioButton.formFieldValue()
}
//--------------------------------------------------
// MARK: - Server Value
//--------------------------------------------------
open override func formFieldServerValue() -> AnyHashable? {
return formFieldValue()
}
//--------------------------------------------------
// MARK: - Keys
//--------------------------------------------------
private enum CodingKeys: String, CodingKey {
case radioButtons
}
//--------------------------------------------------
// MARK: - Initializer
//--------------------------------------------------
public init(with radioButtons: [RadioButtonLabelModel]){
self.radioButtons = radioButtons
super.init()
}
//--------------------------------------------------
// MARK: - Codec
//--------------------------------------------------
required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
radioButtons = try typeContainer.decode([RadioButtonLabelModel].self, forKey: .radioButtons)
try super.init(from: decoder)
}
public override func encode(to encoder: Encoder) throws {
try super.encode(to: encoder)
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(radioButtons, forKey: .radioButtons)
}
}

View File

@ -8,6 +8,7 @@
import MVMCore
import UIKit
import VDS
public typealias ActionBlockConfirmation = () -> (Bool)
@ -19,137 +20,40 @@ public typealias ActionBlockConfirmation = () -> (Bool)
Container: The background of the toggle control.
Knob: The circular indicator that slides on the container.
*/
@objcMembers open class Toggle: Control, MVMCoreUIViewConstrainingProtocol {
//--------------------------------------------------
@objcMembers open class Toggle: VDS.Toggle, VDSMoleculeViewProtocol, MVMCoreUIViewConstrainingProtocol {
//------------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
//------------------------------------------------------
open var viewModel: ToggleModel!
open var delegateObject: MVMCoreUIDelegateObject?
open var additionalData: [AnyHashable : Any]?
/// Holds the on and off colors for the container.
public var containerTintColor: (on: UIColor, off: UIColor) = (on: .mvmGreen, off: .mvmBlack)
/// Holds the on and off colors for the knob.
public var knobTintColor: (on: UIColor, off: UIColor) = (on: .mvmWhite, off: .mvmWhite)
/// Holds the on and off colors for the disabled state..
public var disabledTintColor: (container: UIColor, knob: UIColor) = (container: .mvmCoolGray3, knob: .mvmWhite)
/// Set this flag to false if you do not want to animate state changes.
public var isAnimated = true
public var didToggleAction: ActionBlock?
public var didToggleAction: ActionBlock? {
didSet {
if let didToggleAction {
onChange = { _ in
didToggleAction()
}
} else {
onChange = nil
}
}
}
/// Executes logic before state change. If false, then toggle state will not change and the didToggleAction will not execute.
public var shouldToggleAction: ActionBlockConfirmation? = {
return { true }
}()
// Sizes are from InVision design specs.
static let containerSize = CGSize(width: 51, height: 31)
static let knobSize = CGSize(width: 28, height: 28)
private var knobView: View = {
let view = View()
view.backgroundColor = .white
view.layer.cornerRadius = Toggle.getKnobHeight() / 2.0
return view
}()
//--------------------------------------------------
// MARK: - Computed Properties
//--------------------------------------------------
open override var isEnabled: Bool {
didSet {
isUserInteractionEnabled = isEnabled
changeStateNoAnimation(isEnabled ? isOn : false)
setToggleAppearanceFromState()
accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: isEnabled ? "AccToggleHint" : "AccDisabled")
}
}
/// Simple means to prevent user interaction with the toggle.
public var isLocked: Bool = false {
didSet { isUserInteractionEnabled = !isLocked }
}
/// The state on the toggle. Default value: false.
open var isOn: Bool = false {
didSet {
if isAnimated {
UIView.animate(withDuration: 0.2, delay: 0.0, options: .curveEaseIn, animations: {
if self.isOn {
self.knobView.backgroundColor = self.knobTintColor.on
self.backgroundColor = self.containerTintColor.on
} else {
self.knobView.backgroundColor = self.knobTintColor.off
self.backgroundColor = self.containerTintColor.off
}
}, completion: nil)
UIView.animate(withDuration: 0.33, delay: 0, usingSpringWithDamping: 0.6, initialSpringVelocity: 0.2, options: [], animations: {
self.constrainKnob()
self.knobWidthConstraint?.constant = Self.getKnobWidth()
self.layoutIfNeeded()
}, completion: nil)
} else {
setToggleAppearanceFromState()
self.constrainKnob()
}
toggleModel?.selected = isOn
_ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate)
accessibilityValue = isOn ? MVMCoreUIUtility.hardcodedString(withKey: "AccOn") : MVMCoreUIUtility.hardcodedString(withKey: "AccOff")
setNeedsLayout()
layoutIfNeeded()
}
}
public var toggleModel: ToggleModel? {
model as? ToggleModel
}
//--------------------------------------------------
// MARK: - Delegate
//--------------------------------------------------
private var delegateObject: MVMCoreUIDelegateObject?
//--------------------------------------------------
// MARK: - Constraints
//--------------------------------------------------
private var knobLeadingConstraint: NSLayoutConstraint?
private var knobTrailingConstraint: NSLayoutConstraint?
private var knobHeightConstraint: NSLayoutConstraint?
private var knobWidthConstraint: NSLayoutConstraint?
private var heightConstraint: NSLayoutConstraint?
private var widthConstraint: NSLayoutConstraint?
private func constrainKnob() {
knobLeadingConstraint?.isActive = false
knobTrailingConstraint?.isActive = false
_ = isOn ? constrainKnobOn() : constrainKnobOff()
knobTrailingConstraint?.isActive = true
knobLeadingConstraint?.isActive = true
}
private func constrainKnobOn() {
knobTrailingConstraint = trailingAnchor.constraint(equalTo: knobView.trailingAnchor, constant: 2)
knobLeadingConstraint = knobView.leadingAnchor.constraint(greaterThanOrEqualTo: leadingAnchor)
}
private func constrainKnobOff() {
knobTrailingConstraint = trailingAnchor.constraint(greaterThanOrEqualTo: knobView.trailingAnchor)
knobLeadingConstraint = knobView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 2)
}
//--------------------------------------------------
// MARK: - Initializers
//--------------------------------------------------
@ -158,7 +62,7 @@ public typealias ActionBlockConfirmation = () -> (Bool)
super.init(frame: frame)
}
public convenience override init() {
public convenience required init() {
self.init(frame: .zero)
}
@ -171,7 +75,7 @@ public typealias ActionBlockConfirmation = () -> (Bool)
/// - parameter didToggleAction: A closure which is executed after the toggle changes states.
public convenience init(isOn: Bool = false, didToggleAction: ActionBlock?) {
self.init(frame: .zero)
changeStateNoAnimation(isOn)
self.isOn = isOn
self.didToggleAction = didToggleAction
}
@ -191,223 +95,78 @@ public typealias ActionBlockConfirmation = () -> (Bool)
//--------------------------------------------------
// MARK: - Lifecycle
//--------------------------------------------------
public override func updateView(_ size: CGFloat) {
super.updateView(size)
heightConstraint?.constant = Self.getContainerHeight()
widthConstraint?.constant = Self.getContainerWidth()
knobHeightConstraint?.constant = Self.getKnobHeight()
knobWidthConstraint?.constant = Self.getKnobWidth()
layer.cornerRadius = Self.getContainerHeight() / 2.0
knobView.layer.cornerRadius = Self.getKnobHeight() / 2.0
changeStateNoAnimation(isOn)
}
public override func setupView() {
super.setupView()
isAccessibilityElement = true
accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "AccToggleHint")
accessibilityLabel = MVMCoreUIUtility.hardcodedString(withKey: "Toggle_buttonlabel")
accessibilityTraits = .button
heightConstraint = heightAnchor.constraint(equalToConstant: Self.containerSize.height)
heightConstraint?.isActive = true
widthConstraint = widthAnchor.constraint(equalToConstant: Self.containerSize.width)
widthConstraint?.isActive = true
layer.cornerRadius = Self.getContainerHeight() / 2.0
backgroundColor = containerTintColor.off
addSubview(knobView)
knobHeightConstraint = knobView.heightAnchor.constraint(equalToConstant: Self.knobSize.height)
knobHeightConstraint?.isActive = true
knobWidthConstraint = knobView.widthAnchor.constraint(equalToConstant: Self.knobSize.width)
knobWidthConstraint?.isActive = true
knobView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
knobView.topAnchor.constraint(greaterThanOrEqualTo: topAnchor).isActive = true
bottomAnchor.constraint(greaterThanOrEqualTo: knobView.bottomAnchor).isActive = true
constrainKnobOff()
}
public override func reset() {
super.reset()
backgroundColor = containerTintColor.off
knobView.backgroundColor = knobTintColor.off
accessibilityLabel = MVMCoreUIUtility.hardcodedString(withKey: "Toggle_buttonlabel")
isAnimated = true
didToggleAction = nil
shouldToggleAction = { return true }
}
class func getContainerWidth() -> CGFloat {
let containerWidth = Self.containerSize.width
return (MFSizeObject(standardSize: containerWidth, standardiPadPortraitSize: CGFloat(Self.containerSize.width * 1.5)))?.getValueBasedOnApplicationWidth() ?? containerWidth
}
class func getContainerHeight() -> CGFloat {
let containerHeight = Self.containerSize.height
return (MFSizeObject(standardSize: containerHeight, standardiPadPortraitSize: CGFloat(Self.containerSize.height * 1.5)))?.getValueBasedOnApplicationWidth() ?? containerHeight
}
class func getKnobWidth() -> CGFloat {
let knobWidth = Self.knobSize.width
return (MFSizeObject(standardSize: knobWidth, standardiPadPortraitSize: CGFloat(Self.knobSize.width * 1.5)))?.getValueBasedOnApplicationWidth() ?? knobWidth
}
class func getKnobHeight() -> CGFloat {
let knobHeight = Self.knobSize.width
return (MFSizeObject(standardSize: knobHeight, standardiPadPortraitSize: CGFloat(Self.knobSize.height * 1.5)))?.getValueBasedOnApplicationWidth() ?? knobHeight
}
//--------------------------------------------------
// MARK: - Actions
//--------------------------------------------------
open override func sendAction(_ action: Selector, to target: Any?, for event: UIEvent?) {
super.sendAction(action, to: target, for: event)
toggleAndAction()
}
open override func sendActions(for controlEvents: UIControl.Event) {
super.sendActions(for: controlEvents)
toggleAndAction()
}
/// This will toggle the state of the Toggle and execute the actionBlock if provided.
public func toggleAndAction() {
if let result = shouldToggleAction?(), result {
isOn.toggle()
didToggleAction?()
public func viewModelDidUpdate() {
if let accessibilityIdentifier = viewModel.accessibilityIdentifier {
self.accessibilityIdentifier = accessibilityIdentifier
}
}
private func changeStateNoAnimation(_ state: Bool) {
FormValidator.setupValidation(for: viewModel, delegate: delegateObject?.formHolderDelegate)
// Hold state in case User wanted isAnimated to remain off.
let isAnimatedState = isAnimated
isAnimated = false
isOn = state
isAnimated = isAnimatedState
}
override open func accessibilityActivate() -> Bool {
// Hold state in case User wanted isAnimated to remain off.
guard isUserInteractionEnabled else { return false }
let isAnimatedState = isAnimated
isAnimated = false
sendActions(for: .touchUpInside)
isAnimated = isAnimatedState
return true
}
//--------------------------------------------------
// MARK: - UIResponder
//--------------------------------------------------
open override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
UIView.animate(withDuration: 0.1, animations: {
self.knobWidthConstraint?.constant += PaddingOne
self.layoutIfNeeded()
})
}
public override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
knobReformAnimation()
// Action only occurs of the user lifts up from withing acceptable region of the toggle.
guard let coordinates = touches.first?.location(in: self),
coordinates.x > -20,
coordinates.x < bounds.width + 20,
coordinates.y > -20,
coordinates.y < bounds.height + 20
else { return }
sendActions(for: .touchUpInside)
}
public func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent) {
knobReformAnimation()
sendActions(for: .touchCancel)
}
//--------------------------------------------------
// MARK: - Animations
//--------------------------------------------------
public func setToggleAppearanceFromState() {
backgroundColor = isEnabled ? isOn ? containerTintColor.on : containerTintColor.off : disabledTintColor.container
knobView.backgroundColor = isEnabled ? isOn ? knobTintColor.on : knobTintColor.off : disabledTintColor.knob
}
public func knobReformAnimation() {
if isAnimated {
UIView.animate(withDuration: 0.1, animations: {
self.knobWidthConstraint?.constant = Self.getKnobWidth()
self.layoutIfNeeded()
}, completion: nil)
} else {
knobWidthConstraint?.constant = Self.getKnobWidth()
layoutIfNeeded()
isOn = viewModel.selected
surface = viewModel.surface
isAnimated = viewModel.animated
isEnabled = viewModel.isEnabled
showText = viewModel.showText
if let onText = viewModel.onText {
self.onText = onText
}
}
// MARK:- MoleculeViewProtocol
public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
super.set(with: model, delegateObject, additionalData)
self.delegateObject = delegateObject
if let offText = viewModel.offText {
self.offText = offText
}
textSize = viewModel.textSize
textWeight = viewModel.textWeight
textPosition = viewModel.textPosition
guard let model = model as? ToggleModel else { return }
FormValidator.setupValidation(for: model, delegate: delegateObject?.formHolderDelegate)
containerTintColor.on = model.onTintColor.uiColor
containerTintColor.off = model.offTintColor.uiColor
knobTintColor.on = model.onKnobTintColor.uiColor
knobTintColor.off = model.offKnobTintColor.uiColor
isOn = model.selected
changeStateNoAnimation(isOn)
isAnimated = model.animated
isEnabled = model.enabled && !model.readOnly
if let accessibileString = model.accessibilityText {
if let accessibileString = viewModel.accessibilityText {
accessibilityLabel = accessibileString
}
if model.action != nil || model.alternateAction != nil {
if viewModel.action != nil || viewModel.alternateAction != nil {
didToggleAction = { [weak self] in
guard let self = self else { return }
if self.isOn {
if let action = model.action {
if let action = viewModel.action {
MVMCoreUIActionHandler.performActionUnstructured(with: action, sourceModel: model, additionalData: additionalData, delegateObject: delegateObject)
}
} else {
if let action = model.alternateAction ?? model.action {
if let action = viewModel.alternateAction ?? viewModel.action {
MVMCoreUIActionHandler.performActionUnstructured(with: action, sourceModel: model, additionalData: additionalData, delegateObject: delegateObject)
}
}
}
}
}
//--------------------------------------------------
// MARK: - Actions
//--------------------------------------------------
/// This will toggle the state of the Toggle and execute the actionBlock if provided.
public func toggleAndAction() {
toggle()
}
public override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
Self.getContainerHeight()
open override func toggle() {
if let result = shouldToggleAction?(), result {
super.toggle()
viewModel?.selected = isOn
_ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate)
}
}
//--------------------------------------------------
// MARK:- MoleculeViewProtocol
//--------------------------------------------------
public func updateView(_ size: CGFloat) {}
public class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
return Self().intrinsicContentSize.height
}
}

View File

@ -5,80 +5,62 @@
// Created by Scott Pfeil on 1/14/20.
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import VDS
public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol {
public class ToggleModel: FormFieldModel {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public static var identifier: String = "toggle"
public var id: String = UUID().uuidString
public var accessibilityIdentifier: String?
public var backgroundColor: Color?
public override static var identifier: String { "toggle" }
public var selected: Bool = false
public var animated: Bool = true
public var enabled: Bool = true
public var readOnly: Bool = false
public var action: ActionModelProtocol?
public var alternateAction: ActionModelProtocol?
public var accessibilityText: String?
public var onTintColor: Color = Color(uiColor: .mvmGreen)
public var offTintColor: Color = Color(uiColor: .mvmBlack)
public var onKnobTintColor: Color = Color(uiColor: .mvmWhite)
public var offKnobTintColor: Color = Color(uiColor: .mvmWhite)
public var fieldKey: String?
public var groupName: String = FormValidator.defaultGroupName
public var baseValue: AnyHashable?
public var showText: Bool = false
public var onText: String?
public var offText: String?
public var textSize: VDS.Toggle.TextSize = .small
public var textWeight: VDS.Toggle.TextWeight = .regular
public var textPosition: VDS.Toggle.TextPosition = .left
//--------------------------------------------------
// MARK: - Keys
//--------------------------------------------------
private enum CodingKeys: String, CodingKey {
case id
case moleculeName
case state
case animated
case enabled
case readOnly
case action
case backgroundColor
case accessibilityIdentifier
case alternateAction
case accessibilityText
case onTintColor
case offTintColor
case onKnobTintColor
case offKnobTintColor
case fieldKey
case groupName
case showText
case onText
case offText
case textSize
case textWeight
case textPosition
}
//--------------------------------------------------
// MARK: - Form Valdiation
//--------------------------------------------------
public func formFieldValue() -> AnyHashable? {
public override func formFieldValue() -> AnyHashable? {
guard enabled else { return nil }
return selected
}
//--------------------------------------------------
// MARK: - Server Value
//--------------------------------------------------
open func formFieldServerValue() -> AnyHashable? {
return formFieldValue()
}
//--------------------------------------------------
// MARK: - Initializer
//--------------------------------------------------
public init(_ state: Bool, id: String = UUID().uuidString) {
self.selected = state
selected = state
super.init()
baseValue = state
self.id = id
}
@ -90,8 +72,6 @@ public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol {
required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
id = try typeContainer.decodeIfPresent(String.self, forKey: .id) ?? UUID().uuidString
if let state = try typeContainer.decodeIfPresent(Bool.self, forKey: .state) {
self.selected = state
}
@ -102,54 +82,48 @@ public class ToggleModel: MoleculeModelProtocol, FormFieldProtocol {
action = try typeContainer.decodeModelIfPresent(codingKey: .action)
alternateAction = try typeContainer.decodeModelIfPresent(codingKey: .alternateAction)
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
if let onTintColor = try typeContainer.decodeIfPresent(Color.self, forKey: .onTintColor) {
self.onTintColor = onTintColor
}
if let offTintColor = try typeContainer.decodeIfPresent(Color.self, forKey: .offTintColor) {
self.offTintColor = offTintColor
}
if let onKnobTintColor = try typeContainer.decodeIfPresent(Color.self, forKey: .onKnobTintColor) {
self.onKnobTintColor = onKnobTintColor
}
if let offKnobTintColor = try typeContainer.decodeIfPresent(Color.self, forKey: .offKnobTintColor) {
self.offKnobTintColor = offKnobTintColor
}
accessibilityText = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityText)
showText = try typeContainer.decodeIfPresent(Bool.self, forKey: .showText) ?? false
onText = try typeContainer.decodeIfPresent(String.self, forKey: .onText)
offText = try typeContainer.decodeIfPresent(String.self, forKey: .offText)
textSize = try typeContainer.decodeIfPresent(VDS.Toggle.TextSize.self, forKey: .textSize) ?? .small
textWeight = try typeContainer.decodeIfPresent(VDS.Toggle.TextWeight.self, forKey: .textWeight) ?? .regular
textPosition = try typeContainer.decodeIfPresent(VDS.Toggle.TextPosition.self, forKey: .textPosition) ?? .left
try super.init(from: decoder)
baseValue = selected
fieldKey = try typeContainer.decodeIfPresent(String.self, forKey: .fieldKey)
if let groupName = try typeContainer.decodeIfPresent(String.self, forKey: .groupName) {
self.groupName = groupName
}
enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) ?? true
readOnly = try typeContainer.decodeIfPresent(Bool.self, forKey: .readOnly) ?? false
}
public func encode(to encoder: Encoder) throws {
public override func encode(to encoder: Encoder) throws {
try super.encode(to: encoder)
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
try container.encodeModelIfPresent(action, forKey: .action)
try container.encodeModelIfPresent(alternateAction, forKey: .alternateAction)
try container.encode(moleculeName, forKey: .moleculeName)
try container.encode(selected, forKey: .state)
try container.encode(animated, forKey: .animated)
try container.encode(enabled, forKey: .enabled)
try container.encode(onTintColor, forKey: .onTintColor)
try container.encode(onKnobTintColor, forKey: .onKnobTintColor)
try container.encode(onKnobTintColor, forKey: .onKnobTintColor)
try container.encode(offKnobTintColor, forKey: .offKnobTintColor)
try container.encodeIfPresent(accessibilityText, forKey: .accessibilityText)
try container.encodeIfPresent(fieldKey, forKey: .fieldKey)
try container.encodeIfPresent(groupName, forKey: .groupName)
try container.encode(readOnly, forKey: .readOnly)
try container.encode(showText, forKey: .showText)
try container.encodeIfPresent(onText, forKey: .onText)
try container.encodeIfPresent(offText, forKey: .offText)
try container.encode(textSize, forKey: .textSize)
try container.encode(textWeight, forKey: .textWeight)
try container.encode(textPosition, forKey: .textPosition)
}
open override func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard super.isEqual(to: model), let model = model as? Self else { return false }
return selected == model.selected
&& animated == model.animated
&& action.isEqual(to: model.action)
&& alternateAction.isEqual(to: model.alternateAction)
&& accessibilityText == model.accessibilityText
&& showText == model.showText
&& onText == model.onText
&& offText == model.offText
&& textSize == model.textSize
&& textWeight == model.textWeight
&& textPosition == model.textPosition
}
}

View File

@ -19,7 +19,8 @@ open class ArrowModel: MoleculeModelProtocol, EnableableModelProtocol {
}
public var moleculeName: String?
public var id: String = UUID().uuidString
public var accessibilityIdentifier: String?
public var backgroundColor: Color?
public var disabledColor: Color = Color(uiColor: .mvmCoolGray3)
public var color: Color = Color(uiColor: .mvmBlack)
@ -59,6 +60,7 @@ open class ArrowModel: MoleculeModelProtocol, EnableableModelProtocol {
private enum CodingKeys: String, CodingKey {
case id
case accessibilityIdentifier
case moleculeName
case backgroundColor
case disabledColor
@ -79,7 +81,8 @@ open class ArrowModel: MoleculeModelProtocol, EnableableModelProtocol {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
id = try typeContainer.decodeIfPresent(String.self, forKey: .id) ?? UUID().uuidString
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
if let disabledColor = try typeContainer.decodeIfPresent(Color.self, forKey: .disabledColor) {
self.disabledColor = disabledColor
}
@ -116,6 +119,7 @@ open class ArrowModel: MoleculeModelProtocol, EnableableModelProtocol {
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
try container.encode(moleculeName, forKey: .moleculeName)
try container.encode(disabledColor, forKey: .disabledColor)
@ -125,5 +129,19 @@ open class ArrowModel: MoleculeModelProtocol, EnableableModelProtocol {
try container.encode(width, forKey: .width)
try container.encode(height, forKey: .height)
try container.encode(enabled, forKey: .enabled)
try container.encode(inverted, forKey: .inverted)
}
public func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false }
return backgroundColor == model.backgroundColor
&& disabledColor == model.disabledColor
&& color == model.color
&& degrees == model.degrees
&& lineWidth == model.lineWidth
&& width == model.width
&& height == model.height
&& enabled == model.enabled
&& inverted == model.inverted
}
}

View File

@ -27,10 +27,14 @@ open class Badge: VDS.Badge, VDSMoleculeViewProtocol {
//--------------------------------------------------
public func viewModelDidUpdate() {
if let accessibilityIdentifier = viewModel.accessibilityIdentifier {
self.accessibilityIdentifier = accessibilityIdentifier
}
text = viewModel.text
textColor = viewModel.textColorStyle
maxWidth = viewModel.maxWidth
numberOfLines = viewModel.numberOfLines
fillColor = viewModel.fillColor
fillColor = viewModel.fillColorStyle
surface = viewModel.surface
}

View File

@ -0,0 +1,73 @@
//
// BadgeIndicator.swift
// MVMCoreUI
//
// Created by Matt Bruce on 4/12/24.
// Copyright © 2024 Verizon Wireless. All rights reserved.
//
import Foundation
import VDS
open class BadgeIndicator: VDS.BadgeIndicator, VDSMoleculeViewProtocol {
//--------------------------------------------------
// MARK: - Public Properties
//--------------------------------------------------
public var viewModel: BadgeIndicatorModel!
public var delegateObject: MVMCoreUIDelegateObject?
public var additionalData: [AnyHashable : Any]?
//--------------------------------------------------
// MARK: - Public Methods
//--------------------------------------------------
public func viewModelDidUpdate() {
if let accessibilityIdentifier = viewModel.accessibilityIdentifier {
self.accessibilityIdentifier = accessibilityIdentifier
}
surface = viewModel.surface
number = viewModel.number
fillColor = viewModel.fillColor
borderColorLight = viewModel.borderColorLight?.uiColor
borderColorDark = viewModel.borderColorDark?.uiColor
kind = viewModel.kind
maximumDigits = viewModel.maximumDigits
size = viewModel.size
leadingCharacter = viewModel.leadingCharacter
trailingText = viewModel.trailingText
dotSize = viewModel.dotSize
verticalPadding = viewModel.verticalPadding
horizontalPadding = viewModel.horizontalPadding
hideDot = viewModel.hideDot
hideBorder = viewModel.hideBorder
width = viewModel.width
height = viewModel.height
}
public func updateView(_ size: CGFloat) {}
//--------------------------------------------------
// MARK: - Overrides
//--------------------------------------------------
open override func updateAccessibility() {
super.updateAccessibility()
if let viewModel {
if let accessibilityText = viewModel.accessibilityText {
self.accessibilityLabel = accessibilityText
}
}
}
}
//to deal with how it's parent constrains this control
extension BadgeIndicator: MVMCoreUIViewConstrainingProtocol {
public func needsToBeConstrained() -> Bool { true }
public func horizontalAlignment() -> UIStackView.Alignment { .leading }
}

View File

@ -0,0 +1,115 @@
//
// BadgeIndicatorModel.swift
// MVMCoreUI
//
// Created by Matt Bruce on 4/12/24.
// Copyright © 2024 Verizon Wireless. All rights reserved.
//
import Foundation
import VDS
open class BadgeIndicatorModel: MoleculeModelProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public static var identifier: String { "badgeIndicator" }
public var id: String = UUID().uuidString
public var backgroundColor: Color?
public var accessibilityIdentifier: String?
//--------------------------------------------------
// MARK: - VDS Properties
//--------------------------------------------------
public var surface: Surface { inverted ? .dark : .light }
public var inverted: Bool = false
public var number: Int?
public var accessibilityText: String?
public var fillColor = BadgeIndicator.FillColor.red
public var borderColorLight: Color?
public var borderColorDark: Color?
public var kind = BadgeIndicator.Kind.simple
public var maximumDigits = BadgeIndicator.MaximumDigits.two
public var size = BadgeIndicator.Size.xxlarge
public var leadingCharacter: String?
public var trailingText: String?
public var dotSize: CGFloat?
public var verticalPadding: CGFloat?
public var horizontalPadding: CGFloat?
public var hideDot: Bool = false
public var hideBorder: Bool = false
public var width: CGFloat?
public var height: CGFloat?
private enum CodingKeys: String, CodingKey {
case id
case accessibilityIdentifier
case inverted
case accessibilityText
case number
case fillColor
case borderColorLight
case borderColorDark
case kind
case maximumDigits
case size
case leadingCharacter
case trailingText
case dotSize
case verticalPadding
case horizontalPadding
case hideDot
case hideBorder
case width
case height
}
required public convenience init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.init()
id = try container.decodeIfPresent(String.self, forKey: .id) ?? UUID().uuidString
accessibilityIdentifier = try container.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
inverted = try container.decodeIfPresent(Bool.self, forKey: .inverted) ?? false
accessibilityText = try container.decodeIfPresent(String.self, forKey: .accessibilityText)
number = try container.decodeIfPresent(Int.self, forKey: .number)
fillColor = try container.decodeIfPresent(BadgeIndicator.FillColor.self, forKey: .fillColor) ?? .red
borderColorLight = try container.decodeIfPresent(Color.self, forKey: .borderColorLight)
borderColorDark = try container.decodeIfPresent(Color.self, forKey: .borderColorDark)
kind = try container.decodeIfPresent(BadgeIndicator.Kind.self, forKey: .kind) ?? .simple
maximumDigits = try container.decodeIfPresent(BadgeIndicator.MaximumDigits.self, forKey: .maximumDigits) ?? .two
size = try container.decodeIfPresent(BadgeIndicator.Size.self, forKey: .size) ?? .xxlarge
leadingCharacter = try container.decodeIfPresent(String.self, forKey: .leadingCharacter)
trailingText = try container.decodeIfPresent(String.self, forKey: .trailingText)
dotSize = try container.decodeIfPresent(CGFloat.self, forKey: .dotSize)
verticalPadding = try container.decodeIfPresent(CGFloat.self, forKey: .verticalPadding)
horizontalPadding = try container.decodeIfPresent(CGFloat.self, forKey: .horizontalPadding)
hideDot = try container.decodeIfPresent(Bool.self, forKey: .hideDot) ?? false
hideBorder = try container.decodeIfPresent(Bool.self, forKey: .hideBorder) ?? false
width = try container.decodeIfPresent(CGFloat.self, forKey: .width)
height = try container.decodeIfPresent(CGFloat.self, forKey: .height)
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encode(inverted, forKey: .inverted)
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
try container.encodeIfPresent(accessibilityText, forKey: .accessibilityText)
try container.encodeIfPresent(number, forKey: .number)
try container.encodeIfPresent(fillColor, forKey: .fillColor)
try container.encodeIfPresent(borderColorLight, forKey: .borderColorLight)
try container.encodeIfPresent(borderColorDark, forKey: .borderColorDark)
try container.encodeIfPresent(kind, forKey: .kind)
try container.encodeIfPresent(maximumDigits, forKey: .maximumDigits)
try container.encodeIfPresent(size, forKey: .size)
try container.encodeIfPresent(leadingCharacter, forKey: .leadingCharacter)
try container.encodeIfPresent(trailingText, forKey: .trailingText)
try container.encodeIfPresent(dotSize, forKey: .dotSize)
try container.encodeIfPresent(verticalPadding, forKey: .verticalPadding)
try container.encodeIfPresent(hideDot, forKey: .hideDot)
try container.encodeIfPresent(hideBorder, forKey: .hideBorder)
try container.encodeIfPresent(width, forKey: .width)
try container.encodeIfPresent(height, forKey: .height)
}
}

View File

@ -16,28 +16,46 @@ open class BadgeModel: MoleculeModelProtocol {
public static var identifier: String = "badge"
public var id: String = UUID().uuidString
public var backgroundColor: Color?
public var accessibilityIdentifier: String?
//--------------------------------------------------
// MARK: - VDS Properties
//--------------------------------------------------
public var text: String = ""
public var textColorStyle: Badge.TextColor? = nil
public var accessibilityText: String?
public var maxWidth: CGFloat?
public var numberOfLines: Int = 1
public var fillColor = Badge.FillColor.red
public var fillColorStyle = Badge.FillColor.red
public var surface: Surface = .light
private enum CodingKeys: String, CodingKey {
case id, text, accessibilityText, fillColor, surface, numberOfLines, maxWidth
case id, accessibilityIdentifier, accessibilityText
case surface, numberOfLines, maxWidth
case text, textColor
case fillColor, fillColorStyle
}
required public convenience init(from decoder: Decoder) throws {
self.init()
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decodeIfPresent(String.self, forKey: .id) ?? UUID().uuidString
accessibilityIdentifier = try container.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
text = try container.decode(String.self, forKey: .text)
accessibilityText = try container.decodeIfPresent(String.self, forKey: .accessibilityText)
fillColor = try container.decodeIfPresent(Badge.FillColor.self, forKey: .fillColor) ?? .red
//look for a textColor
if let textColor = try container.decodeIfPresent(Color.self, forKey: .textColor) {
textColorStyle = .custom(textColor.uiColor)
}
//look for a style
fillColorStyle = try container.decodeIfPresent(Badge.FillColor.self, forKey: .fillColorStyle) ?? .red
//look for a color and set the style
if let fillColor = try container.decodeIfPresent(Color.self, forKey: .fillColor) {
fillColorStyle = .custom(fillColor.uiColor)
}
surface = try container.decodeIfPresent(Surface.self, forKey: .surface) ?? .light
numberOfLines = try container.decodeIfPresent(Int.self, forKey: .numberOfLines) ?? 1
maxWidth = try container.decodeIfPresent(CGFloat.self, forKey: .maxWidth)
@ -48,9 +66,28 @@ open class BadgeModel: MoleculeModelProtocol {
try container.encode(id, forKey: .id)
try container.encode(text, forKey: .text)
try container.encode(accessibilityText, forKey: .accessibilityText)
try container.encode(fillColor, forKey: .fillColor)
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
try container.encode(surface, forKey: .surface)
try container.encode(numberOfLines, forKey: .numberOfLines)
try container.encodeIfPresent(maxWidth, forKey: .maxWidth)
try container.encode(fillColorStyle, forKey: .fillColorStyle)
switch textColorStyle {
case .custom(let color):
try container.encode(Color(uiColor: color), forKey: .textColor)
default:
break
}
}
public func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard let model = model as? BadgeModel else { return false }
return self.backgroundColor == model.backgroundColor
&& self.fillColorStyle == model.fillColorStyle
&& self.textColorStyle == model.textColorStyle
&& self.numberOfLines == model.numberOfLines
&& self.text == model.text
&& self.surface == model.surface
&& self.accessibilityText == model.accessibilityText
&& self.maxWidth == model.maxWidth
}
}

View File

@ -0,0 +1,85 @@
//
// ButtonIcon.swift
// MVMCoreUI
//
// Created by Matt Bruce on 4/12/24.
// Copyright © 2024 Verizon Wireless. All rights reserved.
//
import Foundation
import VDS
open class ButtonIcon: VDS.ButtonIcon, VDSMoleculeViewProtocol {
//--------------------------------------------------
// MARK: - Public Properties
//--------------------------------------------------
public var viewModel: ButtonIconModel!
public var delegateObject: MVMCoreUIDelegateObject?
public var additionalData: [AnyHashable : Any]?
//--------------------------------------------------
// MARK: - Public Methods
//--------------------------------------------------
public func viewModelDidUpdate() {
if let accessibilityIdentifier = viewModel.accessibilityIdentifier {
self.accessibilityIdentifier = accessibilityIdentifier
}
surface = viewModel.surface
onClick = { [weak self] control in
guard let self, let viewModel = self.viewModel else { return }
MVMCoreUIActionHandler.performActionUnstructured(with: viewModel.action,
sourceModel: viewModel,
additionalData: self.additionalData,
delegateObject: self.delegateObject)
}
badgeIndicatorModel = viewModel.badgeIndicatorModel
kind = viewModel.kind
surfaceType = viewModel.surfaceType
iconName = viewModel.iconName
selectedIconName = viewModel.selectedIconName
size = viewModel.size
customContainerSize = viewModel.customContainerSize
customIconSize = viewModel.customIconSize
customBadgeIndicatorOffset = viewModel.customBadgeIndicatorOffSet
floating = viewModel.floating
fitToIcon = viewModel.fitToIcon
hideBorder = viewModel.hideBorder
showBadgeIndicator = viewModel.showBadgeIndicator
selectable = viewModel.selectable
iconOffset = viewModel.iconOffset
}
public func updateView(_ size: CGFloat) {}
//--------------------------------------------------
// MARK: - Overrides
//--------------------------------------------------
open override func updateAccessibility() {
super.updateAccessibility()
if let viewModel {
if let accessibilityText = viewModel.accessibilityText {
//since this is a container control and the
//icon & badgeIndicator (gets from it's own model) are traversed separatly
icon.accessibilityLabel = accessibilityText
}
}
}
}
//to deal with how it's parent constrains this control
extension ButtonIcon: MVMCoreUIViewConstrainingProtocol {
public func needsToBeConstrained() -> Bool { true }
public func horizontalAlignment() -> UIStackView.Alignment { .leading }
}

View File

@ -0,0 +1,154 @@
//
// ButtonIconModel.swift
// MVMCoreUI
//
// Created by Matt Bruce on 4/12/24.
// Copyright © 2024 Verizon Wireless. All rights reserved.
//
import Foundation
import VDS
open class ButtonIconModel: ButtonModelProtocol, MoleculeModelProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public static var identifier: String = "buttonIcon"
public var id: String = UUID().uuidString
public var backgroundColor: Color?
public var accessibilityIdentifier: String?
//--------------------------------------------------
// MARK: - VDS Properties
//--------------------------------------------------
public var surface: Surface { inverted ? .dark : .light }
public var inverted: Bool = false
public var accessibilityText: String?
public var action: ActionModelProtocol
public var kind = ButtonIcon.Kind.ghost
public var surfaceType = ButtonIcon.SurfaceType.colorFill
public var iconName: Icon.Name = .info
public var selectedIconName: Icon.Name?
public var size = ButtonIcon.Size.large
public var customContainerSize : Int?
public var customIconSize : Int?
public var customBadgeIndicatorOffSet : CGPoint?
public var floating: Bool = false
public var fitToIcon: Bool = false
public var hideBorder: Bool = true
public var showBadgeIndicator: Bool = false
public var selectable: Bool = false
public var iconOffset: CGPoint = .zero
public var badgeIndicatorModel: VDS.ButtonIcon.BadgeIndicatorModel? {
guard let model = badgeIndicator else { return nil }
return .init(kind: model.kind,
fillColor: model.fillColor,
expandDirection: expandDirection,
size: model.size,
maximumDigits: model.maximumDigits,
width: model.width,
height: model.height,
number: model.number,
leadingCharacter: model.leadingCharacter,
trailingText: model.trailingText,
dotSize: model.dotSize,
verticalPadding: model.verticalPadding,
horizontalPadding: model.horizontalPadding,
hideDot: model.hideDot,
hideBorder: model.hideBorder)
}
private var badgeIndicator: BadgeIndicatorModel?
private var expandDirection = ButtonIcon.BadgeIndicatorModel.ExpandDirection.right
//--------------------------------------------------
// MARK: - Initializers
//--------------------------------------------------
public init(with iconName: VDS.Icon.Name, action: ActionModelProtocol) {
self.iconName = iconName
self.action = action
}
//--------------------------------------------------
// MARK: - Keys
//--------------------------------------------------
private enum CodingKeys: String, CodingKey {
case id
case accessibilityIdentifier
case inverted
case accessibilityText
case action
case badgeIndicator
case expandDirection
case kind
case surfaceType
case iconName
case selectedIconName
case size
case customContainerSize
case customIconSize
case customBadgeIndicatorOffSet
case floating
case fitToIcon
case hideBorder
case showBadgeIndicator
case selectable
case iconOffset
}
//--------------------------------------------------
// MARK: - Codec
//--------------------------------------------------
required public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
action = try container.decodeModel(codingKey: .action)
id = try container.decodeIfPresent(String.self, forKey: .id) ?? UUID().uuidString
accessibilityIdentifier = try container.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
inverted = try container.decodeIfPresent(Bool.self, forKey: .inverted) ?? false
accessibilityText = try container.decodeIfPresent(String.self, forKey: .accessibilityText)
badgeIndicator = try container.decodeIfPresent(BadgeIndicatorModel.self, forKey: .badgeIndicator)
expandDirection = try container.decodeIfPresent(ButtonIcon.BadgeIndicatorModel.ExpandDirection.self, forKey: .expandDirection) ?? .right
kind = try container.decodeIfPresent(ButtonIcon.Kind.self, forKey: .kind) ?? .ghost
surfaceType = try container.decodeIfPresent(ButtonIcon.SurfaceType.self, forKey: .kind) ?? .colorFill
iconName = try container.decode(Icon.Name.self, forKey: .iconName)
selectedIconName = try container.decodeIfPresent(Icon.Name.self, forKey: .selectedIconName)
size = try container.decodeIfPresent(ButtonIcon.Size.self, forKey: .size) ?? .large
customContainerSize = try container.decodeIfPresent(Int.self, forKey: .customContainerSize)
customIconSize = try container.decodeIfPresent(Int.self, forKey: .customIconSize)
customBadgeIndicatorOffSet = try container.decodeIfPresent(CGPoint.self, forKey: .customBadgeIndicatorOffSet)
floating = try container.decodeIfPresent(Bool.self, forKey: .floating) ?? false
fitToIcon = try container.decodeIfPresent(Bool.self, forKey: .fitToIcon) ?? false
hideBorder = try container.decodeIfPresent(Bool.self, forKey: .hideBorder) ?? false
showBadgeIndicator = try container.decodeIfPresent(Bool.self, forKey: .showBadgeIndicator) ?? false
selectable = try container.decodeIfPresent(Bool.self, forKey: .selectable) ?? false
iconOffset = try container.decodeIfPresent(CGPoint.self, forKey: .iconOffset) ?? .zero
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
try container.encode(inverted, forKey: .inverted)
try container.encodeIfPresent(accessibilityText, forKey: .accessibilityText)
try container.encodeIfPresent(badgeIndicator, forKey: .badgeIndicator)
try container.encodeIfPresent(expandDirection, forKey: .expandDirection)
try container.encodeIfPresent(kind, forKey: .kind)
try container.encodeIfPresent(surfaceType, forKey: .kind)
try container.encode(iconName, forKey: .iconName)
try container.encodeIfPresent(selectedIconName, forKey: .selectedIconName)
try container.encodeIfPresent(size, forKey: .size)
try container.encodeIfPresent(customContainerSize, forKey: .customContainerSize)
try container.encodeIfPresent(customIconSize, forKey: .customIconSize)
try container.encodeIfPresent(customBadgeIndicatorOffSet, forKey: .customBadgeIndicatorOffSet)
try container.encodeIfPresent(floating, forKey: .floating)
try container.encodeIfPresent(fitToIcon, forKey: .fitToIcon)
try container.encodeIfPresent(hideBorder, forKey: .hideBorder)
try container.encodeIfPresent(showBadgeIndicator, forKey: .showBadgeIndicator)
try container.encodeIfPresent(selectable, forKey: .selectable)
try container.encodeIfPresent(iconOffset, forKey: .iconOffset)
}
}

View File

@ -0,0 +1,12 @@
//
// Calendar.swift
// MVMCoreUI
//
// Created by Matt Bruce on 8/20/24.
// Copyright © 2024 Verizon Wireless. All rights reserved.
//
import Foundation
import VDS
open class CalendarView: VDS.CalendarBase, VDSMoleculeViewProtocol

View File

@ -0,0 +1,65 @@
//
// Calendar.swift
// MVMCoreUI
//
// Created by Matt Bruce on 8/20/24.
// Copyright © 2024 Verizon Wireless. All rights reserved.
//
import Foundation
import VDS
open class CalendarView: VDS.CalendarBase, VDSMoleculeViewProtocol {
//--------------------------------------------------
// MARK: - Public Properties
//--------------------------------------------------
public var viewModel: CalendarViewModel!
public var delegateObject: MVMCoreUIDelegateObject?
public var additionalData: [AnyHashable : Any]?
//--------------------------------------------------
// MARK: - Public Methods
//--------------------------------------------------
public func viewModelDidUpdate() {
if let accessibilityIdentifier = viewModel.accessibilityIdentifier {
self.accessibilityIdentifier = accessibilityIdentifier
}
if let _selectedDate = viewModel.selectedDate {
selectedDate = _selectedDate
}
if let _activeDates = viewModel.activeDates {
activeDates = _activeDates
}
if let _hideContainerBorder = viewModel.hideContainerBorder {
hideContainerBorder = _hideContainerBorder
}
if let _hideCurrentDateIndicator = viewModel.hideCurrentDateIndicator {
hideCurrentDateIndicator = _hideCurrentDateIndicator
}
if let _inactiveDates = viewModel.inactiveDates {
inactiveDates = _inactiveDates
}
if let _indicators = viewModel.indicators {
indicators = _indicators
}
if let _maxDate = viewModel.maxDate {
maxDate = _maxDate
}
if let _minDate = viewModel.minDate {
minDate = _minDate
}
surface = viewModel.surface
}
public func updateView(_ size: CGFloat) {}
}

View File

@ -0,0 +1,159 @@
//
// CalendarModel.swift
// MVMCoreUI
//
// Created by Matt Bruce on 8/20/24.
// Copyright © 2024 Verizon Wireless. All rights reserved.
//
import Foundation
import VDS
open class CalendarViewModel: MoleculeModelProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public static var identifier: String = "calendar"
public var id: String = UUID().uuidString
public var backgroundColor: Color?
public var accessibilityIdentifier: String?
public var dateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateStyle = .medium
formatter.timeZone = NSTimeZone.system
formatter.locale = .current
formatter.formatterBehavior = .default
return formatter
}()
/// Update the property value to alter the format of how the date is presented.
public var dateFormat: String = "MMM d, y" {
didSet { dateFormatter.dateFormat = dateFormat }
}
public var hideContainerBorder: Bool?
public var hideCurrentDateIndicator: Bool?
public var activeDates: [Date]?
public var inactiveDates: [Date]?
public var selectedDate: Date?
public var minDate: Date?
public var maxDate: Date?
public var indicators: [CalendarBase.CalendarIndicatorModel]?
//--------------------------------------------------
// MARK: - VDS Properties
//--------------------------------------------------
public var surface: Surface { inverted ? .dark : .light }
public var inverted: Bool = false
//--------------------------------------------------
// MARK: - Keys
//--------------------------------------------------
private enum CodingKeys: String, CodingKey {
case id
case accessibilityIdentifier
case moleculeName
case inverted
case dateFormat
case hideContainerBorder
case hideCurrentDateIndicator
case activeDates
case inactiveDates
case selectedDate
case minDate
case maxDate
case indicators
}
//--------------------------------------------------
// MARK: - Initializers
//--------------------------------------------------
public init() {}
//--------------------------------------------------
// MARK: - Codec
//--------------------------------------------------
required public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decodeIfPresent(String.self, forKey: .id) ?? UUID().uuidString
inverted = try container.decodeIfPresent(Bool.self, forKey: .inverted) ?? false
accessibilityIdentifier = try container.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
hideContainerBorder = try container.decodeIfPresent(Bool.self, forKey: .hideContainerBorder)
hideCurrentDateIndicator = try container.decodeIfPresent(Bool.self, forKey: .hideCurrentDateIndicator)
if let dateFormat = try container.decodeIfPresent(String.self, forKey: .dateFormat) {
self.dateFormat = dateFormat
dateFormatter.dateFormat = dateFormat
}
if let dates = try container.decodeIfPresent([String].self, forKey: .activeDates) {
activeDates = dates.compactMap { dateFormatter.date(from: $0) }
}
if let dates = try container.decodeIfPresent([String].self, forKey: .inactiveDates) {
inactiveDates = dates.compactMap { dateFormatter.date(from: $0) }
}
if let date = try container.decodeIfPresent(String.self, forKey: .selectedDate) {
selectedDate = dateFormatter.date(from: date)
}
if let date = try container.decodeIfPresent(String.self, forKey: .minDate) {
minDate = dateFormatter.date(from: date)
}
if let date = try container.decodeIfPresent(String.self, forKey: .maxDate) {
maxDate = dateFormatter.date(from: date)
}
indicators = try container.decodeIfPresent([CalendarBase.CalendarIndicatorModel].self, forKey: .indicators)
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(moleculeName, forKey: .moleculeName)
try container.encode(id, forKey: .id)
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
try container.encode(inverted, forKey: .inverted)
try container.encode(dateFormat, forKey: .dateFormat)
try container.encode(hideContainerBorder, forKey: .hideContainerBorder)
try container.encode(hideCurrentDateIndicator, forKey: .hideCurrentDateIndicator)
try container.encode(activeDates, forKey: .activeDates)
try container.encode(selectedDate, forKey: .selectedDate)
try container.encode(minDate, forKey: .minDate)
try container.encode(maxDate, forKey: .maxDate)
try container.encode(indicators, forKey: .indicators)
}
open func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false }
return inverted == model.inverted
&& dateFormat == model.dateFormat
&& hideContainerBorder == model.hideContainerBorder
&& hideCurrentDateIndicator == model.hideCurrentDateIndicator
&& activeDates == model.activeDates
&& inactiveDates == model.inactiveDates
&& selectedDate == model.selectedDate
&& minDate == model.minDate
&& maxDate == model.maxDate
&& indicators == model.indicators
}
}
extension CalendarViewModel {
public func convertToVDSCalendarModel() -> DatePicker.CalendarModel {
let defaults = DatePicker.CalendarModel()
return .init(hideContainerBorder: hideContainerBorder ?? defaults.hideContainerBorder ,
hideCurrentDateIndicator: hideCurrentDateIndicator ?? defaults.hideCurrentDateIndicator,
activeDates: activeDates ?? defaults.activeDates,
inactiveDates: inactiveDates ?? defaults.inactiveDates,
selectedDate: selectedDate ?? defaults.selectedDate,
minDate: minDate ?? defaults.minDate,
maxDate: maxDate ?? defaults.maxDate,
indicators: indicators ?? defaults.indicators)
}
}

View File

@ -16,6 +16,7 @@ import MVMCore
public static var identifier: String = "caretView"
public var id: String = UUID().uuidString
public var accessibilityIdentifier: String?
public var backgroundColor: Color?
public var strokeColor: Color = Color(uiColor: .mvmBlack)
public var strokeColor_inverted: Color = Color(uiColor: .mvmWhite)
@ -30,6 +31,7 @@ import MVMCore
private enum CodingKeys: String, CodingKey {
case id
case accessibilityIdentifier
case moleculeName
case backgroundColor
case strokeColor
@ -54,7 +56,8 @@ import MVMCore
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
id = try typeContainer.decodeIfPresent(String.self, forKey: .id) ?? UUID().uuidString
accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
if let strokeColor = try typeContainer.decodeIfPresent(Color.self, forKey: .strokeColor) {
self.strokeColor = strokeColor
}
@ -84,6 +87,7 @@ import MVMCore
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encode(moleculeName, forKey: .moleculeName)
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
try container.encode(strokeColor, forKey: .strokeColor)
try container.encode(strokeColor_inverted, forKey: .strokeColor_inverted)
try container.encode(inverted, forKey: .inverted)

View File

@ -262,17 +262,12 @@ open class BarsIndicatorView: CarouselIndicator {
refreshAccessibilityLabels()
}
let expression = { [self] in
barReferences[previousIndex].backgroundColor = isEnabled ? indicatorColor : disabledIndicatorColor
barReferences[previousIndex].constraint?.constant = IndicatorBar.unselectedHeight
barReferences[previousIndex].layer.cornerRadius = IndicatorBar.unselectedCornerRadius
barReferences[newIndex].backgroundColor = isEnabled ? currentIndicatorColor : disabledIndicatorColor
barReferences[newIndex].constraint?.constant = IndicatorBar.selectedHeight
barReferences[newIndex].layer.cornerRadius = IndicatorBar.selectedCornerRadius
layoutIfNeeded()
}
// Perform the animation.
isAnimated ? UIView.animate(withDuration: 0.25) { expression() } : expression()
barReferences[previousIndex].backgroundColor = isEnabled ? indicatorColor : disabledIndicatorColor
barReferences[previousIndex].constraint?.constant = IndicatorBar.unselectedHeight
barReferences[previousIndex].layer.cornerRadius = IndicatorBar.unselectedCornerRadius
barReferences[newIndex].backgroundColor = isEnabled ? currentIndicatorColor : disabledIndicatorColor
barReferences[newIndex].constraint?.constant = IndicatorBar.selectedHeight
barReferences[newIndex].layer.cornerRadius = IndicatorBar.selectedCornerRadius
layoutIfNeeded()
}
}

View File

@ -5,7 +5,7 @@
// Created by Kevin Christiano on 1/30/20.
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import VDSColorTokens
import VDSCoreTokens
open class CarouselIndicator: Control, CarouselPageControlProtocol {
//--------------------------------------------------

View File

@ -7,7 +7,7 @@
//
import Foundation
import VDSColorTokens
import VDSCoreTokens
open class CarouselIndicatorModel: CarouselPagingModelProtocol, MoleculeModelProtocol, EnableableModelProtocol {
//--------------------------------------------------
@ -19,14 +19,17 @@ open class CarouselIndicatorModel: CarouselPagingModelProtocol, MoleculeModelPro
}
public var id: String = UUID().uuidString
public var accessibilityIdentifier: String?
public var backgroundColor: Color?
public var moleculeName: String?
// Assigned and computed by parent.
public var numberOfPages: Int = 0
/// Sets the current Index to focus on.
public var currentIndex: Int = 0
public var animated: Bool = true
public var hidesForSinglePage: Bool = false
public var hidesForSinglePage: Bool = true
public var inverted: Bool = false
/// Set true to make the accessibility value as "Slide #currentPage of #totalPage", otherwise will be "Page #currentPage of #totalPage", default is false
public var accessibilityHasSlidesInsteadOfPage: Bool = false
@ -46,10 +49,10 @@ open class CarouselIndicatorModel: CarouselPagingModelProtocol, MoleculeModelPro
private enum CodingKeys: String, CodingKey {
case id
case accessibilityIdentifier
case moleculeName
case backgroundColor
case currentIndex
case numberOfPages
case alwaysSendAction
case animated
case hidesForSinglePage
@ -69,6 +72,7 @@ open class CarouselIndicatorModel: CarouselPagingModelProtocol, MoleculeModelPro
required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
id = try typeContainer.decodeIfPresent(String.self, forKey: .id) ?? UUID().uuidString
accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
moleculeName = try typeContainer.decodeIfPresent(String.self, forKey: .moleculeName)
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
@ -117,8 +121,8 @@ open class CarouselIndicatorModel: CarouselPagingModelProtocol, MoleculeModelPro
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encodeIfPresent(moleculeName, forKey: .moleculeName)
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
try container.encode(numberOfPages, forKey: .numberOfPages)
try container.encode(currentIndex, forKey: .currentIndex)
try container.encode(alwaysSendAction, forKey: .alwaysSendAction)
try container.encode(animated, forKey: .animated)
@ -130,4 +134,31 @@ open class CarouselIndicatorModel: CarouselPagingModelProtocol, MoleculeModelPro
try container.encode(indicatorColor, forKey: .indicatorColor)
try container.encodeIfPresent(position, forKey: .position)
}
public func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false }
return backgroundColor == model.backgroundColor
&& currentIndex == model.currentIndex
&& alwaysSendAction == model.alwaysSendAction
&& animated == model.animated
&& hidesForSinglePage == model.hidesForSinglePage
&& accessibilityHasSlidesInsteadOfPage == model.accessibilityHasSlidesInsteadOfPage
&& enabled == model.enabled
&& inverted == model.inverted
&& disabledIndicatorColor == model.disabledIndicatorColor
&& indicatorColor == model.indicatorColor
&& position == model.position
}
public func isVisuallyEquivalent(to model: any MoleculeModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false }
return backgroundColor == model.backgroundColor
&& animated == model.animated
&& hidesForSinglePage == model.hidesForSinglePage
&& accessibilityHasSlidesInsteadOfPage == model.accessibilityHasSlidesInsteadOfPage
&& enabled == model.enabled
&& inverted == model.inverted
&& disabledIndicatorColor == model.disabledIndicatorColor
&& indicatorColor == model.indicatorColor
}
}

View File

@ -5,140 +5,99 @@
// Created by Kevin Christiano on 9/13/19.
// Copyright © 2019 Verizon Wireless. All rights reserved.
//
import VDS
@objcMembers open class CheckboxLabel: View {
//--------------------------------------------------
// MARK: - Outlets
//--------------------------------------------------
public let checkbox = Checkbox()
public let label = Label(fontStyle: .RegularBodySmall)
private var observation: NSKeyValueObservation? = nil
//--------------------------------------------------
@objcMembers open class CheckboxLabel: VDS.CheckboxItem, VDSMoleculeViewProtocol {
//------------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public var checkboxPosition: CheckboxPosition = .center
//--------------------------------------------------
// MARK: - Constraints
//--------------------------------------------------
//------------------------------------------------------
open var viewModel: CheckboxLabelModel!
open var delegateObject: MVMCoreUIDelegateObject?
open var additionalData: [AnyHashable : Any]?
public var checkboxTopConstraint: NSLayoutConstraint?
public var checkboxBottomConstraint: NSLayoutConstraint?
public var checkboxCenterYConstraint: NSLayoutConstraint?
// Form Validation
var fieldKey: String?
var fieldValue: JSONValue?
var groupName: String?
//--------------------------------------------------
// MARK: - Life Cycle
//--------------------------------------------------
override open func setupView() {
super.setupView()
guard subviews.isEmpty else { return }
addSubview(checkbox)
addSubview(label)
label.text = ""
checkbox.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor).isActive = true
checkboxBottomConstraint = layoutMarginsGuide.bottomAnchor.constraint(equalTo: checkbox.bottomAnchor)
checkboxBottomConstraint?.isActive = true
checkboxTopConstraint = checkbox.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor)
checkboxTopConstraint?.isActive = true
checkboxCenterYConstraint = checkbox.centerYAnchor.constraint(equalTo: centerYAnchor)
label.topAnchor.constraint(equalTo: layoutMarginsGuide.topAnchor).isActive = true
layoutMarginsGuide.trailingAnchor.constraint(equalTo: label.trailingAnchor).isActive = true
label.leadingAnchor.constraint(equalTo: checkbox.trailingAnchor, constant: PaddingTwo).isActive = true
layoutMarginsGuide.bottomAnchor.constraint(greaterThanOrEqualTo: label.bottomAnchor).isActive = true
let bottomLabelConstraint = layoutMarginsGuide.bottomAnchor.constraint(equalTo: label.bottomAnchor)
bottomLabelConstraint.priority = .defaultLow
bottomLabelConstraint.isActive = true
alignCheckbox(.center)
isAccessibilityElement = true
accessibilityHint = checkbox.accessibilityHint
accessibilityTraits = checkbox.accessibilityTraits
observation = observe(\.checkbox.isSelected, options: [.new]) { [weak self] _, _ in
self?.updateAccessibilityLabel()
override open var isSelected: Bool {
didSet {
viewModel?.checkbox.selected = isSelected
_ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate)
}
}
@objc override open func updateView(_ size: CGFloat) {
super.updateView(size)
label.updateView(size)
checkbox.updateView(size)
layoutIfNeeded()
}
//--------------------------------------------------
// MARK: - Methods
//--------------------------------------------------
/// Aligns Checkbox and Label relative to the desired position of the Checkbox.
private func alignCheckbox(_ position: CheckboxPosition) {
checkboxPosition = position
switch position {
case .center:
checkboxBottomConstraint?.isActive = false
checkboxTopConstraint?.isActive = false
checkboxCenterYConstraint?.isActive = true
case .top:
checkboxBottomConstraint?.isActive = false
checkboxTopConstraint?.isActive = true
checkboxCenterYConstraint?.isActive = false
case .bottom:
checkboxBottomConstraint?.isActive = true
checkboxTopConstraint?.isActive = false
checkboxCenterYConstraint?.isActive = false
}
}
//--------------------------------------------------
// MARK: - Atomic
//--------------------------------------------------
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
guard let checkBoxWithLabelModel = model as? CheckboxLabelModel else { return }
open func viewModelDidUpdate() {
if let accessibilityIdentifier = viewModel.accessibilityIdentifier {
self.accessibilityIdentifier = accessibilityIdentifier
}
surface = viewModel.surface
updateCheckbox()
//primary label
labelText = viewModel.label?.text
labelTextAttributes = viewModel.label?.attributes?.toVDSLabelAttributeModel(delegateObject: delegateObject, additionalData: additionalData)
//secondary label
childText = viewModel.subTitle?.text
childTextAttributes = viewModel.subTitle?.attributes?.toVDSLabelAttributeModel(delegateObject: delegateObject, additionalData: additionalData)
}
private func performCheckboxAction(with actionModel: ActionModelProtocol, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
MVMCoreUIActionHandler.performActionUnstructured(with: actionModel, sourceModel: viewModel.checkbox, additionalData: additionalData, delegateObject: delegateObject)
}
if let checkboxAlignment = checkBoxWithLabelModel.checkboxAlignment {
alignCheckbox(checkboxAlignment)
open func updateCheckbox() {
//forms
FormValidator.setupValidation(for: viewModel.checkbox, delegate: delegateObject?.formHolderDelegate)
groupName = viewModel.checkbox.groupName
if let fieldKey = viewModel.checkbox.fieldKey {
self.fieldKey = fieldKey
}
checkbox.set(with: checkBoxWithLabelModel.checkbox, delegateObject, additionalData)
label.set(with: checkBoxWithLabelModel.label, delegateObject, additionalData)
updateAccessibilityLabel()
//properties
isAnimated = viewModel.checkbox.animated
isEnabled = viewModel.checkbox.isEnabled
//call super here to go around the didSet
//in this class
super.isSelected = viewModel.checkbox.selected
//events
viewModel.checkbox.updateUI = {
MVMCoreDispatchUtility.performBlock(onMainThread: { [weak self] in
guard let self = self else { return }
//let isValid = viewModel.checkbox.isValid ?? true
//TODO: Fix issue with default state
//showError = !isValid
errorText = viewModel.checkbox.errorMessage
isEnabled = viewModel.checkbox.isEnabled
})
}
//onChange
if (viewModel.checkbox.action != nil || viewModel.checkbox.offAction != nil) {
onChange = { [weak self] control in
guard let self = self else { return }
if let offAction = viewModel.checkbox.offAction, !isSelected {
performCheckboxAction(with: offAction, delegateObject: delegateObject, additionalData: additionalData)
} else if let action = viewModel.checkbox.action {
performCheckboxAction(with: action, delegateObject: delegateObject, additionalData: additionalData)
}
}
}
}
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
@objc open func updateView(_ size: CGFloat) {}
open class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
return 200
}
open override func reset() {
super.reset()
label.text = ""
checkbox.reset()
alignCheckbox(.center)
}
override open func accessibilityActivate() -> Bool {
checkbox.accessibilityActivate()
}
open func updateAccessibilityLabel() {
checkbox.updateAccessibilityLabel()
accessibilityLabel = [checkbox.accessibilityLabel, label.text].compactMap { $0 }.joined(separator: ",")
}
}

View File

@ -8,31 +8,67 @@
import Foundation
import MVMCore
public enum CheckboxPosition: String, Codable {
case center
case top
case bottom
}
import VDS
@objcMembers open class CheckboxLabelModel: MoleculeModelProtocol, ParentMoleculeModelProtocol {
open class var identifier: String { "checkboxLabel" }
public var moleculeName: String = CheckboxLabelModel.identifier
@DecodableDefault.UUIDString public var id: String
public var accessibilityIdentifier: String?
public var backgroundColor: Color?
public var checkboxAlignment: CheckboxPosition?
public var checkbox: CheckboxModel
public var label: LabelModel
public var label: LabelModel?
public var subTitle: LabelModel?
public var inverted: Bool? = false
public var surface: Surface { inverted ?? false ? .dark : .light }
public var children: [MoleculeModelProtocol] {
var values: [MoleculeModelProtocol] = [checkbox]
if let label { values.append(label) }
if let subTitle { values.append(subTitle) }
return values
}
public var children: [MoleculeModelProtocol] { [checkbox, label] }
//--------------------------------------------------
// MARK: - Initializer
//--------------------------------------------------
public init(checkbox: CheckboxModel, label: LabelModel) {
public init(checkbox: CheckboxModel, label: LabelModel, subTitle: LabelModel?) {
self.checkbox = checkbox
self.label = label
self.subTitle = subTitle
}
open func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false }
return moleculeName == model.moleculeName
&& inverted == model.inverted
&& accessibilityText == model.accessibilityText
&& accessibilityIdentifier == model.accessibilityIdentifier
&& accessibilityTraits == model.accessibilityTraits
}
}
extension Array where Element == CheckboxLabelModel {
internal func convertToVDSCheckboxItemModel(surface: Surface,
delegateObject: MVMCoreUIDelegateObject?,
additionalData: [AnyHashable: Any]?) -> [CheckboxGroup.CheckboxItemModel] {
return compactMap({ model in
var item = CheckboxGroup.CheckboxItemModel()
item.inputId = model.checkbox.fieldKey
item.labelText = model.label?.text
if let attributes = model.label?.attributes?.toVDSLabelAttributeModel(delegateObject: delegateObject, additionalData: additionalData) {
item.labelTextAttributes = attributes
}
item.childText = model.subTitle?.text
if let attributes = model.subTitle?.attributes?.toVDSLabelAttributeModel(delegateObject: delegateObject, additionalData: additionalData) {
item.childTextAttributes = attributes
}
item.surface = surface
item.selected = model.checkbox.selected
item.enabled = model.checkbox.isEnabled
return item
})
}
}

View File

@ -0,0 +1,128 @@
//
// CircularProgressBar.swift
// MVMCoreUI
//
// Created by Xi Zhang on 7/5/24.
// Copyright © 2024 Verizon Wireless. All rights reserved.
//
import UIKit
@objcMembers open class CircularProgressBar: View, MVMCoreUIViewConstrainingProtocol {
var heightConstraint: NSLayoutConstraint?
var graphModel: CircularProgressBarModel? {
return model as? CircularProgressBarModel
}
var viewWidth: CGFloat {
graphModel?.diameter ?? CGFloat(64)
}
private var progressLayer = CAShapeLayer()
private var tracklayer = CAShapeLayer()
private var labelLayer = CATextLayer()
var progressColor: UIColor = UIColor.red
var trackColor: UIColor = UIColor.lightGray
// A path with which CAShapeLayer will be drawn on the screen
private var viewCGPath: CGPath? {
let width = viewWidth
let height = width
return UIBezierPath(arcCenter: CGPoint(x: width / 2.0, y: height / 2.0),
radius: (width - 1.5)/2,
startAngle: CGFloat(-0.5 * Double.pi),
endAngle: CGFloat(1.5 * Double.pi), clockwise: true).cgPath
}
// MARK: setup
override open func setupView() {
super.setupView()
heightConstraint = heightAnchor.constraint(equalToConstant: 0)
heightConstraint?.isActive = true
widthAnchor.constraint(equalTo: heightAnchor).isActive = true
}
override open func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
super.set(with: model, delegateObject, additionalData)
guard let model = model as? CircularProgressBarModel else { return }
// set background color
backgroundColor = model.backgroundColor?.uiColor ?? UIColor.clear
configureProgressViewToBeCircular()
// set progress color
progressColor = model.color?.uiColor ?? .red
progressLayer.strokeColor = progressColor.cgColor
// set track color
trackColor = model.trackColor?.uiColor ?? .lightGray
tracklayer.strokeColor = trackColor.cgColor
// show circular progress view with animation.
showProgressWithAnimation(duration: graphModel?.duration ?? 0, value: Float(graphModel?.percent ?? 0) / 100)
// show progress percentage label.
if let drawText = model.drawText, drawText {
showProgressPercentage()
}
}
private func configureProgressViewToBeCircular() {
let lineWidth = graphModel?.lineWidth ?? 4.0
self.drawShape(using: tracklayer, lineWidth: lineWidth)
self.drawShape(using: progressLayer, lineWidth: lineWidth)
}
private func drawShape(using shape: CAShapeLayer, lineWidth: CGFloat) {
shape.path = self.viewCGPath
shape.fillColor = UIColor.clear.cgColor
shape.lineWidth = lineWidth
self.layer.addSublayer(shape)
}
// value range is [0,1]
private func showProgressWithAnimation(duration: TimeInterval, value: Float) {
let animation = CABasicAnimation(keyPath: "strokeEnd")
animation.duration = duration
animation.fromValue = 0 //start animation at point 0
animation.toValue = value //end animation at point specified
animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear)
progressLayer.strokeEnd = CGFloat(value)
progressLayer.add(animation, forKey: "animateCircle")
}
private func showProgressPercentage() {
let percent = graphModel?.percent ?? 0
let percentLen = String(percent).count
// configure attributed string for progress percentage.
let attributedString = NSMutableAttributedString(string: String(percent) + "%")
// percent value
attributedString.setAttributes([NSAttributedString.Key.font: Styler.Font.BoldTitleXLarge], range: NSMakeRange(0, percentLen))
// % symbol
attributedString.setAttributes([NSAttributedString.Key.font: Styler.Font.RegularMicro], range: NSMakeRange(percentLen, 1))
// show progress percentage in a text layer
let width = viewWidth
let height = width
labelLayer.string = attributedString
labelLayer.frame = CGRectMake((width - CGFloat(percentLen * 20))/2, (height - 40)/2, 80, 40)
self.layer.addSublayer(labelLayer)
}
//MARK: MVMCoreUIViewConstrainingProtocol
public func needsToBeConstrained() -> Bool {
return true
}
}

View File

@ -0,0 +1,123 @@
//
// CircularProgressBarModel.swift
// MVMCoreUI
//
// https://oneconfluence.verizon.com/display/MFD/Circular+Progress+Tracker
//
// Created by Xi Zhang on 7/5/24.
// Copyright © 2024 Verizon Wireless. All rights reserved.
//
import Foundation
public class CircularProgressBarModel: GraphSizeBase, MoleculeModelProtocol {
public static var identifier: String = "circularProgress"
public var id: String = UUID().uuidString
public var accessibilityIdentifier: String?
public var percent: Int = 0
public var diameter: CGFloat? = 64
public var lineWidth: CGFloat? = 4
public var duration : Double? = 0
public var color: Color? = Color(uiColor: UIColor.mfGet(forHex: "#007AB8"))
public var trackColor: Color? = Color(uiColor: .mvmCoolGray3)
public var drawText: Bool? = true
public var backgroundColor: Color? = Color(uiColor: UIColor.clear)
public override init() {
super.init()
updateSize()
}
private enum CodingKeys: String, CodingKey {
case id
case accessibilityIdentifier
case moleculeName
case percent
case size
case diameter
case lineWidth
case duration
case color
case trackColor
case drawText
case backgroundColor
}
required public init(from decoder: Decoder) throws {
super.init()
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
id = try typeContainer.decodeIfPresent(String.self, forKey: .id) ?? UUID().uuidString
accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
percent = try typeContainer.decode(Int.self, forKey: .percent)
if let size = try typeContainer.decodeIfPresent(GraphSize.self, forKey: .size) {
self.size = size
}
updateSize()
if let diameter = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .diameter) {
self.diameter = diameter
}
if let lineWidth = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .lineWidth) {
self.lineWidth = lineWidth
}
if let duration = try typeContainer.decodeIfPresent(Double.self, forKey: .duration) {
self.duration = duration
}
if let drawText = try typeContainer.decodeIfPresent(Bool.self, forKey: .drawText) {
self.drawText = drawText
}
if let color = try typeContainer.decodeIfPresent(Color.self, forKey: .color) {
self.color = color
}
if let trackColor = try typeContainer.decodeIfPresent(Color.self, forKey: .trackColor) {
self.trackColor = trackColor
}
if let backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) {
self.backgroundColor = backgroundColor
}
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encode(moleculeName, forKey: .moleculeName)
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
try container.encode(percent, forKey: .percent)
try container.encodeIfPresent(size, forKey: .size)
try container.encodeIfPresent(diameter, forKey: .diameter)
try container.encodeIfPresent(lineWidth, forKey: .lineWidth)
try container.encodeIfPresent(duration, forKey: .duration)
try container.encodeIfPresent(drawText, forKey: .drawText)
try container.encodeIfPresent(trackColor, forKey: .trackColor)
try container.encodeIfPresent(color, forKey: .color)
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
}
public override func updateSize() {
switch size {
case .small:
diameter = MFSizeObject(standardSize: 64)?.getValueBasedOnApplicationWidth() ?? 64
lineWidth = MFSizeObject(standardSize: 4)?.getValueBasedOnApplicationWidth() ?? 4
break
case .medium:
diameter = MFSizeObject(standardSize: 84)?.getValueBasedOnApplicationWidth() ?? 84
lineWidth = MFSizeObject(standardSize: 4)?.getValueBasedOnApplicationWidth() ?? 4
break
case .large:
diameter = MFSizeObject(standardSize: 124)?.getValueBasedOnApplicationWidth() ?? 124
lineWidth = MFSizeObject(standardSize: 4)?.getValueBasedOnApplicationWidth() ?? 4
break
}
}
}

View File

@ -0,0 +1,29 @@
//
// GraphSizeProtocol.swift
// MVMCoreUI
//
// Created by Xi Zhang on 7/15/24.
// Copyright © 2024 Verizon Wireless. All rights reserved.
//
import Foundation
public enum GraphSize: String, Codable {
case small, medium, large
}
public protocol GraphSizeProtocol {
var size: GraphSize { get set }
func updateSize()
}
public class GraphSizeBase: GraphSizeProtocol {
public var size: GraphSize = .small {
didSet {
updateSize()
}
}
public func updateSize() {
}
}

View File

@ -31,11 +31,15 @@ open class Icon: VDS.Icon, VDSMoleculeViewProtocol{
// MARK: - Public
//--------------------------------------------------
public func viewModelDidUpdate() {
if let accessibilityIdentifier = viewModel.accessibilityIdentifier {
self.accessibilityIdentifier = accessibilityIdentifier
}
surface = viewModel.surface
color = viewModel.color.uiColor
size = viewModel.size
customSize = viewModel.customSize
name = viewModel.name
isAccessibilityElement = viewModel.isAccessibilityElement ?? true
}
//--------------------------------------------------

View File

@ -8,7 +8,7 @@
import Foundation
import VDS
import VDSColorTokens
import VDSCoreTokens
open class IconModel: MoleculeModelProtocol {
@ -21,6 +21,8 @@ open class IconModel: MoleculeModelProtocol {
public var backgroundColor: Color?
public var accessibilityIdentifier: String?
/// A representation that will be used to render the icon with corresponding name.
public var name: Icon.Name
@ -35,4 +37,6 @@ open class IconModel: MoleculeModelProtocol {
/// A custom size of the icon.
public var customSize: Int?
public var isAccessibilityElement: Bool?
}

View File

@ -18,6 +18,7 @@
public var backgroundColor: Color?
public var moleculeName: String = ImageViewModel.identifier
public var image: String
public var accessibilityIdentifier: String?
public var accessibilityText: String?
public var fallbackImage: String?
public var imageFormat: String?
@ -47,6 +48,7 @@
private enum CodingKeys: String, CodingKey {
case id
case accessibilityIdentifier
case moleculeName
case backgroundColor
case image
@ -61,4 +63,20 @@
case shouldMaskRecordedView
case allowServerParameters
}
public func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false }
return backgroundColor == model.backgroundColor
&& image == model.image
&& accessibilityText == model.accessibilityText
&& fallbackImage == model.fallbackImage
&& imageFormat == model.imageFormat
&& width == model.width
&& height == model.height
&& contentMode == model.contentMode
&& cornerRadius == model.cornerRadius
&& clipsImage == model.clipsImage
&& allowServerParameters == model.allowServerParameters
&& shouldMaskRecordedView == model.shouldMaskRecordedView
}
}

View File

@ -16,13 +16,15 @@ public class FormLabel: Label {
//public properties
public override var isEnabled: Bool {
didSet{
self.formModel.enabled = isEnabled
guard let formModel else { return }
formModel.enabled = isEnabled
self.set(with: isRequired ? formModel.model : formModel.requiredModel, delegateObject, additionalData)
}
}
public var isRequired: Bool = true {
didSet{
guard let formModel else { return }
self.set(with: isRequired ? formModel.model : formModel.requiredModel, delegateObject, additionalData)
}
}
@ -50,6 +52,7 @@ public class FormLabel: Label {
/// Text change that will update both enabledModel and disabledModel text values
/// - Parameter text: text you want to see
public func set(text: String?){
self.formModel.set(text: text ?? "")
guard let formModel else { return }
formModel.set(text: text ?? "")
}
}

View File

@ -34,11 +34,7 @@ public typealias ActionBlock = () -> ()
/// A specific text index to use as a unique marker.
public var hero: Int?
public var getRange: NSRange {
NSRange(location: 0, length: text?.count ?? 0)
}
public var shouldMaskWhileRecording: Bool = false
public var hasText: Bool {
@ -186,6 +182,9 @@ public typealias ActionBlock = () -> ()
}
public func viewModelDidUpdate() {
if let accessibilityIdentifier = viewModel.accessibilityIdentifier {
self.accessibilityIdentifier = accessibilityIdentifier
}
shouldMaskWhileRecording = viewModel.shouldMaskRecordedView ?? false
text = viewModel.text
hero = viewModel.hero
@ -364,8 +363,8 @@ extension Label {
public static func boundingRect(forCharacterRange range: NSRange, in label: Label) -> CGRect {
guard let abstractContainer = label.abstractTextContainer() else { return CGRect() }
let textContainer = abstractContainer.0
let layoutManager = abstractContainer.1
let textContainer = abstractContainer.textContainer
let layoutManager = abstractContainer.layoutManager
var glyphRange = NSRange()
@ -374,53 +373,28 @@ extension Label {
return layoutManager.boundingRect(forGlyphRange: glyphRange, in: textContainer)
}
/**
Provides a text container and layout manager of how the text would appear on screen.
They are used in tandem to derive low-level TextKit results of the label.
*/
public func abstractTextContainer() -> (NSTextContainer, NSLayoutManager, NSTextStorage)? {
// Must configure the attributed string to translate what would appear on screen to accurately analyze.
guard let attributedText = attributedText else { return nil }
let paragraph = NSMutableParagraphStyle()
paragraph.alignment = textAlignment
let stagedAttributedString = NSMutableAttributedString(attributedString: attributedText)
stagedAttributedString.addAttributes([NSAttributedString.Key.paragraphStyle: paragraph], range: NSRange(location: 0, length: attributedText.string.count))
let textStorage = NSTextStorage(attributedString: stagedAttributedString)
let layoutManager = NSLayoutManager()
let textContainer = NSTextContainer(size: .zero)
layoutManager.addTextContainer(textContainer)
textStorage.addLayoutManager(layoutManager)
textContainer.lineFragmentPadding = 0.0
textContainer.lineBreakMode = lineBreakMode
textContainer.maximumNumberOfLines = numberOfLines
textContainer.size = bounds.size
return (textContainer, layoutManager, textStorage)
}
}
// MARK: - Atomization
extension Label {
public func needsToBeConstrained() -> Bool { true }
public func horizontalAlignment() -> UIStackView.Alignment { .leading }
public func copyBackgroundColor() -> Bool { true }
}
// MARK: - Multi-Link Functionality
extension Label {
extension VDS.Label {
public var getRange: NSRange {
NSRange(location: 0, length: text?.count ?? 0)
}
/// Underlines the tappable region and stores the tap logic for interation.
private func setTextLinkState(range: NSRange, actionBlock: @escaping ActionBlock) {
internal func setTextLinkState(range: NSRange, actionBlock: @escaping ActionBlock) {
guard let text, text.isValid(range: range) else { return }
var textLink = ActionLabelAttribute(location: range.location, length: range.length)
@ -447,8 +421,16 @@ extension Label {
return { [weak self] in
guard let self = self else { return }
if (delegateObject as? MVMCoreUIDelegateObject)?.buttonDelegate?.button?(self, shouldPerformActionWithMap: actionMap, additionalData: additionalData) ?? true {
MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegateObject: delegateObject)
if let button = self as? MFButtonProtocol {
if (delegateObject as? MVMCoreUIDelegateObject)?.buttonDelegate?.button?(button, shouldPerformActionWithMap: actionMap, additionalData: additionalData) ?? true {
MVMCoreActionHandler.shared()?.handleAction(with: actionMap,
additionalData: additionalData,
delegateObject: delegateObject)
}
} else {
MVMCoreActionHandler.shared()?.handleAction(with: actionMap,
additionalData: additionalData,
delegateObject: delegateObject)
}
}
}

View File

@ -48,4 +48,9 @@ open class LabelAttributeActionModel: LabelAttributeModel {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encodeModel(action, forKey: .action)
}
public override func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard super.isEqual(to: model), let model = model as? Self else { return false }
return action.isEqual(to: model.action)
}
}

View File

@ -43,4 +43,9 @@
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encodeIfPresent(textColor, forKey: .textColor)
}
public override func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard super.isEqual(to: model), let model = model as? Self else { return false }
return textColor == model.textColor
}
}

View File

@ -55,4 +55,11 @@
try container.encodeIfPresent(name, forKey: .name)
try container.encodeIfPresent(size, forKey: .size)
}
public override func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard super.isEqual(to: model), let model = model as? Self else { return false }
return style == model.style
&& name == model.name
&& size == model.size
}
}

View File

@ -69,4 +69,12 @@ class LabelAttributeImageModel: LabelAttributeModel {
try container.encodeIfPresent(URL, forKey: .URL)
try container.encodeIfPresent(tintColor, forKey: .tintColor)
}
public override func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard super.isEqual(to: model), let model = model as? Self else { return false }
return URL == model.URL
&& name == model.name
&& size == model.size
&& tintColor == model.tintColor
}
}

View File

@ -7,7 +7,7 @@
//
@objcMembers open class LabelAttributeModel: ModelProtocol {
@objcMembers open class LabelAttributeModel: ModelProtocol, ModelComparisonProtocol, MoleculeModelComparisonProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
@ -75,4 +75,16 @@
try container.encode(location, forKey: .location)
try container.encode(length, forKey: .length)
}
public func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false }
return location == model.location
&& length == model.length
}
public func isVisuallyEquivalent(to model: any MoleculeModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false }
return location == model.location
&& length == model.length
}
}

View File

@ -66,6 +66,13 @@ import UIKit
try container.encode(style, forKey: .style)
try container.encodeIfPresent(pattern, forKey: .pattern)
}
public override func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard super.isEqual(to: model), let model = model as? Self else { return false }
return style == model.style
&& color == model.color
&& pattern == model.pattern
}
}
public enum UnderlineStyle: String, Codable {

View File

@ -14,7 +14,8 @@ import VDS
open class var identifier: String { "label" }
public var id: String
public var accessibilityIdentifier: String?
public var backgroundColor: Color?
public var text: String
public var accessibilityText: String?
@ -38,6 +39,7 @@ import VDS
private enum CodingKeys: String, CodingKey {
case id
case accessibilityIdentifier
case moleculeName
case text
case accessibilityText
@ -88,6 +90,7 @@ import VDS
required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
id = try typeContainer.decodeIfPresent(String.self, forKey: .id) ?? UUID().uuidString
accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
text = try typeContainer.decode(String.self, forKey: .text)
accessibilityText = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityText)
textColor = try typeContainer.decodeIfPresent(Color.self, forKey: .textColor)
@ -115,6 +118,7 @@ import VDS
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encodeIfPresent(moleculeName, forKey: .moleculeName)
try container.encode(id, forKey: .id)
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
try container.encode(text, forKey: .text)
try container.encodeIfPresent(accessibilityText, forKey: .accessibilityText)
try container.encodeIfPresent(textColor, forKey: .textColor)
@ -132,6 +136,45 @@ import VDS
try container.encodeIfPresent(shouldMaskRecordedView, forKey: .shouldMaskRecordedView)
try container.encodeIfPresent(accessibilityTraits, forKey: .accessibilityTraits)
}
public func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false }
return backgroundColor == model.backgroundColor
&& text == model.text
&& textColor == model.textColor
&& fontStyle == model.fontStyle
&& fontName == model.fontName
&& fontSize == model.fontSize
&& textAlignment == model.textAlignment
&& html == model.html
&& hero == model.hero
&& makeWholeViewClickable == model.makeWholeViewClickable
&& numberOfLines == model.numberOfLines
&& accessibilityText == model.accessibilityText
&& accessibilityTraits == model.accessibilityTraits
&& inverted == inverted
&& shouldMaskRecordedView == model.shouldMaskRecordedView
&& attributes.isEqual(to: model.attributes)
}
public func isVisuallyEquivalent(to model: any MoleculeModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false }
return backgroundColor == model.backgroundColor
&& text == model.text
&& textColor == model.textColor
&& fontStyle == model.fontStyle
&& fontName == model.fontName
&& fontSize == model.fontSize
&& textAlignment == model.textAlignment
&& html == model.html
&& hero == model.hero
&& makeWholeViewClickable == model.makeWholeViewClickable
&& numberOfLines == model.numberOfLines
&& accessibilityText == model.accessibilityText
&& accessibilityTraits == model.accessibilityTraits
&& inverted == inverted
&& attributes.isVisuallyEquivalent(to: model.attributes)
}
}
extension LabelModel {

View File

@ -16,7 +16,8 @@ import UIKit
public static var identifier: String = "leftRightLabelView"
public var moleculeName: String = LeftRightLabelModel.identifier
@DecodableDefault.UUIDString public var id: String
public var accessibilityIdentifier: String?
public var backgroundColor: Color?
public var leftText: LabelModel
public var rightText: LabelModel?

View File

@ -66,7 +66,7 @@ import VDS
}
open func setStyle(_ style: LineModel.Style) {
viewModel.type = style
viewModel?.type = style
update(viewModel: viewModel)
}
@ -85,7 +85,7 @@ import VDS
}
open override func draw(_ rect: CGRect) {
guard viewModel.type != .none else { return }
guard let viewModel, viewModel.type != .none else { return }
super.draw(rect)
}
@ -93,6 +93,9 @@ import VDS
// MARK: - VDSMoleculeViewProtocol
//--------------------------------------------------
open func viewModelDidUpdate() {
if let accessibilityIdentifier = viewModel.accessibilityIdentifier {
self.accessibilityIdentifier = accessibilityIdentifier
}
surface = viewModel.surface
style = VDS.Line.Style(rawValue: viewModel.type.rawValue) ?? .primary
orientation = viewModel.orientation

View File

@ -7,7 +7,7 @@
//
import UIKit
import VDSColorTokens
import VDSCoreTokens
import VDS
public class LineModel: MoleculeModelProtocol, Invertable {
@ -55,6 +55,7 @@ public class LineModel: MoleculeModelProtocol, Invertable {
public static var identifier: String = "line"
public var id: String = UUID().uuidString
public var accessibilityIdentifier: String?
public var backgroundColor: Color?
public var type: Style = .secondary
@ -83,6 +84,7 @@ public class LineModel: MoleculeModelProtocol, Invertable {
private enum CodingKeys: String, CodingKey {
case id
case accessibilityIdentifier
case moleculeName
case type
case frequency
@ -99,7 +101,8 @@ public class LineModel: MoleculeModelProtocol, Invertable {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
id = try typeContainer.decodeIfPresent(String.self, forKey: .id) ?? UUID().uuidString
accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
if let type = try typeContainer.decodeIfPresent(Style.self, forKey: .type) {
self.type = type
}
@ -124,9 +127,18 @@ public class LineModel: MoleculeModelProtocol, Invertable {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(moleculeName, forKey: .moleculeName)
try container.encode(id, forKey: .id)
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
try container.encode(type, forKey: .type)
try container.encode(inverted, forKey: .inverted)
try container.encodeIfPresent(frequency, forKey: .frequency)
try container.encode(orientation == .vertical, forKey: .useVerticalLine)
}
public func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false }
return type == model.type
&& inverted == model.inverted
&& frequency == model.frequency
&& orientation == model.orientation
}
}

View File

@ -22,6 +22,9 @@ open class LoadingSpinner: VDS.Loader, VDSMoleculeViewProtocol {
// MARK: - Public Functions
//--------------------------------------------------
open func viewModelDidUpdate() {
if let accessibilityIdentifier = viewModel.accessibilityIdentifier {
self.accessibilityIdentifier = accessibilityIdentifier
}
size = Int(viewModel.diameter)
surface = viewModel.surface
}

View File

@ -16,7 +16,8 @@ open class LoadingSpinnerModel: MoleculeModelProtocol {
//--------------------------------------------------
public static var identifier: String = "loadingSpinner"
public var id: String = UUID().uuidString
public var accessibilityIdentifier: String?
public var backgroundColor: Color?
public var inverted: Bool = false
public var diameter: CGFloat = 40
@ -27,6 +28,7 @@ open class LoadingSpinnerModel: MoleculeModelProtocol {
private enum CodingKeys: String, CodingKey {
case id
case accessibilityIdentifier
case moleculeName
case strokeColor
case diameter
@ -47,7 +49,8 @@ open class LoadingSpinnerModel: MoleculeModelProtocol {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
id = try typeContainer.decodeIfPresent(String.self, forKey: .id) ?? UUID().uuidString
accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
if let diameter = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .diameter) {
self.diameter = diameter
}
@ -65,6 +68,7 @@ open class LoadingSpinnerModel: MoleculeModelProtocol {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encode(moleculeName, forKey: .moleculeName)
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
try container.encodeIfPresent(diameter, forKey: .diameter)
try container.encodeIfPresent(inverted, forKey: .inverted)
}

View File

@ -22,7 +22,8 @@ import Foundation
public static var identifier: String = "multiProgressBar"
public var id: String = UUID().uuidString
public var accessibilityIdentifier: String?
public var progressList: [SingleProgressBarModel]
public var backgroundColor: Color?
public var thickness: CGFloat?
@ -30,6 +31,7 @@ import Foundation
private enum CodingKeys: String, CodingKey {
case id
case accessibilityIdentifier
case moleculeName
case progressList
case thickness
@ -44,6 +46,7 @@ import Foundation
required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
id = try typeContainer.decodeIfPresent(String.self, forKey: .id) ?? UUID().uuidString
accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
progressList = try typeContainer.decode([SingleProgressBarModel].self, forKey: .progressList)
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
thickness = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .thickness)
@ -54,6 +57,7 @@ import Foundation
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encode(moleculeName, forKey: .moleculeName)
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
try container.encode(progressList, forKey: .progressList)
try container.encodeIfPresent(thickness, forKey: .thickness)
try container.encodeIfPresent(roundedCorners, forKey: .roundedCorners)

View File

@ -0,0 +1,60 @@
//
// Pagination.swift
// MVMCoreUI
//
// Created by Matt Bruce on 8/27/24.
// Copyright © 2024 Verizon Wireless. All rights reserved.
//
import Foundation
import VDS
@objcMembers open class Pagination: VDS.Pagination, VDSMoleculeViewProtocol {
//------------------------------------------------------
// MARK: - Properties
//------------------------------------------------------
open var viewModel: PaginationModel!
open var delegateObject: MVMCoreUIDelegateObject?
open var additionalData: [AnyHashable : Any]?
// Form Validation
open var fieldKey: String?
open var fieldValue: JSONValue?
open var groupName: String?
//--------------------------------------------------
// MARK: - Initializers
//--------------------------------------------------
public convenience required init() {
self.init(frame:.zero)
}
open override func setup() {
super.setup()
pageChangedPublisher
.sink { [weak self] control in
guard let self else { return }
viewModel?.selectedPage = control.selectedPage
}.store(in: &subscribers)
}
open func viewModelDidUpdate() {
if let accessibilityIdentifier = viewModel.accessibilityIdentifier {
self.accessibilityIdentifier = accessibilityIdentifier
}
isEnabled = viewModel.enabled
surface = viewModel.surface
total = viewModel.totalPages
selectedPage = viewModel.selectedPage
}
//--------------------------------------------------
// MARK: - Actions
//--------------------------------------------------
//--------------------------------------------------
// MARK: - MoleculeViewProtocol
//--------------------------------------------------
public func updateView(_ size: CGFloat) {}
}

View File

@ -0,0 +1,76 @@
//
// PaginationModel.swift
// MVMCoreUI
//
// Created by Matt Bruce on 8/27/24.
// Copyright © 2024 Verizon Wireless. All rights reserved.
//
import Foundation
import VDS
import MVMCore
open class PaginationModel: MoleculeModelProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
open class var identifier: String { "pagination" }
open var moleculeName: String { Self.identifier }
open var backgroundColor: Color?
open var id: String = UUID().uuidString
open var accessibilityIdentifier: String?
open var totalPages: Int = 0
open var selectedPage: Int = 0
open var enabled: Bool = true
open var inverted: Bool = false
open var surface: Surface { inverted ? .dark : .light }
//--------------------------------------------------
// MARK: - Keys
//--------------------------------------------------
private enum CodingKeys: String, CodingKey {
case id
case moleculeName
case accessibilityIdentifier
case totalPages
case selectedPage
case enabled
case inverted
}
//--------------------------------------------------
// MARK: - Initializers
//--------------------------------------------------
required public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decode(String.self, forKey: .id)
accessibilityIdentifier = try container.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
totalPages = try container.decode(Int.self, forKey: .totalPages)
selectedPage = try container.decodeIfPresent(Int.self, forKey: .selectedPage) ?? 0
enabled = try container.decodeIfPresent(Bool.self, forKey: .enabled) ?? false
inverted = try container.decodeIfPresent(Bool.self, forKey: .inverted) ?? false
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encode(moleculeName, forKey: .moleculeName)
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
try container.encode(totalPages, forKey: .totalPages)
try container.encode(selectedPage, forKey: .selectedPage)
try container.encode(enabled, forKey: .enabled)
try container.encode(inverted, forKey: .inverted)
}
public func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false }
return inverted == model.inverted
&& enabled == model.enabled
&& totalPages == model.totalPages
&& selectedPage == model.selectedPage
}
}

View File

@ -75,6 +75,9 @@ import Foundation
guard let progressBarModel = model as? ProgressBarModel else { return }
self.progressBarModel = progressBarModel
if let accessibilityIdentifier = model.accessibilityIdentifier {
self.accessibilityIdentifier = accessibilityIdentifier
}
thickness = progressBarModel.thickness ?? 8
progress = Float((progressBarModel.percent) / 100.0)
progressTintColor = progressBarModel.color.uiColor

View File

@ -11,7 +11,8 @@ import Foundation
@objcMembers open class ProgressBarModel: MoleculeModelProtocol {
open class var identifier: String { "progressBar" }
public var id: String = UUID().uuidString
public var accessibilityIdentifier: String?
@Percent public var percent: CGFloat
public var color: Color = Color(uiColor: .mfCerulean())
public var backgroundColor: Color? = Color(uiColor: .mfLightSilver())
@ -20,6 +21,7 @@ import Foundation
private enum CodingKeys: String, CodingKey {
case id
case accessibilityIdentifier
case moleculeName
case roundedCorners
case thickness
@ -35,6 +37,7 @@ import Foundation
required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
id = try typeContainer.decodeIfPresent(String.self, forKey: .id) ?? UUID().uuidString
accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
percent = try typeContainer.decode(CGFloat.self, forKey: .percent)
if let color = try typeContainer.decodeIfPresent(Color.self, forKey: .color) {
self.color = color
@ -50,6 +53,7 @@ import Foundation
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encode(moleculeName, forKey: .moleculeName)
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
try container.encode(percent, forKey: .percent)
try container.encode(color, forKey: .color)
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)

View File

@ -14,7 +14,8 @@ open class StarModel: MoleculeModelProtocol {
//--------------------------------------------------
public static var identifier: String = "star"
public var id: String = UUID().uuidString
public var accessibilityIdentifier: String?
public var backgroundColor: Color?
@Percent public var percent: CGFloat = 0
public var borderColor: Color?
@ -26,6 +27,7 @@ open class StarModel: MoleculeModelProtocol {
//--------------------------------------------------
private enum CodingKeys: String, CodingKey {
case id
case accessibilityIdentifier
case moleculeName
case backgroundColor
case percent
@ -47,6 +49,7 @@ open class StarModel: MoleculeModelProtocol {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
id = try typeContainer.decodeIfPresent(String.self, forKey: .id) ?? UUID().uuidString
accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
if let percent = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .percent) {
self.percent = percent
}
@ -63,6 +66,7 @@ open class StarModel: MoleculeModelProtocol {
try container.encode(id, forKey: .id)
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
try container.encode(moleculeName, forKey: .moleculeName)
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
try container.encode(percent, forKey: .percent)
try container.encodeIfPresent(borderColor, forKey: .borderColor)
try container.encodeIfPresent(fillColor, forKey: .fillColor)

View File

@ -14,7 +14,8 @@ import MVMCore
//--------------------------------------------------
public static var identifier: String = "stars"
public var id: String = UUID().uuidString
public var accessibilityIdentifier: String?
public var backgroundColor: Color?
public var starBackgroundColor: Color?
public var stars: [StarModel]
@ -28,6 +29,7 @@ import MVMCore
//--------------------------------------------------
private enum CodingKeys: String, CodingKey {
case id
case accessibilityIdentifier
case moleculeName
case backgroundColor
case starBackgroundColor
@ -53,6 +55,7 @@ import MVMCore
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
id = try typeContainer.decodeIfPresent(String.self, forKey: .id) ?? UUID().uuidString
accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
stars = try typeContainer.decode([StarModel].self, forKey: .stars)
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
starBackgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .starBackgroundColor)
@ -70,6 +73,7 @@ import MVMCore
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encode(moleculeName, forKey: .moleculeName)
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
try container.encode(stars, forKey: .stars)
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
try container.encodeIfPresent(starBackgroundColor, forKey: .starBackgroundColor)

View File

@ -0,0 +1,145 @@
//
// TileContainer.swift
// MVMCoreUI
//
// Created by Matt Bruce on 4/15/24.
// Copyright © 2024 Verizon Wireless. All rights reserved.
//
import Foundation
import VDS
import Combine
open class TileContainer: VDS.TileContainer, VDSMoleculeViewProtocol{
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public var model: MoleculeModelProtocol?
public var viewModel: TileContainerModel!
public var delegateObject: MVMCoreUIDelegateObject?
public var additionalData: [AnyHashable: Any]?
public var molecule: MoleculeViewProtocol? {
willSet {
if newValue == nil {
molecule?.removeFromSuperview()
}
}
}
//--------------------------------------------------
// MARK: - Initializers
//--------------------------------------------------
public convenience required init() {
self.init(frame: .zero)
}
//--------------------------------------------------
// MARK: - Public
//--------------------------------------------------
public func viewModelDidUpdate() {
if let accessibilityIdentifier = viewModel.accessibilityIdentifier {
self.accessibilityIdentifier = accessibilityIdentifier
}
if let moleculeModel = viewModel.molecule {
if let molecule,
moleculeModel.moleculeName == molecule.model?.moleculeName {
molecule.set(with: moleculeModel, delegateObject, additionalData)
} else if let moleculeView = ModelRegistry.createMolecule(moleculeModel, delegateObject: delegateObject, additionalData: additionalData) {
molecule = moleculeView
addContentView(moleculeView)
}
}
// set backgroundImage
if let imageName = viewModel.backgroundImage {
loadImage(imageName)
}
//set action
if let action = viewModel.action {
//add the subscriber
onClick = { [weak self] control in
guard let self, let viewModel = self.viewModel else { return }
MVMCoreUIActionHandler.performActionUnstructured(with: action,
sourceModel: viewModel,
additionalData: self.additionalData,
delegateObject: self.delegateObject)
}
}
//set the rest of the properties
surface = viewModel.surface
imageFallbackColor = viewModel.imageFallbackColor
width = viewModel.width
height = viewModel.height
showBorder = viewModel.showBorder
showDropShadow = viewModel.showDropShadow
padding = viewModel.padding
color = viewModel.color
aspectRatio = viewModel.aspectRatio
backgroundEffect = viewModel.backgroundEffect
}
private func loadImage(_ imageName: String? = nil) {
guard let imageName else {
if backgroundImage != nil {
backgroundImage = nil
}
return
}
let finishedLoadingBlock: MVMCoreGetImageBlock = {[weak self] (image, data, isFallbackImage) in MVMCoreDispatchUtility.performBlock(onMainThread: { [weak self] in
guard let self = self else { return }
self.backgroundImage = image
})}
MVMCoreCache.shared()?.getImage(imageName, useWidth: false, widthForS7: 0, useHeight: false, heightForS7: 0, format: nil, localFallbackImageName: nil, allowServerQueryParameters: false, localBundle: nil, completionHandler: finishedLoadingBlock)
}
//--------------------------------------------------
// MARK: - MVMCoreViewProtocol
//--------------------------------------------------
open func updateView(_ size: CGFloat) {
(molecule as? MVMCoreViewProtocol)?.updateView(size)
}
//--------------------------------------------------
// MARK: - MoleculeViewProtocol
//--------------------------------------------------
//since this is a class func, we can't reference it directly
public static func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
100
}
/// Allows the molecule to set its name for reuse. Default could be moleculeName. Mainly used for list or collections.
public static func nameForReuse(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> String? {
// This will aggregate names of molecules to make an id.
guard let containerModel = model as? TileContainerModel,
let molecule = containerModel.molecule,
let moleculeClass = ModelRegistry.getMoleculeClass(molecule),
let moleculeName = moleculeClass.nameForReuse(with: molecule, delegateObject)
else { return "\(model.moleculeName)<>" }
return "\(model.moleculeName)<\(moleculeName)>"
}
//--------------------------------------------------
// MARK: - Overrides
//--------------------------------------------------
open override func layoutSubviews() {
super.layoutSubviews()
// Accounts for any collection size changes
DispatchQueue.main.async { [weak self] in
guard let self else { return }
self.delegateObject?.moleculeDelegate?.moleculeLayoutUpdated(self)
}
}
}
extension TileContainer: MVMCoreUIViewConstrainingProtocol {
public func isClippable() -> Bool {
return false
}
}

View File

@ -0,0 +1,123 @@
//
// TileContainerModel.swift
// MVMCoreUI
//
// Created by Matt Bruce on 4/15/24.
// Copyright © 2024 Verizon Wireless. All rights reserved.
//
import Foundation
import VDS
import MVMCore
open class TileContainerModel: TileContainerBaseModel<TileContainer.Padding, TileContainer>, ParentMoleculeModelProtocol, MoleculeModelProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public static var identifier: String = "tileContainer"
public var id: String = UUID().uuidString
public var backgroundColor: Color?
public var molecule: MoleculeModelProtocol?
public var children: [any MoleculeModelProtocol] {
guard let molecule else { return [] }
return [molecule]
}
public func replaceChildMolecule(with molecule: MoleculeModelProtocol) throws -> MoleculeModelProtocol? {
return try replaceChildMolecule(at: &self.molecule, with: molecule)
}
private enum CodingKeys: String, CodingKey {
case id
case moleculeName
case molecule
}
required public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decodeIfPresent(String.self, forKey: .id) ?? UUID().uuidString
molecule = try container.decodeMoleculeIfPresent(codingKey: .molecule)
try super.init(from: decoder)
}
public override func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encode(moleculeName, forKey: .moleculeName)
try container.encodeModelIfPresent(molecule, forKey: .molecule)
try super.encode(to: encoder)
}
}
open class TileContainerBaseModel<PaddingType: DefaultValuing & Codable, TileContainerType:TileContainerBase<PaddingType>> : Codable{
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public var inverted: Bool = false
public var backgroundImage: String?
public var action: ActionModelProtocol?
public var imageFallbackColor: Surface = .light
public var width: CGFloat?
public var height: CGFloat?
public var showBorder: Bool = false
public var showDropShadow: Bool = false
public var padding = PaddingType.defaultValue
public var color: TileContainerType.BackgroundColor = .black
public var aspectRatio: TileContainerType.AspectRatio = .none
public var backgroundEffect: TileContainerType.BackgroundEffect = .none
public var surface: Surface { inverted ? .dark : .light }
public var accessibilityIdentifier: String?
private enum CodingKeys: String, CodingKey {
case accessibilityIdentifier
case inverted
case backgroundImage
case action
case imageFallbackColor
case width
case height
case showBorder
case showDropShadow
case padding
case color
case aspectRatio
case backgroundEffect
}
required public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
accessibilityIdentifier = try container.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
inverted = try container.decodeIfPresent(Bool.self, forKey: .inverted) ?? false
backgroundImage = try container.decodeIfPresent(String.self, forKey: .backgroundImage)
action = try container.decodeModelIfPresent(codingKey: .action)
imageFallbackColor = try container.decodeIfPresent(VDS.Surface.self, forKey: .imageFallbackColor) ?? .light
width = try container.decodeIfPresent(CGFloat.self, forKey: .width)
height = try container.decodeIfPresent(CGFloat.self, forKey: .height)
showBorder = try container.decodeIfPresent(Bool.self, forKey: .showBorder) ?? false
showDropShadow = try container.decodeIfPresent(Bool.self, forKey: .showDropShadow) ?? false
padding = try container.decodeIfPresent(PaddingType.self, forKey: .padding) ?? PaddingType.defaultValue
color = try container.decodeIfPresent(TileContainerType.BackgroundColor.self, forKey: .color) ?? .black
aspectRatio = try container.decodeIfPresent(TileContainerType.AspectRatio.self, forKey: .aspectRatio) ?? .none
backgroundEffect = try container.decodeIfPresent(TileContainerType.BackgroundEffect.self, forKey: .backgroundEffect) ?? .none
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
try container.encodeIfPresent(backgroundImage, forKey: .backgroundImage)
try container.encodeModelIfPresent(action, forKey: .action)
try container.encodeIfPresent(imageFallbackColor, forKey: .imageFallbackColor)
try container.encodeIfPresent(width, forKey: .width)
try container.encodeIfPresent(height, forKey: .height)
try container.encodeIfPresent(showBorder, forKey: .showBorder)
try container.encodeIfPresent(showDropShadow, forKey: .showDropShadow)
try container.encodeIfPresent(padding, forKey: .padding)
try container.encodeIfPresent(color, forKey: .color)
try container.encodeIfPresent(aspectRatio, forKey: .aspectRatio)
try container.encodeIfPresent(backgroundEffect, forKey: .backgroundEffect)
}
}

View File

@ -39,18 +39,19 @@ open class Tilelet: VDS.Tilelet, VDSMoleculeViewProtocol{
// MARK: - Public
//--------------------------------------------------
public func viewModelDidUpdate() {
color = viewModel.color
padding = viewModel.padding
aspectRatio = viewModel.aspectRatio
width = viewModel.width
if let accessibilityIdentifier = viewModel.accessibilityIdentifier {
self.accessibilityIdentifier = accessibilityIdentifier
}
//tilelet specific properties
if let value = viewModel.textWidth {
textWidth = .value(value)
} else if let percentage = viewModel.textPercentage {
textWidth = .percentage(percentage)
}
eyebrowModel = viewModel.eyebrowModel(delegateObject: delegateObject, additionalData: additionalData)
titleModel = viewModel.titleModel(delegateObject: delegateObject, additionalData: additionalData)
subTitleModel = viewModel.subTitleModel(delegateObject: delegateObject, additionalData: additionalData)
badgeModel = viewModel.badge
badgeModel = viewModel.badgeModel()
descriptiveIconModel = viewModel.descriptiveIcon
directionalIconModel = viewModel.directionalIcon
//setup action
@ -64,6 +65,51 @@ open class Tilelet: VDS.Tilelet, VDSMoleculeViewProtocol{
delegateObject: self.delegateObject)
}
}
// TileContainer properties
// set backgroundImage
if let imageName = viewModel.backgroundImage {
loadImage(imageName)
}
//set action
if let action = viewModel.action {
//add the subscriber
onClick = { [weak self] control in
guard let self, let viewModel = self.viewModel else { return }
MVMCoreUIActionHandler.performActionUnstructured(with: action,
sourceModel: viewModel,
additionalData: self.additionalData,
delegateObject: self.delegateObject)
}
}
//set the rest of the properties
surface = viewModel.surface
imageFallbackColor = viewModel.imageFallbackColor
width = viewModel.width
height = viewModel.height
showBorder = viewModel.showBorder
showDropShadow = viewModel.showDropShadow
padding = viewModel.padding
color = viewModel.color
aspectRatio = viewModel.aspectRatio
backgroundEffect = viewModel.backgroundEffect
}
private func loadImage(_ imageName: String? = nil) {
guard let imageName else {
if backgroundImage != nil {
backgroundImage = nil
}
return
}
let finishedLoadingBlock: MVMCoreGetImageBlock = {[weak self] (image, data, isFallbackImage) in MVMCoreDispatchUtility.performBlock(onMainThread: { [weak self] in
guard let self = self else { return }
self.backgroundImage = image
})}
MVMCoreCache.shared()?.getImage(imageName, useWidth: false, widthForS7: 0, useHeight: false, heightForS7: 0, format: nil, localFallbackImageName: nil, allowServerQueryParameters: false, localBundle: nil, completionHandler: finishedLoadingBlock)
}
//--------------------------------------------------
@ -91,3 +137,9 @@ open class Tilelet: VDS.Tilelet, VDSMoleculeViewProtocol{
}
}
}
extension Tilelet: MVMCoreUIViewConstrainingProtocol {
public func isClippable() -> Bool {
return false
}
}

Some files were not shown because too many files have changed in this diff Show More