Compare commits

...

417 Commits

Author SHA1 Message Date
Pfeil, Scott Robert
3e1581e28e Merge branch 'bugfix/prevent_feed_cache_clearing' into 'develop'
Bugfix/prevent feed cache clearing

### Summary
Prevent premature feeds cache clearing.

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

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/351
2024-10-04 18:06:12 +00:00
Hedden, Kyle Matthew
8f2483eb1b Digital PCT265 defect MVAPCT-322: Mesasge to log for modules missing their ResponseInfo. 2024-10-04 12:20:59 -04:00
Hedden, Kyle Matthew
12d17dbca8 Digital PCT265 defect MVAPCT-322: Convert couple more hard coded restarts to be soft. 2024-10-04 12:20:35 -04:00
Pfeil, Scott Robert
c360c75512 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/-/merge_requests/349
2024-10-03 21:23:07 +00:00
Pfeil, Scott Robert
d57a86e140 Merge branch 'bugfix/prevent_feed_cache_clearing' into 'develop'
Digital PCT265 defect: Prevent standard session restarts from clearing the persistent cache.

### Summary
Discovered during Monday's outage, the feed cache is actually getting prematurely cleared on standard session timeouts. Moving logic to be based on the logout action itself.

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

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/350
2024-10-03 19:23:07 +00:00
Hedden, Kyle Matthew
214ccfd8f6 Digital PCT265 defect MVAPCT-322: Spelling fix. 2024-10-03 15:15:11 -04:00
Pfeil, Scott Robert
31aa1d6df7 Merge branch 'feature/CXTDT-552152' into 'develop'
CXTDT-552152

### Summary
Potential Fix for Crash in New Relic

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

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/348
2024-10-03 13:29:14 +00:00
Hedden, Kyle Matthew
817d7900f4 Digital PCT265 defect: Prevent standard session restarts from clearing the persistent cache. 2024-10-02 17:45:58 -04:00
Danish Phiroz
4b35a8bb2d PR Review comment fixed 2024-10-02 13:27:33 -04:00
Danish Phiroz
a29fa60e5e PR Review comments fixed 2024-10-02 12:47:26 -04:00
Hedden, Kyle Matthew
3103f8dd89 Digital ACT192 story ONEAPP-11359: Lift the minimum supported iOS version number to 15. 2024-10-01 20:23:42 -04:00
Danish Phiroz
2b36711bca Potential Fix for Crash 2024-10-01 16:08:55 -04:00
Hedden, Kyle Matthew
a570f3c0e6 Merge branch 'feature/action_id_initial_parameters' into 'develop'
Digital ACT191 story ONEAPP-10840 - Passing action id through to initialParameters getter

### Summary
Passing actionId through to initial parameters getter

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

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/347
2024-09-20 18:42:35 +00:00
Scott Pfeil
038fb8cdf7 Digital ACT191 story ONEAPP-10840 - Optimizing, passing in existing actionId variable 2024-09-20 09:54:47 -04:00
Scott Pfeil
dd2b0f9de5 Digital ACT191 story ONEAPP-10840 - Passing action id through to initialParameters getter 2024-09-19 16:27:08 -04:00
Hedden, Kyle Matthew
d61cb6cfb9 Merge branch 'feature/MVAPCT-273' into 'develop'
MVAPCT-273

### Summary
Action 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/-/merge_requests/346
2024-09-19 12:30:48 +00:00
Phiroz, Danish
cf3d7810d4 MVAPCT-273 2024-09-19 12:30:48 +00:00
Hedden, Kyle Matthew
3c8af09752 Merge branch 'feature/atomic-vds-new-forms-atoms' into 'develop'
ModelComparisonProtocol addition

### Summary
Appending to existing Protocol for == and !=

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/343
2024-08-22 20:38:56 +00:00
Matt Bruce
b219f3f75d added == and != to existing
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-08-22 15:35:07 -05:00
Pfeil, Scott Robert
fba2e80b8a 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: Scott Pfeil <Scott.Pfeil3@verizonwireless.com>
Co-authored-by: Xi Zhang <xi.zhang@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/334
2024-06-26 14:34:53 +00:00
Pfeil, Scott Robert
460aa06678 Merge branch 'bugfix/CXTDT-574791-2' into 'release/20_0_0'
Bugfix/cxtdt 574791 2

### Summary
Fix navigation crash on controller replace.

### 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/-/merge_requests/338
2024-06-21 14:44:42 +00:00
Hedden, Kyle Matthew
c18ce5e811 Digital PCT265 defect CXTDT-574791: Prevent crash when modifying the controller array slice. 2024-06-21 10:27:12 -04:00
Pfeil, Scott Robert
4bf30550ef Merge branch 'feature/offlineFeedbackClearAppCache' into 'release/20_0_0'
Add support for removing persistent cache properly.

Add support for removing persistent cache properly including the application level cache.

JIRA:
MVAPCT-155

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/335
2024-06-18 21:15:55 +00:00
Hedden, Kyle Matthew
317815d44a Merge branch 'bugfix/CXTDT-573619' into 'release/20_0_0'
Digital PCT265 defect CXTDT-573619 - Add a flag to create a new controller instead of go to

### Summary
Add a flag to create a new controller instead of go to

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

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/336
2024-06-18 20:08:32 +00:00
Scott Pfeil
3054f7e62d Digital PCT265 defect CXTDT-573619 - Add a flag to create a new controller instead of go to 2024-06-18 10:33:01 -04:00
Xi Zhang
25e05c6c53 update API description. 2024-06-17 20:55:20 -04:00
Xi Zhang
a1c6332131 Add support for removing persistent cache properly. 2024-06-17 20:39:39 -04:00
Bruce, Matt R
9744fc5333 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/-/merge_requests/332
2024-06-06 12:48:57 +00:00
Scott Pfeil
8a92c9cdd3 removing dead references 2024-06-05 12:29:41 -04:00
Hedden, Kyle Matthew
a00eff7cf1 Merge branch 'feature/ONEAPP-7249' into 'develop'
Digital PCT265 story ONEAPP-7249 - Enhancement for allowing background polling.

### Summary
1. Logging change for less verbose logging statements and standardization. Used to help tracking pollingBehavior state.
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/-/merge_requests/328
2024-05-29 23:51:04 +00:00
Hedden, Kyle Matthew
0104570bc9 Digital PCT265 story PCT-135: Code reivew. Restore debug crash. 2024-05-28 17:43:41 -04:00
Hedden, Kyle Matthew
134ce14e5a Digital PCT265 story PCT-135: Code review. Missing pageType check in ActionRestartModel. 2024-05-28 16:25:32 -04:00
Hedden, Kyle Matthew
220b8530da Digital PCT265 story PCT-135: 'curent' comment typo. 2024-05-28 16:23:59 -04:00
Hedden, Kyle Matthew
05df4ad6ef Merge remote-tracking branch 'origin/develop' into feature/ONEAPP-7249 2024-05-21 20:03:58 -04:00
Bruce, Matt R
8f88e94ed8 Merge branch 'feature/register_model_default_parameter' into 'develop'
Update for convenience in registration of models that replace

### Summary
Update for convenience in registration of models that replace

### 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/-/merge_requests/330
2024-05-20 20:46:37 +00:00
Scott Pfeil
d2572c4543 Digital ACT191 story ONEAPP-7459 - Update for convenience in registration of models that replace 2024-05-20 16:44:10 -04:00
Hedden, Kyle Matthew
71689b957b 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:18 -04:00
Hedden, Kyle Matthew
009bb01e1b Digital PCT265 story PCT-135: Code review comments, cleanups and isEquals expansion. 2024-05-13 21:22:57 -04:00
Pfeil, Scott Robert
4bded0a433 Merge branch 'bugfix/CXTDT-552909' into 'develop'
Digital PCT265 defect CXTDT-552909 - Client crash prevention on invalid module JSON.

### Summary
Client resilience check for invalid module data.

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

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/329
2024-05-13 13:06:13 +00:00
Hedden, Kyle Matthew
20d4d323e0 Digital PCT265 story ONEAPP-7249 - isVisuallyEquivalent build out to work with stabilizing carousel refreshes. 2024-05-08 20:34:21 -04:00
Hedden, Kyle Matthew
62a5799312 Digital PCT265 story ONEAPP-7249 - Prevent UI updates when there are no model changes. 2024-05-07 23:27:31 -04:00
Hedden, Kyle Matthew
e8552b0aa2 Digital PCT265 story ONEAPP-7249 - More logging cleanups and categorization. 2024-05-06 12:53:28 -04:00
Hedden, Kyle Matthew
dde3e565a3 Digital PCT265 defect CXTDT-552909 - Client crash prevention on invalid module JSON. 2024-05-02 19:03:21 -04:00
Hedden, Kyle Matthew
62b7955406 Digital PCT265 defect CXTDT-552909 - Client crash prevention on invalid module JSON. 2024-05-02 17:17:57 -04:00
Hedden, Kyle Matthew
a5763d4516 Digital PCT265 story ONEAPP-7249 - Pipe logs to stdout when the message is too long. 2024-05-02 17:03:03 -04:00
Hedden, Kyle Matthew
9ff641060e Digital PCT265 story ONEAPP-7249 - Registry signature update. 2024-04-30 20:36:00 -04:00
Hedden, Kyle Matthew
85747b146e Digital PCT265 story ONEAPP-7249 - Pipe logs to system logger rather than stdout. Logging updates to categorize logs. 2024-04-30 20:35:30 -04:00
Hedden, Kyle Matthew
9b718ce0d4 Merge remote-tracking branch 'origin/develop' into feature/ONEAPP-7249 2024-04-30 13:47:25 -04:00
Hedden, Kyle Matthew
39a8451314 Digital PCT265 story ONEAPP-7249 - CoreLogging protocol for easier logging. 2024-04-30 13:42:33 -04:00
Hedden, Kyle Matthew
c38030bdb8 Merge branch 'bugfix/CXTDT-531317' into 'develop'
Digital PCT265 defect CXTDT-531317 - Adjust logging to capture webview errors.

### 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/-/merge_requests/327
2024-04-26 14:32:47 +00:00
Hedden, Kyle Matthew
09ff3b6457 Digital PCT265 defect CXTDT-531317 - Updated error messaging 2024-04-25 16:01:55 -04:00
Hedden, Kyle Matthew
a428d5f7ce Digital PCT265 defect CXTDT-531317 - Adjust logging to capture webview errors. 2024-04-25 15:50:41 -04:00
Pfeil, Scott Robert
fe7e98f615 Merge branch 'bugfix/PRODDEF-28200' into 'release/11_6_0'
Digital PCT265 defect PRODDEF-28200 - Prevent navigation to the same controller fixing hang ups.

### Summary
Prevent navigation to the same controller 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/-/merge_requests/324
2024-04-23 23:06:18 +00:00
Hedden, Kyle Matthew
f7a348a8b0 Digital PCT265 defect PRODDEF-28200 - Prevent navigation to the same controller fixing hang ups. 2024-04-23 19:02:05 -04:00
Pfeil, Scott Robert
58f7abb5fc Merge branch 'bugfix/CXTDT-544924' into 'develop'
Digital PCT32 defect CXTDT-544924 - Insert missing OpenUrlOptionsModel handling.

### Summary
Insert missing OpenUrlOptionsModel handling for universalLinksOnly.

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

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/322
2024-04-17 15:41:36 +00:00
Hedden, Kyle Matthew
262881f52b Digital PCT32 defect CXTDT-544924 - Code review. Formatting. 2024-04-17 15:32:13 +00:00
Hedden, Kyle Matthew
c4b6122d4c Digital PCT32 defect CXTDT-544924 - Insert missing OpenUrlOptionsModel handling. 2024-04-16 18:15:23 -04:00
Hedden, Kyle Matthew
0f89fb51d2 Merge branch 'bugfix/CXTDT-509545' into 'develop'
CXTDT-509545 : old topNotification tagging fix

### Summary
Declaring the logLoadFinished function to be overriden from MFLoggingHandler to log the tagging data for BAU top notification

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

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/321
2024-04-15 17:38:44 +00:00
Hedden, Kyle Matthew
c63a7f6d90 Merge branch 'release/11_5_0' into 'develop'
release/11_5_0 hotfix merge

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/320
2024-04-12 13:39:27 +00:00
Nandhini Rajendran
fac3e77984 CXTDT-509545 : old topNotification tagging fix 2024-04-09 21:54:56 +05:30
Bruce, Matt R
f6f272f727 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>
Co-authored-by: Hedden, Kyle Matthew <kyle.hedden@verizonwireless.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/319
2024-04-05 20:17:36 +00:00
Scott Pfeil
19c277d68e Digital PCT265 story MVAPCT-48 - exposing constants. 2024-04-04 17:33:05 -04:00
Scott Pfeil
64aba6a100 Digital PCT265 story MVAPCT-48 - Bug fixes and optimizations 2024-04-03 21:49:19 -04:00
Scott Pfeil
25b79530eb Digital PCT265 story MVAPCT-48 - Code cleanup 2024-04-03 12:20:24 -04:00
Scott Pfeil
8235aff75f Digital PCT265 story MVAPCT-48 - Added cache timing hacks 2024-04-01 18:07:52 -04:00
Hedden, Kyle Matthew
d08a8f6782 Digital PCT265 story MVAPCT-48 - Caches root directory, file protection for encryption, atomicWrite API deprecation. 2024-03-29 16:45:23 -04:00
Scott Pfeil
4fc4aa21f3 Digital PCT265 story MVAPCT-48 - More expiry logic fixes 2024-03-28 13:35:07 -04:00
Scott Pfeil
4bdd93dbe5 Digital PCT265 story MVAPCT-48 - Minor cache code cleanup 2024-03-27 13:38:13 -04:00
Scott Pfeil
3b410fb522 Digital PCT265 story MVAPCT-48 - Add logging and fix expiry bug 2024-03-27 11:30:52 -04:00
Scott Pfeil
c90f267599 Digital PCT265 story MVAPCT-48 - Remove test code 2024-03-27 11:03:27 -04:00
Scott Pfeil
f89bad1c7a Digital PCT265 story MVAPCT-48 - Loading overlay cleanup 2024-03-26 11:07:10 -04:00
Scott Pfeil
54e2ecb313 Manager updates for navigating to controller. 2024-03-25 13:29:29 -04:00
Scott Pfeil
b9097361ab Digital PCT265 story MVAPCT-48 - Caching piping improvements 2024-03-22 14:50:39 -04:00
Scott Pfeil
a16e09c569 Digital PCT265 story MVAPCT-48 - Cache piping improvements. 2024-03-22 11:02:04 -04:00
Scott Pfeil
84f4a1ac46 Digital PCT265 story MVAPCT-48 - code fixes for cache optimizations 2024-03-21 10:39:25 -04:00
Scott Pfeil
8c32dbbd7d Digital PCT265 story MVAPCT-48 - Initial demo of loading feed from cache 2024-03-20 19:09:13 -04:00
Hedden, Kyle Matthew
c636cc1ca4 Merge branch 'bugfix/PRODDEF-21579' into 'develop'
Removed characters from urlQueryAllowed characterSet

### Summary
Make removing the incoming percent encoding optional via shouldRemoveDefaultEncoding.

```swift
If urlQuery value contains '/' , ':'  these characters are passed without encoding, 
due to this we are seeing inconsistent behaviour.
For Eg: value contains a url: https://vzwsso/executeTask
Expected: https%3A%2F%2Fvzwsso%2FexecuteTask
Current: https://vzwsso/executeTask
So removed possible characters from urlQueryAllowed characterSet.
```

### JIRA Ticket
PRODDEF-21579

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/311
2024-03-05 22:03:58 +00:00
Krishna Kishore Bandaru
d46093887c updated to shouldRemoveDefaultEncoding 2024-03-05 11:31:31 +05:30
Pfeil, Scott Robert
03f81ca9fc Merge branch 'feature/open_page_fallback' into 'develop'
Fallback response JSON handling.

### Summary
Adds a fallback response and handling to the openPage action.

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/313
2024-02-22 14:07:57 +00:00
Hedden, Kyle Matthew
0c8012d40f Reverse assigning the loadObject identifier to the operation. (self.identifer will always be nil on init.) 2024-02-21 17:55:39 -05:00
Hedden, Kyle Matthew
1e487dd58b Address code review comment of piping data for page. 2024-02-21 17:54:49 -05:00
Hedden, Kyle Matthew
c8cabfaee1 Merge branch 'feature/client_parameter_web_bridge' into 'develop'
Remove unnecessary throws

### Summary
Remove unused throws to simplify callers

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

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/315
2024-02-21 21:39:34 +00:00
Scott Pfeil
402708ecdc Remove unnecessary throws 2024-02-16 15:02:01 -05:00
Krishna Kishore Bandaru
bed4b5c837 Added extraEncodedParameters 2024-02-16 21:20:21 +05:30
Keerthy
e741805f35 Merge branch 'develop' into bugfix/PRODDEF-21579 2024-02-16 16:18:11 +05:30
Hedden, Kyle Matthew
d394bbea0e Merge remote-tracking branch 'refs/remotes/origin/develop' 2024-02-15 22:33:08 -05:00
Hedden, Kyle Matthew
c59dd70348 Fallback response JSON handling. 2024-02-15 22:15:22 -05:00
Pfeil, Scott Robert
6db21b612d Merge branch 'feature/clientParameter-refactor' into 'develop'
- updated the ClientParameterProtocol to use an associatedType for the Model...

### Summary
Strict models for client parameters.

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/308
2024-02-15 18:13:44 +00:00
Scott Pfeil
fc0bd385c6 Revert Logging UUID for the run 2024-02-14 15:48:33 -05:00
Scott Pfeil
94b2f5b1e3 Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core into feature/clientParameter-refactor 2024-02-14 13:56:20 -05:00
Krishna Kishore Bandaru
0b23bd8e93 Added new character 2024-02-14 16:26:44 +05:30
Krishna Kishore Bandaru
10b569e3a9 Added comments 2024-02-14 13:14:53 +05:30
Krishna Kishore Bandaru
a0b8459a79 removed extra characters from urlQueryAllowed CharacterSet 2024-02-14 12:58:56 +05:30
Scott Pfeil
3bde28c2d2 Cleanup 2024-02-02 15:28:32 -05:00
Scott Pfeil
606dbf6131 client parameter handler refactoring 2024-02-02 15:15:22 -05:00
Hedden, Kyle Matthew
1efd261de3 Merge branch 'feature/utility_tweaks' into 'develop'
Core utility tweaks

### Summary
unixMilleseconds calculation using an existing date object. 
Open toJSONString options.

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/310
2024-02-01 20:00:23 +00:00
Hedden, Kyle Matthew
4552a57ea2 unixMilleseconds calculation off of existing date. open toJSONString options. 2024-02-01 13:50:12 -05:00
Scott Pfeil
ec610690fb update to protocol non optional 2024-01-31 15:55:11 -05:00
Hedden, Kyle Matthew
b0bc8994ee Merge branch 'bugfix/missing_error_screen' into 'develop'
add missing error screen

### Summary
Fix to error hanging.

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/309
2024-01-31 14:53:39 +00:00
Scott Pfeil
c89efeb3e7 shift call to avoid duplication 2024-01-31 09:29:07 -05:00
Scott Pfeil
98f55d4bc5 add missing error screen 2024-01-31 09:18:36 -05:00
Scott Pfeil
fb090fee64 Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core into feature/clientParameter-refactor 2024-01-29 11:12:43 -05:00
Hedden, Kyle Matthew
7b61615d39 Merge branch 'bugfix/logging_handler_loop' into 'develop'
Prevent addError SO

### Summary
Prevent stack overflow if the logging handler is its own delegate.

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/306
2024-01-26 21:16:06 +00:00
Hedden, Kyle Matthew
435b5a4c97 Scott recommendation to simplify. 2024-01-26 16:12:17 -05:00
Hedden, Kyle Matthew
d91dbbd460 Prevent stack overflow if the logging handler is its own delegate. 2024-01-26 14:03:01 -05:00
Hedden, Kyle Matthew
84b00f7d19 Merge branch 'bugfix/loggingHandler_fix' into 'develop'
Logging handler code fix

### Summary
making recordEvent open to make it overridable

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/305
2024-01-24 14:44:46 +00:00
Rajendran, Nandhini
d7db83583f Logging handler code fix 2024-01-24 14:44:45 +00:00
Hedden, Kyle Matthew
3e8cd2a6e8 Merge branch 'bugfix/loggingHandlerFix' into 'develop'
Logging handler fix

### Summary
making handleDebugMessage open, to override it from MF

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/304
2024-01-23 14:33:02 +00:00
Nandhini Rajendran
47286a9e35 Fixing function declaration to override from MF 2024-01-23 15:22:19 +05:30
Scott Pfeil
27233a39a2 Merge branch 'feature/clientParameter-refactor' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core into feature/clientParameter-refactor 2024-01-19 12:01:46 -05:00
Scott Pfeil
7ccb191f6e change convenience return 2024-01-19 12:00:08 -05:00
Scott Pfeil
a8606e6641 Fix Open Page 2024-01-19 10:44:14 -05:00
Scott Pfeil
0316828728 async await 2024-01-18 16:23:10 -05:00
Pfeil, Scott Robert
62ffdd605a Merge branch 'bugfix/sharehandler' into 'develop'
Added sourceRect.origin for UIActivityViewController while presenting in iPad.

### Summary
In iPad, when presenting UIActivityViewController, its presenting outside of app window at top left corner.
Added sourceRect.origin for UIActivityViewController while presenting so that it displays inside our app window 

Added SS for ref
![Screenshot_2024-01-09_at_3.39.33_PM](/uploads/bcbacbcb19b365fc4223499010495eaa/Screenshot_2024-01-09_at_3.39.33_PM.png)

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/302
2024-01-18 16:42:15 +00:00
Bandaru, Krishna Kishore
15f1be66fe Added sourceRect.origin for UIActivityViewController while presenting in iPad. 2024-01-18 16:42:15 +00:00
Scott Pfeil
f5e8c0b2e6 async await client parameters 2024-01-17 15:44:07 -05:00
Scott Pfeil
e04bd2cefe Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core into feature/clientParameter-refactor 2024-01-09 18:48:46 -05:00
Hedden, Kyle Matthew
9ef78a9c15 Merge branch 'bugfix/subscript_safety' into 'develop'
add collection safe subscript for index out of bound safety

### Summary
Moving safe subscripting from MF to MVM Core for reusability.

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/301
2024-01-03 22:05:46 +00:00
Hedden, Kyle Matthew
6d169ea203 add collection safe subscript for index out of bound safety 2024-01-02 17:10:46 -05:00
Hedden, Kyle Matthew
7e02aa17b6 Merge branch 'feature/oneApp_4156-LoggingHandlerSwiftMigration' into 'develop'
story: ONEAPP-4156 LoggingHandler Swift migration

### Summary
Swiftify Logging handler

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

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/290
2023-12-21 16:29:40 +00:00
Rajendran, Nandhini
b70220902a story: ONEAPP-4156 LoggingHandler Swift migration 2023-12-21 16:29:40 +00:00
Pfeil, Scott Robert
3ea582efc9 Merge branch 'feature/hardcoded_json_delay' into 'develop'
HARD_CODED_RESPONSE_DELAY added to the up front request handling,

### Summary
Fixed HARD_CODED_RESPONSE_DELAY positioning.

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/300
2023-12-19 22:13:00 +00:00
Hedden, Kyle Matthew
2e7fd9ddd4 reposition after having a response 2023-12-19 17:11:43 -05:00
Pfeil, Scott Robert
ab43e791cf Merge branch 'bugfix/hardcoded_handling' into 'develop'
adjust to xcode .app file reuse

### Summary
Adjusting hardcoded handling to avoid silently keeping old .json files. Stash in dedicated folder to avoid flooding root app folder.

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/298
2023-12-19 22:06:23 +00:00
Hedden, Kyle Matthew
b8f785fbc2 Merge remote-tracking branch 'origin/develop' into feature/hardcoded_json_delay 2023-12-19 15:49:56 -05:00
Bruce, Matt R
dd0688985e Merge branch 'bugfix/CXTDT-497252' into 'develop'
bug fix for earlier OS versions

### Summary
Fixing share action for older iOS versions.

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

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/299
2023-12-14 22:10:32 +00:00
Scott Pfeil
c53bbd254b bug fix for earlier OS versions 2023-12-14 15:57:37 -05:00
Hedden, Kyle Matthew
291cf99604 HARD_CODED_RESPONSE_DELAY added to the up front request handling, 2023-12-13 14:10:52 -05:00
Hedden, Kyle Matthew
293c3bf864 adjust to xcode .app file reuse 2023-12-01 17:41:44 -05:00
Scott Pfeil
64e5f9eb3d Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core into feature/clientParameter-refactor 2023-11-15 13:44:05 -05:00
Scott Pfeil
9549dca564 casting error 2023-11-15 13:25:02 -05:00
Matt Bruce
641ebcac7f - updated the ClientParameterProtocol to use an associatedType for the Model being used in then Handler
- refactored the ClientParameterHandler with the above changes.

Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2023-11-09 10:57:05 -06:00
Pfeil, Scott Robert
f64ba3aff4 Merge branch 'feature/accessibilityHandler' into 'develop'
Feature/accessibility handler

### Summary
Dependency for accessibilityHandler class

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/291
2023-11-02 20:34:31 +00:00
Krishna Kishore Bandaru
89a6c7e204 Merge branch 'develop' into feature/accessibilityHandler 2023-11-02 19:52:11 +05:30
Hedden, Kyle Matthew
7a8500153f Merge branch 'feature/LoadingOverlay-Text' into 'develop'
Option to show text in the loading overlay screen

### Summary
Adding option to show text on loading overlay screen. 

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

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/286
2023-11-01 17:01:51 +00:00
Sumanth Nadigadda
3cab2464be Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core into feature/LoadingOverlay-Text 2023-10-31 19:48:34 +05:30
Krishna Kishore Bandaru
48efbc73bf Merge branch 'develop' into feature/accessibilityHandler 2023-10-27 19:08:57 +05:30
Hedden, Kyle Matthew
77ab27d79d Merge branch 'bugfix/marketingCloudVisitorId_client_param_timeouts' into 'develop'
Address ClientParameter timeout logging issues

### Summary
Update timeout signature to use standard TimeInterval for split second handling.

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/289
2023-10-23 18:28:00 +00:00
Hedden, Kyle Matthew
f7ca8da8f9 Add additional task completion guard to suppress late callbacks. 2023-10-20 13:38:39 -04:00
Hedden, Kyle Matthew
2a438e68a7 Improve MVMCoreActionUtility.perform signature. Remove odd default. Use TimeInterval for better typing and to allow split seconds. 2023-10-20 12:04:28 -04:00
Pfeil, Scott Robert
fc0075a92d Merge branch 'feature/action_share_items' into 'develop'
Action Share update

### Summary
Enhance share to allow multiple items.
https://oneconfluence.verizon.com/display/MFD/share

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

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/288
2023-10-20 15:57:18 +00:00
Scott Pfeil
def76778e5 Code review updates for scoping of functions.
Fix continuation leak.
2023-10-20 11:51:14 -04:00
Pfeil, Scott Robert
c5dab7d70d Merge branch 'feature/molecule_replacement_behavior' into 'develop'
Fix module mapping

### Summary
Fixes the optional and required module mapping for atomic when RequestParameters are pre-generated as part of the openPage model.

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/287
2023-10-19 18:55:15 +00:00
Scott Pfeil
d44235bd03 Action Share update 2023-10-19 12:30:13 -04:00
Sumanth Nadigadda
48de2b1869 Enabling the loading overlay info text to take attributed string. 2023-10-19 16:59:12 +05:30
Hedden, Kyle Matthew
1e8f7f417e HARD_CODED_RESPONSE_DELAY for simulations. 2023-10-17 16:26:57 -04:00
Hedden, Kyle Matthew
3dc05bea61 Reset optional and required module mapping at the time of request. 2023-10-17 16:26:38 -04:00
Krishna Kishore Bandaru
31b5dc2171 added getAccessibilityElements func to MVMCoreViewManagerProtocol 2023-10-13 23:02:27 +05:30
Sumanth Nadigadda
a8f3407ed8 Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core into feature/LoadingOverlay-Text 2023-10-13 14:03:00 +05:30
Pfeil, Scott Robert
f2df0f52e6 Merge branch 'release/11_0_0' into 'develop'
release/11_0_0 hotfix merge

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/283
2023-10-10 13:29:58 +00:00
Pfeil, Scott Robert
223ff22612 Merge branch 'feature/new_relic_open_page_tracking' into 'release/11_0_0'
NSA migration tracking changes

### Summary
Track bridge open page destinations for NSA migration tracking.

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/284
2023-10-06 13:39:22 +00:00
Pfeil, Scott Robert
5a8147655b Merge branch 'feature/core_object_swift' into 'develop'
MVMCoreObject to swift

### Summary
MVMCoreObject to swift

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/285
2023-10-04 20:53:48 +00:00
Scott Pfeil
b1e4c55281 remove missing file 2023-10-04 16:45:06 -04:00
Scott Pfeil
db9bd9e3b3 change name back.... wishful thinking removed 2023-10-04 11:37:43 -04:00
Scott Pfeil
51597121bd MVMCoreObject to swift 2023-10-04 10:18:52 -04:00
Hedden, Kyle Matthew
a94cc27168 comment typos 2023-10-02 20:22:44 -04:00
Hedden, Kyle Matthew
a5d237df8b push model in action events for model specfic attributes 2023-10-02 12:32:00 -04:00
Pfeil, Scott Robert
e5402bb6eb Merge branch 'bugfix/account_native_testing' into 'develop'
improvement to hardcoded debugging functions

### Summary
Minor improvements to hardcoded debugging parameters.

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/282
2023-09-28 13:44:11 +00:00
Scott Pfeil
c93fe59b5c improvement to hardcoded debugging functions 2023-09-28 09:26:17 -04:00
Pfeil, Scott Robert
975ee661fb Merge branch 'feature/remove-VzAnalytics-VZWYZDL-1051' into 'develop'
VzAnalytics Removal - VZWYZDL 1051

### Summary
To remove VZAnalytics from the codebase since new FBL is live in production.

### JIRA Ticket
https://onejira.verizon.com/browse/VZWYZDL-1051

Co-authored-by: Sourabh Bhardwaj <sourabh.bhardwaj@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/281
2023-09-18 17:41:33 +00:00
Sumanth Nadigadda
3d4f8938dc Adding option to show a label to loading overlay 2023-09-15 15:42:35 +05:30
Sourabh Bhardwaj
79915b3f6f Removing VzAnalytics - VZWYZDL-1051 2023-09-15 10:52:51 +05:30
Pfeil, Scott Robert
20d6149918 Merge branch 'feature/molecule_id_replacement' into 'develop'
DecodableDefault for UUID

### Summary
Adding DecodableDefault for a UUID string.

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/280
2023-09-07 16:58:06 +00:00
Hedden, Kyle Matthew
ba8f0b90ca DecodableDefault.UUID -> UUIDString 2023-09-07 12:46:04 -04:00
Hedden, Kyle Matthew
d6096c7ee5 Change ID default initializer, DecodableDefault for implicit decoding models. Add missing id encodes and decodes. 2023-09-07 09:20:43 -04:00
Hedden, Kyle Matthew
46bcd6618d Merge branch 'bugfix/share_url' into 'develop'
Change to have 1 item shared

### Summary
Minor code bug fixes. Share url as 1 item, warning fix.

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/279
2023-09-05 14:27:59 +00:00
Scott Pfeil
3459e067b3 Change to have 1 item shared 2023-09-05 10:21:19 -04:00
Pfeil, Scott Robert
e942bbfe15 Merge branch 'bugfix/async_and_warnings' into 'develop'
Bugfixes for getInitialParameters, completion block consolidation with async,...

### Summary
Bugfixes for getInitialParameters, completion block consolidation with async, and minor warning fixes

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/278
2023-08-31 19:11:45 +00:00
Scott Pfeil
f340ac61c7 Review comments 2023-08-31 12:56:44 -04:00
Scott Pfeil
e31fe71fae Bugfixes for getInitialParameters, completion block consolidation with async, and minor warning fixes 2023-08-31 11:13:14 -04:00
Hedden, Kyle Matthew
9419fd51a2 Merge branch 'bugfix/qos_async' into 'develop'
Bugfix/qos async

### Summary
Shift thread blocking functions to swift async/await and fix QOS warnings.

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/277
2023-08-30 00:16:51 +00:00
Scott Pfeil
dc0be54444 Code review undo 2023-08-29 17:38:10 -04:00
Scott Pfeil
4542e82060 code review fixes 2023-08-29 17:27:44 -04:00
Scott Pfeil
2af3badb4b missing return 2023-08-29 17:24:19 -04:00
Scott Pfeil
66693289ed Remove debug code 2023-08-28 18:44:00 -04:00
Scott Pfeil
99da8d56d5 merge develop 2023-08-28 18:21:50 -04:00
Scott Pfeil
a5be9469ee Shift to swift async to resolve thread hanging wait functions. 2023-08-28 18:15:12 -04:00
Pfeil, Scott Robert
296b1df0e9 Merge branch 'feature/navigation_handler_modernize' into 'develop'
Feature/navigation handler modernize

### Summary
Modernize navigation handler.

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

Co-authored-by: Scott Pfeil <Scott.Pfeil3@verizonwireless.com>
Co-authored-by: Scott Pfeil <pfeilsc@nn6f6wg04x.uswin.ad.vzwcorp.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/269
2023-08-28 21:56:41 +00:00
Scott Pfeil
034133e4a5 ONEAPP-5208: Review feedback 2023-08-28 11:13:39 -04:00
Scott Pfeil
fe5dc7c6b7 Removed MVMCoreNotificationViewControllerChanged 2023-08-22 16:22:44 -04:00
Scott Pfeil
9d88dd70af Review comments 2023-08-22 15:39:41 -04:00
Scott Pfeil
f2a5586061 testing bug fixes for navigation 2023-08-22 13:33:07 -04:00
Scott Pfeil
64535c6b21 ONEAPP-5208: Swiftify the navigation handler 2023-08-21 17:03:47 -04:00
Pfeil, Scott Robert
2a8bf6d695 Merge branch 'bugfix/request_id_carryover' into 'develop'
initialize request params id without an action. copy the id for the e2eRequestId carry over

### Summary
Fix for the initial authentication page processing.

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/276
2023-08-21 12:59:33 +00:00
Hedden, Kyle Matthew
8b912d5d87 initialize request params id without an action. copy the id for the e2eRequestId carry over 2023-08-18 20:27:22 -04:00
Scott Pfeil
6877763d07 remove intermediary work files 2023-08-15 16:24:46 -04:00
Scott Pfeil
a4e0203de5 Swiftification of Navigation Handler 2023-08-15 16:23:13 -04:00
Scott Pfeil
2300678d96 Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core into feature/navigation_handler_modernize 2023-08-02 11:11:57 -04:00
Hedden, Kyle Matthew
30a8f48f4d Merge branch 'feature/fastlane_launch_app_build_customization' into 'develop'
expose mvm core configuration to the workspace settings. clean up ENABLE_HARD_CODED_RESPONSE.

### Summary
SRE + App Clip build customization efforts.

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/267
2023-08-01 21:01:02 +00:00
Hedden, Kyle Matthew
1aed90a1fe Merge branch 'feature/hardcoded_helpers' into 'develop'
Hardcoded response testing.

### Summary
Make it easy to modify json for local testing.

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/274
2023-07-31 21:52:46 +00:00
Scott Pfeil
985d01842d Hardcoded response testing. 2023-07-31 16:54:17 -04:00
Kyle Hedden
fd27a82e5c Merge remote-tracking branch 'origin/develop' into feature/fastlane_launch_app_build_customization 2023-07-31 16:19:31 -04:00
Hedden, Kyle Matthew
5493c32682 Merge branch 'bugfix/request_signature_nullability' into 'develop'
fix nullability for request creation. don't force a default error to be passed in

### Summary
Request signature fix. Related to error logging Swift conversion.

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/273
2023-07-28 14:32:14 +00:00
Kyle Hedden
3bccc503cf fix nullability for request creation. don't force a default error to be passed in 2023-07-28 09:56:10 -04:00
Kyle Hedden
28842d673e migrate DEBUG flags to proper feature flags. dev configs for local debug build defaults. 2023-07-26 19:44:30 -04:00
Kyle Hedden
24ddfbfd34 Merge remote-tracking branch 'origin/develop' into feature/fastlane_launch_app_build_customization 2023-07-25 19:57:58 -04:00
Hedden, Kyle Matthew
890a8c7fe2 Merge branch 'feature/ONEAPP-4561' into 'develop'
ONEAPP-4561 Biometric Settings page updates.

### Summary
Biometric changes on the settings page to increase adoption.

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

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/271
2023-07-24 21:42:00 +00:00
Scott Pfeil
eafd275527 ONEAPP-4561 Biometric Settings page updates. 2023-07-24 12:26:58 -04:00
Scott Pfeil
5becbbb7f1 combine 2023-07-21 09:21:00 -04:00
Kyle Hedden
d86462427a Merge remote-tracking branch 'origin/release/10_8_0' into feature/fastlane_launch_app_build_customization 2023-07-20 16:14:33 -04:00
Scott Pfeil
2466d06698 merge develop 2023-07-17 10:45:37 -04:00
Hedden, Kyle Matthew
674cff506d Merge branch 'feature/ONEAPP-3998' into 'develop'
ONEAPP-3998: Convenience function to simplify the current objc-swift bridge of...

### Summary
Allows convenient testing of flows through json modification.

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

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/266
2023-06-22 15:03:32 +00:00
Scott Pfeil
25394dc640 remove debug code for now 2023-06-21 12:23:59 -04:00
Scott Pfeil
05289f88aa main thread change for session handler 2023-06-21 12:11:15 -04:00
Kyle Hedden
3b315096cc expose mvm core configuration to the workspace settings. clean up ENABLE_HARD_CODED_RESPONSE. 2023-06-21 10:26:57 -04:00
Scott Pfeil
ce246523ac remove old test code 2023-06-20 16:07:47 -04:00
Scott Pfeil
7426e5956e Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core into feature/ONEAPP-3998 2023-06-20 16:04:37 -04:00
Hedden, Kyle Matthew
5091d82962 Merge branch 'release/10_7_3' into 'develop'
release/10_7_3 hotfix merge

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/264
2023-06-19 13:45:54 +00:00
Scott Pfeil
3383d71c19 ONEAPP-3998: Allow a chance to override code. 2023-06-15 12:16:17 -04:00
Scott Pfeil
53634fcaa1 ONEAPP-3998: Convenience function to simplify the current objc-swift bridge of having two action protocols. 2023-06-15 12:12:03 -04:00
Pfeil, Scott Robert
30f7737b4c Merge branch 'bugfix/restart_timer_crash' into 'release/10_7_3'
Allow session handler objects to be initialized without MainActor to inline...

### Summary
Adjust session creation for async await incompatible code.

### Crash Trace
https://console.firebase.google.com/project/api-project-396418606732/crashlytics/app/ios:com.vzw.hss.myverizon/issues/235a6b2af0c9f6b0311f61dff3f01104?versions=10.7.2%20(20280)&time=last-seven-days&sessionEventKey=c0188bc4f7ec477796d67ab09c9ad3d9_1823128717650065330

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/265
2023-06-15 01:10:16 +00:00
Kyle Hedden
cba4af9ce8 Allow session handler objects to be initialized without MainActor to inline session creation with async await incompatible code. Fixes a Main thread dispatch clash. 2023-06-14 19:47:26 -04:00
Scott Pfeil
a5c5397c92 Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core into feature/ONEAPP-3998 2023-05-30 10:18:07 -04:00
Bruce, Matt R
3af64af961 Merge branch 'feature/oneApp_4067-SessionHandlerSwiftMigration' into 'develop'
story: story: ONEAPP-4067 Swiftify sessionTimeHandler

### Summary
ObjC to Swift migration for SessionHandler class

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

Co-authored-by: Scott Pfeil <Scott.Pfeil3@verizonwireless.com>
Co-authored-by: Hedden, Kyle Matthew <kyle.hedden@verizonwireless.com>
Co-authored-by: Nandhini Rajendran <nandhini.rajendran@verizon.com>

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/260
2023-05-15 23:03:45 +00:00
Rajendran, Nandhini
c21e4b680b story: story: ONEAPP-4067 Swiftify sessionTimeHandler 2023-05-15 23:03:45 +00:00
Scott Pfeil
17025101bc Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core into feature/ONEAPP-3998 2023-05-04 10:18:45 -04:00
Hedden, Kyle Matthew
cdff607cf1 Merge branch 'feature/pageLoadTracking' into 'develop'
Page load time event

### Summary
Added pageload tracking event

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/256
2023-05-03 18:08:18 +00:00
Krishna Kishore Bandaru
87135f31ed added public access specifier 2023-05-03 22:12:09 +05:30
Krishna Kishore Bandaru
e6ca9ec67d Bug fix while setting identifier 2023-05-02 20:07:40 +05:30
Krishna Kishore Bandaru
6372fcb56d removed correlationId 2023-05-02 17:20:05 +05:30
Krishna Kishore Bandaru
3d1f1617c5 added identifier in requestparameters & correlationId 2023-04-28 21:05:37 +05:30
Krishna Kishore Bandaru
85f7096499 updated request url 2023-04-25 18:35:18 +05:30
Krishna Kishore Bandaru
27f138d6c1 updated to requestParameters.URL 2023-04-24 23:06:17 +05:30
Scott Pfeil
ba8621cea1 Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core into feature/ONEAPP-3998 2023-04-24 10:26:34 -04:00
Krishna Kishore Bandaru
c10cb0792e updated request url 2023-04-24 15:43:38 +05:30
Krishna Kishore Bandaru
cbb17edcf9 Merge branch 'develop' into feature/pageLoadTracking 2023-04-24 11:57:53 +05:30
Pfeil, Scott Robert
e14c01e0d4 Merge branch 'feature/swiftify_alerts' into 'develop'
Feature/swiftify alerts

### Summary
Swiftify/Modernize the Alert Handler

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

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/257
2023-04-21 20:06:52 +00:00
Pfeil, Scott Robert
6a0be99ce2 Merge branch 'feature/url_resolution' into 'develop'
Move URL request resolution to MVMCoreRequestParameters.

### Summary
Adjusting request URL resolution to be sooner for page tracking.

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/258
2023-04-21 17:25:30 +00:00
Kyle Matthew Hedden
519093a24f remove synthesis 2023-04-21 13:24:01 -04:00
Krishna Kishore Bandaru
10db5ff1ba addressed review comments 2023-04-20 16:51:45 +05:30
Kyle Matthew Hedden
14af9f2d5f Move URL request resolution to MVMCoreRequestParameters. 2023-04-19 20:06:44 -04:00
Scott Pfeil
bc46ff3174 revert 2023-04-19 16:38:53 -04:00
Scott Pfeil
f0f842f87e Bug fixes 2023-04-19 16:36:15 -04:00
Scott Pfeil
38cb3eb80e queue changes 2023-04-18 19:39:45 -04:00
Krishna Kishore Bandaru
e3cbc7a7cd added backgroundRequest check & addressed reviewcomments 2023-04-18 18:01:43 +05:30
Scott Pfeil
15ca6142fe Remove reference to AlertObject from core. 2023-04-17 13:02:24 -04:00
Scott Pfeil
3c9786b4d6 Migrate AlertHandler files to swift. 2023-04-13 11:54:50 -04:00
Krishna Kishore Bandaru
01b14b02e4 moved pagestarted event 2023-04-12 17:45:40 +05:30
Krishna Kishore Bandaru
f93e1866c1 added error msg in pagerender 2023-04-11 18:28:25 +05:30
Krishna Kishore Bandaru
11d635fdd4 added pageload tracking event 2023-04-10 23:34:48 +05:30
Scott Pfeil
40741deac3 setup biometrics action 2023-04-10 11:50:42 -04:00
Pfeil, Scott Robert
5ee5c39ff8 Merge branch 'release/10_5_1' into 'develop'
release/10_5_1 hotfix merge

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/250
2023-03-24 18:56:27 +00:00
Hedden, Kyle Matthew
14b0dc2c3e Merge branch 'feature/enhanced_error_logging' into 'release/10_5_1'
Omar's enhanced error logging initiative.

### Summary
Omar's enhanced error logging initiative.

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/251
2023-03-15 20:52:54 +00:00
Kyle Matthew Hedden
8ab9609724 code review. remove silentError hard set. 2023-03-15 13:28:29 -04:00
Kyle Matthew Hedden
a07807e693 code review 2023-03-15 09:04:58 -04:00
Kyle Matthew Hedden
ab0c13efaf Prevent double logging and double error popup. 2023-03-13 19:45:58 -04:00
Kyle Matthew Hedden
4799c3fcbb Add image loading failures to error log. 2023-03-13 16:13:44 -04:00
Kyle Matthew Hedden
85ebbdf44c code review catches 2023-03-13 15:49:12 -04:00
Kyle Matthew Hedden
cb401ee3f0 Fix prior commit. Allow error alerts if there isn't a full screen error. 2023-03-06 17:43:06 -05:00
Kyle Matthew Hedden
7a38ecf62b Crash fix for missing UserMessage. Suppress alertToShow dialogs when a native error screen is present. Pipe template parsing description messages to error object. Provide a messageToLog for invalid openURL calls. 2023-03-06 15:58:33 -05:00
Kyle Matthew Hedden
3b85ca1ff8 Track web view navigation failures (timeouts, etc). 2023-03-03 19:24:33 -05:00
Kyle Matthew Hedden
56857f187b Silence most errors. Push getNativeScreenForRequestError to LoadHandler decoration. Native error screen error message handling. 2023-03-02 20:26:48 -05:00
Kyle Matthew Hedden
52883a534b Create MFPerformanceErrorObject for error logging. 2023-02-28 22:08:40 -05:00
Kyle Matthew Hedden
a74aa6ef2d Shift logging load errors until after background handling is resolved. 2023-02-27 14:17:01 -05:00
Kyle Matthew Hedden
5006517bb1 wrapper function to add additoinal request data to error objects. begin working on better silentError handling. 2023-02-25 00:20:55 -05:00
Hedden, Kyle Matthew
6d9da1f958 Merge branch 'feature/artifactory_ci' into 'develop'
update artifactory url from prod to ci

### Summary
Updating dependency downloads from https://oneartifactoryprod.verizon.com/artifactory to https://oneartifactoryci.verizon.com/artifactory

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/249
2023-02-17 16:32:14 +00:00
Scott Pfeil
74c16205e1 update artifactory url from prod to ci 2023-02-16 17:15:47 -05:00
Pfeil, Scott Robert
e26a09e1ec Merge branch 'bugfix/missing_action_fail_reporting' into 'develop'
Bugfix/missing action fail reporting

### Summary
Adding missing action failure event reporting to NewRelic.

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/247
2023-01-27 01:43:01 +00:00
Kyle Matthew Hedden
3e9d66e5e0 add missing event data 2023-01-26 19:03:10 -05:00
Hedden, Kyle Matthew
08a1718f11 Merge branch 'bugfix/session_timer_bkg_reset' into 'develop'
Fix the session timer

### Summary
Fixes an issue with the session timer resetting without a session update when the app returns from the background.

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/246
2023-01-17 17:26:26 +00:00
Kyle Matthew Hedden
1f377dfb51 remainingWarningTime fix. code comment cleanups. 2023-01-17 12:10:43 -05:00
Kyle Matthew Hedden
16d169c46c Code review suggestion to use default values. Bug fix for warning track timeouts from the background. 2023-01-13 18:57:23 -05:00
Kyle Matthew Hedden
80512a0b8a Shift app background check to resumeSessionTimer to make isAppInSession and revalidateSessionTimestamp background safe. 2022-12-28 11:02:02 -05:00
Kyle Matthew Hedden
c7bfda216a Trigger a keep alive attempt when returning from background. 2022-12-28 10:54:31 -05:00
Kyle Matthew Hedden
aa1be3f1c5 Fix isAppInSession and appEnteredForeground collision. Fix FaceId session timer restart skip. Encapsulate timeTimerStarted referenceDate. 2022-12-28 10:23:10 -05:00
Kyle Matthew Hedden
920b975294 expose method to report the final load operation source 2022-12-27 16:47:41 -05:00
Pfeil, Scott Robert
3f59a1c9fe Merge branch 'bugfix/alertcontrollerOrientation' into 'develop'
Added supportedInterfaceOrientations in MVMCoreAlertController

### Summary
Added supportedInterfaceOrientations fix in MVMCoreAlertController when iPhone device is rotated while alert controller is presented.

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/244
2022-12-20 14:54:42 +00:00
Krishna Kishore Bandaru
6874424dd1 added supportedInterfaceOrientations in MVMCoreAlertController 2022-12-12 13:58:39 +05:30
Hedden, Kyle Matthew
8e586e5f01 Merge branch 'release/10_4_0' into 'develop'
release/10_4_0 hotfix merge

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/236
2022-11-11 19:44:38 +00:00
Hedden, Kyle Matthew
9243b8e285 Merge branch 'bugfix/open_url_error_code' into 'release/10_4_0'
Add back legacy error code

### Summary
Adding back the legacy link away error code for easier tracking of url errors.

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/238
2022-10-28 14:28:59 +00:00
Scott Pfeil
11728703ce Add back legacy error code 2022-10-28 10:07:36 -04:00
Pfeil, Scott Robert
a8b5db4d28 Merge branch 'bugfix/user_facing_error_msg' into 'release/10_4_0'
fix user facing error message for json errors

### Summary
Adjustment to JSONError to avoid displaying Swift Decoding errors to the user.

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/237
2022-10-27 03:44:21 +00:00
Kyle Matthew Hedden
d7b80e87ed fix user facing error message for json errors 2022-10-26 20:44:18 -04:00
Pfeil, Scott Robert
9aaeb1d266 Merge branch 'feature/Restart-requestUrl' into 'develop'
Feature/restart request url

### Summary

Changes are to add requestURL param to restart action object.

### JIRA Ticket

Brand 3.0 - Multi user screen - [ONEAPP-2784](https://onejira.verizon.com/browse/ONEAPP-2784)

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/234
2022-10-25 15:03:37 +00:00
Sumanth Nadigadda
ee98b9fe5f Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core into feature/Restart-requestUrl 2022-10-25 20:06:06 +05:30
Sumanth Nadigadda
217cceb84b Removing the codable method for the restart action type 2022-10-25 20:04:32 +05:30
Pfeil, Scott Robert
2b09f58686 Merge branch 'bugfix/always_embed_swift' into 'develop'
always embed swift to no

### Summary
Remove always embed swift flag. Embedding frameworks in frameworks blocks Apple submission.

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

See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core/-/merge_requests/235
2022-10-20 20:30:51 +00:00
Scott Pfeil
8dd0aebf7e always embed swift to no 2022-10-20 16:19:47 -04:00
Sumanth Nadigadda
85dcc57513 Changing the requestURL type to NSURL from NSString 2022-10-17 17:52:43 +05:30
Hedden, Kyle Matthew
130208a080 Merge branch 'bugfix/crashissue' into 'develop'
Fixed crash array out of bounds exception

See merge request BPHV_MIPS/mvm_core!233
2022-10-14 17:56:09 +00:00
Sumanth Nadigadda
45b89ca7d3 Change the requestUrl param key 2022-10-14 22:54:25 +05:30
Krishna Kishore Bandaru
cdd2eb2f04 fixed crash array out of bounds exception 2022-10-14 12:27:15 +05:30
Sumanth Nadigadda
0340f9dda6 Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core into feature/Restart-requestUrl 2022-10-10 10:40:46 +05:30
Hedden, Kyle Matthew
4f1cbf6c61 Merge branch 'bugfix/request_param_copy' into 'develop'
copy over the actionMap to the new object for presentationStyle resolution fix.

See merge request BPHV_MIPS/mvm_core!232
2022-10-03 17:40:01 +00:00
Kyle Matthew Hedden
de280960f7 copy over the actionMap to the new object for presentationStyle resolution fix. 2022-10-03 11:32:49 -04:00
Bruce, Matt R
c95def255b Merge branch 'feature/JSONError_description' into 'develop'
add error description to JSONErrors

See merge request BPHV_MIPS/mvm_core!231
2022-09-28 21:14:56 +00:00
Sumanth Nadigadda
afead9710d Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core into feature/Restart-requestUrl 2022-09-29 00:31:50 +05:30
Sumanth Nadigadda
ec70621ea0 Changed to read and set requestUrl in restart action. 2022-09-28 10:15:57 +05:30
Kyle Matthew Hedden
89d9809b9e add error description to JSONErrors 2022-09-23 18:34:19 -04:00
Pfeil, Scott Robert
f8dec38c13 Merge branch 'bugfix/open_page_request_parameters' into 'develop'
copy fix

See merge request BPHV_MIPS/mvm_core!230
2022-09-20 21:46:04 +00:00
Scott Pfeil
793e64143d copy fix 2022-09-20 17:29:38 -04:00
Hedden, Kyle Matthew
3ecd769f1c Merge branch 'feature/new_relic_action_tracking' into 'develop'
create core events for actions and clientparameters tracking

See merge request BPHV_MIPS/mvm_core!225
2022-09-19 21:52:09 +00:00
Kyle Matthew Hedden
645d304907 expose getUUID to obj-c 2022-09-19 15:36:16 -04:00
Kyle Matthew Hedden
3abf053e4e Merge remote-tracking branch 'origin/develop' into feature/new_relic_action_tracking 2022-09-19 13:03:29 -04:00
Pfeil, Scott Robert
b5e579f59a Merge branch 'bugfix-screenfrozen' into 'develop'
Setting animatingIn to false

See merge request BPHV_MIPS/mvm_core!229
2022-09-13 16:02:06 +00:00
Krishna Kishore Bandaru
61ce51cefd setting animatingIn to false 2022-09-13 21:28:50 +05:30
Hedden, Kyle Matthew
3b18e3dd55 Merge branch 'bugfix/remove_bitcode' into 'develop'
Remove bitcode

See merge request BPHV_MIPS/mvm_core!228
2022-09-08 14:56:50 +00:00
svc-mips_ios_tower
13e03375d4 Remove bitcode 2022-09-08 10:49:48 -04:00
Pfeil, Scott Robert
05f6ed1013 Merge branch 'feature/deprecation_removal' into 'develop'
remove deprecated MVMCoreLoadObject code

See merge request BPHV_MIPS/mvm_core!227
2022-09-06 15:44:59 +00:00
Pfeil, Scott Robert
343020ad20 Merge branch 'feature/openpage-ActionTypeEncode' into 'develop'
Adding actiontype attribute to encode in OpenPage action class

See merge request BPHV_MIPS/mvm_core!226
2022-09-06 14:28:02 +00:00
Sumanth Nadigadda
aff3d52fe8 Adding actiontype attribute to encode in OpenPage action class 2022-09-06 19:55:16 +05:30
Scott Pfeil
e7e829bb44 remove deprecated MVMCoreLoadObject code 2022-09-02 15:49:06 -04:00
Scott Pfeil
d747980805 Swift operations 2022-09-01 12:29:20 -04:00
Kyle Matthew Hedden
dfb58e04b6 wire in source request UUID for client parameter events 2022-08-31 14:34:59 -04:00
Kyle Matthew Hedden
55d6df4e25 client parameter stats changes 2022-08-30 17:51:36 -04:00
Kyle Matthew Hedden
571d55aebd missing log error call 2022-08-30 10:46:38 -04:00
Kyle Matthew Hedden
068714a001 create core events for actions and clientparameters tracking 2022-08-29 20:08:21 -04:00
Bruce, Matt R
dcbaa316ac Merge branch 'feature/action_modernize' into 'develop'
Feature/action modernize

See merge request BPHV_MIPS/mvm_core!223
2022-08-25 15:28:02 +00:00
Scott Pfeil
3739812379 class to struct 2022-08-15 17:46:02 -04:00
Scott Pfeil
c4f8bd955b Version Bump 2022-08-15 15:30:51 -04:00
Scott Pfeil
27c239cab2 remove duplicate declaration 2022-08-15 10:45:34 -04:00
Scott Pfeil
17b2a4368f cleanup 2022-08-15 10:33:15 -04:00
Scott Pfeil
5c53466dac Centralize SoureModel 2022-08-12 16:17:00 -04:00
Scott Pfeil
0196d5c190 bug fixes 2022-08-11 22:34:35 -04:00
Scott Pfeil
e6164026f6 Drive through delegate up front. Remove some legacy delegate back and forth 2022-08-10 22:19:00 -04:00
Scott Pfeil
4d72b31a51 Button -> Delegate -> ActionHandler.
Components will go through delegate. Delegate will choose how to handle it.
2022-08-08 17:45:27 -04:00
Scott Pfeil
bf14282eb5 remove added line 2022-08-02 11:19:56 -04:00
Scott Pfeil
dcc81a2c08 Clean the load request 2022-08-02 11:18:30 -04:00
Scott Pfeil
36ec79f353 Descriptor changes 2022-07-29 16:20:21 -04:00
Scott Pfeil
cbb5ccded8 Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core into feature/action_modernize 2022-07-28 22:52:15 -04:00
Scott Pfeil
e6dca10d87 modernization.
Adding json protocol to continue to support legacy (unfortunately)
2022-07-28 18:22:00 -04:00
Pfeil, Scott Robert
b62a67fcc7 Merge branch 'feature/dictionary_extensions' into 'develop'
add additional dictionary convenience functions for transformations

See merge request BPHV_MIPS/mvm_core!222
2022-07-26 15:33:32 +00:00
Kyle Matthew Hedden
a0f2111a51 add additional dictionary convenience functions for transformations 2022-07-22 15:52:17 -04:00
Scott Pfeil
71b2146862 Minor cleanup 2022-07-22 10:20:46 -04:00
Pfeil, Scott Robert
064fd5d621 Merge branch 'feature/JSONValue-Update' into 'develop'
added more extension methods

See merge request BPHV_MIPS/mvm_core!217
2022-07-22 13:16:18 +00:00
Matt Bruce
d09834f19c Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core.git into feature/JSONValue-Update 2022-07-22 08:06:24 -05:00
Scott Pfeil
f123be046c Modernization migrations and json passing 2022-07-21 12:39:43 -04:00
Scott Pfeil
90adc247d1 modernization 2022-07-19 14:36:57 -04:00
Scott Pfeil
606fd93fc3 Action modernization 2022-07-18 18:54:11 -04:00
Bruce, Matt R
9bb56d09db Merge branch 'feature/remove_legacy_deprecations' into 'develop'
Deprecated function removal.

See merge request BPHV_MIPS/mvm_core!220
2022-07-18 22:00:31 +00:00
Scott Pfeil
27c5be0415 Deprecated function removal. 2022-07-18 17:45:28 -04:00
Matt Bruce
ec8552ea12 Merge branch 'develop' into feature/JSONValue-Update 2022-07-18 13:55:16 -05:00
Pfeil, Scott Robert
8bfea9b093 Merge branch 'feature/session_timer_keepalive_fix' into 'develop'
Update session keep alive to account for all new session tokens outside of BAU server session.

See merge request BPHV_MIPS/mvm_core!216
2022-07-14 17:40:11 +00:00
Pfeil, Scott Robert
9ffb6f044d Merge branch 'feature/cookies_for_url' into 'develop'
reduce cookie noise

See merge request BPHV_MIPS/mvm_core!218
2022-07-14 16:57:45 +00:00
Kyle Matthew Hedden
ded68fe51f reduce cookie noise 2022-07-13 23:31:43 -04:00
Matt Bruce
863a9fbbe5 added more extension methods
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2022-07-13 10:26:09 -05:00
Scott Pfeil
80a257c066 merge develop 2022-07-11 14:37:04 -04:00
Pfeil, Scott Robert
a7d6fff40e Merge branch 'bugfix/build_scripts' into 'develop'
merge

See merge request BPHV_MIPS/mvm_core!215
2022-07-06 15:07:45 +00:00
Kyle Matthew Hedden
a5f5ed3cd1 Update session keep alive to account for all new session tokens outside of BAU server session. 2022-07-05 18:03:13 -04:00
Scott Pfeil
aaa2bb664e typo fix 2022-07-05 14:22:51 -04:00
Scott Pfeil
0a9aca1a98 typo fix 2022-07-05 14:12:53 -04:00
Scott Pfeil
83a814ddb1 typo fix 2022-07-05 14:05:32 -04:00
Scott Pfeil
07bb18fe75 Add dSYM 2022-07-05 14:02:13 -04:00
Scott Pfeil
e9b8ccec18 try again 2022-07-01 17:53:36 -04:00
Scott Pfeil
22f2b18057 version fix for upload 2022-07-01 17:43:10 -04:00
Scott Pfeil
8fb9f7e605 adding back upload 2022-07-01 17:24:43 -04:00
Scott Pfeil
1b4a673802 remove stuffs 2022-07-01 17:21:21 -04:00
Scott Pfeil
dfaa2b0364 testing 2022-07-01 17:15:34 -04:00
Scott Pfeil
5979945304 testing 2022-07-01 17:08:24 -04:00
Scott Pfeil
1031443180 testing 2022-07-01 17:00:05 -04:00
Scott Pfeil
463756fa75 testing 2022-07-01 16:56:24 -04:00
Scott Pfeil
61a54e831f merge 2022-07-01 16:35:14 -04:00
Scott Pfeil
9d4caedbe5 Modernize actions 2022-07-01 15:26:09 -04:00
Pfeil, Scott Robert
d2a1e316ba Merge branch 'feature/develop_mvp_3' into 'develop'
Feature/develop mvp 3

See merge request BPHV_MIPS/mvm_core!200
2022-06-24 21:01:13 +00:00
Pfeil, Scott Robert
fa6f79f3d0 Merge branch 'feature/JSONValue-Update' into 'develop'
updated JSONValue with Helper methods

See merge request BPHV_MIPS/mvm_core!213
2022-06-24 16:10:41 +00:00
Matt Bruce
acf5aae880 added JSONValue additions
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2022-06-24 10:41:39 -05:00
Matt Bruce
05a549c633 added toJSONArray
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2022-06-24 10:41:26 -05:00
Pfeil, Scott Robert
88f8ee0859 Merge branch 'feature/ModelInitUpdate' into 'feature/develop_mvp_3'
added public initializers to models

See merge request BPHV_MIPS/mvm_core!212
2022-06-22 00:01:18 +00:00
Matt Bruce
5ca22837bf added default value
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2022-06-21 15:39:41 -05:00
Matt Bruce
464df10708 resolved for comments
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2022-06-21 15:31:51 -05:00
Matt Bruce
71fb70c6eb added initializer
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2022-06-21 14:56:52 -05:00
Pfeil, Scott Robert
c84f9b5388 Merge branch 'release/10_0_0' into 'feature/develop_mvp_3'
added userInfo into the Decoders

See merge request BPHV_MIPS/mvm_core!211
2022-06-20 14:50:56 +00:00
Matt Bruce
f2bde996a8 created init for Model
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2022-06-20 09:48:37 -05:00
Matt Bruce
2db6fb923c ordered headers above compilation in BuildPhase for Xcode 13 fix
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2022-06-20 09:44:14 -05:00
Pfeil, Scott Robert
f69dd7339c Merge branch 'develop' into 'release/10_0_0'
added userInfo into the Decoders

See merge request BPHV_MIPS/mvm_core!210
2022-05-25 15:47:32 +00:00
Pfeil, Scott Robert
506717d682 Merge branch 'feature/Decoders+Context' into 'develop'
added userInfo into the Decoders

See merge request BPHV_MIPS/mvm_core!208
2022-05-24 19:02:25 +00:00
Matt Bruce
071cb16870 ensure context exists for JSONDecoder within extension method
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2022-05-24 12:07:03 -05:00
Matt Bruce
9e9421f66a added property wrapper for default values
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2022-05-11 09:17:39 -05:00
Matt Bruce
9bb90b2153 refactored create method
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2022-05-10 14:49:59 -05:00
Matt Bruce
a7e32f3ca4 removed try
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2022-05-10 12:16:30 -05:00
Matt Bruce
3f0450547a Merge branch 'develop' into feature/Decoders+Context 2022-05-10 12:07:37 -05:00
Matt Bruce
1718f87f40 updated to user the JSONDecoder.create()
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2022-05-10 12:06:18 -05:00
Matt Bruce
cb053464b5 added userInfo into the Decoders
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2022-05-10 12:05:57 -05:00
Pfeil, Scott Robert
129159a9a2 Merge branch 'develop' into 'feature/develop_mvp_3'
Develop

See merge request BPHV_MIPS/mvm_core!207
2022-05-04 15:58:27 +00:00
Pfeil, Scott Robert
ce0d984c0b Merge branch 'develop' into 'feature/develop_mvp_3'
Develop

See merge request BPHV_MIPS/mvm_core!206
2022-04-29 15:41:42 +00:00
Pfeil, Scott Robert
a4770c4c79 Develop 2022-04-29 15:41:40 +00:00
Pfeil, Scott Robert
51580bdbd0 Merge branch 'bugfix/client_parameter_handler' into 'develop'
saftey against handler implementations

See merge request BPHV_MIPS/mvm_core!205
2022-04-28 15:18:15 +00:00
Kyle Matthew Hedden
a05da2695b Simplify change. 2022-04-28 09:44:46 -04:00
Kyle Matthew Hedden
c21858c48c further safety 2022-04-25 18:32:11 -04:00
Kyle Matthew Hedden
e19ed416bb saftey against handler implementtations 2022-04-25 17:15:12 -04:00
Hedden, Kyle Matthew
edeaefc346 Merge branch 'bugfix/missing_prepare_navigation' into 'feature/develop_mvp_3'
fix missing prepare statements

See merge request BPHV_MIPS/mvm_core!201
2022-03-25 20:00:12 +00:00
Scott Pfeil
374c83bddd fix missing prepare statements 2022-03-24 18:39:06 -04:00
Pfeil, Scott Robert
c093a224b4 Merge branch 'feature/minimum_ios_13' into 'feature/develop_mvp_3'
minimum 13

See merge request BPHV_MIPS/mvm_core!199
2022-03-10 17:32:59 +00:00
Scott Pfeil
ef59c73a5b version changes 2022-03-10 10:59:00 -05:00
Scott Pfeil
f4b9245a51 minimum 13 2022-03-10 10:36:29 -05:00
Pfeil, Scott Robert
fa43578968 Merge branch 'bugfix/missing_modules' into 'develop'
add missing modules to openPage model

See merge request BPHV_MIPS/mvm_core!198
2022-03-08 18:25:47 +00:00
Scott Pfeil
ba9dab019f add missing modules to openPage model 2022-03-08 12:49:35 -05:00
Hedden, Kyle Matthew
1866c0c28a Merge branch 'feature/nil_class_exception' into 'develop'
improve exception handling

See merge request BPHV_MIPS/mvm_core!196
2022-03-01 23:51:06 +00:00
Scott Pfeil
30d4c7730f improve exception handling 2022-03-01 17:53:58 -05:00
Hedden, Kyle Matthew
e89c10daae Merge branch 'feature/open_url_options' into 'develop'
Feature/open url options

See merge request BPHV_MIPS/mvm_core!190
2022-02-18 15:49:10 +00:00
Pfeil, Scott Robert
7f57d493f6 Merge branch 'feature/TrialFraud-DEVAO-1533' into 'develop'
TrialFraud extension additions

See merge request BPHV_MIPS/mvm_core!194
2022-02-15 16:11:37 +00:00
Bruce, Matt R
3e06f6ee44 TrialFraud extension additions 2022-02-15 16:11:33 +00:00
Scott Pfeil
4fa85ecc34 Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core into feature/open_url_options 2022-02-11 14:44:06 -05:00
Pfeil, Scott Robert
e0d3bfb9e3 Merge branch 'release/9_6_0' into 'develop'
release/9_6_0 hotfix merge

See merge request BPHV_MIPS/mvm_core!191
2022-02-07 17:02:49 +00:00
Hedden, Kyle Matthew
d3d198b007 Merge branch 'bugfix/urlQueryParameters' into 'release/9_6_0'
Added helper functions

See merge request BPHV_MIPS/mvm_core!192
2022-01-24 23:57:09 +00:00
Scott Pfeil
40c365829a JSONARRAY fix 2022-01-24 18:51:05 -05:00
Scott Pfeil
306e66a3b2 review changes 2022-01-24 18:14:37 -05:00
Krishna Kishore Bandaru
f2d824f829 added helper functions 2022-01-22 00:42:17 +05:30
Scott Pfeil
c21b677048 Move legacy delegate call out of core. 2022-01-13 15:41:55 -05:00
Scott Pfeil
a2d9196bca Allows replace 2022-01-10 11:36:54 -05:00
Scott Pfeil
6fe6d6ea8b simplified core openURL action 2022-01-07 16:02:31 -05:00
Hedden, Kyle Matthew
1dcdc12919 Merge branch 'feature/remove_mdn_dependency' into 'develop'
change mdn calculation

See merge request BPHV_MIPS/mvm_core!188
2021-12-28 21:06:06 +00:00
Scott Pfeil
0711efee00 Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core into feature/remove_mdn_dependency 2021-11-22 10:31:54 -05:00
Hedden, Kyle Matthew
b63e60e58a Merge branch 'release/9_5_0' into 'develop'
release/9_5_0 hotfix merge

See merge request BPHV_MIPS/mvm_core!184
2021-11-19 16:10:41 +00:00
Pfeil, Scott Robert
247adceb98 Merge branch 'bugfix/open_url_decode' into 'release/9_5_0'
add page type for legacy open url....

See merge request BPHV_MIPS/mvm_core!186
2021-11-16 20:10:01 +00:00
Scott Pfeil
5d4995322b add page type for legacy open url.... 2021-11-16 13:46:49 -05:00
Scott Pfeil
324be22ad2 Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core into feature/remove_mdn_dependency 2021-11-09 11:50:57 -05:00
Hedden, Kyle Matthew
11888424f6 Merge branch 'feature/swift_subnav' into 'develop'
add missing pass through

See merge request BPHV_MIPS/mvm_core!183
2021-11-04 18:27:15 +00:00
Scott Pfeil
80be78a401 Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core into feature/swift_subnav 2021-11-04 14:21:59 -04:00
Scott Pfeil
64f6624e00 silly! 2021-11-04 14:16:21 -04:00
Pfeil, Scott Robert
cc06f93e50 Merge branch 'feature/ft_enhancements' into 'develop'
static MVMCoreLoggingHandler addError

See merge request BPHV_MIPS/mvm_core!182
2021-11-04 18:11:55 +00:00
Scott Pfeil
35b96b2fde add missing pass through 2021-11-02 16:38:57 -04:00
Scott Pfeil
c93bb7f0f6 Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core into feature/remove_mdn_dependency 2021-11-02 15:26:39 -04:00
Suresh, Kamlesh
f569d5279d static MVMCoreLoggingHandler addError 2021-11-01 11:54:35 -04:00
Pfeil, Scott Robert
b03532a364 Merge branch 'bugfix/ActionHandler' into 'develop'
fixed bug in the new ActionHandler logic

See merge request BPHV_MIPS/mvm_core!181
2021-10-29 18:29:07 +00:00
Scott Pfeil
d3bf9481fc change mdn calculation
default errors not received from server
2021-10-25 17:32:18 -04:00
Scott Pfeil
d1ea9518a0 NSA launch 2021-10-25 13:56:39 -04:00
136 changed files with 4866 additions and 3550 deletions

View File

@ -13,8 +13,7 @@ stages:
build_project:
stage: build
script:
- xcodebuild build -project MVMCore/MVMCore.xcodeproj -scheme FatLibrary | xcpretty
- BUILD_DIR=$(xcodebuild -showBuildSettings -project MVMCore/MVMCore.xcodeproj | grep BUILD_DIR)
- xcodebuild build -project MVMCore/MVMCore.xcodeproj -scheme FatLibrary
only:
- branches
- develop
@ -32,9 +31,9 @@ deploy_snapshot:
- bash_shell
environment:
name: oneartifactory
url: https://oneartifactoryprod.verizon.com/artifactory
url: https://oneartifactoryci.verizon.com/artifactory
variables:
ARTIFACTORY_URL: https://oneartifactoryprod.verizon.com/artifactory
ARTIFACTORY_URL: https://oneartifactoryci.verizon.com/artifactory
#promote_snapshot:
# stage: go live
@ -50,9 +49,9 @@ deploy_snapshot:
# - bash_shell
# environment:
# name: oneartifactory
# url: https://oneartifactoryprod.verizon.com/artifactory
# url: https://oneartifactoryci.verizon.com/artifactory
# variables:
# ARTIFACTORY_URL: https://oneartifactoryprod.verizon.com/artifactory
# ARTIFACTORY_URL: https://oneartifactoryci.verizon.com/artifactory
#
#create_version_tag:
# stage: tag

View File

@ -39,8 +39,14 @@
0AEBB84625FA75C000EA80EE /* ActionOpenSMSModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AEBB84525FA75C000EA80EE /* ActionOpenSMSModel.swift */; };
0AFF597A23FC6E60005C24E8 /* ActionShareModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AFF597923FC6E60005C24E8 /* ActionShareModel.swift */; };
1DAD0FFE26AAB40000216E83 /* ActionRunJavaScriptModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DAD0FFD26AAB3FF00216E83 /* ActionRunJavaScriptModel.swift */; };
30349BF11FCCA78A00546A1E /* MVMCoreSessionTimeHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = 30349BEF1FCCA78A00546A1E /* MVMCoreSessionTimeHandler.h */; settings = {ATTRIBUTES = (Public, ); }; };
30349BF21FCCA78A00546A1E /* MVMCoreSessionTimeHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 30349BF01FCCA78A00546A1E /* MVMCoreSessionTimeHandler.m */; };
2723337B28BD534D004EAEE0 /* MVMCoreEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2723337A28BD534D004EAEE0 /* MVMCoreEvent.swift */; };
2723337D28BD53C2004EAEE0 /* Date+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2723337C28BD53C2004EAEE0 /* Date+Extension.swift */; };
5846ABF42B44BB9000FA6C76 /* Collection+Safe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5846ABF32B44BB9000FA6C76 /* Collection+Safe.swift */; };
5878F0B22BDAA63E00ADE23D /* ReadableDecodingErrors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5878F0B12BDAA63E00ADE23D /* ReadableDecodingErrors.swift */; };
6042E8FC2B317B190031644B /* MVMCoreLoggingHandlerHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 6042E8FB2B3094680031644B /* MVMCoreLoggingHandlerHelper.h */; settings = {ATTRIBUTES = (Public, ); }; };
605A9A2A2ABD712F00487E47 /* MVMCoreLoggingHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 605A9A292ABD712F00487E47 /* MVMCoreLoggingHandler.swift */; };
6079EDCE2AD97AA5004B7A85 /* MVMCoreLoggingDelegateProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6079EDCD2AD97AA5004B7A85 /* MVMCoreLoggingDelegateProtocol.swift */; };
60CBD0542A02397A00056CB0 /* MVMCoreSessionTimeHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60CBD0532A02397A00056CB0 /* MVMCoreSessionTimeHandler.swift */; };
881D26931FCC9D180079C521 /* MVMCoreErrorObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 881D268F1FCC9D180079C521 /* MVMCoreErrorObject.m */; };
881D26941FCC9D180079C521 /* MVMCoreOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 881D26901FCC9D180079C521 /* MVMCoreOperation.m */; };
881D26951FCC9D180079C521 /* MVMCoreErrorObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 881D26911FCC9D180079C521 /* MVMCoreErrorObject.h */; settings = {ATTRIBUTES = (Public, ); }; };
@ -69,7 +75,9 @@
94C014D924212360005811A9 /* ActionSettingModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94C014D824212360005811A9 /* ActionSettingModel.swift */; };
A332F33F20C7231700DCD9D9 /* MVMCoreViewControllerAnimatedTransitioning.h in Headers */ = {isa = PBXBuildFile; fileRef = A332F33E20C7231600DCD9D9 /* MVMCoreViewControllerAnimatedTransitioning.h */; settings = {ATTRIBUTES = (Public, ); }; };
AF1201832108C9B400E2F592 /* MVMCoreViewManagerViewControllerProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = AF1201812108C9B400E2F592 /* MVMCoreViewManagerViewControllerProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; };
AF130B8E2788DF6E00C6C03C /* OpenURLOptionsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF130B8D2788DF6E00C6C03C /* OpenURLOptionsModel.swift */; };
AF26DDAE1FCE6A37004E8F65 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = AF26DDB01FCE6A37004E8F65 /* Localizable.strings */; };
AF3A3F3F2ACC716A005094B2 /* MVMCoreObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF3A3F3E2ACC716A005094B2 /* MVMCoreObject.swift */; };
AF43A5771FBA5B7C008E9347 /* MVMCoreJSONConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = AF43A5751FBA5B7C008E9347 /* MVMCoreJSONConstants.h */; settings = {ATTRIBUTES = (Public, ); }; };
AF43A5781FBA5B7C008E9347 /* MVMCoreJSONConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = AF43A5761FBA5B7C008E9347 /* MVMCoreJSONConstants.m */; };
AF43A57B1FBA5E6A008E9347 /* MVMCoreHardcodedStringsConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = AF43A5791FBA5E6A008E9347 /* MVMCoreHardcodedStringsConstants.h */; settings = {ATTRIBUTES = (Public, ); }; };
@ -82,8 +90,6 @@
AF43A6FD1FBE2F65008E9347 /* Reachability.h in Headers */ = {isa = PBXBuildFile; fileRef = AF43A6FA1FBE2F2A008E9347 /* Reachability.h */; settings = {ATTRIBUTES = (Public, ); }; };
AF43A6FF1FBE3252008E9347 /* Reachability.m in Sources */ = {isa = PBXBuildFile; fileRef = AF43A6FB1FBE2F2A008E9347 /* Reachability.m */; };
AF43A7011FC4B227008E9347 /* MVMCoreGlobalLoadProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = AF43A7001FC4B227008E9347 /* MVMCoreGlobalLoadProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; };
AF43A7061FC4D7A2008E9347 /* MVMCoreObject.h in Headers */ = {isa = PBXBuildFile; fileRef = AF43A7041FC4D7A2008E9347 /* MVMCoreObject.h */; settings = {ATTRIBUTES = (Public, ); }; };
AF43A7071FC4D7A2008E9347 /* MVMCoreObject.m in Sources */ = {isa = PBXBuildFile; fileRef = AF43A7051FC4D7A2008E9347 /* MVMCoreObject.m */; };
AF43A70A1FC4F415008E9347 /* MVMCoreCache.m in Sources */ = {isa = PBXBuildFile; fileRef = AF43A7081FC4F415008E9347 /* MVMCoreCache.m */; };
AF43A70B1FC4F415008E9347 /* MVMCoreCache.h in Headers */ = {isa = PBXBuildFile; fileRef = AF43A7091FC4F415008E9347 /* MVMCoreCache.h */; settings = {ATTRIBUTES = (Public, ); }; };
AF43A71B1FC5BEBB008E9347 /* MVMCoreViewControllerProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = AF43A71A1FC5BEBB008E9347 /* MVMCoreViewControllerProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; };
@ -91,6 +97,27 @@
AF43A7411FC5FA6F008E9347 /* MVMCoreViewProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = AF43A7401FC5FA6F008E9347 /* MVMCoreViewProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; };
AF43A74C1FC6109F008E9347 /* MVMCoreSessionObject.h in Headers */ = {isa = PBXBuildFile; fileRef = AF43A74A1FC6109F008E9347 /* MVMCoreSessionObject.h */; settings = {ATTRIBUTES = (Public, ); }; };
AF43A74D1FC6109F008E9347 /* MVMCoreSessionObject.m in Sources */ = {isa = PBXBuildFile; fileRef = AF43A74B1FC6109F008E9347 /* MVMCoreSessionObject.m */; };
AF4955E22BAB1EB200567276 /* MVMCoreCache+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF4955E12BAB1EB200567276 /* MVMCoreCache+Extension.swift */; };
AF60A7F2289212CA00919EEB /* MVMError.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF60A7F1289212CA00919EEB /* MVMError.swift */; };
AF60A7F4289212EB00919EEB /* MVMCoreError.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF60A7F3289212EB00919EEB /* MVMCoreError.swift */; };
AF686FDA2A8A876A008F666A /* NavigationOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF686FD92A8A876A008F666A /* NavigationOperation.swift */; };
AF686FDE2A8D29CD008F666A /* MVMCoreLoadRequestOperation+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF686FDD2A8D29CD008F666A /* MVMCoreLoadRequestOperation+Extension.swift */; };
AF6870292A9CD0E9008F666A /* MVMCoreLoadHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF6870282A9CD0E9008F666A /* MVMCoreLoadHandler.swift */; };
AF69D4E9286E54D500BC6862 /* ActionCallHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF69D4E8286E54D500BC6862 /* ActionCallHandler.swift */; };
AF69D4EB286E586200BC6862 /* ActionRestartHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF69D4EA286E586200BC6862 /* ActionRestartHandler.swift */; };
AF69D4ED286E5D8C00BC6862 /* ActionCancelHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF69D4EC286E5D8C00BC6862 /* ActionCancelHandler.swift */; };
AF69D4EF286E612800BC6862 /* ActionOpenSMSHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF69D4EE286E612800BC6862 /* ActionOpenSMSHandler.swift */; };
AF69D4F1286E9D8000BC6862 /* ActionNoopHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF69D4F0286E9D8000BC6862 /* ActionNoopHandler.swift */; };
AF69D4F3286E9DCE00BC6862 /* ActionActionsHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF69D4F2286E9DCE00BC6862 /* ActionActionsHandler.swift */; };
AF69D4F5286E9F5900BC6862 /* ActionSettingHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF69D4F4286E9F5900BC6862 /* ActionSettingHandler.swift */; };
AF69D4F7286EA0B800BC6862 /* ActionPreviousSubmitHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF69D4F6286EA0B800BC6862 /* ActionPreviousSubmitHandler.swift */; };
AF70699A287DD02400077CF6 /* ActionContactHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF706999287DD02400077CF6 /* ActionContactHandler.swift */; };
AF70699E2880D01400077CF6 /* ActionShareHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF70699D2880D01400077CF6 /* ActionShareHandler.swift */; };
AF7069A02880F0EB00077CF6 /* ActionOpenPageHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF70699F2880F0EB00077CF6 /* ActionOpenPageHandler.swift */; };
AF787413286DEF8B00670588 /* ActionBackHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF787412286DEF8B00670588 /* ActionBackHandler.swift */; };
AF8D13392774EA1D008AF4A9 /* ActionOpenUrlHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF8D13382774EA1D008AF4A9 /* ActionOpenUrlHandler.swift */; };
AF925DEE28BD35A2008E8677 /* NavigationHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF925DED28BD35A2008E8677 /* NavigationHandler.swift */; };
AFA4931E29E5C988001A9663 /* MVMCoreActionUtility+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFA4931D29E5C988001A9663 /* MVMCoreActionUtility+Extension.swift */; };
AFBB96341FBA34310008D868 /* MVMCoreErrorConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = AFBB96321FBA34310008D868 /* MVMCoreErrorConstants.h */; settings = {ATTRIBUTES = (Public, ); }; };
AFBB96351FBA34310008D868 /* MVMCoreErrorConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = AFBB96331FBA34310008D868 /* MVMCoreErrorConstants.m */; };
AFBB96381FBA39E70008D868 /* MVMCoreLoadDelegateProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = AFBB96371FBA39E70008D868 /* MVMCoreLoadDelegateProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; };
@ -102,28 +129,12 @@
AFBB96641FBA3A570008D868 /* MVMCoreLoadHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = AFBB964B1FBA3A560008D868 /* MVMCoreLoadHandler.m */; };
AFBB96691FBA3A570008D868 /* MVMCoreRequestParameters.m in Sources */ = {isa = PBXBuildFile; fileRef = AFBB96511FBA3A560008D868 /* MVMCoreRequestParameters.m */; };
AFBB966A1FBA3A570008D868 /* MVMCoreLoadRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = AFBB96521FBA3A570008D868 /* MVMCoreLoadRequestOperation.m */; };
AFBB968B1FBA3A9A0008D868 /* MVMCoreDismissViewControllerOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = AFBB966D1FBA3A9A0008D868 /* MVMCoreDismissViewControllerOperation.h */; settings = {ATTRIBUTES = (Public, ); }; };
AFBB968C1FBA3A9A0008D868 /* MVMCoreDismissViewControllerOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = AFBB966E1FBA3A9A0008D868 /* MVMCoreDismissViewControllerOperation.m */; };
AFBB968D1FBA3A9A0008D868 /* MVMCoreNavigationHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = AFBB966F1FBA3A9A0008D868 /* MVMCoreNavigationHandler.h */; settings = {ATTRIBUTES = (Public, ); }; };
AFBB968E1FBA3A9A0008D868 /* MVMCoreNavigationHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = AFBB96701FBA3A9A0008D868 /* MVMCoreNavigationHandler.m */; };
AFBB968F1FBA3A9A0008D868 /* MVMCoreNavigationObject.h in Headers */ = {isa = PBXBuildFile; fileRef = AFBB96711FBA3A9A0008D868 /* MVMCoreNavigationObject.h */; settings = {ATTRIBUTES = (Public, ); }; };
AFBB96901FBA3A9A0008D868 /* MVMCoreNavigationObject.m in Sources */ = {isa = PBXBuildFile; fileRef = AFBB96721FBA3A9A0008D868 /* MVMCoreNavigationObject.m */; };
AFBB96911FBA3A9A0008D868 /* MVMCoreNavigationOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = AFBB96731FBA3A9A0008D868 /* MVMCoreNavigationOperation.h */; settings = {ATTRIBUTES = (Public, ); }; };
AFBB96921FBA3A9A0008D868 /* MVMCoreNavigationOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = AFBB96741FBA3A9A0008D868 /* MVMCoreNavigationOperation.m */; };
AFBB96931FBA3A9A0008D868 /* MVMCorePresentAnimationOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = AFBB96751FBA3A9A0008D868 /* MVMCorePresentAnimationOperation.h */; settings = {ATTRIBUTES = (Public, ); }; };
AFBB96941FBA3A9A0008D868 /* MVMCorePresentAnimationOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = AFBB96761FBA3A9A0008D868 /* MVMCorePresentAnimationOperation.m */; };
AFBB96951FBA3A9A0008D868 /* MVMCorePresentationDelegateProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = AFBB96771FBA3A9A0008D868 /* MVMCorePresentationDelegateProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; };
AFBB96961FBA3A9A0008D868 /* MVMCorePresentViewControllerOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = AFBB96781FBA3A9A0008D868 /* MVMCorePresentViewControllerOperation.h */; settings = {ATTRIBUTES = (Public, ); }; };
AFBB96971FBA3A9A0008D868 /* MVMCorePresentViewControllerOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = AFBB96791FBA3A9A0008D868 /* MVMCorePresentViewControllerOperation.m */; };
AFBB96981FBA3A9A0008D868 /* MVMCoreAlertController.h in Headers */ = {isa = PBXBuildFile; fileRef = AFBB967B1FBA3A9A0008D868 /* MVMCoreAlertController.h */; settings = {ATTRIBUTES = (Public, ); }; };
AFBB96991FBA3A9A0008D868 /* MVMCoreAlertController.m in Sources */ = {isa = PBXBuildFile; fileRef = AFBB967C1FBA3A9A0008D868 /* MVMCoreAlertController.m */; };
AFBB96B01FBA3B590008D868 /* MVMCoreDispatchUtility.h in Headers */ = {isa = PBXBuildFile; fileRef = AFBB96AC1FBA3B590008D868 /* MVMCoreDispatchUtility.h */; settings = {ATTRIBUTES = (Public, ); }; };
AFBB96B11FBA3B590008D868 /* MVMCoreDispatchUtility.m in Sources */ = {isa = PBXBuildFile; fileRef = AFBB96AD1FBA3B590008D868 /* MVMCoreDispatchUtility.m */; };
AFBB96B21FBA3B590008D868 /* MVMCoreGetterUtility.h in Headers */ = {isa = PBXBuildFile; fileRef = AFBB96AE1FBA3B590008D868 /* MVMCoreGetterUtility.h */; settings = {ATTRIBUTES = (Public, ); }; };
AFBB96B31FBA3B590008D868 /* MVMCoreGetterUtility.m in Sources */ = {isa = PBXBuildFile; fileRef = AFBB96AF1FBA3B590008D868 /* MVMCoreGetterUtility.m */; };
AFBB96B81FBA3CEC0008D868 /* MVMCoreActionDelegateProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = AFBB96B51FBA3CEC0008D868 /* MVMCoreActionDelegateProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; };
AFBB96B91FBA3CEC0008D868 /* MVMCoreActionHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = AFBB96B61FBA3CEC0008D868 /* MVMCoreActionHandler.h */; settings = {ATTRIBUTES = (Public, ); }; };
AFBB96BA1FBA3CEC0008D868 /* MVMCoreActionHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = AFBB96B71FBA3CEC0008D868 /* MVMCoreActionHandler.m */; };
AFBB96EC1FBA4A260008D868 /* MFHardCodedServerResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = AFBB96E91FBA4A260008D868 /* MFHardCodedServerResponse.h */; };
AFBB96ED1FBA4A260008D868 /* MFHardCodedServerResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = AFBB96EA1FBA4A260008D868 /* MFHardCodedServerResponse.m */; };
AFEA17A8209B6A1C00BC6740 /* MVMCoreBlockOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = AFEA17A6209B6A1C00BC6740 /* MVMCoreBlockOperation.h */; settings = {ATTRIBUTES = (Public, ); }; };
@ -136,9 +147,6 @@
AFED77A61FCCA29400BAE689 /* MVMCoreViewControllerStoryBoardMappingObject.m in Sources */ = {isa = PBXBuildFile; fileRef = AFED779E1FCCA29400BAE689 /* MVMCoreViewControllerStoryBoardMappingObject.m */; };
AFED77A71FCCA29400BAE689 /* MVMCoreViewControllerProgrammaticMappingObject.m in Sources */ = {isa = PBXBuildFile; fileRef = AFED779F1FCCA29400BAE689 /* MVMCoreViewControllerProgrammaticMappingObject.m */; };
AFED77A81FCCA29400BAE689 /* MVMCoreViewControllerStoryBoardMappingObject.h in Headers */ = {isa = PBXBuildFile; fileRef = AFED77A01FCCA29400BAE689 /* MVMCoreViewControllerStoryBoardMappingObject.h */; settings = {ATTRIBUTES = (Public, ); }; };
AFEEE8191FCDEB8D00B5EDD0 /* MVMCoreLoggingDelegateProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = AFEEE8181FCDDE6B00B5EDD0 /* MVMCoreLoggingDelegateProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; };
AFEEE81E1FCDF3CA00B5EDD0 /* MVMCoreLoggingHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = AFEEE81C1FCDF3CA00B5EDD0 /* MVMCoreLoggingHandler.h */; settings = {ATTRIBUTES = (Public, ); }; };
AFEEE81F1FCDF3CA00B5EDD0 /* MVMCoreLoggingHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = AFEEE81D1FCDF3CA00B5EDD0 /* MVMCoreLoggingHandler.m */; };
AFFCFA651FCCC0D700FD0730 /* MVMCoreLoadingOverlayDelegateProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = AFFCFA611FCCC0D600FD0730 /* MVMCoreLoadingOverlayDelegateProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; };
AFFCFA661FCCC0D700FD0730 /* MVMCoreLoadingOverlayHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = AFFCFA621FCCC0D600FD0730 /* MVMCoreLoadingOverlayHandler.h */; settings = {ATTRIBUTES = (Public, ); }; };
AFFCFA671FCCC0D700FD0730 /* MVMCoreLoadingOverlayHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = AFFCFA631FCCC0D600FD0730 /* MVMCoreLoadingOverlayHandler.m */; };
@ -147,8 +155,8 @@
D268D82B26700292008BD413 /* MVMCoreViewManagerViewControllerProtocolHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = D268D82926700292008BD413 /* MVMCoreViewManagerViewControllerProtocolHelper.h */; settings = {ATTRIBUTES = (Public, ); }; };
D268D82C26700292008BD413 /* MVMCoreViewManagerViewControllerProtocolHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = D268D82A26700292008BD413 /* MVMCoreViewManagerViewControllerProtocolHelper.m */; };
D27073B725BB45C4001C7246 /* ActionActionsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D27073B625BB45C4001C7246 /* ActionActionsModel.swift */; };
D27073CD25BB4CEF001C7246 /* MVMCoreActionHandler+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D27073CC25BB4CEF001C7246 /* MVMCoreActionHandler+Extension.swift */; };
D27073D125BB844B001C7246 /* MVMCoreActionDelegateProtocol+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D27073D025BB844B001C7246 /* MVMCoreActionDelegateProtocol+Extension.swift */; };
D27073CD25BB4CEF001C7246 /* MVMCoreActionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = D27073CC25BB4CEF001C7246 /* MVMCoreActionHandler.swift */; };
D27073D125BB844B001C7246 /* ActionDelegateProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D27073D025BB844B001C7246 /* ActionDelegateProtocol.swift */; };
D282AAB62240085300C46919 /* MVMCoreGetterUtility+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D282AAB52240085300C46919 /* MVMCoreGetterUtility+Extension.swift */; };
D282AAB82240342D00C46919 /* NSNumber+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D282AAB72240342D00C46919 /* NSNumber+Extension.swift */; };
D288D5F526C6EFE000A5C365 /* MVMCoreLoggingHandler+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D288D5F426C6EFE000A5C365 /* MVMCoreLoggingHandler+Extension.swift */; };
@ -156,6 +164,8 @@
D2DEDCB923C6400600C44CC4 /* UnitInterval.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2DEDCB823C6400600C44CC4 /* UnitInterval.swift */; };
D2DEDCBB23C65BC300C44CC4 /* Percent.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2DEDCBA23C65BC300C44CC4 /* Percent.swift */; };
D2E1FAD92260C3E400AEFD8C /* DelegateObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E1FAD82260C3E400AEFD8C /* DelegateObject.swift */; };
EA09CD62282ACDDB00A7835F /* Decoder+UserInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA09CD61282ACDDB00A7835F /* Decoder+UserInfo.swift */; };
EA09CD99282BF83600A7835F /* DecodableDefault.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA09CD98282BF83600A7835F /* DecodableDefault.swift */; };
EA3B264C25FC0B7600008074 /* ModelHandlerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA3B264B25FC0B7600008074 /* ModelHandlerProtocol.swift */; };
/* End PBXBuildFile section */
@ -180,8 +190,16 @@
0AEBB84525FA75C000EA80EE /* ActionOpenSMSModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionOpenSMSModel.swift; sourceTree = "<group>"; };
0AFF597923FC6E60005C24E8 /* ActionShareModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionShareModel.swift; sourceTree = "<group>"; };
1DAD0FFD26AAB3FF00216E83 /* ActionRunJavaScriptModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionRunJavaScriptModel.swift; sourceTree = "<group>"; };
30349BEF1FCCA78A00546A1E /* MVMCoreSessionTimeHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreSessionTimeHandler.h; sourceTree = "<group>"; };
30349BF01FCCA78A00546A1E /* MVMCoreSessionTimeHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreSessionTimeHandler.m; sourceTree = "<group>"; };
2723337A28BD534D004EAEE0 /* MVMCoreEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MVMCoreEvent.swift; sourceTree = "<group>"; };
2723337C28BD53C2004EAEE0 /* Date+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+Extension.swift"; sourceTree = "<group>"; };
581FABEE2A71D0E6003A8508 /* mvmcore_dev.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = mvmcore_dev.xcconfig; sourceTree = "<group>"; };
5836B8E22A4338DF002553D9 /* mvmcore.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = mvmcore.xcconfig; sourceTree = "<group>"; };
5846ABF32B44BB9000FA6C76 /* Collection+Safe.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Collection+Safe.swift"; sourceTree = "<group>"; };
5878F0B12BDAA63E00ADE23D /* ReadableDecodingErrors.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadableDecodingErrors.swift; sourceTree = "<group>"; };
6042E8FB2B3094680031644B /* MVMCoreLoggingHandlerHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreLoggingHandlerHelper.h; sourceTree = "<group>"; };
605A9A292ABD712F00487E47 /* MVMCoreLoggingHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MVMCoreLoggingHandler.swift; sourceTree = "<group>"; };
6079EDCD2AD97AA5004B7A85 /* MVMCoreLoggingDelegateProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MVMCoreLoggingDelegateProtocol.swift; sourceTree = "<group>"; };
60CBD0532A02397A00056CB0 /* MVMCoreSessionTimeHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MVMCoreSessionTimeHandler.swift; sourceTree = "<group>"; };
881D268F1FCC9D180079C521 /* MVMCoreErrorObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreErrorObject.m; sourceTree = "<group>"; };
881D26901FCC9D180079C521 /* MVMCoreOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreOperation.m; sourceTree = "<group>"; };
881D26911FCC9D180079C521 /* MVMCoreErrorObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreErrorObject.h; sourceTree = "<group>"; };
@ -212,7 +230,9 @@
94C014D824212360005811A9 /* ActionSettingModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionSettingModel.swift; sourceTree = "<group>"; };
A332F33E20C7231600DCD9D9 /* MVMCoreViewControllerAnimatedTransitioning.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreViewControllerAnimatedTransitioning.h; sourceTree = "<group>"; };
AF1201812108C9B400E2F592 /* MVMCoreViewManagerViewControllerProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreViewManagerViewControllerProtocol.h; sourceTree = "<group>"; };
AF130B8D2788DF6E00C6C03C /* OpenURLOptionsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenURLOptionsModel.swift; sourceTree = "<group>"; };
AF26DDAF1FCE6A37004E8F65 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
AF3A3F3E2ACC716A005094B2 /* MVMCoreObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MVMCoreObject.swift; sourceTree = "<group>"; };
AF43A5751FBA5B7C008E9347 /* MVMCoreJSONConstants.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreJSONConstants.h; sourceTree = "<group>"; };
AF43A5761FBA5B7C008E9347 /* MVMCoreJSONConstants.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MVMCoreJSONConstants.m; sourceTree = "<group>"; };
AF43A5791FBA5E6A008E9347 /* MVMCoreHardcodedStringsConstants.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreHardcodedStringsConstants.h; sourceTree = "<group>"; };
@ -228,8 +248,6 @@
AF43A6FB1FBE2F2A008E9347 /* Reachability.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Reachability.m; sourceTree = "<group>"; };
AF43A6FE1FBE2FEE008E9347 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };
AF43A7001FC4B227008E9347 /* MVMCoreGlobalLoadProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreGlobalLoadProtocol.h; sourceTree = "<group>"; };
AF43A7041FC4D7A2008E9347 /* MVMCoreObject.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreObject.h; sourceTree = "<group>"; };
AF43A7051FC4D7A2008E9347 /* MVMCoreObject.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MVMCoreObject.m; sourceTree = "<group>"; };
AF43A7081FC4F415008E9347 /* MVMCoreCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreCache.m; sourceTree = "<group>"; };
AF43A7091FC4F415008E9347 /* MVMCoreCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreCache.h; sourceTree = "<group>"; };
AF43A71A1FC5BEBB008E9347 /* MVMCoreViewControllerProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreViewControllerProtocol.h; sourceTree = "<group>"; };
@ -237,6 +255,27 @@
AF43A7401FC5FA6F008E9347 /* MVMCoreViewProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreViewProtocol.h; sourceTree = "<group>"; };
AF43A74A1FC6109F008E9347 /* MVMCoreSessionObject.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreSessionObject.h; sourceTree = "<group>"; };
AF43A74B1FC6109F008E9347 /* MVMCoreSessionObject.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MVMCoreSessionObject.m; sourceTree = "<group>"; };
AF4955E12BAB1EB200567276 /* MVMCoreCache+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MVMCoreCache+Extension.swift"; sourceTree = "<group>"; };
AF60A7F1289212CA00919EEB /* MVMError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MVMError.swift; sourceTree = "<group>"; };
AF60A7F3289212EB00919EEB /* MVMCoreError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MVMCoreError.swift; sourceTree = "<group>"; };
AF686FD92A8A876A008F666A /* NavigationOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationOperation.swift; sourceTree = "<group>"; };
AF686FDD2A8D29CD008F666A /* MVMCoreLoadRequestOperation+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MVMCoreLoadRequestOperation+Extension.swift"; sourceTree = "<group>"; };
AF6870282A9CD0E9008F666A /* MVMCoreLoadHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MVMCoreLoadHandler.swift; sourceTree = "<group>"; };
AF69D4E8286E54D500BC6862 /* ActionCallHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionCallHandler.swift; sourceTree = "<group>"; };
AF69D4EA286E586200BC6862 /* ActionRestartHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionRestartHandler.swift; sourceTree = "<group>"; };
AF69D4EC286E5D8C00BC6862 /* ActionCancelHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionCancelHandler.swift; sourceTree = "<group>"; };
AF69D4EE286E612800BC6862 /* ActionOpenSMSHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionOpenSMSHandler.swift; sourceTree = "<group>"; };
AF69D4F0286E9D8000BC6862 /* ActionNoopHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionNoopHandler.swift; sourceTree = "<group>"; };
AF69D4F2286E9DCE00BC6862 /* ActionActionsHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionActionsHandler.swift; sourceTree = "<group>"; };
AF69D4F4286E9F5900BC6862 /* ActionSettingHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionSettingHandler.swift; sourceTree = "<group>"; };
AF69D4F6286EA0B800BC6862 /* ActionPreviousSubmitHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionPreviousSubmitHandler.swift; sourceTree = "<group>"; };
AF706999287DD02400077CF6 /* ActionContactHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionContactHandler.swift; sourceTree = "<group>"; };
AF70699D2880D01400077CF6 /* ActionShareHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionShareHandler.swift; sourceTree = "<group>"; };
AF70699F2880F0EB00077CF6 /* ActionOpenPageHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionOpenPageHandler.swift; sourceTree = "<group>"; };
AF787412286DEF8B00670588 /* ActionBackHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionBackHandler.swift; sourceTree = "<group>"; };
AF8D13382774EA1D008AF4A9 /* ActionOpenUrlHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionOpenUrlHandler.swift; sourceTree = "<group>"; };
AF925DED28BD35A2008E8677 /* NavigationHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationHandler.swift; sourceTree = "<group>"; };
AFA4931D29E5C988001A9663 /* MVMCoreActionUtility+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MVMCoreActionUtility+Extension.swift"; sourceTree = "<group>"; };
AFBB96321FBA34310008D868 /* MVMCoreErrorConstants.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreErrorConstants.h; sourceTree = "<group>"; };
AFBB96331FBA34310008D868 /* MVMCoreErrorConstants.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MVMCoreErrorConstants.m; sourceTree = "<group>"; };
AFBB96371FBA39E70008D868 /* MVMCoreLoadDelegateProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreLoadDelegateProtocol.h; sourceTree = "<group>"; };
@ -248,29 +287,12 @@
AFBB964B1FBA3A560008D868 /* MVMCoreLoadHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreLoadHandler.m; sourceTree = "<group>"; };
AFBB96511FBA3A560008D868 /* MVMCoreRequestParameters.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreRequestParameters.m; sourceTree = "<group>"; };
AFBB96521FBA3A570008D868 /* MVMCoreLoadRequestOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreLoadRequestOperation.m; sourceTree = "<group>"; };
AFBB966D1FBA3A9A0008D868 /* MVMCoreDismissViewControllerOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreDismissViewControllerOperation.h; sourceTree = "<group>"; };
AFBB966E1FBA3A9A0008D868 /* MVMCoreDismissViewControllerOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreDismissViewControllerOperation.m; sourceTree = "<group>"; };
AFBB966F1FBA3A9A0008D868 /* MVMCoreNavigationHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreNavigationHandler.h; sourceTree = "<group>"; };
AFBB96701FBA3A9A0008D868 /* MVMCoreNavigationHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreNavigationHandler.m; sourceTree = "<group>"; };
AFBB96711FBA3A9A0008D868 /* MVMCoreNavigationObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreNavigationObject.h; sourceTree = "<group>"; };
AFBB96721FBA3A9A0008D868 /* MVMCoreNavigationObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreNavigationObject.m; sourceTree = "<group>"; };
AFBB96731FBA3A9A0008D868 /* MVMCoreNavigationOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreNavigationOperation.h; sourceTree = "<group>"; };
AFBB96741FBA3A9A0008D868 /* MVMCoreNavigationOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreNavigationOperation.m; sourceTree = "<group>"; };
AFBB96751FBA3A9A0008D868 /* MVMCorePresentAnimationOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCorePresentAnimationOperation.h; sourceTree = "<group>"; };
AFBB96761FBA3A9A0008D868 /* MVMCorePresentAnimationOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCorePresentAnimationOperation.m; sourceTree = "<group>"; };
AFBB96771FBA3A9A0008D868 /* MVMCorePresentationDelegateProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCorePresentationDelegateProtocol.h; sourceTree = "<group>"; };
AFBB96781FBA3A9A0008D868 /* MVMCorePresentViewControllerOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCorePresentViewControllerOperation.h; sourceTree = "<group>"; };
AFBB96791FBA3A9A0008D868 /* MVMCorePresentViewControllerOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCorePresentViewControllerOperation.m; sourceTree = "<group>"; };
AFBB967B1FBA3A9A0008D868 /* MVMCoreAlertController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreAlertController.h; sourceTree = "<group>"; };
AFBB967C1FBA3A9A0008D868 /* MVMCoreAlertController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreAlertController.m; sourceTree = "<group>"; };
AFBB96AC1FBA3B590008D868 /* MVMCoreDispatchUtility.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreDispatchUtility.h; sourceTree = "<group>"; };
AFBB96AD1FBA3B590008D868 /* MVMCoreDispatchUtility.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreDispatchUtility.m; sourceTree = "<group>"; };
AFBB96AE1FBA3B590008D868 /* MVMCoreGetterUtility.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreGetterUtility.h; sourceTree = "<group>"; };
AFBB96AF1FBA3B590008D868 /* MVMCoreGetterUtility.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreGetterUtility.m; sourceTree = "<group>"; };
AFBB96B51FBA3CEC0008D868 /* MVMCoreActionDelegateProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreActionDelegateProtocol.h; sourceTree = "<group>"; };
AFBB96B61FBA3CEC0008D868 /* MVMCoreActionHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreActionHandler.h; sourceTree = "<group>"; };
AFBB96B71FBA3CEC0008D868 /* MVMCoreActionHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreActionHandler.m; sourceTree = "<group>"; };
AFBB96D21FBA44420008D868 /* VZWAuthentication.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = VZWAuthentication.framework; path = ../../SharedFrameworks/VZWAuthentication.framework; sourceTree = "<group>"; };
AFBB96E91FBA4A260008D868 /* MFHardCodedServerResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MFHardCodedServerResponse.h; sourceTree = "<group>"; };
AFBB96EA1FBA4A260008D868 /* MFHardCodedServerResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MFHardCodedServerResponse.m; sourceTree = "<group>"; };
AFEA17A6209B6A1C00BC6740 /* MVMCoreBlockOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreBlockOperation.h; sourceTree = "<group>"; };
@ -283,9 +305,6 @@
AFED779E1FCCA29400BAE689 /* MVMCoreViewControllerStoryBoardMappingObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreViewControllerStoryBoardMappingObject.m; sourceTree = "<group>"; };
AFED779F1FCCA29400BAE689 /* MVMCoreViewControllerProgrammaticMappingObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreViewControllerProgrammaticMappingObject.m; sourceTree = "<group>"; };
AFED77A01FCCA29400BAE689 /* MVMCoreViewControllerStoryBoardMappingObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreViewControllerStoryBoardMappingObject.h; sourceTree = "<group>"; };
AFEEE8181FCDDE6B00B5EDD0 /* MVMCoreLoggingDelegateProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreLoggingDelegateProtocol.h; sourceTree = "<group>"; };
AFEEE81C1FCDF3CA00B5EDD0 /* MVMCoreLoggingHandler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreLoggingHandler.h; sourceTree = "<group>"; };
AFEEE81D1FCDF3CA00B5EDD0 /* MVMCoreLoggingHandler.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MVMCoreLoggingHandler.m; sourceTree = "<group>"; };
AFFCFA611FCCC0D600FD0730 /* MVMCoreLoadingOverlayDelegateProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreLoadingOverlayDelegateProtocol.h; sourceTree = "<group>"; };
AFFCFA621FCCC0D600FD0730 /* MVMCoreLoadingOverlayHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreLoadingOverlayHandler.h; sourceTree = "<group>"; };
AFFCFA631FCCC0D600FD0730 /* MVMCoreLoadingOverlayHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreLoadingOverlayHandler.m; sourceTree = "<group>"; };
@ -294,8 +313,8 @@
D268D82926700292008BD413 /* MVMCoreViewManagerViewControllerProtocolHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreViewManagerViewControllerProtocolHelper.h; sourceTree = "<group>"; };
D268D82A26700292008BD413 /* MVMCoreViewManagerViewControllerProtocolHelper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MVMCoreViewManagerViewControllerProtocolHelper.m; sourceTree = "<group>"; };
D27073B625BB45C4001C7246 /* ActionActionsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionActionsModel.swift; sourceTree = "<group>"; };
D27073CC25BB4CEF001C7246 /* MVMCoreActionHandler+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MVMCoreActionHandler+Extension.swift"; sourceTree = "<group>"; };
D27073D025BB844B001C7246 /* MVMCoreActionDelegateProtocol+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MVMCoreActionDelegateProtocol+Extension.swift"; sourceTree = "<group>"; };
D27073CC25BB4CEF001C7246 /* MVMCoreActionHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MVMCoreActionHandler.swift; sourceTree = "<group>"; };
D27073D025BB844B001C7246 /* ActionDelegateProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionDelegateProtocol.swift; sourceTree = "<group>"; };
D282AAB52240085300C46919 /* MVMCoreGetterUtility+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MVMCoreGetterUtility+Extension.swift"; sourceTree = "<group>"; };
D282AAB72240342D00C46919 /* NSNumber+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSNumber+Extension.swift"; sourceTree = "<group>"; };
D288D5F426C6EFE000A5C365 /* MVMCoreLoggingHandler+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MVMCoreLoggingHandler+Extension.swift"; sourceTree = "<group>"; };
@ -303,6 +322,8 @@
D2DEDCB823C6400600C44CC4 /* UnitInterval.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnitInterval.swift; sourceTree = "<group>"; };
D2DEDCBA23C65BC300C44CC4 /* Percent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Percent.swift; sourceTree = "<group>"; };
D2E1FAD82260C3E400AEFD8C /* DelegateObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DelegateObject.swift; sourceTree = "<group>"; };
EA09CD61282ACDDB00A7835F /* Decoder+UserInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Decoder+UserInfo.swift"; sourceTree = "<group>"; };
EA09CD98282BF83600A7835F /* DecodableDefault.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DecodableDefault.swift; sourceTree = "<group>"; };
EA3B264B25FC0B7600008074 /* ModelHandlerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModelHandlerProtocol.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
@ -355,7 +376,6 @@
8876D5D41FB50AAB00EB2E3D /* Utility */,
AF43A7191FC5BE9E008E9347 /* MainProtocols */,
AFBB96B41FBA3CEC0008D868 /* ActionHandling */,
AFBB967A1FBA3A9A0008D868 /* AlertHandling */,
AFBB966B1FBA3A9A0008D868 /* PresentationHandling */,
AFBB96361FBA39E70008D868 /* LoadHandling */,
AFBB96131FBA26650008D868 /* ViewControllerMapping */,
@ -366,6 +386,8 @@
AF26DDAB1FCE5CF2004E8F65 /* Strings */,
8876D5CC1FB50A9E00EB2E3D /* MVMCore.h */,
8876D5CD1FB50A9E00EB2E3D /* Info.plist */,
5836B8E22A4338DF002553D9 /* mvmcore.xcconfig */,
581FABEE2A71D0E6003A8508 /* mvmcore_dev.xcconfig */,
);
path = MVMCore;
sourceTree = "<group>";
@ -373,6 +395,9 @@
8876D5D41FB50AAB00EB2E3D /* Utility */ = {
isa = PBXGroup;
children = (
AF60A7F1289212CA00919EEB /* MVMError.swift */,
AF60A7F3289212EB00919EEB /* MVMCoreError.swift */,
5878F0B12BDAA63E00ADE23D /* ReadableDecodingErrors.swift */,
881D26911FCC9D180079C521 /* MVMCoreErrorObject.h */,
881D268F1FCC9D180079C521 /* MVMCoreErrorObject.m */,
881D26921FCC9D180079C521 /* MVMCoreOperation.h */,
@ -389,6 +414,7 @@
8876D5D91FB50AB000EB2E3D /* Categories */ = {
isa = PBXGroup;
children = (
5846ABF32B44BB9000FA6C76 /* Collection+Safe.swift */,
01DF561321F90ADC00CC099B /* Dictionary+MFConvenience.swift */,
D282AAB72240342D00C46919 /* NSNumber+Extension.swift */,
8876D5DA1FB50AB000EB2E3D /* NSArray+MFConvenience.h */,
@ -401,6 +427,7 @@
8876D5E51FB50AB000EB2E3D /* UIFont+MFSpacing.m */,
8876D5E61FB50AB000EB2E3D /* UILabel+MFCustom.h */,
8876D5E71FB50AB000EB2E3D /* UILabel+MFCustom.m */,
2723337C28BD53C2004EAEE0 /* Date+Extension.swift */,
);
path = Categories;
sourceTree = "<group>";
@ -431,6 +458,7 @@
isa = PBXGroup;
children = (
946EE1AA237B5C940036751F /* Decoder.swift */,
EA09CD61282ACDDB00A7835F /* Decoder+UserInfo.swift */,
946EE1B3237B619D0036751F /* Encoder.swift */,
0A42538E23F3414800554656 /* Codable+Helpers.swift */,
);
@ -453,20 +481,7 @@
1DAD0FFD26AAB3FF00216E83 /* ActionRunJavaScriptModel.swift */,
016FF6EC259A4E3E00F5E4AA /* Client Parameters */,
01F2A03523A80A7300D954D8 /* ActionModelProtocol.swift */,
946EE1BB237B691A0036751F /* ActionOpenPageModel.swift */,
01DB1F2A26444F7F000F1AF4 /* ActionOpenPageProtocol.swift */,
01F2A03823A812DD00D954D8 /* ActionOpenUrlModel.swift */,
01F2A04B23A82B1B00D954D8 /* ActionCallModel.swift */,
01C851D023CF97FE0021F976 /* ActionBackModel.swift */,
0AFF597923FC6E60005C24E8 /* ActionShareModel.swift */,
94C014D024211869005811A9 /* ActionRestartModel.swift */,
94C014D2242119E6005811A9 /* ActionPreviousSubmitModel.swift */,
94C014D424211AF0005811A9 /* ActionCancelModel.swift */,
94C014D824212360005811A9 /* ActionSettingModel.swift */,
BB780ADE250F8C890030BD2F /* ActionNoopModel.swift */,
D27073B625BB45C4001C7246 /* ActionActionsModel.swift */,
0AEBB84525FA75C000EA80EE /* ActionOpenSMSModel.swift */,
0ACC81A12613C73800A9C886 /* ActionContactModel.swift */,
);
path = ActionType;
sourceTree = "<group>";
@ -492,8 +507,7 @@
AF43A70C1FC4F42B008E9347 /* Session */ = {
isa = PBXGroup;
children = (
30349BEF1FCCA78A00546A1E /* MVMCoreSessionTimeHandler.h */,
30349BF01FCCA78A00546A1E /* MVMCoreSessionTimeHandler.m */,
60CBD0532A02397A00056CB0 /* MVMCoreSessionTimeHandler.swift */,
AF43A74A1FC6109F008E9347 /* MVMCoreSessionObject.h */,
AF43A74B1FC6109F008E9347 /* MVMCoreSessionObject.m */,
);
@ -510,7 +524,7 @@
D268D82926700292008BD413 /* MVMCoreViewManagerViewControllerProtocolHelper.h */,
D268D82A26700292008BD413 /* MVMCoreViewManagerViewControllerProtocolHelper.m */,
AF43A7401FC5FA6F008E9347 /* MVMCoreViewProtocol.h */,
AFEEE8181FCDDE6B00B5EDD0 /* MVMCoreLoggingDelegateProtocol.h */,
6079EDCD2AD97AA5004B7A85 /* MVMCoreLoggingDelegateProtocol.swift */,
AF43A7001FC4B227008E9347 /* MVMCoreGlobalLoadProtocol.h */,
);
path = MainProtocols;
@ -553,8 +567,10 @@
AFBB96371FBA39E70008D868 /* MVMCoreLoadDelegateProtocol.h */,
AFBB96391FBA3A550008D868 /* MVMCoreLoadHandler.h */,
AFBB964B1FBA3A560008D868 /* MVMCoreLoadHandler.m */,
AF6870282A9CD0E9008F666A /* MVMCoreLoadHandler.swift */,
AFBB964A1FBA3A560008D868 /* MVMCoreLoadRequestOperation.h */,
AFBB96521FBA3A570008D868 /* MVMCoreLoadRequestOperation.m */,
AF686FDD2A8D29CD008F666A /* MVMCoreLoadRequestOperation+Extension.swift */,
AFBB96471FBA3A560008D868 /* MVMCoreLoadObject.h */,
AFBB96481FBA3A560008D868 /* MVMCoreLoadObject.m */,
AFBB96491FBA3A560008D868 /* MVMCoreRequestParameters.h */,
@ -566,33 +582,14 @@
AFBB966B1FBA3A9A0008D868 /* PresentationHandling */ = {
isa = PBXGroup;
children = (
AFBB966D1FBA3A9A0008D868 /* MVMCoreDismissViewControllerOperation.h */,
AFBB966E1FBA3A9A0008D868 /* MVMCoreDismissViewControllerOperation.m */,
AFBB966F1FBA3A9A0008D868 /* MVMCoreNavigationHandler.h */,
AFBB96701FBA3A9A0008D868 /* MVMCoreNavigationHandler.m */,
AFBB96711FBA3A9A0008D868 /* MVMCoreNavigationObject.h */,
AFBB96721FBA3A9A0008D868 /* MVMCoreNavigationObject.m */,
AFBB96731FBA3A9A0008D868 /* MVMCoreNavigationOperation.h */,
AFBB96741FBA3A9A0008D868 /* MVMCoreNavigationOperation.m */,
AFBB96751FBA3A9A0008D868 /* MVMCorePresentAnimationOperation.h */,
AFBB96761FBA3A9A0008D868 /* MVMCorePresentAnimationOperation.m */,
AF925DED28BD35A2008E8677 /* NavigationHandler.swift */,
AF686FD92A8A876A008F666A /* NavigationOperation.swift */,
AFBB96771FBA3A9A0008D868 /* MVMCorePresentationDelegateProtocol.h */,
AFBB96781FBA3A9A0008D868 /* MVMCorePresentViewControllerOperation.h */,
AFBB96791FBA3A9A0008D868 /* MVMCorePresentViewControllerOperation.m */,
A332F33E20C7231600DCD9D9 /* MVMCoreViewControllerAnimatedTransitioning.h */,
);
path = PresentationHandling;
sourceTree = "<group>";
};
AFBB967A1FBA3A9A0008D868 /* AlertHandling */ = {
isa = PBXGroup;
children = (
AFBB967B1FBA3A9A0008D868 /* MVMCoreAlertController.h */,
AFBB967C1FBA3A9A0008D868 /* MVMCoreAlertController.m */,
);
path = AlertHandling;
sourceTree = "<group>";
};
AFBB96AB1FBA3B590008D868 /* Helpers */ = {
isa = PBXGroup;
children = (
@ -603,6 +600,7 @@
D282AAB52240085300C46919 /* MVMCoreGetterUtility+Extension.swift */,
AF43A5851FBB67D6008E9347 /* MVMCoreActionUtility.h */,
AF43A5861FBB67D6008E9347 /* MVMCoreActionUtility.m */,
AFA4931D29E5C988001A9663 /* MVMCoreActionUtility+Extension.swift */,
);
path = Helpers;
sourceTree = "<group>";
@ -611,10 +609,35 @@
isa = PBXGroup;
children = (
AFBB96B51FBA3CEC0008D868 /* MVMCoreActionDelegateProtocol.h */,
D27073D025BB844B001C7246 /* MVMCoreActionDelegateProtocol+Extension.swift */,
AFBB96B61FBA3CEC0008D868 /* MVMCoreActionHandler.h */,
AFBB96B71FBA3CEC0008D868 /* MVMCoreActionHandler.m */,
D27073CC25BB4CEF001C7246 /* MVMCoreActionHandler+Extension.swift */,
D27073D025BB844B001C7246 /* ActionDelegateProtocol.swift */,
D27073CC25BB4CEF001C7246 /* MVMCoreActionHandler.swift */,
946EE1BB237B691A0036751F /* ActionOpenPageModel.swift */,
AF70699F2880F0EB00077CF6 /* ActionOpenPageHandler.swift */,
AF130B8D2788DF6E00C6C03C /* OpenURLOptionsModel.swift */,
01F2A03823A812DD00D954D8 /* ActionOpenUrlModel.swift */,
AF8D13382774EA1D008AF4A9 /* ActionOpenUrlHandler.swift */,
01C851D023CF97FE0021F976 /* ActionBackModel.swift */,
AF787412286DEF8B00670588 /* ActionBackHandler.swift */,
01F2A04B23A82B1B00D954D8 /* ActionCallModel.swift */,
AF69D4E8286E54D500BC6862 /* ActionCallHandler.swift */,
94C014D024211869005811A9 /* ActionRestartModel.swift */,
AF69D4EA286E586200BC6862 /* ActionRestartHandler.swift */,
94C014D424211AF0005811A9 /* ActionCancelModel.swift */,
AF69D4EC286E5D8C00BC6862 /* ActionCancelHandler.swift */,
0AEBB84525FA75C000EA80EE /* ActionOpenSMSModel.swift */,
AF69D4EE286E612800BC6862 /* ActionOpenSMSHandler.swift */,
BB780ADE250F8C890030BD2F /* ActionNoopModel.swift */,
AF69D4F0286E9D8000BC6862 /* ActionNoopHandler.swift */,
D27073B625BB45C4001C7246 /* ActionActionsModel.swift */,
AF69D4F2286E9DCE00BC6862 /* ActionActionsHandler.swift */,
94C014D824212360005811A9 /* ActionSettingModel.swift */,
AF69D4F4286E9F5900BC6862 /* ActionSettingHandler.swift */,
94C014D2242119E6005811A9 /* ActionPreviousSubmitModel.swift */,
AF69D4F6286EA0B800BC6862 /* ActionPreviousSubmitHandler.swift */,
0ACC81A12613C73800A9C886 /* ActionContactModel.swift */,
AF706999287DD02400077CF6 /* ActionContactHandler.swift */,
0AFF597923FC6E60005C24E8 /* ActionShareModel.swift */,
AF70699D2880D01400077CF6 /* ActionShareHandler.swift */,
);
path = ActionHandling;
sourceTree = "<group>";
@ -627,7 +650,6 @@
AF43A6FC1FBE2F2A008E9347 /* Reachability */,
AF43A5C01FBB76D5008E9347 /* CoreGraphics.framework */,
AF43A5BF1FBB76C3008E9347 /* UIKit.framework */,
AFBB96D21FBA44420008D868 /* VZWAuthentication.framework */,
);
name = Frameworks;
sourceTree = "<group>";
@ -637,9 +659,11 @@
children = (
AF43A7091FC4F415008E9347 /* MVMCoreCache.h */,
AF43A7081FC4F415008E9347 /* MVMCoreCache.m */,
AFEEE81C1FCDF3CA00B5EDD0 /* MVMCoreLoggingHandler.h */,
AFEEE81D1FCDF3CA00B5EDD0 /* MVMCoreLoggingHandler.m */,
AF4955E12BAB1EB200567276 /* MVMCoreCache+Extension.swift */,
605A9A292ABD712F00487E47 /* MVMCoreLoggingHandler.swift */,
6042E8FB2B3094680031644B /* MVMCoreLoggingHandlerHelper.h */,
D288D5F426C6EFE000A5C365 /* MVMCoreLoggingHandler+Extension.swift */,
2723337A28BD534D004EAEE0 /* MVMCoreEvent.swift */,
);
path = OtherHandlers;
sourceTree = "<group>";
@ -647,8 +671,7 @@
AFBB96DE1FBA48CE0008D868 /* Singletons */ = {
isa = PBXGroup;
children = (
AF43A7041FC4D7A2008E9347 /* MVMCoreObject.h */,
AF43A7051FC4D7A2008E9347 /* MVMCoreObject.m */,
AF3A3F3E2ACC716A005094B2 /* MVMCoreObject.swift */,
);
path = Singletons;
sourceTree = "<group>";
@ -679,6 +702,7 @@
D2DEDCB623C63F3B00C44CC4 /* Clamping.swift */,
D2DEDCB823C6400600C44CC4 /* UnitInterval.swift */,
D2DEDCBA23C65BC300C44CC4 /* Percent.swift */,
EA09CD98282BF83600A7835F /* DecodableDefault.swift */,
);
path = PropertyWrappers;
sourceTree = "<group>";
@ -693,29 +717,22 @@
AF43A7411FC5FA6F008E9347 /* MVMCoreViewProtocol.h in Headers */,
AFBB96EC1FBA4A260008D868 /* MFHardCodedServerResponse.h in Headers */,
AFBB96B21FBA3B590008D868 /* MVMCoreGetterUtility.h in Headers */,
6042E8FC2B317B190031644B /* MVMCoreLoggingHandlerHelper.h in Headers */,
8876D5F21FB50AB000EB2E3D /* UIFont+MFSpacing.h in Headers */,
30349BF11FCCA78A00546A1E /* MVMCoreSessionTimeHandler.h in Headers */,
AFBB96931FBA3A9A0008D868 /* MVMCorePresentAnimationOperation.h in Headers */,
AFBB96961FBA3A9A0008D868 /* MVMCorePresentViewControllerOperation.h in Headers */,
AFBB96911FBA3A9A0008D868 /* MVMCoreNavigationOperation.h in Headers */,
AFBB968F1FBA3A9A0008D868 /* MVMCoreNavigationObject.h in Headers */,
8876D5EC1FB50AB000EB2E3D /* NSDictionary+MFConvenience.h in Headers */,
AFFCFA651FCCC0D700FD0730 /* MVMCoreLoadingOverlayDelegateProtocol.h in Headers */,
AF1201832108C9B400E2F592 /* MVMCoreViewManagerViewControllerProtocol.h in Headers */,
AFBB96981FBA3A9A0008D868 /* MVMCoreAlertController.h in Headers */,
881D26961FCC9D180079C521 /* MVMCoreOperation.h in Headers */,
8876D5EA1FB50AB000EB2E3D /* NSDecimalNumber+MFConvenience.h in Headers */,
AF43A7201FC5D2BA008E9347 /* MVMCoreViewManagerProtocol.h in Headers */,
881D26951FCC9D180079C521 /* MVMCoreErrorObject.h in Headers */,
AFBB96341FBA34310008D868 /* MVMCoreErrorConstants.h in Headers */,
A332F33F20C7231700DCD9D9 /* MVMCoreViewControllerAnimatedTransitioning.h in Headers */,
AFBB968D1FBA3A9A0008D868 /* MVMCoreNavigationHandler.h in Headers */,
AFBB96951FBA3A9A0008D868 /* MVMCorePresentationDelegateProtocol.h in Headers */,
AFED77A51FCCA29400BAE689 /* MVMCoreViewControllerProgrammaticMappingObject.h in Headers */,
AF43A5871FBB67D6008E9347 /* MVMCoreActionUtility.h in Headers */,
AF43A6FD1FBE2F65008E9347 /* Reachability.h in Headers */,
AFBB96601FBA3A570008D868 /* MVMCoreLoadObject.h in Headers */,
AF43A7061FC4D7A2008E9347 /* MVMCoreObject.h in Headers */,
AFED77A11FCCA29400BAE689 /* MVMCoreViewControllerNibMappingObject.h in Headers */,
AF43A71B1FC5BEBB008E9347 /* MVMCoreViewControllerProtocol.h in Headers */,
AFBB96381FBA39E70008D868 /* MVMCoreLoadDelegateProtocol.h in Headers */,
@ -723,7 +740,6 @@
8876D5E81FB50AB000EB2E3D /* NSArray+MFConvenience.h in Headers */,
AFBB96621FBA3A570008D868 /* MVMCoreRequestParameters.h in Headers */,
AFBB96531FBA3A570008D868 /* MVMCoreLoadHandler.h in Headers */,
AFEEE81E1FCDF3CA00B5EDD0 /* MVMCoreLoggingHandler.h in Headers */,
AF43A7011FC4B227008E9347 /* MVMCoreGlobalLoadProtocol.h in Headers */,
AF43A5771FBA5B7C008E9347 /* MVMCoreJSONConstants.h in Headers */,
AFBB96631FBA3A570008D868 /* MVMCoreLoadRequestOperation.h in Headers */,
@ -731,13 +747,10 @@
8876D5CE1FB50A9E00EB2E3D /* MVMCore.h in Headers */,
AF43A57B1FBA5E6A008E9347 /* MVMCoreHardcodedStringsConstants.h in Headers */,
AFBB96B81FBA3CEC0008D868 /* MVMCoreActionDelegateProtocol.h in Headers */,
AFBB968B1FBA3A9A0008D868 /* MVMCoreDismissViewControllerOperation.h in Headers */,
AF43A70B1FC4F415008E9347 /* MVMCoreCache.h in Headers */,
AFEA17A8209B6A1C00BC6740 /* MVMCoreBlockOperation.h in Headers */,
AF43A5831FBB66DE008E9347 /* MVMCoreConstants.h in Headers */,
AFED77A81FCCA29400BAE689 /* MVMCoreViewControllerStoryBoardMappingObject.h in Headers */,
AFEEE8191FCDEB8D00B5EDD0 /* MVMCoreLoggingDelegateProtocol.h in Headers */,
AFBB96B91FBA3CEC0008D868 /* MVMCoreActionHandler.h in Headers */,
AF43A74C1FC6109F008E9347 /* MVMCoreSessionObject.h in Headers */,
8876D5F41FB50AB000EB2E3D /* UILabel+MFCustom.h in Headers */,
AFFCFA681FCCC0D700FD0730 /* MVMCoreLoadingViewControllerProtocol.h in Headers */,
@ -753,9 +766,9 @@
isa = PBXNativeTarget;
buildConfigurationList = 8876D5D11FB50A9E00EB2E3D /* Build configuration list for PBXNativeTarget "MVMCore" */;
buildPhases = (
8876D5C61FB50A9E00EB2E3D /* Headers */,
8876D5C41FB50A9E00EB2E3D /* Sources */,
8876D5C51FB50A9E00EB2E3D /* Frameworks */,
8876D5C61FB50A9E00EB2E3D /* Headers */,
8876D5C71FB50A9E00EB2E3D /* Resources */,
);
buildRules = (
@ -773,7 +786,7 @@
8876D5C01FB50A9E00EB2E3D /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1010;
LastUpgradeCheck = 1320;
ORGANIZATIONNAME = myverizon;
TargetAttributes = {
8876D5C81FB50A9E00EB2E3D = {
@ -831,7 +844,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "unset TOOLCHAINS #Xcode 7.3 BUG FIX http://stackoverflow.com/questions/36184930/xcodebuild-7-3-cant-enable-bitcode\n\n# define output folder environment variable\nC_PROJECT_NAME=\"MVMCore\"\nPHONE_CONFIGURATION=\"Release\"\nSIMULATOR_CONFIGURATION=\"Debug\"\nSIMULATOR_LIBRARY_PATH=\"${BUILD_DIR}/${SIMULATOR_CONFIGURATION}-iphonesimulator/${C_PROJECT_NAME}.framework\"\nUNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/universal\n\n# Step 1. Build Device and Simulator versions\nxcodebuild -scheme \"${C_PROJECT_NAME}\" ONLY_ACTIVE_ARCH=NO -configuration ${PHONE_CONFIGURATION} -sdk iphoneos -archivePath \"${BUILD_DIR}/${PHONE_CONFIGURATION}-iphoneos/${C_PROJECT_NAME}\" archive SKIP_INSTALL=false\n\nxcodebuild -target \"${C_PROJECT_NAME}\" ONLY_ACTIVE_ARCH=NO -configuration ${SIMULATOR_CONFIGURATION} -sdk iphonesimulator -arch x86_64 BUILD_DIR=\"${BUILD_DIR}\" ALWAYS_SEARCH_USER_PATHS=true\n\nmkdir -p \"${UNIVERSAL_OUTPUTFOLDER}\"\n\nrm -rf ${UNIVERSAL_OUTPUTFOLDER}/${C_PROJECT_NAME}.framework\ncp -R ${BUILD_DIR}/${PHONE_CONFIGURATION}-iphoneos/\"${C_PROJECT_NAME}\".xcarchive/Products/Library/Frameworks/${C_PROJECT_NAME}.framework ${UNIVERSAL_OUTPUTFOLDER}\n\n# Step 2. Create universal binary file using lipo\nlipo -create -output \"${UNIVERSAL_OUTPUTFOLDER}/${C_PROJECT_NAME}\" \"${UNIVERSAL_OUTPUTFOLDER}/${C_PROJECT_NAME}.framework/${C_PROJECT_NAME}\" \"${SIMULATOR_LIBRARY_PATH}/${C_PROJECT_NAME}\"\n\nmv ${UNIVERSAL_OUTPUTFOLDER}/${C_PROJECT_NAME} ${UNIVERSAL_OUTPUTFOLDER}/${C_PROJECT_NAME}.framework/${C_PROJECT_NAME}\n\n# For Swift framework, Swiftmodule needs to be copied in the universal framework\nif [ -d \"${SIMULATOR_LIBRARY_PATH}/Modules/${C_PROJECT_NAME}.swiftmodule/\" ]; then\ncp -a \"${SIMULATOR_LIBRARY_PATH}/Modules/${C_PROJECT_NAME}.swiftmodule/\" \"${UNIVERSAL_OUTPUTFOLDER}/${C_PROJECT_NAME}.framework/Modules/${C_PROJECT_NAME}.swiftmodule/\"\nfi\n";
shellScript = "unset TOOLCHAINS #Xcode 7.3 BUG FIX http://stackoverflow.com/questions/36184930/xcodebuild-7-3-cant-enable-bitcode\n\n# define output folder environment variable\nC_PROJECT_NAME=\"MVMCore\"\nPHONE_CONFIGURATION=\"Release\"\nPHONE_ARCHIVE_PATH=\"${BUILD_DIR}/${PHONE_CONFIGURATION}-iphoneos/${C_PROJECT_NAME}.xcarchive\"\nSIMULATOR_CONFIGURATION=\"Debug\"\nSIMULATOR_ARCHIVE_PATH=\"${BUILD_DIR}/${SIMULATOR_CONFIGURATION}-iphonesimulator/${C_PROJECT_NAME}.xcarchive\"\nUNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/universal\n\n# Build device archive\nxcodebuild archive \\\n -scheme \"${C_PROJECT_NAME}\" \\\n -configuration ${PHONE_CONFIGURATION} \\\n -archivePath \"${PHONE_ARCHIVE_PATH}\" \\\n -sdk iphoneos \\\n -destination 'generic/platform=iOS' \\\n SKIP_INSTALL=NO \\\n ONLY_ACTIVE_ARCH=NO\n \n# Build simulator archive\nxcodebuild archive \\\n -scheme \"${C_PROJECT_NAME}\" \\\n -configuration ${SIMULATOR_CONFIGURATION} \\\n -archivePath \"${SIMULATOR_ARCHIVE_PATH}\" \\\n -sdk iphonesimulator \\\n -destination 'generic/platform=iOS Simulator' \\\n SKIP_INSTALL=NO \\\n ONLY_ACTIVE_ARCH=NO\n\nmkdir -p \"${UNIVERSAL_OUTPUTFOLDER}\"\n\n# Remove any existing xc framework.\nrm -rf ${UNIVERSAL_OUTPUTFOLDER}/${C_PROJECT_NAME}.xcframework\n\n# Create the xcframework in the universal output folder.\nxcodebuild -create-xcframework \\\n -framework \"${PHONE_ARCHIVE_PATH}/Products/Library/Frameworks/${C_PROJECT_NAME}.framework\" \\\n -framework \"${SIMULATOR_ARCHIVE_PATH}/Products/Library/Frameworks/${C_PROJECT_NAME}.framework\" \\\n -output ${UNIVERSAL_OUTPUTFOLDER}/${C_PROJECT_NAME}.xcframework\n\n# Copy the dSYM file as well.\nditto \"${PHONE_ARCHIVE_PATH}/dSYMs/${C_PROJECT_NAME}.framework.dSYM\" \"${UNIVERSAL_OUTPUTFOLDER}/${C_PROJECT_NAME}.xcframework.dSYM\"\n";
};
/* End PBXShellScriptBuildPhase section */
@ -840,79 +853,100 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
AF69D4ED286E5D8C00BC6862 /* ActionCancelHandler.swift in Sources */,
AFED77A71FCCA29400BAE689 /* MVMCoreViewControllerProgrammaticMappingObject.m in Sources */,
946EE1A7237B5B1C0036751F /* ModelRegistry.swift in Sources */,
AFBB96641FBA3A570008D868 /* MVMCoreLoadHandler.m in Sources */,
AFFCFA671FCCC0D700FD0730 /* MVMCoreLoadingOverlayHandler.m in Sources */,
AFBB968E1FBA3A9A0008D868 /* MVMCoreNavigationHandler.m in Sources */,
AF8D13392774EA1D008AF4A9 /* ActionOpenUrlHandler.swift in Sources */,
AF925DEE28BD35A2008E8677 /* NavigationHandler.swift in Sources */,
AF130B8E2788DF6E00C6C03C /* OpenURLOptionsModel.swift in Sources */,
AF69D4EB286E586200BC6862 /* ActionRestartHandler.swift in Sources */,
BB780ADF250F8C890030BD2F /* ActionNoopModel.swift in Sources */,
D2E1FAD92260C3E400AEFD8C /* DelegateObject.swift in Sources */,
01F2A03623A80A7300D954D8 /* ActionModelProtocol.swift in Sources */,
AFBB96991FBA3A9A0008D868 /* MVMCoreAlertController.m in Sources */,
881D26941FCC9D180079C521 /* MVMCoreOperation.m in Sources */,
AFED77A41FCCA29400BAE689 /* MVMCoreViewControllerMappingObject.m in Sources */,
01C851CF23CF7B260021F976 /* JSONMap.swift in Sources */,
01F2A04C23A82B1B00D954D8 /* ActionCallModel.swift in Sources */,
8876D5ED1FB50AB000EB2E3D /* NSDictionary+MFConvenience.m in Sources */,
AFBB968C1FBA3A9A0008D868 /* MVMCoreDismissViewControllerOperation.m in Sources */,
AFBB96BA1FBA3CEC0008D868 /* MVMCoreActionHandler.m in Sources */,
AF686FDA2A8A876A008F666A /* NavigationOperation.swift in Sources */,
605A9A2A2ABD712F00487E47 /* MVMCoreLoggingHandler.swift in Sources */,
AFBB96ED1FBA4A260008D868 /* MFHardCodedServerResponse.m in Sources */,
AF43A74D1FC6109F008E9347 /* MVMCoreSessionObject.m in Sources */,
D282AAB62240085300C46919 /* MVMCoreGetterUtility+Extension.swift in Sources */,
AFBB96901FBA3A9A0008D868 /* MVMCoreNavigationObject.m in Sources */,
AFA4931E29E5C988001A9663 /* MVMCoreActionUtility+Extension.swift in Sources */,
1DAD0FFE26AAB40000216E83 /* ActionRunJavaScriptModel.swift in Sources */,
946EE1AB237B5C940036751F /* Decoder.swift in Sources */,
5878F0B22BDAA63E00ADE23D /* ReadableDecodingErrors.swift in Sources */,
2723337D28BD53C2004EAEE0 /* Date+Extension.swift in Sources */,
AF70699A287DD02400077CF6 /* ActionContactHandler.swift in Sources */,
AF69D4F3286E9DCE00BC6862 /* ActionActionsHandler.swift in Sources */,
946EE1BC237B691A0036751F /* ActionOpenPageModel.swift in Sources */,
0A42538F23F3414800554656 /* Codable+Helpers.swift in Sources */,
881D26931FCC9D180079C521 /* MVMCoreErrorObject.m in Sources */,
94C014D124211869005811A9 /* ActionRestartModel.swift in Sources */,
D288D5F526C6EFE000A5C365 /* MVMCoreLoggingHandler+Extension.swift in Sources */,
946EE1B0237B5EF70036751F /* JSONHelper.swift in Sources */,
30349BF21FCCA78A00546A1E /* MVMCoreSessionTimeHandler.m in Sources */,
D2DEDCB923C6400600C44CC4 /* UnitInterval.swift in Sources */,
94C014D3242119E6005811A9 /* ActionPreviousSubmitModel.swift in Sources */,
6079EDCE2AD97AA5004B7A85 /* MVMCoreLoggingDelegateProtocol.swift in Sources */,
AF60A7F2289212CA00919EEB /* MVMError.swift in Sources */,
8876D5E91FB50AB000EB2E3D /* NSArray+MFConvenience.m in Sources */,
D27073B725BB45C4001C7246 /* ActionActionsModel.swift in Sources */,
946EE1B2237B5F260036751F /* JSONValue.swift in Sources */,
0ACC81A22613C73800A9C886 /* ActionContactModel.swift in Sources */,
AFBB96971FBA3A9A0008D868 /* MVMCorePresentViewControllerOperation.m in Sources */,
AF69D4EF286E612800BC6862 /* ActionOpenSMSHandler.swift in Sources */,
AF43A5781FBA5B7C008E9347 /* MVMCoreJSONConstants.m in Sources */,
AFBB96691FBA3A570008D868 /* MVMCoreRequestParameters.m in Sources */,
AFED77A31FCCA29400BAE689 /* MVMCoreViewControllerNibMappingObject.m in Sources */,
8876D5EB1FB50AB000EB2E3D /* NSDecimalNumber+MFConvenience.m in Sources */,
01F2A03923A812DD00D954D8 /* ActionOpenUrlModel.swift in Sources */,
01934FE725A4FFC2003DCD67 /* ClientParameterActionProtocol.swift in Sources */,
AF69D4E9286E54D500BC6862 /* ActionCallHandler.swift in Sources */,
AFBB96351FBA34310008D868 /* MVMCoreErrorConstants.m in Sources */,
AF43A5881FBB67D6008E9347 /* MVMCoreActionUtility.m in Sources */,
AFED77A61FCCA29400BAE689 /* MVMCoreViewControllerStoryBoardMappingObject.m in Sources */,
AF4955E22BAB1EB200567276 /* MVMCoreCache+Extension.swift in Sources */,
016CF36925FA6DD400B82A1F /* ClientParameterHandler.swift in Sources */,
5846ABF42B44BB9000FA6C76 /* Collection+Safe.swift in Sources */,
AF69D4F7286EA0B800BC6862 /* ActionPreviousSubmitHandler.swift in Sources */,
AF43A57C1FBA5E6A008E9347 /* MVMCoreHardcodedStringsConstants.m in Sources */,
0AFF597A23FC6E60005C24E8 /* ActionShareModel.swift in Sources */,
AFEEE81F1FCDF3CA00B5EDD0 /* MVMCoreLoggingHandler.m in Sources */,
D27073CD25BB4CEF001C7246 /* MVMCoreActionHandler+Extension.swift in Sources */,
AF69D4F5286E9F5900BC6862 /* ActionSettingHandler.swift in Sources */,
D27073CD25BB4CEF001C7246 /* MVMCoreActionHandler.swift in Sources */,
01F2A05223A8325100D954D8 /* ModelMapping.swift in Sources */,
8876D5F51FB50AB000EB2E3D /* UILabel+MFCustom.m in Sources */,
AFBB96B31FBA3B590008D868 /* MVMCoreGetterUtility.m in Sources */,
AF43A7071FC4D7A2008E9347 /* MVMCoreObject.m in Sources */,
2723337B28BD534D004EAEE0 /* MVMCoreEvent.swift in Sources */,
94C014D924212360005811A9 /* ActionSettingModel.swift in Sources */,
D2DEDCB723C63F3B00C44CC4 /* Clamping.swift in Sources */,
AF70699E2880D01400077CF6 /* ActionShareHandler.swift in Sources */,
01DF561421F90ADC00CC099B /* Dictionary+MFConvenience.swift in Sources */,
EA3B264C25FC0B7600008074 /* ModelHandlerProtocol.swift in Sources */,
AF7069A02880F0EB00077CF6 /* ActionOpenPageHandler.swift in Sources */,
AFBB96B11FBA3B590008D868 /* MVMCoreDispatchUtility.m in Sources */,
946EE1A3237B59C30036751F /* ModelProtocol.swift in Sources */,
AF6870292A9CD0E9008F666A /* MVMCoreLoadHandler.swift in Sources */,
AFEA17A9209B6A1C00BC6740 /* MVMCoreBlockOperation.m in Sources */,
AF43A70A1FC4F415008E9347 /* MVMCoreCache.m in Sources */,
AF43A6FF1FBE3252008E9347 /* Reachability.m in Sources */,
AF3A3F3F2ACC716A005094B2 /* MVMCoreObject.swift in Sources */,
EA09CD62282ACDDB00A7835F /* Decoder+UserInfo.swift in Sources */,
EA09CD99282BF83600A7835F /* DecodableDefault.swift in Sources */,
01C851D123CF97FE0021F976 /* ActionBackModel.swift in Sources */,
D27073D125BB844B001C7246 /* MVMCoreActionDelegateProtocol+Extension.swift in Sources */,
AFBB96921FBA3A9A0008D868 /* MVMCoreNavigationOperation.m in Sources */,
D27073D125BB844B001C7246 /* ActionDelegateProtocol.swift in Sources */,
AFBB96611FBA3A570008D868 /* MVMCoreLoadObject.m in Sources */,
AF787413286DEF8B00670588 /* ActionBackHandler.swift in Sources */,
946EE1B4237B619D0036751F /* Encoder.swift in Sources */,
AFBB96941FBA3A9A0008D868 /* MVMCorePresentAnimationOperation.m in Sources */,
AF60A7F4289212EB00919EEB /* MVMCoreError.swift in Sources */,
94C014D524211AF0005811A9 /* ActionCancelModel.swift in Sources */,
AF43A5841FBB66DE008E9347 /* MVMCoreConstants.m in Sources */,
AF69D4F1286E9D8000BC6862 /* ActionNoopHandler.swift in Sources */,
016FF6F2259A4FCC00F5E4AA /* ClientParameterModel.swift in Sources */,
D2DEDCBB23C65BC300C44CC4 /* Percent.swift in Sources */,
AF686FDE2A8D29CD008F666A /* MVMCoreLoadRequestOperation+Extension.swift in Sources */,
60CBD0542A02397A00056CB0 /* MVMCoreSessionTimeHandler.swift in Sources */,
AFBB966A1FBA3A570008D868 /* MVMCoreLoadRequestOperation.m in Sources */,
D268D82C26700292008BD413 /* MVMCoreViewManagerViewControllerProtocolHelper.m in Sources */,
0AEBB84625FA75C000EA80EE /* ActionOpenSMSModel.swift in Sources */,
@ -942,8 +976,10 @@
/* Begin XCBuildConfiguration section */
8876D5CF1FB50A9E00EB2E3D /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 581FABEE2A71D0E6003A8508 /* mvmcore_dev.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
@ -966,6 +1002,7 @@
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
@ -978,7 +1015,6 @@
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
@ -993,10 +1029,11 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
@ -1004,8 +1041,10 @@
};
8876D5D01FB50A9E00EB2E3D /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 5836B8E22A4338DF002553D9 /* mvmcore.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
@ -1028,6 +1067,7 @@
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
@ -1040,7 +1080,6 @@
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
@ -1049,8 +1088,9 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
MTL_ENABLE_DEBUG_INFO = NO;
ONLY_ACTIVE_ARCH = NO;
SDKROOT = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
VALIDATE_PRODUCT = YES;
@ -1062,7 +1102,6 @@
8876D5D21FB50A9E00EB2E3D /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
BITCODE_GENERATION_MODE = bitcode;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "";
CODE_SIGN_STYLE = Automatic;
@ -1074,10 +1113,10 @@
FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/../../SharedFrameworks";
INFOPLIST_FILE = MVMCore/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
LIBRARY_SEARCH_PATHS = "$(inherited)";
ONLY_ACTIVE_ARCH = YES;
MARKETING_VERSION = 3.1;
PRODUCT_BUNDLE_IDENTIFIER = com.vzw.MVMCore;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SKIP_INSTALL = YES;
@ -1090,7 +1129,6 @@
8876D5D31FB50A9E00EB2E3D /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
BITCODE_GENERATION_MODE = bitcode;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "";
CODE_SIGN_STYLE = Automatic;
@ -1102,9 +1140,10 @@
FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/../../SharedFrameworks";
INFOPLIST_FILE = MVMCore/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
LIBRARY_SEARCH_PATHS = "$(inherited)";
MARKETING_VERSION = 3.1;
PRODUCT_BUNDLE_IDENTIFIER = com.vzw.MVMCore;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SKIP_INSTALL = YES;

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1010"
LastUpgradeVersion = "1320"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@ -29,8 +29,6 @@
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
@ -51,8 +49,6 @@
ReferencedContainer = "container:MVMCore.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"

View File

@ -0,0 +1,51 @@
//
// ActionActionsHandler.swift
// MVMCore
//
// Created by Scott Pfeil on 6/30/22.
// Copyright © 2022 myverizon. All rights reserved.
//
import Foundation
open class ActionActionsHandler: MVMCoreJSONActionHandlerProtocol {
required public init() {}
open func performAction(with JSON: [AnyHashable : Any], model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {
guard let model = model as? ActionActionsModel else { return }
let actions = JSON.arrayForKey("actions")
if model.concurrent {
await withThrowingTaskGroup(of: Void.self) { group in
for case let (index, action as [AnyHashable: Any]) in actions.enumerated() {
group.addTask{
try await MVMCoreActionHandler.shared()?.handleAction(with: model.actions[index], json: action, additionalData: additionalData, delegateObject: delegateObject)
}
}
}
} else {
for case let (index, action as [AnyHashable: Any]) in actions.enumerated() {
try Task.checkCancellation()
try await MVMCoreActionHandler.shared()?.handleAction(with: model.actions[index], json: action, additionalData: additionalData, delegateObject: delegateObject)
}
}
}
open func execute(with model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {
guard let model = model as? ActionActionsModel else { return }
if model.concurrent {
// TODO: inspect warning.
await withThrowingTaskGroup(of: Void.self) { group in
for action in model.actions {
group.addTask{
try await (delegateObject?.actionDelegate as? ActionDelegateProtocol)?.performAction(with: action, additionalData: additionalData, delegateObject: delegateObject)
}
}
}
} else {
for action in model.actions {
try Task.checkCancellation()
try await (delegateObject?.actionDelegate as? ActionDelegateProtocol)?.performAction(with: action, additionalData: additionalData, delegateObject: delegateObject)
}
}
}
}

View File

@ -8,7 +8,7 @@
import Foundation
@objcMembers open class ActionActionsModel: ActionModelProtocol {
public struct ActionActionsModel: ActionModelProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
@ -46,7 +46,7 @@ import Foundation
// MARK: - Codec
//--------------------------------------------------
required public init(from decoder: Decoder) throws {
public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
actions = try typeContainer.decodeModels(codingKey: .actions)
if let concurrent = try typeContainer.decodeIfPresent(Bool.self, forKey: .concurrent) {
@ -64,4 +64,19 @@ import Foundation
try container.encodeIfPresent(extraParameters, forKey: .extraParameters)
try container.encodeIfPresent(analyticsData, forKey: .analyticsData)
}
public func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false }
return actions.isEqual(to: model.actions)
&& concurrent == model.concurrent
&& extraParameters == model.extraParameters
&& analyticsData == model.analyticsData
}
}
extension ActionActionsModel: CustomDebugStringConvertible {
public var debugDescription: String {
return "\(Self.self) [\(actions)]"
}
}

View File

@ -0,0 +1,26 @@
//
// ActionBackHandler.swift
// MVMCore
//
// Created by Scott Pfeil on 6/30/22.
// Copyright © 2022 myverizon. All rights reserved.
//
import Foundation
open class ActionBackHandler: MVMCoreJSONActionHandlerProtocol {
required public init() {}
open func performAction(with JSON: [AnyHashable : Any], model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {
if let closure = delegateObject?.actionDelegate?.handleBackAction {
// Legacy code will use the old handler function and break the task chain here.
closure(JSON, additionalData)
} else {
try await execute(with: model, delegateObject: delegateObject, additionalData: additionalData)
}
}
open func execute(with model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {
await NavigationHandler.shared().removeCurrentViewController(delegateObject: delegateObject)
}
}

View File

@ -7,7 +7,7 @@
//
@objcMembers public class ActionBackModel: ActionModelProtocol {
public struct ActionBackModel: ActionModelProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
@ -25,4 +25,12 @@
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

@ -0,0 +1,19 @@
//
// ActionCallHandler.swift
// MVMCore
//
// Created by Scott Pfeil on 6/30/22.
// Copyright © 2022 myverizon. All rights reserved.
//
import Foundation
open class ActionCallHandler: MVMCoreActionHandlerProtocol {
required public init() {}
open func execute(with model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {
guard let model = model as? ActionCallModel else { return }
// https://developer.apple.com/library/archive/featuredarticles/iPhoneURLScheme_Reference/PhoneLinks/PhoneLinks.html#//apple_ref/doc/uid/TP40007899-CH6-SW1
try await ActionOpenUrlHandler.openURL(with: "tel://\(model.callNumber)")
}
}

View File

@ -7,7 +7,7 @@
//
@objcMembers public class ActionCallModel: ActionModelProtocol {
public struct ActionCallModel: ActionModelProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
@ -28,4 +28,11 @@
self.extraParameters = extraParameters
self.analyticsData = analyticsData
}
public func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false }
return extraParameters == model.extraParameters
&& analyticsData == model.analyticsData
&& callNumber == model.callNumber
}
}

View File

@ -0,0 +1,20 @@
//
// ActionCancelHandler.swift
// MVMCore
//
// Created by Scott Pfeil on 6/30/22.
// Copyright © 2022 myverizon. All rights reserved.
//
import Foundation
open class ActionCancelHandler: MVMCoreJSONActionHandlerProtocol {
required public init() {}
open func performAction(with JSON: [AnyHashable : Any], model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {
delegateObject?.actionDelegate?.handleCancel?(JSON, additionalData: additionalData)
}
open func execute(with model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {
}
}

View File

@ -7,7 +7,7 @@
//
@objcMembers public class ActionCancelModel: ActionModelProtocol {
public struct ActionCancelModel: ActionModelProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
@ -25,4 +25,12 @@
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

@ -0,0 +1,126 @@
//
// ActionContactHandler.swift
// MVMCore
//
// Created by Scott Pfeil on 7/12/22.
// Copyright © 2022 myverizon. All rights reserved.
//
import Foundation
import ContactsUI
open class ActionContactHandler: NSObject, MVMCoreActionHandlerProtocol, CNContactPickerDelegate, CNContactViewControllerDelegate {
/// A continuation to keep the process running until we are finished.
private var continuation: CheckedContinuation<Bool, Never>?
required public override init() {}
/// Sets the continuation and runs the closure.
private func continueInTask(with closure: @escaping () async -> Void) async {
let _: Bool = await withCheckedContinuation { continuation in
self.continuation = continuation
Task(priority: .userInitiated) {
await closure()
}
}
}
open func execute(with model: ActionModelProtocol, delegateObject: DelegateObject? = nil, additionalData: [AnyHashable: Any]? = nil) async throws {
guard let model = model as? ActionContactModel else { return }
switch model.approach {
case .add:
await continueInTask {
await MainActor.run {
let controller = CNContactPickerViewController()
// Setting to accessibilityValue as a workaround to pass data via the delegate function.
controller.view.accessibilityIdentifier = model.phoneNumber
controller.delegate = self
Task(priority: .userInitiated) {
await NavigationHandler.shared().present(viewController: controller, delegateObject: delegateObject, animated: true)
}
}
}
case .create:
let contact = CNMutableContact()
let phone = CNLabeledValue(label: CNLabelOther, value: CNPhoneNumber(stringValue: model.phoneNumber))
contact.phoneNumbers = [phone]
if let givenName = model.firstName {
contact.givenName = givenName
}
if let familyName = model.lastName {
contact.familyName = familyName
}
let store = CNContactStore()
await continueInTask {
await MainActor.run {
let controller = CNContactViewController(forNewContact: contact)
controller.contactStore = store
controller.delegate = self
Task(priority: .userInitiated) {
await NavigationHandler.shared().push(viewController: controller, delegateObject: delegateObject, animated: true)
}
}
}
case .view:
let symbols = CharacterSet(charactersIn: ".+()-  ")
let contactPhoneNumber = model.phoneNumber.components(separatedBy: symbols).joined(separator: "")
let number = CNPhoneNumber(stringValue: contactPhoneNumber)
let contactPredicate = CNContact.predicateForContacts(matching: number)
let displayedKeys = [await CNContactViewController.descriptorForRequiredKeys()]
let store = CNContactStore()
let viewContact = try store.unifiedContacts(matching: contactPredicate, keysToFetch: displayedKeys).first
await continueInTask {
await MainActor.run {
let controller = CNContactViewController(forNewContact: viewContact)
controller.contactStore = store
controller.delegate = self
Task(priority: .userInitiated) {
await NavigationHandler.shared().push(viewController: controller, delegateObject: delegateObject, animated: true)
}
}
}
}
}
public func contactViewController(_ viewController: CNContactViewController, didCompleteWith contact: CNContact?) {
Task(priority: .userInitiated) {
await NavigationHandler.shared().popTopViewController()
self.continuation?.resume(returning: true)
}
}
public func contactViewController(_ viewController: CNContactViewController, shouldPerformDefaultActionFor property: CNContactProperty) -> Bool {
true
}
public func contactPickerDidCancel(_ picker: CNContactPickerViewController) {
Task(priority: .userInitiated) {
await NavigationHandler.shared().dismissTopViewController()
self.continuation?.resume(returning: true)
}
}
public func contactPicker(_ picker: CNContactPickerViewController, didSelect contact: CNContact) {
// This is a means to pass the data to this delegate function.
guard let phoneNumber = picker.view.accessibilityIdentifier else { return }
let store = CNContactStore()
let existingContact = contact.mutableCopy() as! CNMutableContact
let number = CNPhoneNumber(stringValue: phoneNumber)
let labelValue = CNLabeledValue(label: CNLabelOther, value: number)
var phoneNumbers = [labelValue]
phoneNumbers.append(contentsOf: existingContact.phoneNumbers)
existingContact.phoneNumbers = phoneNumbers
Task { @MainActor in
let controller = CNContactViewController(forNewContact: existingContact)
controller.contactStore = store
controller.delegate = self
Task(priority: .userInitiated) {
await NavigationHandler.shared().push(viewController: controller)
}
}
}
}

View File

@ -9,18 +9,24 @@
import ContactsUI
@objcMembers public class ActionContactModel: ActionModelProtocol {
public struct ActionContactModel: ActionModelProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public enum Approach: String, Codable {
case add
case create
case view
}
public static var identifier: String = "contact"
public var actionType: String = ActionContactModel.identifier
public var phoneNumber: String
public var firstName: String?
public var lastName: String?
public var approach: String = KeyCreate
public var approach: Approach = .create
public var extraParameters: JSONValueDictionary?
public var analyticsData: JSONValueDictionary?
@ -28,7 +34,7 @@ import ContactsUI
// MARK: - Initializer
//--------------------------------------------------
public init(phoneNumber: String, firstName: String? = nil, lastName: String? = nil, approach: String = KeyCreate, _ extraParameters: JSONValueDictionary? = nil, _ analyticsData: JSONValueDictionary? = nil) {
public init(phoneNumber: String, firstName: String? = nil, lastName: String? = nil, approach: Approach = .create, _ extraParameters: JSONValueDictionary? = nil, _ analyticsData: JSONValueDictionary? = nil) {
self.phoneNumber = phoneNumber
self.firstName = firstName
self.lastName = lastName
@ -36,4 +42,14 @@ import ContactsUI
self.extraParameters = extraParameters
self.analyticsData = analyticsData
}
public func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false }
return extraParameters == model.extraParameters
&& analyticsData == model.analyticsData
&& phoneNumber == model.phoneNumber
&& firstName == model.firstName
&& lastName == model.lastName
&& approach == model.approach
}
}

View File

@ -0,0 +1,27 @@
//
// MVMCoreActionDelegateProtocolExtension.swift
// MVMCore
//
// Created by Scott Pfeil on 1/22/21.
// Copyright © 2021 myverizon. All rights reserved.
//
import Foundation
public protocol ActionDelegateProtocol: MVMCoreActionDelegateProtocol {
/// Asks the delegate to perform the action.
func performAction(with model: ActionModelProtocol, additionalData: [AnyHashable : Any]?, delegateObject: DelegateObject?) async throws
}
public extension ActionDelegateProtocol {
func performAction(with model: ActionModelProtocol, additionalData: [AnyHashable : Any]?, delegateObject: DelegateObject?) async throws {
try await MVMCoreActionHandler.shared()?.handleAction(with: model, additionalData: additionalData, delegateObject: delegateObject)
}
}
public extension MVMCoreActionDelegateProtocol {
func action(with model: ActionModelProtocol, additionalData: [AnyHashable : Any]?, delegateObject: DelegateObject?) async throws {
try await (self as? ActionDelegateProtocol)?.performAction(with: model, additionalData: additionalData, delegateObject: delegateObject)
}
}

View File

@ -0,0 +1,15 @@
//
// ActionNoopHandler.swift
// MVMCore
//
// Created by Scott Pfeil on 6/30/22.
// Copyright © 2022 myverizon. All rights reserved.
//
import Foundation
open class ActionNoopHandler: MVMCoreActionHandlerProtocol {
required public init() {}
open func execute(with model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {}
}

View File

@ -6,7 +6,8 @@
// Copyright © 2020 myverizon. All rights reserved.
//
@objcMembers public class ActionNoopModel: ActionModelProtocol {
public struct ActionNoopModel: ActionModelProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
@ -24,4 +25,12 @@
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

@ -0,0 +1,127 @@
//
// OpenPageHandler.swift
// MVMCore
//
// Created by Scott Pfeil on 7/14/22.
// Copyright © 2022 myverizon. All rights reserved.
//
import Foundation
open class ActionOpenPageHandler: MVMCoreJSONActionHandlerProtocol {
required public init() {}
func requestParamaters(for model: ActionOpenPageModel) -> MVMCoreRequestParameters {
let requestParameters = model.requestParameters.copy() as! MVMCoreRequestParameters
if let pageType = requestParameters.pageType {
// Re-evaluate required & optional modules as action models might have been generated prior to recent additions to the mapping.
requestParameters.modules = MVMCoreViewControllerMappingObject.shared()?.modulesRequired(forPageType: pageType) as? [String]
requestParameters.optionalModules = MVMCoreViewControllerMappingObject.shared()?.modulesOptional(forPageType: pageType) as? [String]
}
return requestParameters
}
open func performAction(with JSON: [AnyHashable : Any], model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {
guard let model = model as? ActionOpenPageModel else { return }
let requestParameters = requestParamaters(for: model)
do {
if let closure = delegateObject?.actionDelegate?.handleOpenPage {
// Legacy code will use the old handler function and break the task chain here.
closure(requestParameters, JSON, additionalData)
} else if let operation = try await performRequestAddingClientParameters(with: requestParameters, model: model, delegateObject: delegateObject, additionalData: additionalData) {
await withCheckedContinuation { continuation in
operation.completionBlock = {
continuation.resume()
}
}
if operation.error != nil, let fallbackResponseJson = model.fallbackResponse?.toJSON() {
await runFallback(response: fallbackResponseJson, requestParameters: requestParameters, delegateObject: delegateObject, additionalData: additionalData)
}
}
} catch {
try handle(error: error, model: model, delegateObject: delegateObject)
}
}
/// Given backup JSON data, run it through the load handler.
fileprivate func runFallback(response: JSONDictionary, requestParameters: MVMCoreRequestParameters, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async {
guard let loadHandler = MVMCoreLoadHandler.sharedGlobal(), let fallbackLoadObject = MVMCoreLoadObject(requestParameters: requestParameters, dataForPage: additionalData, delegateObject: delegateObject)
else { return }
let (loadObject, errorObject) = await MVMCoreLoadRequestOperation.processJSON(fromServer: response, loadObject: fallbackLoadObject)
if let errorObject {
MVMCoreLoggingHandler.shared()?.addError(toLog: errorObject)
} else {
let operation = loadHandler.loadObject(loadObject)
await withCheckedContinuation { continuation in
operation.completionBlock = {
continuation.resume()
}
}
}
}
open func execute(with model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {
guard let model = model as? ActionOpenPageModel else { return }
do {
// Pass through the old function for legacy open page.
let json = try MVMCoreActionHandler.convertActionToJSON(model)
try await performAction(with: json, model: model, delegateObject: delegateObject, additionalData: additionalData)
} catch {
try handle(error: error, model: model, delegateObject: delegateObject)
}
}
/// Adds client parameters and makes calls performRequest()
open func performRequestAddingClientParameters(with requestParameters: MVMCoreRequestParameters, model: ActionOpenPageModel, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws -> MVMCoreLoadRequestOperation? {
let actionUUID = MVMCoreActionHandler.getUUID(additionalData: additionalData) ?? UUID().uuidString
requestParameters.identifier = actionUUID
if !requestParameters.backgroundRequest, let pageType = requestParameters.pageType {
MVMCoreLoggingHandler.shared()?.logCoreEvent(.pageStarted(pageType: pageType, requestUUID: actionUUID))
}
// Adds any client parameters to the request parameters.
if let parametersToFetch = model.clientParameters,
let fetchedParameters = await ClientParameterHandler().getClientParameters(
with: parametersToFetch,
requestParameters: requestParameters.parameters as? [String : Any] ?? [:],
actionId: actionUUID,
showLoadingOverlay: !requestParameters.backgroundRequest) {
requestParameters.add(fetchedParameters)
}
try Task.checkCancellation()
let coreLoadRequestOperation = MVMCoreLoadHandler.sharedGlobal()?.loadRequest(requestParameters, dataForPage: additionalData, delegateObject: delegateObject)
coreLoadRequestOperation?.identifier = actionUUID
return coreLoadRequestOperation
}
/// Ensures background requests do not have showing errors.
private func handle(error: Error, model: ActionOpenPageModel, delegateObject: DelegateObject?) throws {
switch error {
case MVMCoreError.errorObject(let errorObject):
errorObject.silentError = model.background == true
throw MVMCoreError.errorObject(errorObject)
default:
let errorObject = MVMCoreErrorObject.createErrorObject(for: error, location: MVMCoreActionHandler.getErrorLocation(with: delegateObject?.actionDelegate, actionType: model.actionType))!
errorObject.silentError = model.background == true
throw MVMCoreError.errorObject(errorObject)
}
}
}
public extension ClientParameterHandler {
/// Iterates through the clientParameters list. Gets values from the individual handlers and attaches the parameters to extraParameters.
func getClientParameters(with model: ClientParameterModel, requestParameters: [String: Any], actionId: String, showLoadingOverlay: Bool) async -> [String: Any]? {
if showLoadingOverlay {
MVMCoreLoadingOverlayHandler.sharedLoadingOverlay()?.startLoading()
}
defer {
if showLoadingOverlay {
MVMCoreLoadingOverlayHandler.sharedLoadingOverlay()?.stopLoading(true)
}
}
return await getParameters(with: model, requestParameters: requestParameters, actionId: actionId)
}
}

View File

@ -0,0 +1,145 @@
//
// ActionModel.swift
// MVMCore
//
// Created by Suresh, Kamlesh on 10/3/19.
// Copyright © 2019 Suresh, Kamlesh. All rights reserved.
//
import Foundation
public struct ActionOpenPageModel: ActionModelProtocol, ActionOpenPageProtocol, ClientParameterActionProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public static var identifier: String = "openPage"
public var actionType: String = identifier
public var pageType: String
public var modules: [String]?
public var baseURL: URL?
public var appContext: String?
public var requestURL: URL?
public var extraParameters: JSONValueDictionary?
public var analyticsData: JSONValueDictionary?
public var presentationStyle: String?
public var tabBarIndex: Int?
public var background: Bool?
public var clientParameters: ClientParameterModel?
public var customTimeoutTime: TimeInterval?
public var fallbackResponse: JSONValueDictionary?
public var requestParameters: MVMCoreRequestParameters
//--------------------------------------------------
// MARK: - Initialzier
//--------------------------------------------------
public init(pageType: String, presentationStyle: String? = nil, extraParameters: JSONValueDictionary? = nil, analyticsData: JSONValueDictionary? = nil, tabBarIndex: Int? = nil, background: Bool? = nil) {
self.pageType = pageType
self.presentationStyle = presentationStyle
self.extraParameters = extraParameters
self.analyticsData = analyticsData
self.tabBarIndex = tabBarIndex
self.background = background
requestParameters = MVMCoreRequestParameters(pageType: pageType, extraParameters: extraParameters.toJSON())!
if let background = background {
requestParameters.backgroundRequest = background
}
requestParameters.actionMap = toJSON()
}
//--------------------------------------------------
// MARK: - Codable
//--------------------------------------------------
private enum CodingKeys: String, CodingKey {
case actionType
case pageType
case modules
case baseURL
case appContext
case requestURL
case extraParameters
case analyticsData
case presentationStyle
case tabBarIndex
case background
case clientParameters
case customTimeoutTime
case fallbackResponse
}
public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
pageType = try typeContainer.decode(String.self, forKey: .pageType)
baseURL = try typeContainer.decodeIfPresent(URL.self, forKey: .baseURL)
appContext = try typeContainer.decodeIfPresent(String.self, forKey: .appContext)
requestURL = try typeContainer.decodeIfPresent(URL.self, forKey: .requestURL)
modules = try typeContainer.decodeIfPresent([String].self, forKey: .modules)
presentationStyle = try typeContainer.decodeIfPresent(String.self, forKey: .presentationStyle)
tabBarIndex = try typeContainer.decodeIfPresent(Int.self, forKey: .tabBarIndex)
background = try typeContainer.decodeIfPresent(Bool.self, forKey: .background)
clientParameters = try typeContainer.decodeIfPresent(ClientParameterModel.self, forKey: .clientParameters)
customTimeoutTime = try typeContainer.decodeIfPresent(TimeInterval.self, forKey: .customTimeoutTime)
extraParameters = try typeContainer.decodeIfPresent(JSONValueDictionary.self, forKey: .extraParameters)
analyticsData = try typeContainer.decodeIfPresent(JSONValueDictionary.self, forKey: .analyticsData)
fallbackResponse = try typeContainer.decodeIfPresent(JSONValueDictionary.self, forKey: .fallbackResponse)
requestParameters = MVMCoreRequestParameters(pageType: pageType, additionalModules: modules ?? [], extraParameters: extraParameters.toJSON())!
requestParameters.contextRoot = appContext
requestParameters.alternateBaseURL = baseURL
requestParameters.url = requestURL
requestParameters.customTimeoutTime = customTimeoutTime as NSNumber?
if let background = background {
requestParameters.backgroundRequest = background
}
requestParameters.actionMap = toJSON()
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(pageType, forKey: .pageType)
try container.encode(actionType, forKey: .actionType)
try container.encodeIfPresent(baseURL, forKey: .baseURL)
try container.encodeIfPresent(appContext, forKey: .appContext)
try container.encodeIfPresent(requestURL, forKey: .requestURL)
try container.encodeIfPresent(modules, forKey: .modules)
try container.encodeIfPresent(presentationStyle, forKey: .presentationStyle)
try container.encodeIfPresent(tabBarIndex, forKey: .tabBarIndex)
try container.encodeIfPresent(background, forKey: .background)
try container.encodeIfPresent(clientParameters, forKey: .clientParameters)
try container.encodeIfPresent(customTimeoutTime, forKey: .customTimeoutTime)
try container.encodeIfPresent(extraParameters, forKey: .extraParameters)
try container.encodeIfPresent(analyticsData, forKey: .analyticsData)
try container.encodeIfPresent(fallbackResponse, forKey: .fallbackResponse)
}
public func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false }
return pageType == model.pageType
&& baseURL == model.baseURL
&& appContext == model.appContext
&& requestURL == model.requestURL
&& modules == model.modules
&& presentationStyle == model.presentationStyle
&& tabBarIndex == model.tabBarIndex
&& background == model.background
&& clientParameters == model.clientParameters
&& customTimeoutTime == model.customTimeoutTime
&& extraParameters == model.extraParameters
&& analyticsData == model.analyticsData
&& fallbackResponse == model.fallbackResponse
}
}
extension ActionOpenPageModel: CustomDebugStringConvertible {
public var debugDescription: String {
if let requestURL {
return "\(Self.self) for \(pageType) @ \(requestURL)"
} else {
return "\(Self.self) for \(pageType)"
}
}
}

View File

@ -0,0 +1,33 @@
//
// ActionOpenSMSHandler.swift
// MVMCore
//
// Created by Scott Pfeil on 6/30/22.
// Copyright © 2022 myverizon. All rights reserved.
//
import Foundation
extension String {
public enum StringError: Error {
case addingPercentEncoding(string: String)
}
func addingPercentEncodingThrowable(withAllowedCharacters characterSet: CharacterSet) throws -> String {
guard let string = addingPercentEncoding(withAllowedCharacters: characterSet) else {
throw StringError.addingPercentEncoding(string: self)
}
return string
}
}
open class ActionOpenSMSHandler: MVMCoreActionHandlerProtocol {
required public init() {}
open func execute(with model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {
guard let model = model as? ActionOpenSMSModel else { return }
// https://developer.apple.com/library/archive/featuredarticles/iPhoneURLScheme_Reference/SMSLinks/SMSLinks.html#:~:text=Note%3A%20SMS%20text%20links%20are,number%20of%20the%20SMS%20message.
let string = try "sms:\(model.phoneNumber)&body=\(model.message ?? "")".addingPercentEncodingThrowable(withAllowedCharacters: CharacterSet.urlQueryAllowed)
try await ActionOpenUrlHandler.openURL(with: string)
}
}

View File

@ -7,7 +7,7 @@
//
@objcMembers public class ActionOpenSMSModel: ActionModelProtocol {
public struct ActionOpenSMSModel: ActionModelProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
@ -30,4 +30,13 @@
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.phoneNumber == phoneNumber
&& model.message == message
}
}

View File

@ -0,0 +1,96 @@
//
// ActionOpenUrlHandler.swift
// MVMCore
//
// Created by Scott Pfeil on 12/23/21.
// Copyright © 2021 myverizon. All rights reserved.
//
import Foundation
public extension URL {
enum URLError: MVMError, CustomStringConvertible {
case invalid(string: String)
public var description: String {
switch self {
case URLError.invalid(let string):
return "Failed to create url with string: \(string)"
}
}
}
static func createURL(with string: String) throws -> URL {
guard let url = URL(string: string) else {
throw URL.URLError.invalid(string: string)
}
return url
}
}
open class ActionOpenUrlHandler: MVMCoreJSONActionHandlerProtocol {
required public init() {}
public enum URLError: MVMError, CustomStringConvertible {
case failedToOpen(url: URL)
public var description: String {
switch self {
case ActionOpenUrlHandler.URLError.failedToOpen(let url):
return "Failed to open url: \(url.absoluteString)"
}
}
public var errorCode: Int {
return ErrorCode.linkawayFailed.rawValue
}
}
/// Creates a url and calls open(url: URL)
public static func openURL(with string: String) async throws {
let url = try URL.createURL(with: string)
try await ActionOpenUrlHandler.open(url: url)
}
/// Opens the url using UIApplication open(url:). Throws URLError.failedToOpen if it fails.
@MainActor
public static func open(url: URL, options: [UIApplication.OpenExternalURLOptionsKey : Any] = [:]) async throws {
try await withCheckedThrowingContinuation { continuation in
UIApplication.shared.open(url, options: options) { successful in
if successful {
continuation.resume()
} else {
continuation.resume(throwing: ActionOpenUrlHandler.URLError.failedToOpen(url: url))
}
}
} as Void
}
open func performAction(with JSON: [AnyHashable : Any], model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {
try await execute(with: model, delegateObject: delegateObject, additionalData: additionalData)
}
open func execute(with model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {
guard let model = model as? ActionOpenUrlModel else { return }
// Try loading the app url first, otherwise fall back to browser url.
if let appURL = model.appURL {
do {
try await ActionOpenUrlHandler.open(url: appURL, options: model.appURLOptions?.options ?? [:])
return
} catch {
// Log error and continue
MVMCoreLoggingHandler.shared()?.handleDebugMessage("Failed to open app url: \(appURL)")
let isUsingUniversalLinksOnly = model.appURLOptions?.options[.universalLinksOnly] as? Bool ?? false
if !isUsingUniversalLinksOnly, let errorObject = MVMCoreErrorObject.createErrorObject(for: error, location: MVMCoreActionHandler.getErrorLocation(with: delegateObject?.actionDelegate, actionType: model.actionType)) {
MVMCoreLoggingHandler.shared()?.addError(toLog: errorObject)
}
}
}
try await openURL(model: model, additionalData: additionalData, delegateObject: delegateObject)
}
open func openURL(model: ActionOpenUrlModel, additionalData: [AnyHashable : Any]?, delegateObject: DelegateObject?) async throws {
try await ActionOpenUrlHandler.open(url: model.browserUrl)
}
}

View File

@ -0,0 +1,72 @@
//
// ActionOpenUrlModel.swift
// MVMCore
//
// Created by Suresh, Kamlesh on 12/16/19.
// Copyright © 2019 myverizon. All rights reserved.
//
import Foundation
open class ActionOpenUrlModel: ActionModelProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
open class var identifier: String { "openURL" }
open var actionType: String = ActionOpenUrlModel.identifier
open var browserUrl: URL
open var appURL: URL?
open var appURLOptions: OpenUrlOptionsModel?
open var extraParameters: JSONValueDictionary?
open var analyticsData: JSONValueDictionary?
//--------------------------------------------------
// MARK: - Initialzier
//--------------------------------------------------
public init(browserUrl: URL) {
self.browserUrl = browserUrl
}
//--------------------------------------------------
// MARK: - Codable
//--------------------------------------------------
private enum CodingKeys: String, CodingKey {
case actionType
case browserUrl
case appURL
case appURLOptions
case extraParameters
case analyticsData
}
required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
browserUrl = try typeContainer.decode(URL.self, forKey: .browserUrl)
appURL = try typeContainer.decodeIfPresent(URL.self, forKey: .appURL)
appURLOptions = try typeContainer.decodeIfPresent(OpenUrlOptionsModel.self, forKey: .appURLOptions)
extraParameters = try typeContainer.decodeIfPresent(JSONValueDictionary.self, forKey: .extraParameters)
analyticsData = try typeContainer.decodeIfPresent(JSONValueDictionary.self, forKey: .analyticsData)
}
open func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(actionType, forKey: .actionType)
try container.encode(browserUrl, forKey: .browserUrl)
try container.encodeIfPresent(appURL, forKey: .appURL)
try container.encodeIfPresent(appURLOptions, forKey: .appURLOptions)
try container.encodeIfPresent(extraParameters, forKey: .extraParameters)
try container.encodeIfPresent(analyticsData, forKey: .analyticsData)
}
public func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false }
return extraParameters == model.extraParameters
&& analyticsData == model.analyticsData
&& browserUrl == model.browserUrl
&& appURL == model.appURL
&& appURLOptions == model.appURLOptions
}
}

View File

@ -0,0 +1,47 @@
//
// ActionPreviousSubmitHandler.swift
// MVMCore
//
// Created by Scott Pfeil on 6/30/22.
// Copyright © 2022 myverizon. All rights reserved.
//
import Foundation
/// Makes the previous request, needs the delegate for this
open class ActionPreviousSubmitHandler: MVMCoreJSONActionHandlerProtocol {
required public init() {}
private var json: [AnyHashable: Any]?
// Conform to MVMCoreJSONActionHandlerProtocol To allow for legacy handleOpenPage delegate
open func performAction(with JSON: [AnyHashable : Any], model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {
json = JSON
try await execute(with: model, delegateObject: delegateObject, additionalData: additionalData)
}
open func execute(with model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {
guard let loadObject = (delegateObject?.actionDelegate as? MVMCoreViewControllerProtocol)?.loadObject,
let previousRequest = loadObject?.requestParameters else { return }
// Combines data
var data = loadObject?.dataForPage
if let previousData = data,
let additionalData = additionalData {
data = previousData.merging(additionalData) {(new,_) in new}
}
if let _ = delegateObject?.actionDelegate?.handleOpenPage {
// Legacy handling. Will lose the task.
let json = try json ?? MVMCoreActionHandler.convertActionToJSON(model)
delegateObject?.actionDelegate?.handleOpenPage?(for: previousRequest, actionInformation: json, additionalData: additionalData)
} else {
guard let operation = MVMCoreLoadHandler.sharedGlobal()?.loadRequest(previousRequest, dataForPage: additionalData, delegateObject: delegateObject) else { return }
await withCheckedContinuation { continuation in
operation.completionBlock = {
continuation.resume()
}
}
}
}
}

View File

@ -7,7 +7,7 @@
//
@objcMembers public class ActionPreviousSubmitModel: ActionModelProtocol {
public struct ActionPreviousSubmitModel: ActionModelProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
@ -25,4 +25,12 @@
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

@ -0,0 +1,42 @@
//
// ActionRestartHandler.swift
// MVMCore
//
// Created by Scott Pfeil on 6/30/22.
// Copyright © 2022 myverizon. All rights reserved.
//
import Foundation
open class ActionRestartHandler: MVMCoreActionHandlerProtocol {
required public init() {}
open func execute(with model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {
guard let model = model as? ActionRestartModel else { return }
let _: Void = try await withCheckedThrowingContinuation { continuation in
// Invalidates the session before restarting.
Task { @MainActor in
MVMCoreSessionTimeHandler.shared().invalidateSession({ error in
if let error = error {
guard error.code != NSURLErrorCancelled else {
continuation.resume()
return
}
continuation.resume(throwing: MVMCoreError.errorObject(error))
return
}
if let sessionObject = MVMCoreSessionObject.sharedGlobal() {
if model.hardReset {
sessionObject.clearPersistentCache()
}
// Restarts the app (forcing any passed in page types).
sessionObject.restartSession(withPageType: model.pageType, request: model.requestURL, parameters: model.extraParameters?.toJSON(), clearAllVariables: true)
}
continuation.resume()
})
}
}
}
}

View File

@ -6,14 +6,17 @@
// Copyright © 2020 myverizon. All rights reserved.
//
import Foundation
@objcMembers public class ActionRestartModel: ActionModelProtocol {
public struct ActionRestartModel: ActionModelProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public static var identifier: String = "restart"
public var actionType: String = ActionRestartModel.identifier
public var requestURL: URL?
@DecodableDefault.True public var hardReset: Bool
public var extraParameters: JSONValueDictionary?
public var analyticsData: JSONValueDictionary?
@ -24,9 +27,20 @@
// MARK: - Initializer
//--------------------------------------------------
public init(_ pageType: String? = nil, _ extraParameters: JSONValueDictionary? = nil, _ analyticsData: JSONValueDictionary? = nil) {
public init(_ pageType: String? = nil, _ requestUrl: URL? = nil, hardReset: Bool? = nil, _ extraParameters: JSONValueDictionary? = nil, _ analyticsData: JSONValueDictionary? = nil) {
self.pageType = pageType
self.requestURL = requestUrl
self.extraParameters = extraParameters
self.analyticsData = analyticsData
self.hardReset = hardReset ?? true
}
public func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false }
return extraParameters == model.extraParameters
&& analyticsData == model.analyticsData
&& requestURL == model.requestURL
&& pageType == model.pageType
&& hardReset == model.hardReset
}
}

View File

@ -0,0 +1,17 @@
//
// ActionSettingHandler.swift
// MVMCore
//
// Created by Scott Pfeil on 6/30/22.
// Copyright © 2022 myverizon. All rights reserved.
//
import Foundation
open class ActionSettingHandler: MVMCoreActionHandlerProtocol {
required public init() {}
open func execute(with model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws {
try await ActionOpenUrlHandler.openURL(with: await UIApplication.openSettingsURLString)
}
}

View File

@ -7,7 +7,7 @@
//
@objcMembers public class ActionSettingModel: ActionModelProtocol {
public struct ActionSettingModel: ActionModelProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
@ -25,4 +25,10 @@
self.extraParameters = extraParameters
self.analyticsData = analyticsData
}
public func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false }
return extraParameters == model.extraParameters
&& analyticsData == model.analyticsData
}
}

View File

@ -0,0 +1,54 @@
//
// ActionShareHandler.swift
// MVMCore
//
// Created by Scott Pfeil on 7/14/22.
// Copyright © 2022 myverizon. All rights reserved.
//
import Foundation
open class ActionShareHandler: MVMCoreActionHandlerProtocol {
required public init() {}
open func execute(with model: ActionModelProtocol, delegateObject: DelegateObject? = nil, additionalData: [AnyHashable: Any]? = nil) async throws {
guard let model = model as? ActionShareModel else { return }
try await shareWith(activityItems: model.items.map { $0.value }, model: model)
}
@MainActor
open func shareWith(activityItems: [Any], model: ActionShareModel, delegateObject: DelegateObject? = nil) async throws {
try await withCheckedThrowingContinuation { continuation in
let controller = UIActivityViewController(activityItems: activityItems, applicationActivities: nil)
controller.popoverPresentationController?.sourceView = NavigationHandler.shared().viewControllerToPresentOn?.view
var originPoint: CGPoint = .zero
if let view = NavigationHandler.shared().viewControllerToPresentOn?.view {
originPoint = CGPoint(x: view.frame.midX, y: view.frame.maxY)
}
controller.popoverPresentationController?.sourceRect.origin = originPoint
controller.completionWithItemsHandler = {(activityType: UIActivity.ActivityType?, completed: Bool, returnedItems: [Any]?, error: Error?) in
if completed {
// Activity was completed, considered finished.
continuation.resume()
} else if let error = error {
// Activity sharing failed.
continuation.resume(throwing: error)
} else {
// Activity was probably cancelled
if #available(iOS 16.4, *) {
continuation.resume()
} else if let _ = activityType {
// Pre iOS 16.4, this block gets called multiple times. Each time a specific activityType was selected and was cancelled, and when the whole share activity itself is cancelled.
return
} else {
continuation.resume()
}
}
}
Task(priority: .high) {
await NavigationHandler.shared().present(viewController: controller)
}
} as Void
}
}

View File

@ -0,0 +1,131 @@
//
// ActionShareModel.swift
// MVMCore
//
// Created by Kevin Christiano on 2/18/20.
// Copyright © 2020 myverizon. All rights reserved.
//
public struct ActionShareItemModel: Codable, Equatable {
public enum SharedType: String, Codable {
case text
case url
}
public var type: SharedType
public var value: AnyHashable // Common Equatable type between String and URL.
private enum CodingKeys: String, CodingKey {
case type
case value
}
public init(type: SharedType, value: AnyHashable) {
self.type = type
self.value = value
}
public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
type = try typeContainer.decode(SharedType.self, forKey: .type)
switch type {
case .text:
value = try typeContainer.decode(String.self, forKey: .value)
case .url:
value = try typeContainer.decode(URL.self, forKey: .value)
}
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(type, forKey: .type)
switch type {
case .text:
try container.encode(value as! String, forKey: .value)
case .url:
try container.encode(value as! URL, forKey: .value)
}
}
public static func == (lhs: ActionShareItemModel, rhs: ActionShareItemModel) -> Bool {
return lhs.type == rhs.type
&& lhs.value == rhs.value
}
}
public struct ActionShareModel: ActionModelProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public static var identifier: String = "share"
public var actionType: String = ActionShareModel.identifier
public var items: [ActionShareItemModel]
public var extraParameters: JSONValueDictionary?
public var analyticsData: JSONValueDictionary?
//--------------------------------------------------
// MARK: - Initializer
//--------------------------------------------------
public init(items: [ActionShareItemModel], _ extraParameters: JSONValueDictionary? = nil, _ analyticsData: JSONValueDictionary? = nil) {
self.items = items
self.extraParameters = extraParameters
self.analyticsData = analyticsData
}
//--------------------------------------------------
// MARK: - Codable
//--------------------------------------------------
private enum CodingKeys: String, CodingKey {
case actionType
case items
case sharedType
case sharedText
}
private enum DeprecatedCodingKeys: String, CodingKey {
case sharedType
case sharedText
}
public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
if let items = try typeContainer.decodeIfPresent([ActionShareItemModel].self, forKey: .items) {
self.init(items: items)
} else {
// Legacy
try self.init(deprecatedFrom: decoder)
}
}
private init(deprecatedFrom decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: DeprecatedCodingKeys.self)
let type = try typeContainer.decode(ActionShareItemModel.SharedType.self, forKey: .sharedType)
var value: AnyHashable
switch type {
case .url:
value = try typeContainer.decode(URL.self, forKey: .sharedText)
default:
value = try typeContainer.decode(String.self, forKey: .sharedText)
}
items = [ActionShareItemModel(type: type, value: value)]
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(actionType, forKey: .actionType)
try container.encode(items, forKey: .items)
}
public func isEqual(to model: any ModelComparisonProtocol) -> Bool {
guard let model = model as? Self else { return false }
return extraParameters == model.extraParameters
&& analyticsData == model.analyticsData
&& items == model.items
}
}

View File

@ -1,16 +0,0 @@
//
// MVMCoreActionDelegateProtocolExtension.swift
// MVMCore
//
// Created by Scott Pfeil on 1/22/21.
// Copyright © 2021 myverizon. All rights reserved.
//
import Foundation
public extension MVMCoreActionDelegateProtocol {
/// Handles any action errors.
func handleAction(error: MVMCoreErrorObject, action: ActionModelProtocol, additionalData: [AnyHashable: Any]?) {
MVMCoreActionHandler.shared()?.defaultHandleActionError(error, additionalData: additionalData)
}
}

View File

@ -24,9 +24,6 @@
// Handles the back actions. Can overwrite for special loading.
- (void)handleBackAction:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData;
// Prepares to call the previous submit request again. Can overwrite for special loading. Be sure to call submit() block to perform the actual load.
- (void)prepareRequestForPreviousSubmission:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData submit:(nonnull void (^)(MVMCoreRequestParameters * _Nonnull requestParameters, NSDictionary * _Nullable dataForPage))submit;
// Handles the linkaway action. Call the block to continue to linkaway.
- (void)shouldLinkAwayWithURL:(nullable NSURL *)URL appURL:(nullable NSURL *)appURL actionInformation:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData linkAwayBlock:(nonnull void (^)(NSURL * _Nullable appURL, NSURL * _Nullable URL, NSDictionary * _Nullable actionInformation, NSDictionary * _Nullable additionalData))linkAwayBlock;
@ -36,9 +33,6 @@
// Handles any unknown action types. Can overwrite for more specific handling.
- (void)handleUnknownActionType:(nullable NSString *)actionType actionInformation:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData;
// Handles any action errors. Can overwrite for more specific handling.
- (void)handleActionError:(nonnull MVMCoreErrorObject *)error additionalData:(nullable NSDictionary *)additionalData;
// Lets the delegate know that another internal module app is about to be launched
- (void)prepareForOpenOtherAppModule:(nullable NSString *)module;

View File

@ -1,80 +0,0 @@
//
// MVMCoreActionHandler+Extension.swift
// MVMCore
//
// Created by Scott Pfeil on 1/22/21.
// Copyright © 2021 myverizon. All rights reserved.
//
import Foundation
public protocol MVMCoreActionHandlerProtocol: ModelHandlerProtocol {
init()
func handleAction(_ model: ActionModelProtocol, additionalData: [AnyHashable : Any]?, delegateObject: DelegateObject?)
}
public extension MVMCoreActionHandler {
/// Converts the action to json for old action handler to handle.
func convertActionToJSON(_ model: ActionModelProtocol, delegateObject: DelegateObject?) -> [AnyHashable: Any]? {
do {
let data = try model.encode()
guard let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [AnyHashable: Any] else {
throw ModelRegistry.Error.decoderError
}
return json
} catch {
if let errorObject = MVMCoreErrorObject.createErrorObject(for: error, location: "") {
delegateObject?.actionDelegate?.handleAction(error: errorObject, action: model, additionalData: model.extraParameters) ?? MVMCoreActionHandler.shared()?.defaultHandleActionError(errorObject, additionalData: model.extraParameters)
}
return nil
}
}
@objc func hasActionHandler(actionType: String?, actionInformation: [String: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) -> Bool {
guard //ensure there is a actinType
let actionType = actionType,
//ensure there is a serialized version of the Action
let actionInformation = actionInformation,
//esnure the actionModelType
let actionModelType = ModelRegistry.getType(for: actionType, with: ActionModelProtocol.self),
//ensure there is handlerType for the action of MVMCoreActionHandlerProtocol
let actionHandlerType = try? ModelRegistry.getHandlerType(for: actionModelType) as? MVMCoreActionHandlerProtocol.Type
else { return false }
do {
//ensure the decoded actionModel is of ActionModelProtocol
guard let actionModel = try actionModelType.decode(jsonDict: actionInformation) as? ActionModelProtocol else {
throw ModelRegistry.Error.decoderOther(message: "Could not decode to ActionModelProtocol")
}
//create the handler since we know it can initialize
let actionHandler = actionHandlerType.init()
//call the handleAction of the handler
actionHandler.handleAction(actionModel, additionalData: additionalData, delegateObject: delegateObject)
} catch {
//log the error
if let errorObject = MVMCoreErrorObject.createErrorObject(for: error, location: "") {
MVMCoreActionHandler.shared()?.defaultHandleActionError(errorObject, additionalData: additionalData)
}
}
//found the handler, returning true no matter if there was a failure in the do...catch
return true
}
/// Start action on current thread.
func syncHandleAction(with model: ActionModelProtocol, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) {
guard let json = convertActionToJSON(model, delegateObject: delegateObject) else { return }
synchronouslyHandleAction(model.actionType, actionInformation: json, additionalData: additionalData, delegateObject: delegateObject)
}
/// Start action on dispatched background thread.
func asyncHandleAction(with model: ActionModelProtocol, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) {
guard let json = convertActionToJSON(model, delegateObject: delegateObject) else { return }
handleAction(model.actionType, actionInformation: json, additionalData: additionalData, delegateObject: delegateObject)
}
}

View File

@ -1,116 +0,0 @@
//
// MVMCoreActionHandler.h
// myverizon
//
// Created by Scott Pfeil on 11/20/15.
// Copyright © 2015 Verizon Wireless. All rights reserved.
//
// Can be subclassed to handle app specific actions as well.
#import <Foundation/Foundation.h>
#import <MVMCore/MVMCoreActionDelegateProtocol.h>
#import <MVMCore/MVMCoreLoadDelegateProtocol.h>
#import <MVMCore/MVMCorePresentationDelegateProtocol.h>
@class DelegateObject;
extern NSString * _Nonnull const KeyActionType;
extern NSString * _Nonnull const KeyActionTypeLinkAway;
extern NSString * _Nonnull const KeyActionTypeOpen;
@interface MVMCoreActionHandler : NSObject
/// Returns the shared action handler
+ (nullable instancetype)sharedActionHandler;
/// Convenience function for handling actions. This will pull action and pageInfo out of the dictionary and call handleAction: actionInformation: with those values
- (void)handleActionWithDictionary:(nullable NSDictionary *)dictionary additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject;
/// Asynchronously handles action (dispatches and calls below function). Used by server driven user actions..
- (void)handleAction:(nullable NSString *)actionType actionInformation:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject;
/// Synchronously handles action. Used by server driven user actions..
- (void)synchronouslyHandleAction:(nullable NSString *)actionType actionInformation:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject;
/// Iterates through the clientParameters list. Gets values from the individual handlers and attaches the parameters to extraParameters.
- (void)getClientParameter:(nullable NSDictionary *)clientParametersMap requestParameters:(nullable NSDictionary *)requestParameters showLoadingOverlay:(BOOL)showLoadingOverlay completionHandler:(nonnull void (^)(NSDictionary * _Nullable jsonDictionary))completionHandler;
#pragma mark - Actions
/// by default, returns the original RequestParameter that passed in. Can be overriden for some generic updates to the RequestParameter before handle open page action gets called.
- (void)updateRequestParametersBeforeHandleOpenPageAction:(nonnull MVMCoreRequestParameters *)requestParameters callBack:(void (^_Nonnull)(MVMCoreRequestParameters * _Nonnull requestParameters))callback;
/// Logs the action. Currently is not action information driven... depends on delegate.
- (void)logAction:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject;
/// Tries to open a page
- (void)openPageAction:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject;
/// restarts the app
- (void)restartAction:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject;
/// Goes back
- (void)backAction:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject;
/// Opens Text Message
- (void)smsAction:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject;
/// Makes a phone call
- (void)callAction:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject;
/// Makes the previous request, needs the delegate for this
- (void)previousSubmitAction:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject;
/// Redirects to another experience
- (void)redirectAction:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject;
/// Cancels (like in a popup)
- (void)cancelAction:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject;
/// Goes to settings app
- (void)settingsAction:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject;
/// Performs multiple actions
- (void)actions:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject;
/// Subclass this to handle other custom actions. Return YES if handled, and NO if not.
- (BOOL)handleOtherActions:(nullable NSString *)actionType actionInformation:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject;
/// Last chance to handle unknown actions before throwing an error
- (void)unknownAction:(nullable NSString *)actionType actionInformation:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject;
/// Handles action errors.
- (void)handleActionError:(nullable MVMCoreErrorObject *)error actionInformation:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject;
#pragma mark - Link away action
/// Links away to app or browser
- (void)linkAwayAction:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject;
/// Can subclass to add to urls if needed at global level (delegate is also called)
- (void)prepareLinkAwayWithURL:(nullable NSURL *)url appURL:(nullable NSURL *)appURL actionInformation:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject;
/// Opens the url
- (void)openURL:(nullable NSURL *)url appURL:(nullable NSURL *)appURL actionInformation:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject;
/// opens the url in a webview.
- (void)openURLInWebView:(nullable NSURL *)url actionInformation:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject;
#pragma mark - Default Action Protocol Functions
/// Currently no default log action but this will eventually be server driven.
+ (void)defaultLogAction:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject;
/// Sends the request to the load handler.
+ (void)defaultHandleOpenPageForRequestParameters:(nonnull MVMCoreRequestParameters *)requestParameters actionInformation:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject;
/// By default, throws an error, calling defaultHandleActionError.
+ (void)defaultHandleUnknownActionType:(nullable NSString *)actionType actionInformation:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject;
/// Logs the error.
- (void)defaultHandleActionError:(nonnull MVMCoreErrorObject *)error additionalData:(nullable NSDictionary *)additionalData;
#pragma mark - Deprecated
/// Convenience function for handling actions. This will pull action and pageInfo out of the dictionary and call handleAction: actionInformation: with those values
- (void)handleActionWithDictionary:(nullable NSDictionary *)dictionary additionalData:(nullable NSDictionary *)additionalData delegate:(nullable NSObject <MVMCoreLoadDelegateProtocol,MVMCorePresentationDelegateProtocol,MVMCoreActionDelegateProtocol>*)delegate __deprecated;
@end

View File

@ -1,586 +0,0 @@
//
// MVMCoreActionHandler.m
// myverizon
//
// Created by Scott Pfeil on 11/20/15.
// Copyright © 2015 Verizon Wireless. All rights reserved.
//
#import <MVMCore/MVMCoreActionHandler.h>
#import "MVMCoreLoggingHandler.h"
#import "MVMCoreCache.h"
#import "MVMCoreSessionTimeHandler.h"
#import "MVMCoreLoadHandler.h"
#import "MVMCoreNavigationHandler.h"
#import "MVMCoreDispatchUtility.h"
#import "NSDictionary+MFConvenience.h"
#import "MVMCoreGetterUtility.h"
#import "MVMCoreRequestParameters.h"
#import "MVMCoreErrorObject.h"
#import "MVMCoreJSONConstants.h"
#import "MVMCoreHardcodedStringsConstants.h"
#import "MVMCoreErrorConstants.h"
#import "MVMCoreActionUtility.h"
#import "MVMCoreSessionObject.h"
#import "MVMCoreObject.h"
#import "MVMCorePresentationDelegateProtocol.h"
#import <SafariServices/SafariServices.h>
#import <MVMCore/MVMCore-Swift.h>
#import "MVMCoreLoadingOverlayHandler.h"
#import <ContactsUI/ContactsUI.h>
NSString * const KeyActionType = @"actionType";
NSString * const KeyActionTypeLinkAway = @"openURL";
NSString * const KeyActionTypeOpen = @"openPage";
@interface MVMCoreActionHandler() <CNContactViewControllerDelegate, CNContactPickerDelegate>
@end
@implementation MVMCoreActionHandler
+ (nullable instancetype)sharedActionHandler {
return [MVMCoreActionUtility initializerClassCheck:[MVMCoreObject sharedInstance].actionHandler classToVerify:self];
}
- (void)handleActionWithDictionary:(nullable NSDictionary *)dictionary additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject {
NSString *action = [dictionary stringForKey:KeyActionType];
[self handleAction:action actionInformation:dictionary additionalData:additionalData delegateObject:delegateObject];
}
- (void)handleAction:(nullable NSString *)actionType actionInformation:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self synchronouslyHandleAction:actionType actionInformation:actionInformation additionalData:additionalData delegateObject:delegateObject];
});
}
- (void)synchronouslyHandleAction:(nullable NSString *)actionType actionInformation:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject {
// Logs the action.
[self logAction:actionInformation additionalData:additionalData delegateObject:delegateObject];
if ([actionType isEqualToString:KeyActionTypeOpen]) {
[self openPageAction:actionInformation additionalData:additionalData delegateObject:delegateObject];
} else if ([actionType isEqualToString:KeyActionTypeLinkAway]) {
[self linkAwayAction:actionInformation additionalData:additionalData delegateObject:delegateObject];
} else if ([actionType isEqualToString:KeyActionTypeRestart]) {
[self restartAction:actionInformation additionalData:additionalData delegateObject:delegateObject];
} else if ([actionType isEqualToString:KeyActionTypeBack]) {
[self backAction:actionInformation additionalData:additionalData delegateObject:delegateObject];
} else if ([actionType isEqualToString:KeyActionTypeCall]) {
[self callAction:actionInformation additionalData:additionalData delegateObject:delegateObject];
} else if ([actionType isEqualToString:KeyActionTypeSMS]) {
[self smsAction:actionInformation additionalData:additionalData delegateObject:delegateObject];
} else if ([actionType isEqualToString:KeyActionTypeContact]) {
[self contactAction:actionInformation additionalData:additionalData delegateObject:delegateObject];
} else if ([actionType isEqualToString:KeyActionTypeShare]) {
[self shareAction:actionInformation additionalData:additionalData delegateObject:delegateObject];
} else if ([actionType isEqualToString:KeyActionTypePreviousSubmit]) {
[self previousSubmitAction:actionInformation additionalData:additionalData delegateObject:delegateObject];
} else if ([actionType isEqualToString:KeyActionTypeRedirect]) {
[self redirectAction:actionInformation additionalData:additionalData delegateObject:delegateObject];
} else if ([actionType isEqualToString:KeyActionTypeCancel]) {
[self cancelAction:actionInformation additionalData:additionalData delegateObject:delegateObject];
} else if ([actionType isEqualToString:KeyActionTypeSettings]) {
[self settingsAction:actionInformation additionalData:additionalData delegateObject:delegateObject];
} else if ([actionType isEqualToString:KeyActionTypeNoop]) {
} else if ([actionType isEqualToString:KeyActionTypeActions]) {
[self actions:actionInformation additionalData:additionalData delegateObject:delegateObject];
} else if (![self handleOtherActions:actionType actionInformation:actionInformation additionalData:additionalData delegateObject:delegateObject]) {
// not a known action type.
[self unknownAction:actionType actionInformation:actionInformation additionalData:additionalData delegateObject:delegateObject];
}
}
- (void)getClientParameter:(nullable NSDictionary *)clientParametersMap requestParameters:(nullable NSDictionary *)requestParameters showLoadingOverlay:(BOOL)showLoadingOverlay completionHandler:(nonnull void (^)(NSDictionary * _Nullable parameters))completionHandler {
if (!clientParametersMap) {
completionHandler(nil);
return;
}
if (showLoadingOverlay) {
[[MVMCoreLoadingOverlayHandler sharedLoadingOverlay] startLoading];
}
void (^stopLoadingOverlay)(void) = ^(void) {
if (showLoadingOverlay) {
[[MVMCoreLoadingOverlayHandler sharedLoadingOverlay] stopLoading:true];
}
};
NSError *error = nil;
[MVMCoreLoggingHandler logDebugMessageWithDelegate:@"Fetching client parameters"];
ClientParameterHandler *clientParameterHandler = [[ClientParameterHandler alloc] init];
[clientParameterHandler getParametersWith:clientParametersMap
requestParameters:requestParameters
error:&error
completionHandler:^(NSDictionary<NSString *,id> * _Nullable clientParameters) {
[MVMCoreLoggingHandler logDebugMessageWithDelegate:@"Finshed fetching client parameters"];
if (clientParameters) {
stopLoadingOverlay();
completionHandler(clientParameters);
} else {
[MVMCoreLoggingHandler logDebugMessageWithDelegate:@"No client parameters"];
stopLoadingOverlay();
completionHandler(nil);
}
}];
if (error) {
stopLoadingOverlay();
completionHandler(nil);
[MVMCoreLoggingHandler addErrorToLog:[MVMCoreErrorObject createErrorObjectForNSError:error location:@"MVMCoreActionHandler->setClientParameter"]];
}
}
#pragma mark - Actions
- (void)updateRequestParametersBeforeHandleOpenPageAction:(nonnull MVMCoreRequestParameters *)requestParameters callBack:(void (^_Nonnull)(MVMCoreRequestParameters * _Nonnull requestParameters))callback {
//does not do anything by default, can be override
callback(requestParameters);
}
- (void)logAction:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject {
if ([delegateObject.actionDelegate respondsToSelector:@selector(logActionWithActionInformation:additionalData:)]) {
[delegateObject.actionDelegate logActionWithActionInformation:actionInformation additionalData:additionalData];
} else {
[[self class] defaultLogAction:actionInformation additionalData:additionalData delegateObject:delegateObject];
}
}
- (void)openPageAction:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject {
// Loads the given page type.
NSString *pageType = [actionInformation stringForKey:KeyPageType];
if (pageType.length == 0) {
// No page type to load, show error.
MVMCoreErrorObject *error = [[MVMCoreErrorObject alloc] initWithTitle:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorTitle] message:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorUnableToProcess] code:ErrorCodeNoPageType domain:ErrorDomainNative location:[NSString stringWithFormat:@"%@_%@",NSStringFromClass([delegateObject.actionDelegate class]),KeyActionTypeOpen]];
[self handleActionError:error actionInformation:actionInformation additionalData:additionalData delegateObject:delegateObject];
return;
}
MVMCoreRequestParameters *requestParameters = [[MVMCoreRequestParameters alloc] initWithActionMap:actionInformation];
[self updateRequestParametersBeforeHandleOpenPageAction:requestParameters callBack:^(MVMCoreRequestParameters * _Nonnull requestParameters) {
if ([delegateObject.actionDelegate respondsToSelector:@selector(handleOpenPageForRequestParameters:actionInformation:additionalData:)]) {
[delegateObject.actionDelegate handleOpenPageForRequestParameters:requestParameters actionInformation:actionInformation additionalData:additionalData];
} else {
[MVMCoreActionHandler defaultHandleOpenPageForRequestParameters:requestParameters
actionInformation:actionInformation
additionalData:additionalData
delegateObject:delegateObject];
}
}];
}
- (void)shareAction:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject {
NSString *shareType = [actionInformation string:KeyShareType];
NSString *shareText = [actionInformation string:KeyShareText];
if (!shareText || !shareType) {
return;
}
NSArray *shareData = nil;
if ([shareType isEqualToString:@"text"]) {
shareData = @[shareText];
} else if ([shareType isEqualToString:@"url"]) {
NSURL *url = [NSURL URLWithString:shareText];
if (url) {
shareData = @[shareText, url];
} else {
shareData = @[shareText];
}
} else if ([shareType isEqualToString:@"image"]) {
// TODO: Implement image parsing. 🏂
} else if ([shareType isEqualToString:@"file"]) {
// TODO: Implement file parsing. 🌋
}
if (shareData.count > 0) {
[MVMCoreDispatchUtility performBlockOnMainThread:^{
UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:shareData applicationActivities:nil];
void(^activityCompletion)(UIActivityType, BOOL, NSArray*, NSError*) = ^(UIActivityType activityType, BOOL completed, NSArray *returnedItems, NSError *activityError) {
if (activityType == UIActivityTypeCopyToPasteboard) {
[[MVMCoreSessionObject sharedGlobal] copyStringToClipboard:shareText];
}
};
activityViewController.completionWithItemsHandler = activityCompletion;
activityViewController.popoverPresentationController.sourceView = [MVMCoreNavigationHandler sharedNavigationHandler].viewControllerToPresentOn.view;
[[MVMCoreNavigationHandler sharedNavigationHandler] presentViewController:activityViewController animated:YES];
}];
}
}
- (void)restartAction:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject {
// Invalidates the session before restarting.
[[MVMCoreSessionTimeHandler sharedSessionHandler] invalidateSession:^(MVMCoreErrorObject * _Nullable error) {
// Restarts the app (forcing any passed in page types).
if (error.code != NSURLErrorCancelled) {
if (error) {
// Error invalidating.
[self handleActionError:error actionInformation:actionInformation additionalData:additionalData delegateObject:delegateObject];
} else {
// Restart the application with the page type.
NSString *pageType = [actionInformation string:KeyPageType];
NSDictionary *parameters = [actionInformation dict:KeyExtraParameters];
[[MVMCoreSessionObject sharedGlobal] restartSessionWithPageType:pageType parameters:parameters clearAllVariables:YES];
}
}
}];
}
- (void)backAction:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject {
// Go back.
if ([delegateObject.actionDelegate respondsToSelector:@selector(handleBackAction:additionalData:)]) {
[delegateObject.actionDelegate handleBackAction:actionInformation additionalData:additionalData];
} else {
[[MVMCoreNavigationHandler sharedNavigationHandler] removeCurrentViewController];
}
}
- (void)smsAction:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject {
NSString *phoneNumber = [actionInformation stringForKey:@"phoneNumber"];
NSString *message = [actionInformation stringForKey:KeyMessage];
NSString *smsQuery = [NSString stringWithFormat:@"sms:%@&body=%@", phoneNumber, message];
[MVMCoreActionUtility linkAway:[smsQuery stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding] appURLString:nil];
}
- (void)contactAction:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject {
__weak typeof(self) weakSelf = self;
NSString *phoneNumber = [actionInformation string:@"phoneNumber"];
if (!phoneNumber) { return; }
CNMutableContact *contact = [[CNMutableContact alloc] init];
NSString *approach = [actionInformation stringForKey:@"approach"];
CNLabeledValue *phone = [[CNLabeledValue alloc] initWithLabel:CNLabelOther value:[[CNPhoneNumber alloc] initWithStringValue:phoneNumber]];
contact.phoneNumbers = @[phone];
if ([approach isEqualToString:KeyAdd]) {
[MVMCoreDispatchUtility performBlockOnMainThread:^{
CNContactPickerViewController *controller = [[CNContactPickerViewController alloc] init];
// Setting to accessibilityValue as a workaround to pass data via the delegate function.
[controller.view setAccessibilityIdentifier:phoneNumber];
controller.delegate = weakSelf;
[[MVMCoreNavigationHandler sharedNavigationHandler] presentViewController:controller animated:YES];
}];
} else if ([approach isEqualToString:KeyCreate]) {
contact.givenName = [actionInformation string:@"firstName"];
contact.familyName = [actionInformation string:@"lastName"];
[MVMCoreDispatchUtility performBlockOnMainThread:^{
CNContactStore *store = [[CNContactStore alloc] init];
CNContactViewController *controller = [CNContactViewController viewControllerForNewContact:contact];
controller.contactStore = store;
controller.delegate = weakSelf;
[[MVMCoreNavigationHandler sharedNavigationHandler] pushViewController:controller animated:YES];
}];
} else if ([approach isEqualToString:KeyView]) {
NSCharacterSet *symbols = [NSCharacterSet characterSetWithCharactersInString:@".+()-  "];
NSString *contactPhoneNumber = [actionInformation string:@"phoneNumber"];
contactPhoneNumber = [[contactPhoneNumber componentsSeparatedByCharactersInSet:symbols] componentsJoinedByString:@""];
CNPhoneNumber *number = [[CNPhoneNumber alloc] initWithStringValue:contactPhoneNumber];
NSPredicate *contactPredicate = [CNContact predicateForContactsMatchingPhoneNumber:number];
NSArray *displayedKeys = @[[CNContactViewController descriptorForRequiredKeys]];
CNContactStore *store = [[CNContactStore alloc] init];
NSError *error;
CNContact *viewContact = [[store unifiedContactsMatchingPredicate:contactPredicate keysToFetch:displayedKeys error:&error] firstObject];
if (viewContact) {
[MVMCoreDispatchUtility performBlockOnMainThread:^{
CNContactViewController *controller = [CNContactViewController viewControllerForNewContact:viewContact];
controller.contactStore = store;
controller.delegate = weakSelf;
[[MVMCoreNavigationHandler sharedNavigationHandler] pushViewController:controller animated:YES];
}];
} else {
// No contacts found, show an alert
MVMCoreErrorObject *error = [[MVMCoreErrorObject alloc] initWithTitle:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorTitle] message:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorContactUnAvailable] code:ErrorCodeDefault domain:ErrorDomainNative location:[NSString stringWithFormat:@"%@_%@",NSStringFromClass([delegateObject.actionDelegate class]),KeyActionTypeContact]];
error.silentError = NO;
[self handleActionError:error actionInformation:actionInformation additionalData:additionalData delegateObject:delegateObject];
}
}
}
- (void)callAction:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject {
// Call
NSString *callNumber = [actionInformation stringForKey:KeyCallNumber];
[MVMCoreActionUtility linkAway:[@"tel://" stringByAppendingString:callNumber] appURLString:nil];
}
- (void)previousSubmitAction:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject {
// Perform the previous submission.
__weak typeof(self) weakSelf = self;
if ([delegateObject.actionDelegate respondsToSelector:@selector(prepareRequestForPreviousSubmission:additionalData:submit:)]) {
[delegateObject.actionDelegate prepareRequestForPreviousSubmission:actionInformation additionalData:additionalData submit:^(MVMCoreRequestParameters * _Nonnull requestParameters, NSDictionary * _Nullable dataForPage) {
[weakSelf updateRequestParametersBeforeHandleOpenPageAction:requestParameters callBack:^(MVMCoreRequestParameters * _Nonnull requestParameters) {
// Give the delegate a chance to alter the request parameters
if ([delegateObject.actionDelegate respondsToSelector:@selector(handleOpenPageForRequestParameters:actionInformation:additionalData:)]) {
[delegateObject.actionDelegate handleOpenPageForRequestParameters:requestParameters actionInformation:actionInformation additionalData:dataForPage];
} else {
[MVMCoreActionHandler defaultHandleOpenPageForRequestParameters:requestParameters
actionInformation:actionInformation
additionalData:additionalData
delegateObject:delegateObject];
}
}];
}];
}
}
- (void)redirectAction:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject {
// Have delegate redirect.
[[MVMCoreSessionObject sharedGlobal] redirectWithInfo:actionInformation];
}
- (void)cancelAction:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject {
if ([delegateObject.actionDelegate respondsToSelector:@selector(handleCancel:additionalData:)]) {
[delegateObject.actionDelegate handleCancel:actionInformation additionalData:additionalData];
}
}
- (void)settingsAction:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject {
[MVMCoreActionUtility linkAway:UIApplicationOpenSettingsURLString appURLString:nil];
}
- (void)actions:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject {
NSArray *actions = [actionInformation array:@"actions"];
BOOL concurrent = [actionInformation boolForKey:@"concurrent"];
for (NSDictionary *action in actions) {
NSString *actionType = [action string:KeyActionType];
if (concurrent) {
[self handleAction:actionType actionInformation:action additionalData:additionalData delegateObject:delegateObject];
} else {
[self synchronouslyHandleAction:actionType actionInformation:action additionalData:additionalData delegateObject:delegateObject];
}
}
}
- (BOOL)handleOtherActions:(nullable NSString *)actionType actionInformation:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject {
return [self hasActionHandlerWithActionType:actionType actionInformation:actionInformation additionalData:additionalData delegateObject:delegateObject];
}
- (void)unknownAction:(nullable NSString *)actionType actionInformation:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject {
if ([delegateObject.actionDelegate respondsToSelector:@selector(handleUnknownActionType:actionInformation:additionalData:)]) {
[delegateObject.actionDelegate handleUnknownActionType:actionType actionInformation:actionInformation additionalData:additionalData];
} else {
[MVMCoreActionHandler defaultHandleUnknownActionType:actionType actionInformation:actionInformation additionalData:additionalData delegateObject:delegateObject];
}
}
- (void)handleActionError:(nullable MVMCoreErrorObject *)error actionInformation:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject {
if (error) {
if ([delegateObject.actionDelegate respondsToSelector:@selector(handleActionError:additionalData:)]) {
[delegateObject.actionDelegate handleActionError:error additionalData:additionalData];
} else {
[self defaultHandleActionError:error additionalData:additionalData];
}
}
}
#pragma mark - CNContactViewControllerDelegate
- (void)contactViewController:(CNContactViewController *)viewController didCompleteWithContact:(CNContact *)contact {
[[MVMCoreNavigationHandler sharedNavigationHandler] removeCurrentViewController];
}
- (BOOL)contactViewController:(CNContactViewController *)viewController shouldPerformDefaultActionForContactProperty:(CNContactProperty *)property {
return YES;
}
#pragma mark - CNContactPickerDelegate
- (void)contactPickerDidCancel:(CNContactPickerViewController *)picker {
[[MVMCoreNavigationHandler sharedNavigationHandler] removeCurrentViewController];
}
- (void)contactPicker:(CNContactPickerViewController *)picker didSelectContact:(CNContact *)contact {
// This is a means to pass the data to this delegate function.
NSString *phoneNumber = picker.view.accessibilityIdentifier;
if (!phoneNumber) { return; }
CNContactStore *store = [[CNContactStore alloc] init];
CNMutableContact *existingContact = [(CNMutableContact *)contact mutableCopy];
CNPhoneNumber *number = [[CNPhoneNumber alloc] initWithStringValue:phoneNumber];
CNLabeledValue *labelValue = [[CNLabeledValue alloc] initWithLabel:CNLabelOther value:number];
NSMutableArray<CNLabeledValue *> *phoneNumbers = [NSMutableArray new];
[phoneNumbers addObject:labelValue];
[phoneNumbers addObjectsFromArray:existingContact.phoneNumbers];
existingContact.phoneNumbers = phoneNumbers;
__weak typeof(self) weakSelf = self;
[MVMCoreDispatchUtility performBlockOnMainThread:^{
CNContactViewController *controller = [CNContactViewController viewControllerForNewContact:existingContact];
controller.contactStore = store;
controller.delegate = weakSelf;
[[MVMCoreNavigationHandler sharedNavigationHandler] pushViewController:controller animated:YES];
}];
}
#pragma mark - Open URL
- (void)linkAwayAction:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject {
__weak typeof(self) weakSelf = self;
void (^performAction)(NSDictionary*) = ^(NSDictionary* extraParamters) {
NSMutableDictionary *actionWithClientParameters = [actionInformation mutableCopy];
NSMutableDictionary *extraParametersT = [extraParamters mutableCopy];
[extraParametersT addEntriesFromDictionary:[actionWithClientParameters dictionaryForKey:KeyExtraParameters]];
actionWithClientParameters[KeyExtraParameters] = extraParametersT;
// Gets the app url
NSURL *appURL = nil;
NSString *appURLString = [actionWithClientParameters string:KeyLinkAwayAppURL];
if (appURLString.length > 0) {
appURL = [NSURL URLWithString:appURLString];
}
// Gets the browser url
NSURL *otherURL = nil;
NSString *otherURLString = [actionWithClientParameters string:KeyLinkAwayURL];
if (otherURLString.length > 0) {
otherURL = [NSURL URLWithString:otherURLString];
}
// Provide the URL and App URL to be modified if needed by a subclass or delegate.
[weakSelf prepareLinkAwayWithURL:otherURL appURL:appURL actionInformation:actionWithClientParameters additionalData:additionalData delegateObject:delegateObject];
};
[self getClientParameter:[actionInformation dict:KeyClientParameters]
requestParameters:nil
showLoadingOverlay:true
completionHandler:performAction];
}
- (void)prepareLinkAwayWithURL:(nullable NSURL *)url appURL:(nullable NSURL *)appURL actionInformation:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject {
void(^openURL)(NSURL *, NSURL *, NSDictionary *, NSDictionary *) = ^(NSURL *appURL, NSURL *URL, NSDictionary *actionInformation, NSDictionary *additionalData) {
[self openURL:url appURL:appURL actionInformation:actionInformation additionalData:additionalData delegateObject:delegateObject];
};
// Allow delegate to modify before opening the url.
if ([delegateObject.actionDelegate respondsToSelector:@selector(shouldLinkAwayWithURL:appURL:actionInformation:additionalData:linkAwayBlock:)]) {
[delegateObject.actionDelegate shouldLinkAwayWithURL:url appURL:appURL actionInformation:actionInformation additionalData:additionalData linkAwayBlock:openURL];
} else {
openURL(appURL,url,actionInformation,additionalData);
}
}
- (void)openURL:(nullable NSURL *)url appURL:(nullable NSURL *)appURL actionInformation:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject {
[MVMCoreDispatchUtility performBlockOnMainThread:^{
// First try to open the application.
if (appURL && [[UIApplication sharedApplication] canOpenURL:appURL]) {
[[UIApplication sharedApplication] openURL:appURL options:@{} completionHandler:NULL];
} else if (url && [[UIApplication sharedApplication] canOpenURL:url]) {
// Check if we should load in webview
BOOL openInWebview = [actionInformation boolForKey:@"openInWebview"];
if (openInWebview) {
[self openURLInWebView:url actionInformation:actionInformation additionalData:additionalData delegateObject:delegateObject];
} else {
[[UIApplication sharedApplication] openURL:url options:@{} completionHandler:NULL];
}
} else {
[MVMCoreDispatchUtility performBlockInBackground:^{
// Cannot linkaway, show error.
MVMCoreErrorObject *error = [[MVMCoreErrorObject alloc] initWithTitle:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorTitle] message:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorUnableToProcess] code:ErrorCodeLinkawayFailed domain:ErrorDomainNative location:[NSString stringWithFormat:@"%@_%@",NSStringFromClass([delegateObject.actionDelegate class]),KeyActionTypeLinkAway]];
[self handleActionError:error actionInformation:actionInformation additionalData:additionalData delegateObject:delegateObject];
}];
}
}];
}
- (void)openURLInWebView:(nullable NSURL *)url actionInformation:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject {
// Presents standard webview.
SFSafariViewController *safariViewController = [[SFSafariViewController alloc] initWithURL:url];
//safariViewController.delegate = self;
safariViewController.preferredBarTintColor = [UIColor whiteColor];
safariViewController.preferredControlTintColor = [UIColor blackColor];
[[MVMCoreNavigationHandler sharedNavigationHandler] presentViewController:safariViewController animated:YES];
}
#pragma mark - Default Action Protocol
+ (void)defaultLogAction:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject{
// Currently no default log action but this will eventually be server driven.
}
+ (void)defaultHandleOpenPageForRequestParameters:(nonnull MVMCoreRequestParameters *)requestParameters actionInformation:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject {
NSDictionary *clientParamters = [actionInformation dict:KeyClientParameters];
if (clientParamters) {
[[MVMCoreActionHandler sharedActionHandler] getClientParameter:clientParamters
requestParameters: requestParameters.parameters
showLoadingOverlay: !requestParameters.backgroundRequest
completionHandler: ^(NSDictionary * _Nullable jsonDictionary) {
[requestParameters addRequestParameters:jsonDictionary];
[[MVMCoreLoadHandler sharedGlobal] loadRequest:requestParameters dataForPage:additionalData delegateObject:delegateObject];
}];
} else {
[[MVMCoreLoadHandler sharedGlobal] loadRequest:requestParameters dataForPage:additionalData delegateObject:delegateObject];
}
}
+ (void)defaultHandleUnknownActionType:(nullable NSString *)actionType actionInformation:(nullable NSDictionary *)actionInformation additionalData:(nullable NSDictionary *)additionalData delegateObject:(nullable DelegateObject *)delegateObject {
MVMCoreErrorObject *error = [[MVMCoreErrorObject alloc] initWithTitle:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorTitle] message:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorUnableToProcess] code:ErrorCodeUnknownActionType domain:ErrorDomainNative location:[NSString stringWithFormat:@"%@Requests_%@",NSStringFromClass([delegateObject.actionDelegate class]),actionType]];
[[self sharedActionHandler] defaultHandleActionError:error additionalData:additionalData];
}
- (void)defaultHandleActionError:(nonnull MVMCoreErrorObject *)error additionalData:(nullable NSDictionary *)additionalData {
// Logs the error.
if (error.logError) {
[MVMCoreLoggingHandler addErrorToLog:error];
}
}
#pragma mark - Deprecated
- (void)handleActionWithDictionary:(nullable NSDictionary *)dictionary additionalData:(nullable NSDictionary *)additionalData delegate:(nullable NSObject <MVMCoreLoadDelegateProtocol, MVMCorePresentationDelegateProtocol,MVMCoreActionDelegateProtocol>*)delegate {
DelegateObject *delegateObject = [[DelegateObject alloc] init];
delegateObject.actionDelegate = delegate;
delegateObject.presentationDelegate = delegate;
delegateObject.loadDelegate = delegate;
[self handleActionWithDictionary:dictionary additionalData:additionalData delegateObject:delegateObject];
}
@end

View File

@ -0,0 +1,228 @@
//
// MVMCoreActionHandler.swift
// MVMCore
//
// Created by Scott Pfeil on 1/22/21.
// Copyright © 2021 myverizon. All rights reserved.
//
import Foundation
/// Handlers that can be registered and used by the MVMCoreActionHandler to handle actions.
public protocol MVMCoreActionHandlerProtocol: ModelHandlerProtocol {
init()
func execute(with model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws
}
/// Protocol used to bridge legacy, non model based code. Allows us to keep the original json intact and not lose key values during decode/encode. Should not be used for new actions.
public protocol MVMCoreJSONActionHandlerProtocol: MVMCoreActionHandlerProtocol {
/// Perform the function using the original json and model.
func performAction(with JSON: [AnyHashable : Any], model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws
}
@objc open class MVMCoreActionHandler: NSObject {
enum ActionError: MVMError, CustomStringConvertible {
case unknownAction(type: String)
public var description: String {
switch self {
case MVMCoreActionHandler.ActionError.unknownAction(let type):
return "Couldn't perform action: \(type)"
}
}
public var errorCode: Int {
ErrorCode.unknownActionType.rawValue
}
}
/// Used to temporarily store the json in additionalData.
private let jsonKey = "MVMCore.JSON"
/// Returns the action handler stored in the MVMCoreObject
@objc(sharedActionHandler)
public static func shared() -> Self? {
return MVMCoreActionUtility.initializerClassCheck(MVMCoreObject.sharedInstance()?.actionHandler, classToVerify: self) as? Self
}
// MARK: - Conversions
/// Converts the action to json for legacy functions.
static public func convertActionToJSON(_ model: ActionModelProtocol) throws -> [AnyHashable: Any] {
let data = try model.encode()
guard let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [AnyHashable: Any] else {
throw ModelRegistry.Error.decoderError
}
return json
}
/// Creates a model from the action json.
static public func createModel(with json: [AnyHashable: Any], delegateObject: DelegateObject? = nil) throws -> ActionModelProtocol {
guard let castedSelf = json as? [String: Any] else {
throw ModelRegistry.Error.decoderOther(message: "Dictionary is not of type [String: Any]")
}
guard let actionType = ModelRegistry.getType(for: castedSelf.stringForkey(KeyActionType), with: ActionModelProtocol.self) else {
throw ModelRegistry.Error.decoderErrorModelNotMapped()
}
guard let actionModel = try actionType.decode(jsonDict: castedSelf, delegateObject: delegateObject) as? ActionModelProtocol else {
throw ModelRegistry.Error.decoderOther(message: "Could not decode to ActionModelProtocol")
}
return actionModel
}
// MARK: - Error Handling
/// Returns a common description for the error location.
@objc public static func getErrorLocation(with delegate: MVMCoreActionDelegateProtocol?, actionType: String) -> String {
return "\(String(describing: delegate))_\(actionType)"
}
// MARK: - Action Handling
/// Handle an action with the given model.
open func handleAction(with model: ActionModelProtocol, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) async throws {
try Task.checkCancellation()
var (additionalData, uuid) = MVMCoreActionHandler.setUUID(additionalData: additionalData)
MVMCoreActionHandler.log(string: "Begin Action: \(model)", additionalData: additionalData)
defer {
MVMCoreActionHandler.log(string: "End Action: \(model)", additionalData: additionalData)
}
let json = try additionalData.removeValue(forKey: jsonKey) as? [AnyHashable : Any] ?? MVMCoreActionHandler.convertActionToJSON(model)
// Log the action
logAction(with: json, additionalData: additionalData, delegateObject: delegateObject)
do {
let handlerType = try ModelRegistry.getHandler(model) as! MVMCoreActionHandlerProtocol.Type
let handler = handlerType.init()
MVMCoreLoggingHandler.shared()?.logCoreEvent(.actionInvoked(name: model.actionType, pageType: pageType(from: delegateObject), uuid: uuid, model: model))
if let handler = handler as? MVMCoreJSONActionHandlerProtocol {
// Needed until we can remove legacy delegate functions.
try await handler.performAction(with: json, model: model, delegateObject: delegateObject, additionalData: additionalData)
} else {
try await handler.execute(with: model, delegateObject: delegateObject, additionalData: additionalData)
}
MVMCoreLoggingHandler.shared()?.logCoreEvent(.actionComplete(name: model.actionType, pageType: pageType(from: delegateObject), uuid: uuid, model: model))
} catch ModelRegistry.Error.handlerNotMapped {
try Task.checkCancellation()
// Allows custom handling if there no handler for the action.
guard try await handleUnregisteredAction(with: model, json: json, additionalData: additionalData, delegateObject: delegateObject) else {
MVMCoreActionHandler.log(string: "Failed Action Unknown", additionalData: additionalData)
MVMCoreLoggingHandler.shared()?.logCoreEvent(.actionNotFound(name: model.actionType , pageType: pageType(from: delegateObject)))
throw ActionError.unknownAction(type: model.actionType)
}
} catch {
MVMCoreLoggingHandler.shared()?.logCoreEvent(.actionFailed(name: model.actionType, pageType: pageType(from: delegateObject), uuid: uuid, model: model, error: error))
MVMCoreActionHandler.log(string: "Failed Action \(error)", additionalData: additionalData)
throw error
}
}
// MARK: - Subclassables
/// Subclass to log the action was fired.
open func logAction(with JSON: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) {
// Calls legacy log action function.
delegateObject?.actionDelegate?.logAction?(withActionInformation: JSON, additionalData: additionalData)
}
/// Logs the error.
@objc open func defaultHandleActionError(_ error: MVMCoreErrorObject, additionalData: [AnyHashable: Any]? = nil, delegateObject: DelegateObject? = nil) {
guard error.logError else { return }
MVMCoreLoggingHandler.shared()?.addError(toLog: error)
error.logError = false // Further attempts to log the same error will be skipped. (Legacy action flow.)
}
// MARK: - Legacy Holdovers
static public func setUUID(additionalData: [AnyHashable: Any]?, force: Bool = false) -> ([AnyHashable: Any], String) {
if !force, let uuid = getUUID(additionalData: additionalData) { return (additionalData!, uuid) }
let newUUID = UUID().uuidString
return (additionalData.dictionaryAdding(key: "Action-UUID", value: newUUID), newUUID)
}
@objc static public func getUUID(additionalData: [AnyHashable: Any]?) -> String? {
return additionalData?.optionalStringForKey("Action-UUID")
}
static public func log(string: String, additionalData: [AnyHashable: Any]?) {
MVMCoreLoggingHandler.shared()?.handleDebugMessage("ActionHandler: UUID: \(getUUID(additionalData: additionalData) ?? "untracked"), \(string)", category: String(describing: Self.self))
}
fileprivate func logActionError(_ error: Error, _ actionType: String?, _ additionalData: [AnyHashable: Any]?, _ delegateObject: DelegateObject?) {
MVMCoreActionHandler.log(string: "Failed Action: Error \(error)", additionalData: additionalData)
if let errorObject = MVMCoreErrorObject.createErrorObject(for: error, location: MVMCoreActionHandler.getErrorLocation(with: delegateObject?.actionDelegate, actionType: actionType ?? "noAction")) {
if let fromBridge = additionalData?["fromBridge"] as? Bool, fromBridge, let browserUrl = additionalData?["browserUrl"] as? String {
errorObject.requestUrl = browserUrl
}
if let humanReadableMessage = (error as? HumanReadableDecodingErrorProtocol)?.readableDescription {
errorObject.messageToLog = "Failed to decode the \(actionType ?? "") action model. " + humanReadableMessage
}
defaultHandleActionError(errorObject, additionalData: additionalData)
}
}
fileprivate func pageType(from delegateObject: DelegateObject?) -> String {
return (delegateObject?.loadDelegate as? MVMCoreViewControllerProtocol)?.pageType ?? "unknown"
}
/// Legacy handle action with json.
@objc(handleActionWithDictionary:additionalData:delegateObject:)
open func handleAction(with json: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) {
_ = Task(priority: .userInitiated) {
try Task.checkCancellation()
do {
guard let json = json else {
throw ModelRegistry.Error.keyNotFound
}
let model = try MVMCoreActionHandler.createModel(with: json, delegateObject: delegateObject)
try await handleAction(with: model, json: json, additionalData: additionalData, delegateObject: delegateObject)
} catch {
let actionType = json?.optionalStringForKey(KeyActionType)
switch error {
case is ModelRegistry.Error, is DecodingError:
MVMCoreLoggingHandler.shared()?.logCoreEvent(.actionFailedToDecode(pageType: pageType(from: delegateObject), error: error))
logActionError(error, actionType, additionalData, delegateObject)
case ModelRegistry.Error.decoderErrorModelNotMapped:
// If the model is not mapped, give the legacy classes a chance to handle it.
if try await handleUnregisteredAction(with: nil, json: json!, additionalData: additionalData, delegateObject: delegateObject) == false {
MVMCoreLoggingHandler.shared()?.logCoreEvent(.actionNotFound(name: actionType ?? "noAction", pageType: pageType(from: delegateObject)))
logActionError(error, actionType, additionalData, delegateObject)
}
default:
logActionError(error, actionType, additionalData, delegateObject)
}
}
}
}
/// Bridges the legacy json using functions and the new model using functions.
open func handleAction(with model: ActionModelProtocol, json: [AnyHashable: Any], additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) async throws {
try Task.checkCancellation()
let additionalDataWithJSON = additionalData.dictionaryAdding(key: jsonKey, value: json)
let (additionalData, _) = MVMCoreActionHandler.setUUID(additionalData: additionalDataWithJSON, force: true)
MVMCoreActionHandler.log(string: "JSON \(json)", additionalData: additionalData)
if let closure = (delegateObject?.actionDelegate as? ActionDelegateProtocol)?.performAction {
// Allow newer delegates to handle calls from legacy functions
try await closure(model, additionalData, delegateObject)
} else {
try await handleAction(with: model, additionalData: additionalData, delegateObject: delegateObject)
}
}
/// Subclass to handle and any actions where a handler was not registered. Checks with the delegate handlesUnknownAction function
open func handleUnregisteredAction(with model: ActionModelProtocol?, json: [AnyHashable: Any], additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) async throws -> Bool {
// Check if the delegate handles the action.
let actionType = json.optionalStringForKey(KeyActionType)
if let closure = delegateObject?.actionDelegate?.handleUnknownActionType {
MVMCoreActionHandler.log(string: "Unknown handled (Handler not registered): \(String(describing: actionType)) \(String(describing: delegateObject?.actionDelegate))", additionalData: additionalData)
// Check if the legacy delegate handles the action.
closure(actionType, json, additionalData)
return true
} else {
return false
}
}
}

View File

@ -0,0 +1,58 @@
//
// OpenURLOptionsModel.swift
// MVMCore
//
// Created by Scott Pfeil on 1/7/22.
// Copyright © 2022 myverizon. All rights reserved.
//
import Foundation
/// A model for UIApplication.OpenExternalURLOptionsKey
open class OpenUrlOptionsModel: Codable, Equatable {
public var options: [UIApplication.OpenExternalURLOptionsKey: Any]
//--------------------------------------------------
// MARK: - Initializer
//--------------------------------------------------
public init(options: [UIApplication.OpenExternalURLOptionsKey: Any] = [:]) {
self.options = options
}
//--------------------------------------------------
// MARK: - Codable
//--------------------------------------------------
// TODO: add eventAttribution
private enum CodingKeys: String, CodingKey {
case universalLinksOnly // UIApplicationOpenURLOptionUniversalLinksOnly
}
public required init(from decoder: Decoder) throws {
options = [:]
let container = try decoder.container(keyedBy: CodingKeys.self)
if let universalLinksValue = try container.decodeIfPresent(Bool.self, forKey: .universalLinksOnly) {
options[.universalLinksOnly] = universalLinksValue
}
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
if let universalLinksValue = options[.universalLinksOnly] as? Bool {
try container.encode(universalLinksValue, forKey: .universalLinksOnly)
}
}
public static func == (lhs: OpenUrlOptionsModel, rhs: OpenUrlOptionsModel) -> Bool {
return lhs.options.allSatisfy { pair in
switch(pair.key) {
case .universalLinksOnly:
return rhs.options[pair.key] as? Bool == pair.value as? Bool
default:
return true
}
}
}
}

View File

@ -1,18 +0,0 @@
//
// MVMCoreAlertController.h
// alerts
//
// Created by Scott Pfeil on 10/22/14.
// Copyright (c) 2014 Verizon Wireless. All rights reserved.
//
// Used by our alert handler. Not for subclassing. Simply keeps track of if it's visible. Tries to parallel the UIAlertView to make it easier for the MVMCoreAlertHandler.
#import <UIKit/UIKit.h>
@class MVMCoreAlertObject;
@interface MVMCoreAlertController : UIAlertController
@property (nonatomic, readonly, getter=isVisible) BOOL visible;
@property (nullable, nonatomic, strong) MVMCoreAlertObject *alertObject;
@end

View File

@ -1,40 +0,0 @@
//
// MVMAlertController.m
// alerts
//
// Created by Scott Pfeil on 10/22/14.
// Copyright (c) 2014 Verizon Wireless. All rights reserved.
//
#import "MVMCoreAlertController.h"
#import "MVMCoreLoggingHandler.h"
@interface MVMCoreAlertController ()
@property (nonatomic, readwrite, getter=isVisible) BOOL visible;
@end
@implementation MVMCoreAlertController
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self willChangeValueForKey:@"isVisible"];
self.visible = YES;
[self didChangeValueForKey:@"isVisible"];
[MVMCoreLoggingHandler logAlertForAlertController:self];
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
[self willChangeValueForKey:@"isVisible"];
self.visible = NO;
[self didChangeValueForKey:@"isVisible"];
}
- (NSString *)description {
return [NSString stringWithFormat:@"%@|title=%@|message=%@", [super description],self.title,self.message];
}
@end

View File

@ -0,0 +1,16 @@
//
// Collection+Safe.swift
// MVMCore
//
// Created by Kyle on 2/13/20.
// Copyright © 2020 Verizon Wireless. All rights reserved.
//
import Foundation
public extension Collection {
/// Returns the element at the specified index if it is within bounds, otherwise nil.
subscript (safe index: Index) -> Element? {
return indices.contains(index) ? self[index] : nil
}
}

View File

@ -0,0 +1,20 @@
//
// Date+Extension.swift
// MVMCore
//
// Created by Kyle on 8/29/22.
// Copyright © 2022 myverizon. All rights reserved.
//
import Foundation
public extension Date {
static func unixMillisecondsNow() -> Int64 {
return Self().unixMilliseconds()
}
func unixMilliseconds() -> Int64 {
return Int64(self.timeIntervalSince1970 * 1000)
}
}

View File

@ -192,6 +192,61 @@ public extension Dictionary {
return previousObject
}
/// Transforms dictionary keys without modifying values.
/// Deduplicates transformed keys.
///
/// Example:
/// ```
/// ["one": 1, "two": 2, "three": 3, "": 4].mapKeys({ $0.first }, uniquingKeysWith: { max($0, $1) })
/// // [Optional("o"): 1, Optional("t"): 3, nil: 4]
/// ```
///
/// - Parameters:
/// - transform: A closure that accepts each key of the dictionary as
/// its parameter and returns a transformed key of the same or of a different type.
/// - combine:A closure that is called with the values for any duplicate
/// keys that are encountered. The closure returns the desired value for
/// the final dictionary.
/// - Returns: A dictionary containing the transformed keys and values of this dictionary.
func mapKeys<T>(_ transform: (Key) throws -> T, uniquingKeysWith combine: (Value, Value) throws -> Value) rethrows -> [T: Value] {
try .init(map { (try transform($0.key), $0.value) }, uniquingKeysWith: combine)
}
/// Transforms dictionary keys without modifying values.
/// Drops (key, value) pairs where the transform results in a nil key.
/// Deduplicates transformed keys.
///
/// Example:
/// ```
/// ["one": 1, "two": 2, "three": 3, "": 4].compactMapKeys({ $0.first }, uniquingKeysWith: { max($0, $1) })
/// // ["o": 1, "t": 3]
/// ```
///
/// - Parameters:
/// - transform: A closure that accepts each key of the dictionary as
/// its parameter and returns an optional transformed key of the same or of a different type.
/// - combine: A closure that is called with the values for any duplicate
/// keys that are encountered. The closure returns the desired value for
/// the final dictionary.
/// - Returns: A dictionary containing the non-nil transformed keys and values of this dictionary.
func compactMapKeys<T>(_ transform: (Key) throws -> T?, uniquingKeysWith combine: (Value, Value) throws -> Value) rethrows -> [T: Value] {
try .init(compactMap { (try transform($0.key), $0.value) as? (T, Value) }, uniquingKeysWith: combine)
}
/// Unconditionally merge another dictionary into this one with preference to the incoming keys.
func mergingLeft(_ other: Self) -> Self {
return merging(other) { first, second in
second
}
}
/// Unconditionally merge this dictionary into another with preference to the existing keys.
func mergingRight(_ other: Self) -> Self {
return merging(other) { first, second in
first
}
}
}
public extension Optional where Wrapped == Dictionary<AnyHashable, Any> {

View File

@ -9,13 +9,6 @@
#import <Foundation/Foundation.h>
#import <CoreGraphics/CoreGraphics.h>
typedef NS_ENUM(NSInteger, MVMAppContext) {
MVMAppContextNone = 0,
MVMAppContextMF,
MVMAppContextMFPrepay,
MVMAppContextContentTransfer
};
typedef NS_ENUM(NSInteger, NavigationType) {
NavigationTypePush = 0,
NavigationTypeSet,
@ -41,8 +34,6 @@ extern NSString * const URLComponentKeepAlive;
#pragma mark - Notification Names
extern NSString * const NotificationResponseLoaded;
extern NSString * const MVMCoreNotificationGoingToServer;
extern NSString * const MVMCoreNotificationViewControllerChanged;
#pragma mark - Image Cache
extern NSTimeInterval const ImageTimeOut;

View File

@ -28,8 +28,6 @@ NSString * const URLComponentKeepAlive = @"isAlive.jsp";
#pragma mark - Notification Names
NSString * const NotificationResponseLoaded = @"responseLoaded";
NSString * const MVMCoreNotificationGoingToServer = @"MVMCoreGoServer";
NSString * const MVMCoreNotificationViewControllerChanged = @"MVMCoreNotificationViewControllerChanged";
#pragma mark - Image Cache
NSTimeInterval const ImageTimeOut = 60;

View File

@ -40,5 +40,6 @@ typedef NS_ENUM(NSInteger, ErrorCode) {
ErrorCodeSSL,//23
ErrorCodeNoViewControllerToPresentOn,//24
ErrorCodeNoErrorPageSent, //25
ErrorCodeFontNotFound //26
ErrorCodeFontNotFound, //26
ErrorCodePoorPerformance //27
};

View File

@ -9,6 +9,10 @@
#import "MVMCoreErrorConstants.h"
// Error Domains
/// Communication breakdowns.
NSString * const ErrorDomainSystem = @"ErrorDomainSystem";
/// Any sort of native error not due to server directives.
NSString * const ErrorDomainNative = @"ErrorDomainNative";
/// Specific errors defined by the server.
NSString * const ErrorDomainServer = @"ErrorDomainServer";

View File

@ -33,6 +33,10 @@ extern NSString * const KeyView;
extern NSString * const KeyLinks;
extern NSString * const KeyTitle;
extern NSString * const KeyMessage;
extern NSString * const KeyActionType;
extern NSString * const KeyActionTypeLinkAway;
extern NSString * const KeyActionTypeOpen;
extern NSString * const KeyActionTypeRestart;
extern NSString * const KeyActionTypeBack;
extern NSString * const KeyActionTypeShare;

View File

@ -35,6 +35,10 @@ NSString * const KeyView = @"view";
NSString * const KeyLinks = @"Links";
NSString * const KeyTitle = @"title";
NSString * const KeyMessage = @"message";
NSString * const KeyActionType = @"actionType";
NSString * const KeyActionTypeLinkAway = @"openURL";
NSString * const KeyActionTypeOpen = @"openPage";
NSString * const KeyActionTypeRestart = @"restart";
NSString * const KeyActionTypeBack = @"back";
NSString * const KeyActionTypeShare = @"share";

View File

@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<string>$(MARKETING_VERSION)</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>

View File

@ -17,6 +17,9 @@
// Starts Loading. Every start loading call must be terminated with an end loading call.
- (void)startLoading;
// Starts Loading, by showing the text in the center
- (void)startLoadingWith:(nullable NSAttributedString *) text;
// Returns if it is showing.
- (BOOL)isShowing;

View File

@ -6,11 +6,12 @@
// Copyright (c) 2014 Verizon Wireless. All rights reserved.
//
@import UIKit;
#import "MVMCoreLoadingOverlayHandler.h"
#import "MVMCoreSessionObject.h"
#import <MVMCore/MVMCoreDispatchUtility.h>
#import "MVMCoreLoadingViewControllerProtocol.h"
#import "MVMCoreObject.h"
#import <MVMCore/MVMCore-Swift.h>
@interface MVMCoreLoadingOverlayHandler ()
// The loading ui elements
@ -51,6 +52,10 @@
#pragma mark - Overlay Functions
- (void)startLoading {
[self startLoadingWith:nil];
}
- (void)startLoadingWith:(nullable NSAttributedString *)text {
[MVMCoreDispatchUtility performBlockOnMainThread:^{
@ -72,7 +77,7 @@
}
// Restarts the loading animation.
[self.loadingViewController startLoading];
[self.loadingViewController startLoadingWith:text];
if (self.animatingOut) {
@ -139,7 +144,7 @@
if (animate) {
self.animatingOut = YES;
self.animatingIn = NO;
[UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
self.loadingViewController.view.alpha = 0;
} completion:^(BOOL finished) {

View File

@ -14,4 +14,8 @@
// Called when the view controller should stop animating loading.
- (void)stopLoading;
@optional
// Called when the view controller should animate loading with custom text
- (void)startLoadingWith:(nullable NSAttributedString *) text;
@end

View File

@ -11,7 +11,6 @@
#import <MVMCore/MVMCoreViewControllerProtocol.h>
@class MVMCoreRequestParameters;
@class MVMCoreErrorObject;
@class MVMCoreAlertObject;
@class MVMCoreLoadObject;
@protocol MVMCoreLoadDelegateProtocol

View File

@ -33,18 +33,33 @@
// Returns the error location for the given requesting object and page type and modules. Important for proper logging.
- (nonnull NSString *)errorLocationForRequest:(nonnull id)requestingObject pageType:(nonnull NSString *)pageType modules:(nonnull NSString *)modules;
// Returns an error given a load object and error details. Attaches session data related to the load. Important for proper logging.
- (nonnull MVMCoreErrorObject *)errorForLoadObject:(nonnull MVMCoreLoadObject *)loadObject withTitle:(nullable NSString *)title message:(nullable NSString *)message code:(NSInteger)code domain:(nonnull NSString *)domain;
- (nonnull MVMCoreErrorObject *)errorForLoadObject:(nonnull MVMCoreLoadObject *)loadObject withTitle:(nullable NSString *)title message:(nullable NSString *)message messageToLog:(nullable NSString *)messageToLog code:(NSInteger)code domain:(nonnull NSString *)domain;
// Returns an error given a load object and NSError. Attaches session data related to the load. Important for proper logging.
- (nonnull MVMCoreErrorObject *)errorForLoadObject:(nonnull MVMCoreLoadObject *)loadObject causedBy:(nonnull NSError *)error;
// Decorates an error object given a load object.
- (nonnull MVMCoreErrorObject *)attachLoadInformation:(nonnull MVMCoreLoadObject *)loadObject toError:(nonnull MVMCoreErrorObject *)error;
#pragma mark - Request Functions.
- (void)setHeadersForRequest:(nonnull NSMutableURLRequest *)request requestParameters:(nonnull MVMCoreRequestParameters *)requestParameters;
// Converts the core request parameters into a JSON object dictionary.
- (nonnull NSDictionary *)convertToJsonDictionary:(nonnull MVMCoreRequestParameters *)requestParameters;
- (void)getJsonDictionary:(nonnull MVMCoreRequestParameters *)requestParameters completion:(nonnull void (^)(NSDictionary * _Nullable jsonDictionary))completion;
- (void)getJsonData:(nonnull MVMCoreRequestParameters *)requestParameters forUrl:(nonnull NSURL *)url completion:(nonnull void (^)(NSData * _Nullable data, MVMCoreErrorObject *_Nullable error))completion;
- (void)getInitialParametersExcludingSections:(NSSet<NSString *> *_Nullable)excludeSections actionId:(nonnull NSString *)actionId completion:(nonnull void (^)(NSDictionary *_Nullable parameters))completion NS_SWIFT_NAME(initialParameters(excludingSections:actionId:completion:));
// Creates a request object with the given parameters.
- (nullable NSURLRequest *)requestWithParameters:(nonnull MVMCoreRequestParameters *)requestParameters error:(MVMCoreErrorObject *_Nonnull *_Nonnull)error;
- (void)transformToRequestWithParameters:(nonnull MVMCoreRequestParameters *)requestParameters completion:(nonnull void (^)(NSURLRequest * _Nullable request, MVMCoreErrorObject *_Nullable error))completion;
// Sends a given request to the server. When it is finished, it calls request finished, passing along the json object or nil if there is an error.
- (nullable NSURLSessionTask *)sendRequest:(nonnull MVMCoreRequestParameters *)requestParameters locationForError:(nonnull NSString *)locationForError requestFinished:(nullable void (^)(id _Nullable jsonObject, MVMCoreErrorObject * _Nullable error))requestFinished;
- (void)sendRequest:(nonnull MVMCoreRequestParameters *)requestParameters locationForError:(nonnull NSString *)locationForError requestFinished:(nullable void (^)(id _Nullable jsonObject, MVMCoreErrorObject * _Nullable error))requestFinished;
- (nullable NSURLSessionTask *)sendRequest:(nonnull NSURLRequest *)request requestParameters:(nonnull MVMCoreRequestParameters *)requestParameters locationForError:(nonnull NSString *)locationForError requestFinished:(nullable void (^)(id _Nullable jsonObject, MVMCoreErrorObject *_Nullable error))requestFinished;
#pragma mark - Loading Functions
@ -68,12 +83,4 @@
// By default, returns continue loading and decides not to throw an error.
+ (BOOL)defaultHandleModuleError:(nonnull NSString *)module loadObject:(nonnull MVMCoreLoadObject *)loadObject error:(nonnull MVMCoreErrorObject *)error;
#pragma mark - Deprecated
// Loads a blocking request with the passed in parameters and data for the next page. Pass in the data to handle certain functions.
- (nonnull MVMCoreLoadRequestOperation *)loadRequest:(nonnull MVMCoreRequestParameters *)requestParameters dataForPage:(nullable NSDictionary *)dataForPage delegate:(nullable NSObject<MVMCoreLoadDelegateProtocol,MVMCorePresentationDelegateProtocol,MVMCoreActionDelegateProtocol>*)delegate __deprecated;
// Loads a background request with the passed in parameters and data for the next page. Pass in the data to handle certain functions.
- (nonnull MVMCoreLoadRequestOperation *)loadBackgroundRequest:(nonnull MVMCoreRequestParameters *)requestParameters dataForPage:(nullable NSDictionary *)dataForPage delegate:(nullable NSObject<MVMCoreLoadDelegateProtocol,MVMCorePresentationDelegateProtocol,MVMCoreActionDelegateProtocol>*)delegate __deprecated;
@end

View File

@ -8,20 +8,18 @@
#import "MVMCoreLoadHandler.h"
#import "MVMCoreGetterUtility.h"
#import "MVMCoreLoggingHandler.h"
#import "MVMCoreLoadRequestOperation.h"
#import "MVMCoreCache.h"
#import "MFHardCodedServerResponse.h"
#import "MVMCoreNavigationHandler.h"
#import "MVMCoreLoadObject.h"
#import "MVMCoreSessionObject.h"
#import "MVMCoreJSONConstants.h"
#import "MVMCoreErrorObject.h"
#import "MVMCoreErrorConstants.h"
#import "MVMCoreHardcodedStringsConstants.h"
#import "MVMCoreObject.h"
#import "MVMCoreConstants.h"
#import "MVMCoreActionUtility.h"
#import "MVMCoreLoggingHandlerHelper.h"
#import <MVMCore/MVMCore-Swift.h>
@interface MVMCoreLoadHandler ()
@ -95,9 +93,34 @@
}
}
- (nonnull MVMCoreErrorObject *)errorForLoadObject:(MVMCoreLoadObject *)loadObject withTitle:(NSString *)title message:(NSString *)message code:(NSInteger)code domain:(NSString *)domain {
return [self attachLoadInformation:loadObject toError:[[MVMCoreErrorObject alloc] initWithTitle:title messageToLog:message code:code domain:domain location:[self errorLocationForRequest:loadObject]]];
}
- (nonnull MVMCoreErrorObject *)errorForLoadObject:(MVMCoreLoadObject *)loadObject withTitle:(NSString *)title message:(NSString *)message messageToLog:(NSString *)messageToLog code:(NSInteger)code domain:(NSString *)domain {
return [self attachLoadInformation:loadObject toError:[[MVMCoreErrorObject alloc] initWithTitle:title message:message messageToLog:messageToLog code:code domain:domain location:[self errorLocationForRequest:loadObject]]];
}
- (nonnull MVMCoreErrorObject *)errorForLoadObject:(MVMCoreLoadObject *)loadObject causedBy:(NSError *)error {
return [self attachLoadInformation:loadObject toError:[MVMCoreErrorObject createErrorObjectForNSError:error location:[[MVMCoreLoadHandler sharedGlobal] errorLocationForRequest:loadObject]]];
}
- (nonnull MVMCoreErrorObject *)attachLoadInformation:(MVMCoreLoadObject *)loadObject toError:(MVMCoreErrorObject *)error {
// Native and system errors have an error screen.
if (![error.domain isEqualToString:ErrorDomainServer] && [[MVMCoreObject sharedInstance].globalLoadDelegate respondsToSelector:@selector(getNativeScreenForRequestError:requestObject:)]) {
error.errorScreenError = YES;
error.nativeDrivenErrorScreen = YES;
error.silentError = NO;
error.messageToDisplay = error.messageToDisplay ?: [MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorUnableToProcess];
error.requestId = loadObject.identifier; //To track for errors due to invalid JSON or any errors thrown at viewcontroller level.
}
return error;
}
- (nonnull NSString *)errorLocationForRequest:(nonnull MVMCoreLoadObject *)loadObject {
return [self errorLocationForRequest:loadObject.delegateObject.loadDelegate pageType:loadObject.requestParameters.pageType modules:[NSString stringWithFormat:@"%@",loadObject.requestParameters.modules]];
return [self errorLocationForRequest:loadObject.delegateObject.loadDelegate
pageType:loadObject.requestParameters.pageType
modules:[NSString stringWithFormat:@"%@", loadObject.requestParameters.modules]];
}
- (nonnull NSString *)errorLocationForRequest:(nonnull id)requestingObject pageType:(nonnull NSString *)pageType modules:(nonnull NSString *)modules {
@ -108,33 +131,9 @@
#pragma mark - Request Functions.
- (nullable NSURLRequest *)requestWithParameters:(nonnull MVMCoreRequestParameters *)requestParameters error:(MVMCoreErrorObject *_Nonnull *_Nonnull)error {
- (void)transformToRequestWithParameters:(nonnull MVMCoreRequestParameters *)requestParameters completion:(nonnull void (^)(NSURLRequest * _Nullable request, MVMCoreErrorObject *_Nullable error))completion {
NSURL *url = requestParameters.URL;
if (!url) {
if (requestParameters.alternateBaseURL) {
url = requestParameters.alternateBaseURL;
} else {
url = [MVMCoreSessionObject sharedGlobal].baseURL ?: [NSURL URLWithString:URLProdPostpayBase];
}
// Appends the context root.
if (requestParameters.contextRoot) {
url = [url URLByAppendingPathComponent:requestParameters.contextRoot];
} else if ([MVMCoreSessionObject sharedGlobal].contextRoot) {
url = [url URLByAppendingPathComponent:[MVMCoreSessionObject sharedGlobal].contextRoot];
}
// Appends the page type
if (requestParameters.pageType) {
url = [url URLByAppendingPathComponent:requestParameters.pageType];
}
// This has changed since the initial agreement. Seems server always needs page type now.
/* else if (requestParameters.modules) {
url = [url URLByAppendingPathComponent:KeyModuleMap];
}*/
}
NSURL *url = [requestParameters resolveURL:[MVMCoreSessionObject sharedGlobal]];
// Adds modules needed to the request parameters.
if (requestParameters.modules.count > 0) {
@ -152,26 +151,15 @@
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:timeOutInterval];
[self setHeadersForRequest:request requestParameters:requestParameters];
MVMCoreErrorObject *jsonError;
NSData *jsonData = [self convertToJsonData:requestParameters forUrl:url error:&jsonError];
if (!jsonData) {
*error = jsonError;
return nil;
}
NSError *bodyError;
NSData *body = jsonData;
if (requestParameters.imageData) {
body = [self createMultipartFormBodyForRequestJsonData:jsonData imageData:requestParameters.imageData error:&bodyError];
}
if (body) {
[request setHTTPBody:body];
} else {
*error = [[MVMCoreErrorObject alloc] initWithTitle:nil message:nil code:ErrorCodeParsingJSON domain:ErrorDomainNative location:[NSString stringWithFormat:@"requestWithParameters_%@",requestParameters.pageType]];
return nil;
}
return request;
[self getJsonData:requestParameters forUrl:url completion:^(NSData * _Nullable jsonData, MVMCoreErrorObject * _Nullable error) {
/// Ensures that something in the body is always set.
if (!jsonData) {
completion(nil, error ?: [[MVMCoreErrorObject alloc] initWithTitle:nil message:nil code:ErrorCodeParsingJSON domain:ErrorDomainNative location:[NSString stringWithFormat:@"requestWithParameters_%@",requestParameters.pageType]]);
return;
}
[request setHTTPBody:jsonData];
completion(request, nil);
}];
}
- (NSString *)boundaryForMultipartRequest {
@ -202,64 +190,67 @@
}
}
- (nonnull NSDictionary *)convertToJsonDictionary:(nonnull MVMCoreRequestParameters *)requestParameters {
- (void)getInitialParametersExcludingSections:(NSSet<NSString *> *)excludeSections actionId:(NSString *)actionId completion:(void (^)(NSDictionary * _Nullable))completion {}
- (void)getJsonDictionary:(nonnull MVMCoreRequestParameters *)requestParameters completion:(nonnull void (^)(NSDictionary * _Nullable jsonDictionary))completion {
NSMutableDictionary *parameters = [NSMutableDictionary dictionary];
// Sets up the Initial parameters.
if (requestParameters.addInitialRequestParameters) {
NSDictionary *initialParameters = [[MVMCoreSessionObject sharedGlobal] getInitialParametersExcludingSections:requestParameters.excludedInitialParameters];
if (initialParameters) {
[parameters setObject:initialParameters forKey:@"InitialParams"];
}
}
// Adds request specific parameters
if (requestParameters.parameters.count) {
[parameters setObject:requestParameters.parameters forKey:@"RequestParams"];
}
return parameters;
if (!requestParameters.addInitialRequestParameters) {
completion(parameters);
return;
}
// Sets up the Initial parameters.
[self getInitialParametersExcludingSections:requestParameters.excludedInitialParameters actionId:requestParameters.identifier ?: [NSUUID UUID].UUIDString completion:^(NSDictionary * _Nullable initialParameters) {
if (initialParameters) {
[parameters setObject:initialParameters forKey:@"InitialParams"];
}
completion(parameters);
}];
}
- (nullable NSData *)convertToJsonData:(nonnull MVMCoreRequestParameters *)requestParameters forUrl:(nonnull NSURL *)url error:(MVMCoreErrorObject *_Nullable *_Nullable)error {
NSDictionary *parameters = [self convertToJsonDictionary:requestParameters];
// Ensure the parameters are valid json.
if (![NSJSONSerialization isValidJSONObject:parameters]) {
if (error) {
*error = [[MVMCoreErrorObject alloc] initWithTitle:nil message:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorUnableToProcess] code:ErrorCodeParsingJSON domain:ErrorDomainNative location:[NSString stringWithFormat:@"requestWithParameters:pageType_%@:parameters_%@",requestParameters.pageType,parameters.description]];
- (void)getJsonData:(nonnull MVMCoreRequestParameters *)requestParameters forUrl:(nonnull NSURL *)url completion:(nonnull void (^)(NSData * _Nullable data, MVMCoreErrorObject * _Nullable error))completion {
[self getJsonDictionary:requestParameters completion:^(NSDictionary * _Nullable parameters) {
// Ensure the parameters are valid json.
if (![NSJSONSerialization isValidJSONObject:parameters]) {
completion(nil, [[MVMCoreErrorObject alloc] initWithTitle:nil message:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorUnableToProcess] code:ErrorCodeParsingJSON domain:ErrorDomainNative location:[NSString stringWithFormat:@"requestWithParameters:pageType_%@:parameters_%@",requestParameters.pageType,parameters.description]]);
return;
}
return nil;
}
NSError *jsonError = nil;
NSData *data = nil;
#if DEBUG
// Pretty print for logging the request parameters.
data = [NSJSONSerialization dataWithJSONObject:parameters options:NSJSONWritingPrettyPrinted error:&jsonError];
if (!data) {
if (error) {
*error = [[MVMCoreErrorObject alloc] initWithTitle:nil message:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorUnableToProcess] messageToLog:jsonError.localizedDescription code:jsonError.code domain:ErrorDomainSystem location:[NSString stringWithFormat:@"requestWithParameters:pageType_%@:parameters_%@",requestParameters.pageType,parameters.description]];
NSError *jsonError = nil;
NSData *data = nil;
#if LOGGING
// Pretty print for logging the request parameters.
data = [NSJSONSerialization dataWithJSONObject:parameters options:NSJSONWritingPrettyPrinted error:&jsonError];
if (!data) {
completion(nil, [[MVMCoreErrorObject alloc] initWithTitle:nil message:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorUnableToProcess] messageToLog:jsonError.localizedDescription code:jsonError.code domain:ErrorDomainSystem location:[NSString stringWithFormat:@"requestWithParameters:pageType_%@:parameters_%@",requestParameters.pageType,parameters.description]]);
return;
}
return nil;
}
NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
MVMCoreLog(@"Request Parameters for URL %@:\n%@", [url absoluteString], jsonString);
#endif
// Standard condensed to send to the server.
data = [NSJSONSerialization dataWithJSONObject:parameters options:0 error:&jsonError];
if (!data) {
if (error) {
*error = [[MVMCoreErrorObject alloc] initWithTitle:nil message:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorUnableToProcess] messageToLog:jsonError.localizedDescription code:jsonError.code domain:ErrorDomainSystem location:[NSString stringWithFormat:@"requestWithParameters:pageType_%@:parameters_%@",requestParameters.pageType,parameters.description]];
NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
MVMCoreNetworkLog(@"Request Parameters for URL %@:\n%@", [url absoluteString], jsonString);
#endif
// Standard condensed to send to the server.
data = [NSJSONSerialization dataWithJSONObject:parameters options:0 error:&jsonError];
if (!data) {
completion(nil, [[MVMCoreErrorObject alloc] initWithTitle:nil message:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorUnableToProcess] messageToLog:jsonError.localizedDescription code:jsonError.code domain:ErrorDomainSystem location:[NSString stringWithFormat:@"requestWithParameters:pageType_%@:parameters_%@",requestParameters.pageType,parameters.description]]);
return;
}
return nil;
}
return data;
// Add any image data
if (requestParameters.imageData) {
data = [self createMultipartFormBodyForRequestJsonData:data imageData:requestParameters.imageData];
}
completion(data, nil);
}];
}
- (nonnull NSData *)createMultipartFormBodyForRequestJsonData:(nonnull NSData *)jsonData imageData:(nonnull NSData *)imageData error:(NSError *_Nullable *_Nullable)error {
- (nonnull NSData *)createMultipartFormBodyForRequestJsonData:(nonnull NSData *)jsonData imageData:(nonnull NSData *)imageData {
NSMutableData *body = [[NSMutableData alloc] init];
@ -280,11 +271,26 @@
return body;
}
- (nullable NSURLSessionTask *)sendRequest:(nonnull MVMCoreRequestParameters *)requestParameters locationForError:(nonnull NSString *)locationForError requestFinished:(nullable void (^)(id _Nullable jsonObject, MVMCoreErrorObject *_Nullable error))requestFinished {
- (void)sendRequest:(nonnull MVMCoreRequestParameters *)requestParameters locationForError:(nonnull NSString *)locationForError requestFinished:(nullable void (^)(id _Nullable jsonObject, MVMCoreErrorObject *_Nullable error))requestFinished {
[self transformToRequestWithParameters:requestParameters completion:^(NSURLRequest * _Nullable request, MVMCoreErrorObject * _Nullable error) {
if (error) {
if (requestFinished) {
requestFinished(nil, error);
}
return;
}
[self sendRequest:request requestParameters:requestParameters locationForError:locationForError requestFinished:requestFinished];
}];
}
- (nullable NSURLSessionTask *)sendRequest:(nonnull NSURLRequest *)request requestParameters:(nonnull MVMCoreRequestParameters *)requestParameters locationForError:(nonnull NSString *)locationForError requestFinished:(nullable void (^)(id _Nullable jsonObject, MVMCoreErrorObject *_Nullable error))requestFinished {
#if ENABLE_HARD_CODED_RESPONSE
NSDictionary *response = [[MFHardCodedServerResponse sharedInstance] getHardCodedResponseForRequest:requestParameters];
if (response) {
#if HARD_CODED_RESPONSE_DELAY > 0
[NSThread sleepForTimeInterval:HARD_CODED_RESPONSE_DELAY];
#endif
if (requestFinished) {
requestFinished(response, nil);
}
@ -292,34 +298,26 @@
}
#endif
MVMCoreErrorObject *error = nil;
NSTimeInterval startTime = [NSDate timeIntervalSinceReferenceDate];
NSURLRequest *request = [self requestWithParameters:requestParameters error:&error];
if (!request) {
NSURLSession *session = [MVMCoreSessionObject sharedGlobal].session;
if (!session) {
#warning Hotfix for when session is nil. We should switch to logging these errors once we fix how session handler misses canceling certain calls because they happen at the same time.
MVMCoreErrorObject *error = [[MVMCoreErrorObject alloc] initWithTitle:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorTitle] message:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorCritical] messageToLog:nil code:ErrorCodeDefault domain:ErrorDomainNative location:locationForError];
error.logError = NO;
if (requestFinished) {
requestFinished(nil,error);
requestFinished(nil, error);
}
return nil;
}
NSURLSession *session = [MVMCoreSessionObject sharedGlobal].session;
if (!session) {
#warning Hotfix for when session is nil. We should switch to logging these errors once we fix how session handler misses canceling certain calls because they happen at the same time.
error = [[MVMCoreErrorObject alloc] initWithTitle:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorTitle] message:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorCritical] messageToLog:nil code:ErrorCodeDefault domain:ErrorDomainNative location:locationForError];
error.logError = NO;
requestFinished(nil,error);
}
MVMCoreLog(@"********************************* Cookie Sent *********************************");
[[[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies] enumerateObjectsUsingBlock:^(NSHTTPCookie * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
MVMCoreLog(@"Cookie Name: %@, Cookie Value: %@",obj.name, obj.value);
MVMCoreNetworkLog(@"********************************* Cookie Sent *********************************");
[[[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL:request.URL] enumerateObjectsUsingBlock:^(NSHTTPCookie * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
MVMCoreNetworkLog(@"Cookie Name: %@, Cookie Value: %@, Domain: %@", obj.name, obj.value, obj.domain);
}];
[[NSNotificationCenter defaultCenter] postNotificationName:MVMCoreNotificationGoingToServer object:nil];
NSTimeInterval startTime = [NSDate timeIntervalSinceReferenceDate];
NSURLSessionTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
MVMCoreLog(@"Request Time %f", [NSDate timeIntervalSinceReferenceDate] - startTime);
MVMCoreNetworkLog(@"Request Time %f", [NSDate timeIntervalSinceReferenceDate] - startTime);
NSDate *startTimeDate = [NSDate dateWithTimeIntervalSinceReferenceDate:startTime];
@ -332,9 +330,7 @@
[trackInfo setObject:error.localizedDescription forKey:@"error"];
}
MVMCoreLog(@"Set-Cookie %@ Value: %@", requestParameters.pageType, [(NSHTTPURLResponse *)response allHeaderFields][@"Set-Cookie"]);
[MVMCoreLoggingHandler logWithDelegateWithObject:nil withName:@"httpRequestStatus" withExtraInfo:trackInfo];
MVMCoreNetworkLog(@"Set-Cookie %@ Value: %@", requestParameters.pageType, [(NSHTTPURLResponse *)response allHeaderFields][@"Set-Cookie"]);
id jsonObject = nil;
MVMCoreErrorObject *errorObject = nil;
@ -349,7 +345,7 @@
if (!jsonObject) {
// Error serializing json.
errorObject = [[MVMCoreErrorObject alloc] initWithTitle:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorTitle] message:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorCritical] messageToLog:[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] code:ErrorCodeParsingJSON domain:ErrorDomainNative location:locationForError];
errorObject = [[MVMCoreErrorObject alloc] initWithTitle:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorTitle] message:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorCritical] messageToLog:[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] code:ErrorCodeParsingJSON domain:ErrorDomainSystem location:locationForError];
} else {
// Uncomment to get the raw UTF-8 string response from server before it is parsed. Useful for identifying issues such as duplicate definitions which are removed after parsing. (Also, be careful of parsing tools such as jsoneditoronline.org which will autoresolve some of these issues as well.)
@ -358,11 +354,11 @@
// Log the response pretty.
NSData *prettyData = [NSJSONSerialization dataWithJSONObject:jsonObject options:NSJSONWritingPrettyPrinted error:&error];
NSString *responseString = [[NSString alloc] initWithData:prettyData encoding:NSUTF8StringEncoding];
MVMCoreLog(@"Response for Request Page Type %@:\n%@",requestParameters.pageType, responseString);
MVMCoreNetworkLog(@"Response for Request Page Type %@:\n%@",requestParameters.pageType, responseString);
}
} else {
// Empty response.
errorObject = [[MVMCoreErrorObject alloc] initWithTitle:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorTitle] message:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorCritical] code:ErrorCodeEmptyResponse domain:ErrorDomainNative location:locationForError];
errorObject = [[MVMCoreErrorObject alloc] initWithTitle:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorTitle] message:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorCritical] code:ErrorCodeEmptyResponse domain:ErrorDomainSystem location:locationForError];
}
} else if ([[MVMCoreObject sharedInstance].globalLoadDelegate respondsToSelector:@selector(createErrorObjectForRequestNSError:forRequest:location:)]) {
@ -388,6 +384,8 @@
return [self loadBackgroundRequest:requestParameters dataForPage:dataForPage delegateObject:delegateObject];
} else {
MVMCoreLoadRequestOperation *loadOperation = [[MVMCoreLoadRequestOperation alloc] initWithRequestParameters:requestParameters dataForPage:dataForPage delegateObject:delegateObject backgroundLoad:NO];
loadOperation.identifier = requestParameters.identifier;
[loadOperation startLoadingAnimationIfNeeded];
[self.blockingLoadQueue addOperation:loadOperation];
return loadOperation;
}
@ -395,12 +393,15 @@
- (MVMCoreLoadRequestOperation *)loadBackgroundRequest:(nonnull MVMCoreRequestParameters *)requestParameters dataForPage:(nullable NSDictionary *)dataForPage delegateObject:(nullable DelegateObject *)delegateObject {
MVMCoreLoadRequestOperation *loadOperation = [[MVMCoreLoadRequestOperation alloc] initWithRequestParameters:requestParameters dataForPage:dataForPage delegateObject:delegateObject backgroundLoad:YES];
loadOperation.identifier = requestParameters.identifier;
[self.backgroundLoadQueue addOperation:loadOperation];
return loadOperation;
}
- (MVMCoreLoadRequestOperation *)loadObject:(nonnull MVMCoreLoadObject *)loadObject {
MVMCoreLoadRequestOperation *loadOperation = [[MVMCoreLoadRequestOperation alloc] initWithLoadObject:loadObject backgroundLoad:NO];
loadOperation.identifier = loadObject.requestParameters.identifier;
[loadOperation startLoadingAnimationIfNeeded];
[self.blockingLoadQueue addOperation:loadOperation];
return loadOperation;
}
@ -429,20 +430,4 @@
return YES;
}
#pragma mark - Deprecated
- (MVMCoreLoadRequestOperation *)loadRequest:(nonnull MVMCoreRequestParameters *)requestParameters dataForPage:(nullable NSDictionary *)dataForPage delegate:(nullable NSObject<MVMCoreLoadDelegateProtocol,MVMCorePresentationDelegateProtocol,MVMCoreActionDelegateProtocol>*)delegate {
MVMCoreLoadRequestOperation *loadOperation = [[MVMCoreLoadRequestOperation alloc] initWithRequestParameters:requestParameters dataForPage:dataForPage delegate:delegate backgroundLoad:NO];
[self.blockingLoadQueue addOperation:loadOperation];
return loadOperation;
}
- (MVMCoreLoadRequestOperation *)loadBackgroundRequest:(nonnull MVMCoreRequestParameters *)requestParameters dataForPage:(nullable NSDictionary *)dataForPage delegate:(nullable NSObject<MVMCoreLoadDelegateProtocol,MVMCorePresentationDelegateProtocol,MVMCoreActionDelegateProtocol>*)delegate {
MVMCoreLoadRequestOperation *loadOperation = [[MVMCoreLoadRequestOperation alloc] initWithRequestParameters:requestParameters dataForPage:dataForPage delegate:delegate backgroundLoad:YES];
[self.backgroundLoadQueue addOperation:loadOperation];
return loadOperation;
}
@end

View File

@ -0,0 +1,22 @@
//
// MVMCoreLoadHandler.swift
// MVMCore
//
// Created by Scott Pfeil on 8/28/23.
// Copyright © 2023 myverizon. All rights reserved.
//
import Foundation
public extension MVMCoreLoadHandler {
func sendRequest(with parameters: MVMCoreRequestParameters, locationForError: String, requestFinished: @escaping (Any?, MVMCoreErrorObject?) -> Void) async -> URLSessionTask? {
let result = await transformToRequest(with: parameters)
guard let request = result.0 else {
defer {
requestFinished(nil, result.1)
}
return nil
}
return self.send(request, requestParameters: parameters, locationForError: locationForError, requestFinished: requestFinished)
}
}

View File

@ -11,6 +11,7 @@
#import <MVMCore/MVMCoreLoadDelegateProtocol.h>
#import <MVMCore/MVMCorePresentationDelegateProtocol.h>
#import <MVMCore/MVMCoreActionDelegateProtocol.h>
#import <MVMCore/MVMCoreErrorObject.h>
@class MVMCoreLoadRequestOperation;
@class MVMCoreRequestParameters;
@ -46,7 +47,6 @@
@property (nullable, strong, nonatomic) NSDictionary *dataForPage;
// The load delegate
@property (nullable, weak, nonatomic) NSObject <MVMCoreLoadDelegateProtocol,MVMCorePresentationDelegateProtocol,MVMCoreActionDelegateProtocol> *delegate __deprecated;
@property (nullable, strong, nonatomic) DelegateObject *delegateObject;
// The operation that is loading.
@ -59,6 +59,12 @@
// The full response json
@property (nullable, strong, nonatomic) NSDictionary *responseJSON;
// Unique Identifier for event tracking
@property (nullable, strong, nonatomic) NSString *identifier;
// If any error happened during the load.
@property (nullable, strong, nonatomic) MVMCoreErrorObject *error;
- (nullable instancetype)initWithPageJSON:(nullable NSDictionary *)pageJSON modulesJSON:(nullable NSDictionary *)modulesJSON requestParameters:(nullable MVMCoreRequestParameters *)requestParameters dataForPage:(nullable NSDictionary *)dataForPage delegateObject:(nullable DelegateObject *)delegateObject;
- (nullable instancetype)initWithRequestParameters:(nullable MVMCoreRequestParameters *)requestParameters dataForPage:(nullable NSDictionary *)dataForPage delegateObject:(nullable DelegateObject *)delegateObject;
@ -70,12 +76,4 @@
// Returns whether the load will extend the app session timer based on the response provided by the server.
- (BOOL)extendsAppSession;
#pragma mark - Deprecated
- (nullable instancetype)initWithPageJSON:(nullable NSDictionary *)pageJSON modulesJSON:(nullable NSDictionary *)modulesJSON requestParameters:(nullable MVMCoreRequestParameters *)requestParameters dataForPage:(nullable NSDictionary *)dataForPage delegate:(nullable NSObject<MVMCoreLoadDelegateProtocol,MVMCorePresentationDelegateProtocol,MVMCoreActionDelegateProtocol>*)delegate __deprecated;
- (nullable instancetype)initWithRequestParameters:(nullable MVMCoreRequestParameters *)requestParameters dataForPage:(nullable NSDictionary *)dataForPage delegate:(nullable NSObject<MVMCoreLoadDelegateProtocol,MVMCorePresentationDelegateProtocol,MVMCoreActionDelegateProtocol>*)delegate __deprecated;
- (nullable instancetype)initWithDelegate:(nullable NSObject<MVMCoreLoadDelegateProtocol,MVMCorePresentationDelegateProtocol,MVMCoreActionDelegateProtocol>*)delegate __deprecated;
@end

View File

@ -55,54 +55,20 @@
if (errorObject.messageToDisplay) {
[responseInfo setObject:errorObject.messageToDisplay forKey:KeyUserMessage];
}
if (errorObject.requestId) {
self.identifier = errorObject.requestId;
}
self.responseInfoMap = responseInfo;
}
return self;
}
- (BOOL)extendsAppSession {
NSNumber *extendSessionFlag = [self.responseInfoMap optionalNumberForKey:@"appSessionExtended"];
return extendSessionFlag == nil || [extendSessionFlag boolValue]; // Default to YES if the key does not exist.
}
#pragma mark - Deprecated
- (void)setDelegateObject:(DelegateObject *)delegateObject {
_delegateObject = delegateObject;
_delegate = delegateObject.loadDelegate;
}
- (void)setDelegate:(NSObject<MVMCoreLoadDelegateProtocol,MVMCorePresentationDelegateProtocol,MVMCoreActionDelegateProtocol> *)delegate {
_delegate = delegate;
if ([delegate respondsToSelector:@selector(delegateObject)]) {
_delegateObject = [delegate performSelector:@selector(delegateObject)];
} else {
_delegateObject = [DelegateObject createWithDelegateForAll:delegate];
}
}
- (nullable instancetype)initWithPageJSON:(nullable NSDictionary *)pageJSON modulesJSON:(nullable NSDictionary *)modulesJSON requestParameters:(nullable MVMCoreRequestParameters *)requestParameters dataForPage:(nullable NSDictionary *)dataForPage delegate:(nullable NSObject<MVMCoreLoadDelegateProtocol,MVMCorePresentationDelegateProtocol,MVMCoreActionDelegateProtocol>*)delegate {
//NSNumber *extendSessionFlag = [self.responseInfoMap optionalNumberForKey:@"appSessionExtended"];
//return extendSessionFlag == nil || [extendSessionFlag boolValue]; // Default to YES if the key does not exist.
if (self = [self initWithRequestParameters:requestParameters dataForPage:dataForPage delegate:delegate]) {
self.pageJSON = pageJSON;
self.modulesJSON = modulesJSON;
}
return self;
}
- (nullable instancetype)initWithRequestParameters:(nullable MVMCoreRequestParameters *)requestParameters dataForPage:(nullable NSDictionary *)dataForPage delegate:(nullable NSObject<MVMCoreLoadDelegateProtocol,MVMCorePresentationDelegateProtocol,MVMCoreActionDelegateProtocol>*)delegate {
if (self = [self initWithDelegate:delegate]) {
self.requestParameters = requestParameters;
self.dataForPage = dataForPage;
}
return self;
}
- (nullable instancetype)initWithDelegate:(nullable NSObject<MVMCoreLoadDelegateProtocol,MVMCorePresentationDelegateProtocol,MVMCoreActionDelegateProtocol>*)delegate {
if (self = [super init]) {
self.delegate = delegate;
}
return self;
// With the introduciton of NSA and OIDC tokens, we can no longer rely on BAU network touches to update our server session.
return NO;
}
@end

View File

@ -0,0 +1,137 @@
//
// MVMCoreLoadRequestOperation+Extension.swift
// MVMCore
//
// Created by Scott Pfeil on 8/16/23.
// Copyright © 2023 myverizon. All rights reserved.
//
import Foundation
public enum PopBackError: MVMError, CustomStringConvertible {
case noPageType
case noNavigationHandler
case noViewController
public var description: String {
switch self {
case .noPageType:
return "Cannot pop with a pageType."
case .noNavigationHandler:
return "Cannot pop with a navigation controller."
case .noViewController:
return "No View Controller of popBackPageType in the hierarchy"
}
}
public var errorCode: Int {
switch self {
case .noPageType:
return 55
case .noNavigationHandler:
return 56
case .noViewController:
return 57
}
}
}
@objc
public extension MVMCoreLoadRequestOperation {
/// Attempt to navigate to the controller with the given load object. Return the controller that we navigated to if successful.
@objc
@MainActor
func goToViewController(loadObject: MVMCoreLoadObject) async -> UIViewController? {
guard loadObject.requestParameters?.replaceViewIfOnStackElseLoadWithStyle == true,
loadObject.requestParameters?.replaceViewControllerIfOnStackGoToOnly == true,
let pageType = loadObject.pageType else {
MVMCoreLoggingHandler.logDebugMessage(withDelegate: "\(type(of: self)): A new controller should be made. pageType:\(String(describing: loadObject.pageType))")
return nil
}
let template = loadObject.pageJSON?.optionalStringForKey("template")
guard let controllerMappingObject = MVMCoreViewControllerMappingObject.shared()?.getViewControllerMapping(forTemplate: template, pageType: pageType) else {
MVMCoreLoggingHandler.logDebugMessage(withDelegate: "\(type(of: self)): Failed to create a new controller. template:\(String(describing: template)) page:\(pageType)")
return nil
}
var controllerType: AnyClass?
if let programmaticMapping = controllerMappingObject as? MVMCoreViewControllerProgrammaticMappingObject {
controllerType = programmaticMapping.viewControllerClass
} else if let newVC = MVMCoreViewControllerMappingObject.shared()?.createMFViewController(ofTemplate: loadObject.pageJSON?.optionalStringForKey("template"), pageType: pageType) {
// Need to create the view controller to fetch the type.
controllerType = type(of: newVC)
} else {
MVMCoreLoggingHandler.logDebugMessage(withDelegate: "\(type(of: self)): Failed to create a new controller. template:\(String(describing: template)) page:\(pageType)")
return nil
}
guard let viewController = await NavigationHandler.shared().navigateToViewController(of: pageType, controllerType: controllerType) else {
MVMCoreLoggingHandler.logDebugMessage(withDelegate: "\(type(of: self)): No matching controller found in the hierarchy. Will need to create a new controller. pageType:\(pageType) controllerType:\(String(describing: controllerType)).")
return nil
}
MVMCoreLoggingHandler.logDebugMessage(withDelegate: "\(type(of: self)): Navigated to controller. pageType:\(pageType) controllerType:\(String(describing: controllerType))")
stopLoadingAnimationIfNeeded()
return viewController
}
@objc
func popBackToPage(for loadObject: MVMCoreLoadObject) {
Task(priority: .high) {
do {
guard let popBackPageType = loadObject.pageJSON?.optionalStringForKey("popBackPageType") else {
throw PopBackError.noPageType
}
let operation = try await NavigationHandler.shared().getOperationPopToViewController(with: popBackPageType, navigationController: loadObject.requestParameters?.navigationController, delegateObject: loadObject.delegateObject, animated: !(loadObject.requestParameters?.shouldNotAnimatePush ?? false))
await navigate(with: operation, loadObject: loadObject)
MVMCoreLoadRequestOperation.loadFinished(loadObject, loadedViewController: nil, errorObject: nil)
} catch {
let error = MVMCoreErrorObject.createErrorObject(for: error, location: MVMCoreLoadHandler.sharedGlobal()?.errorLocation(forRequest: loadObject))!
MVMCoreLoadHandler.sharedGlobal()?.attachLoadInformation(loadObject, toError: error)
MVMCoreLoadRequestOperation.loadAbortedWithError(error, loadObject: loadObject)
}
}
}
@objc
func display(viewController: UIViewController, loadObject: MVMCoreLoadObject?, completionHandler: @escaping () -> Void) {
Task(priority: .high) {
guard let navigationOperation = await NavigationHandler.shared().getNavigationOperation(with: viewController, loadObject: loadObject) else {
completionHandler()
return
}
await navigate(with: navigationOperation, loadObject: loadObject)
completionHandler()
}
}
func navigate(with navigationOperation: NavigationOperation, loadObject: MVMCoreLoadObject?) async {
// stop any loading animation we may have started if we are about to display
cancellable = NavigationHandler.shared().onNavigation
.filter { $0.0 == .willNavigate && navigationOperation == $0.1 }
.sink { [weak self] (event, operation) in
self?.stopLoadingAnimationIfNeeded()
}
await NavigationHandler.shared().navigate(with: navigationOperation)
cancellable = nil
}
}
public extension NavigationHandler {
@MainActor
func getOperationPopToViewController(with pageType: String, navigationController: UINavigationController? = nil, delegateObject: DelegateObject? = nil, animated: Bool = true) throws -> NavigationOperation {
guard let navigationController = navigationController ?? NavigationHandler.shared().navigationController else {
throw PopBackError.noNavigationHandler
}
guard let viewController = navigationController.viewControllers.first(where: { viewController in
(viewController as? MVMCoreViewManagerProtocol)?.containsPage(withPageType: pageType) == true ||
(viewController as? MVMCoreViewControllerProtocol)?.pageType == pageType
}) else {
throw PopBackError.noViewController
}
return NavigationOperation(with: .popTo(viewController: viewController, navigationController: navigationController, animated: animated), delegate: delegateObject?.presentationDelegate)
}
func popToViewController(with pageType: String, navigationController: UINavigationController? = nil, delegateObject: DelegateObject? = nil, animated: Bool = true) async throws {
try await NavigationHandler.shared().navigate(with: getOperationPopToViewController(with: pageType, navigationController: navigationController, delegateObject: delegateObject, animated: animated))
}
}

View File

@ -16,25 +16,37 @@
@class MVMCoreLoadObject;
@class DelegateObject;
@interface MVMCoreLoadRequestOperation : MVMCoreOperation <MVMCorePresentationDelegateProtocol>
@interface MVMCoreLoadRequestOperation : MVMCoreOperation
@property (nullable, strong, nonatomic) MVMCoreRequestParameters *requestParameters;
@property (nullable, strong, nonatomic) MVMCoreLoadObject *loadObject;
@property (nullable, strong, nonatomic) NSDictionary *dataForPage;
@property (nullable, strong, nonatomic) NSObject <MVMCoreLoadDelegateProtocol,MVMCorePresentationDelegateProtocol,MVMCoreActionDelegateProtocol> *delegate;// __deprecated;
@property (nullable, strong, nonatomic) DelegateObject *delegateObject;
@property (nullable, nonatomic, readonly) NSURLSessionTask *sessionTask;
@property (nullable, nonatomic, readonly) NSString *finalLoadSource;
@property (nonatomic) BOOL backgroundLoad;
@property (nonatomic, getter=areDependenciesAdded) BOOL dependenciesAdded;
@property (nonnull, nonatomic, strong) NSString *identifier;
/// If any error happened during the operation.
@property (nullable, strong, nonatomic) MVMCoreErrorObject *error;
/// Legacy flag for if this operation will have an alert to show when finished.
@property (nonatomic, readonly) BOOL alertToShow;
@property (nullable, strong, nonatomic) id cancellable;
// Initializes the operation with the request parameters object, data for page, and mvm view controller to handle the loading with.
- (nullable instancetype)initWithRequestParameters:(nullable MVMCoreRequestParameters *)requestParameters dataForPage:(nullable NSDictionary *)dataForPage delegateObject:(nullable DelegateObject *)delegateObject backgroundLoad:(BOOL)backgroundLoad;
// Initializes the operation with the load object, data for page, and mvm view controller to handle the loading with. Can be used for loading a screen without going to the cache or server.
- (nullable instancetype)initWithLoadObject:(nullable MVMCoreLoadObject *)loadObject backgroundLoad:(BOOL)backgroundLoad;
/// Begins the loading animation if needed.
- (void)startLoadingAnimationIfNeeded;
/// Ends the loading animation if needed.
- (void)stopLoadingAnimationIfNeeded;
/* Checks the cache for the data and calls the completion handler with any found data.
* @param completionHandler The block that gets called with any fetched data. */
+ (void)checkCacheForDataForRequest:(nonnull MVMCoreRequestParameters *)requestParameters completionHandler:(nonnull void (^)(NSDictionary * _Nullable pageFromCache, NSDictionary * _Nullable modulesFromCache))completionHandler;
@ -83,6 +95,8 @@
*/
+ (void)removeCaches:(nullable NSDictionary *)cacheDictionary;
+ (void)notifyListenersOfNewResponse:(nullable NSDictionary *)pages modules:(nullable NSDictionary *)modules systemParameters:(nullable NSDictionary *)systemParameters loadObject:(nonnull MVMCoreLoadObject *)loadObject;
/** Creates the view controller based on the load object passed in.
* @param loadObject The load data from the cache or server.
* @param completionHandler The completion handler to load once finished. Returns any loaded view controller and the load.*/
@ -105,8 +119,4 @@
* @param loadObject The load data **/
+ (void)loadFinished:(nonnull MVMCoreLoadObject *)loadObject loadedViewController:(nullable UIViewController <MVMCoreViewControllerProtocol> *)loadedViewController errorObject:(nullable MVMCoreErrorObject *)errorObject;
#pragma mark - Deprecated
- (nullable instancetype)initWithRequestParameters:(nullable MVMCoreRequestParameters *)requestParameters dataForPage:(nullable NSDictionary *)dataForPage delegate:(nullable NSObject<MVMCoreLoadDelegateProtocol,MVMCorePresentationDelegateProtocol,MVMCoreActionDelegateProtocol>*)delegate backgroundLoad:(BOOL)backgroundLoad __deprecated;
@end

View File

@ -6,15 +6,13 @@
// Copyright © 2015 Verizon Wireless. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <MVMCore/MVMCoreLoadRequestOperation.h>
#import "MVMCoreLoadHandler.h"
#import "MVMCoreLoadingOverlayHandler.h"
#import "MVMCoreCache.h"
#import "MVMCoreSessionTimeHandler.h"
#import "MVMCoreLoggingHandler.h"
#import "MVMCoreSessionObject.h"
#import "MVMCoreViewControllerMappingObject.h"
#import "MVMCoreNavigationHandler.h"
#import <MVMCore/MVMCoreDispatchUtility.h>
#import "MVMCoreLoadObject.h"
#import "MVMCoreRequestParameters.h"
@ -24,19 +22,20 @@
#import "MVMCoreHardcodedStringsConstants.h"
#import "MVMCoreErrorConstants.h"
#import "MVMCoreActionUtility.h"
#import <MVMCore/MVMCoreActionHandler.h>
#import "MVMCoreObject.h"
#import "MVMCoreConstants.h"
#import "MVMCoreLoggingHandlerHelper.h"
#import <MVMCore/MVMCore-Swift.h>
@interface MVMCoreLoadRequestOperation ()
@property (weak, nonatomic) NSURLSessionTask *sessionTask;
@property (strong, nonatomic) NSURLSessionTask *sessionTask;
// For temporarily storing any alert to show until we determine it's delegate.
@property (nonatomic, readwrite) BOOL alertToShow;
@property (strong, nonatomic, nullable) MVMCoreErrorObject *errorForAlertToShow;
@property (nonatomic, readwrite) BOOL loadingAnimationRunning;
@end
@implementation MVMCoreLoadRequestOperation
@ -56,6 +55,7 @@
- (nullable instancetype)initWithLoadObject:(nullable MVMCoreLoadObject *)loadObject backgroundLoad:(BOOL)backgroundLoad {
if (self = [self initWithRequestParameters:loadObject.requestParameters dataForPage:loadObject.dataForPage delegateObject:loadObject.delegateObject backgroundLoad:backgroundLoad]) {
self.identifier = loadObject.identifier;
self.loadObject = loadObject;
}
return self;
@ -66,26 +66,27 @@
- (void)cancel {
[super cancel];
[self.sessionTask cancel];
[self stopLoadingAnimationIfNeeded];
}
- (void)start {
// Adds a loading overlay if necessary.
if (!self.backgroundLoad && !self.requestParameters.noloadingOverlay) {
[[MVMCoreLoadingOverlayHandler sharedLoadingOverlay] startLoading];
}
[self startLoadingAnimationIfNeeded];
[super start];
}
- (NSString *)finalLoadSource {
return _sessionTask.currentRequest.URL.absoluteString;
}
- (void)markAsFinished {
// stop any loading animation we may have started
if (!self.backgroundLoad && !self.requestParameters.noloadingOverlay) {
[[MVMCoreLoadingOverlayHandler sharedLoadingOverlay] stopLoading:NO];
}
[self stopLoadingAnimationIfNeeded];
MVMCoreLog(@"Load Operation finished for page type %@, background load %@", self.requestParameters.pageType, @(self.backgroundLoad));
MVMCoreNetworkLog(@"Load Operation finished for page type %@, background load %@", self.requestParameters.pageType, @(self.backgroundLoad));
[super markAsFinished];
}
@ -106,7 +107,9 @@
}
- (void)main {
MVMCoreLog(@"Load Operation begun for page type %@, background load %@, delegate %@", self.requestParameters.pageType, @(self.backgroundLoad),self.delegateObject.loadDelegate);
MVMCoreNetworkLog(@"Load Operation begun for page type %@, background load %@, delegate %@", self.requestParameters.pageType, @(self.backgroundLoad),self.delegateObject.loadDelegate);
[self.requestParameters resolveURL:[MVMCoreSessionObject sharedGlobal]];
// Always check for cancellation before launching the task.
if ([self checkAndHandleForCancellation]) {
@ -117,6 +120,7 @@
// No load requested, finish.
MVMCoreLoadObject *loadObject = [[MVMCoreLoadObject alloc] initWithRequestParameters:nil dataForPage:self.dataForPage delegateObject:self.delegateObject];
loadObject.identifier = self.identifier;
loadObject.operation = self;
[MVMCoreLoadRequestOperation loadFinished:loadObject loadedViewController:nil errorObject:nil];
} else if (self.loadObject) {
@ -135,26 +139,45 @@
// Log if loaded from cache.
if (pageFromCache) {
MVMCoreLog(@"loaded from cache page %@",[MVMCoreActionUtility formatDictionaryAsJSONString:pageFromCache]);
MVMCoreNetworkLog(@"loaded from cache page %@",[MVMCoreActionUtility formatDictionaryAsJSONString:pageFromCache]);
}
if (modulesFromCache) {
MVMCoreLog(@"loaded from cache modules %@",[MVMCoreActionUtility formatDictionaryAsJSONString:modulesFromCache]);
MVMCoreNetworkLog(@"loaded from cache modules %@",[MVMCoreActionUtility formatDictionaryAsJSONString:modulesFromCache]);
}
// Create a load object from any data we fetched.
MVMCoreLoadObject *loadObject = [self createLoadObjectWithPageFromCache:pageFromCache modulesFromCache:modulesFromCache];
self.loadObject = loadObject;
// Check if we need to go to server for missing data.
MVMCoreRequestParameters *requestForMissingData = [MVMCoreLoadRequestOperation createRequestForDataWithLoadObject:loadObject];
if (!requestForMissingData) {
[[MVMCoreLoggingHandler sharedLoggingHandler] logPageLoadCompleteFor:loadObject.requestParameters.pageType serverProcessingTime:@"0" requestURL:loadObject.requestParameters.URL.absoluteString requestUUID:loadObject.identifier isFromCache:loadObject.pageDataFromCache];
// We have all the needed data, continue with the load.
[MVMCoreLoadRequestOperation handleLoadObject:loadObject error:nil];
} else {
if(!self.backgroundLoad && loadObject.requestParameters.pageType) {
[[MVMCoreLoggingHandler sharedLoggingHandler] logPageLoadStartedFor:loadObject.requestParameters.pageType requestUUID:loadObject.identifier requestURL:loadObject.requestParameters.URL.absoluteString];
}
// Send a new request to the server.
[MVMCoreLoadRequestOperation sendRequest:requestForMissingData loadObject:loadObject completionHandler:^(NSDictionary * _Nullable json) {
#if ENABLE_HARD_CODED_RESPONSE
if ([[MVMCoreObject sharedInstance].globalLoadDelegate respondsToSelector:@selector(modifyJSON:)]) {
json = [[MVMCoreObject sharedInstance].globalLoadDelegate modifyJSON:json];
}
#endif
NSString *serverProcessTime = [(NSDictionary *)json objectChainOfKeysOrIndexes:@[@"ResponseInfo", @"timeStamp"]] ?: @"0";
if(!self.backgroundLoad && loadObject.requestParameters.pageType && serverProcessTime) {
[[MVMCoreLoggingHandler sharedLoggingHandler] logPageLoadCompleteFor:loadObject.requestParameters.pageType serverProcessingTime:serverProcessTime requestURL:loadObject.requestParameters.URL.absoluteString requestUUID:loadObject.identifier isFromCache:loadObject.pageDataFromCache];
}
// Process the data retrieved from the server.
[MVMCoreLoadRequestOperation processJSONFromServer:json loadObject:loadObject completionHandler:^(MVMCoreLoadObject * _Nonnull loadObject, MVMCoreErrorObject * _Nullable error) {
@ -179,6 +202,20 @@
#pragma mark - Load Functions
- (void)startLoadingAnimationIfNeeded {
if (self.loadingAnimationRunning) { return; }
if (self.backgroundLoad) { return; }
if (self.requestParameters.noloadingOverlay) { return; }
[[MVMCoreLoadingOverlayHandler sharedLoadingOverlay] startLoading];
self.loadingAnimationRunning = YES;
}
- (void)stopLoadingAnimationIfNeeded {
if (!self.loadingAnimationRunning) { return; }
[[MVMCoreLoadingOverlayHandler sharedLoadingOverlay] stopLoading:YES];
self.loadingAnimationRunning = NO;
}
+ (void)checkCacheForDataForRequest:(nonnull MVMCoreRequestParameters *)requestParameters completionHandler:(nonnull void (^)(NSDictionary * _Nullable pageFromCache, NSDictionary * _Nullable modulesFromCache))completionHandler {
if (requestParameters.neverLoadFromCache) {
@ -223,7 +260,7 @@
if (pageFromCache) {
loadObject.pageType = self.requestParameters.pageType;
}
loadObject.identifier = self.identifier;
// Store if we loaded from the cache or not.
loadObject.pageDataFromCache = (pageFromCache != nil);
loadObject.moduleDataFromCache = (modulesFromCache != nil);
@ -273,29 +310,44 @@
return;
}
loadObject.operation.sessionTask = [[MVMCoreLoadHandler sharedGlobal] sendRequest:requestParameters locationForError:[[MVMCoreLoadHandler sharedGlobal] errorLocationForRequest:loadObject] requestFinished:^(id jsonObject, MVMCoreErrorObject *error) {
if ([loadObject.operation checkAndHandleForCancellation]) {
#if ENABLE_HARD_CODED_RESPONSE
if ([[MVMCoreObject sharedInstance].globalLoadDelegate respondsToSelector:@selector(getJSONForRequestParameters:)]) {
NSDictionary *json = [[MVMCoreObject sharedInstance].globalLoadDelegate getJSONForRequestParameters:requestParameters];
if (json) {
#if HARD_CODED_RESPONSE_DELAY > 0
[NSThread sleepForTimeInterval:HARD_CODED_RESPONSE_DELAY];
#endif
completionHandler(json);
return;
}
if (jsonObject) {
}
#endif
[[MVMCoreLoadHandler sharedGlobal] transformToRequestWithParameters:requestParameters completion:^(NSURLRequest * _Nullable request, MVMCoreErrorObject * _Nullable error) {
loadObject.operation.sessionTask = [[MVMCoreLoadHandler sharedGlobal] sendRequest:request requestParameters:requestParameters locationForError:[[MVMCoreLoadHandler sharedGlobal] errorLocationForRequest:loadObject] requestFinished:^(id jsonObject, MVMCoreErrorObject *error) {
if ([jsonObject isKindOfClass:[NSDictionary class]]) {
completionHandler(jsonObject);
} else {
// Error json not correct format.
MVMCoreErrorObject *errorObject = [[MVMCoreErrorObject alloc] initWithTitle:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorTitle] message:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorCritical] code:ErrorCodeJSONNotDictionary domain:ErrorDomainNative location:[[MVMCoreLoadHandler sharedGlobal] errorLocationForRequest:loadObject]];
[MVMCoreLoadRequestOperation loadAbortedWithError:errorObject loadObject:loadObject];
if ([loadObject.operation checkAndHandleForCancellation]) {
return;
}
} else {
// Error with the request/response
[MVMCoreLoadRequestOperation loadAbortedWithError:error loadObject:loadObject];
}
if (jsonObject) {
if ([jsonObject isKindOfClass:[NSDictionary class]]) {
completionHandler(jsonObject);
} else {
// Error json not correct format.
MVMCoreErrorObject *errorObject = [[MVMCoreLoadHandler sharedGlobal] errorForLoadObject:loadObject withTitle:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorTitle] message:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorCritical] code:ErrorCodeJSONNotDictionary domain:ErrorDomainSystem];
[MVMCoreLoadRequestOperation loadAbortedWithError:errorObject loadObject:loadObject];
}
} else {
// Error with the request/response
[[MVMCoreLoadHandler sharedGlobal] attachLoadInformation:loadObject toError:error];
[MVMCoreLoadRequestOperation loadAbortedWithError:error loadObject:loadObject];
}
}];
}];
}
@ -373,7 +425,9 @@
// Update the session timer on a good response.
if (loadObject.extendsAppSession) {
[[MVMCoreSessionTimeHandler sharedSessionHandler] startSessionTimer];
[MVMCoreDispatchUtility performBlockOnMainThread:^{
[[MVMCoreSessionTimeHandler sharedSessionHandler] startSessionTimer];
}];
}
// Adds the modules received from server to any modules we grabbed from the cache.
@ -390,6 +444,10 @@
NSDictionary *systemParameters = [jsonDictionary dict:KeySystemParameters];
loadObject.systemParametersJSON = systemParameters.count > 0 ? systemParameters : nil;
if ([[MVMCoreObject sharedInstance].globalLoadDelegate respondsToSelector:@selector(willProcessLoadObject:)]) {
[[MVMCoreObject sharedInstance].globalLoadDelegate willProcessLoadObject:loadObject];
}
// module items are cached.
MVMCoreErrorObject *moduleCachingError = nil;
BOOL shouldContinue = [MVMCoreLoadRequestOperation cacheModules:modules loadObject:loadObject error:&moduleCachingError];
@ -449,9 +507,7 @@
} else if ([ValuePresentationStylePopToPage isEqualToString:[loadObject.pageJSON string:KeyPresentationStyle]] && !loadObject.operation.backgroundLoad && !loadObject.requestParameters.noViewControllerToLoad) {
// We need to pop back to a page instead of loading a new page.
[[MVMCoreNavigationHandler sharedNavigationHandler] popToViewControllerWithPageType:[loadObject.pageJSON string:@"popBackPageType"] navigationController:loadObject.requestParameters.navigationController animated:!loadObject.requestParameters.shouldNotAnimatePush delegate:loadObject.operation completionHandler:^{
[MVMCoreLoadRequestOperation loadFinished:loadObject loadedViewController:nil errorObject:error];
}];
[loadObject.operation popBackToPageFor:loadObject];
// Notify listeners of module/pages loaded.
[MVMCoreLoadRequestOperation notifyListenersOfNewResponse:pages modules:modules systemParameters:systemParameters loadObject:loadObject];
@ -495,6 +551,7 @@
if (error.errorScreenError && !error.nativeDrivenErrorScreen && loadObject.pageType.length == 0) {
error.logError = YES;
error.errorScreenError = NO;
error.silentError = NO;
error.location = [NSString stringWithFormat:@"%li-%@",(long)ErrorCodeNoErrorPageSent,error.location];
[MVMCoreLoadRequestOperation handleError:error loadObject:loadObject showAlertForErrorIfApplicable:YES];
[MVMCoreLoadRequestOperation loadFinished:loadObject loadedViewController:nil errorObject:error];
@ -514,9 +571,16 @@
if (viewController) {
// Display or finish
if (error.errorScreenError || !loadObject.requestParameters.dontDisplayViewController) {
if (error.errorScreenError) {
error.silentError = NO;
if (error.nativeDrivenErrorScreen) {
[[MVMCoreLoggingHandler sharedLoggingHandler]addErrorToLog:error];
}
[MVMCoreLoadRequestOperation displayViewController:viewController loadObject:loadObject error:error];
} else if (!loadObject.requestParameters.dontDisplayViewController) {
[MVMCoreLoadRequestOperation displayViewController:viewController loadObject:loadObject error:error];
} else {
[[MVMCoreLoggingHandler sharedLoggingHandler]addErrorToLog:error];
[MVMCoreLoadRequestOperation loadFinished:loadObject loadedViewController:viewController errorObject:error];
}
} else if (!loadObject.requestParameters.shouldNotGoToServerOnCacheFail && (loadObject.pageDataFromCache || loadObject.moduleDataFromCache)) {
@ -528,16 +592,25 @@
loadObject.operation.errorForAlertToShow = nil;
[loadObject.operation main];
} else {
[[MVMCoreLoggingHandler sharedLoggingHandler]addErrorToLog:error];
// Otherwise the request is finished.
[MVMCoreLoadRequestOperation loadFinished:loadObject loadedViewController:nil errorObject:error];
}
};
if (!error.nativeDrivenErrorScreen) {
// Server driven screen, create normally
[MVMCoreLoadRequestOperation createViewControllerWithLoadObject:loadObject completionHandler:completionHandler];
[MVMCoreDispatchUtility performBlockOnMainThread:^{
[loadObject.operation goToViewControllerWithLoadObject:loadObject completionHandler:^(UIViewController * _Nullable viewController) {
[MVMCoreDispatchUtility performBlockInBackground:^{
if (viewController) {
[MVMCoreLoadRequestOperation loadFinished:loadObject loadedViewController:viewController errorObject:nil];
} else {
[MVMCoreLoadRequestOperation createViewControllerWithLoadObject:loadObject completionHandler:completionHandler];
}
}];
}];
}];
} else {
// Get the proper native error screen from the delegate
[MVMCoreDispatchUtility performBlockOnMainThread:^{
@ -568,7 +641,8 @@
} else if ([ValueTypeErrorScreen isEqualToString:type]) {
// Error Screen, abort the load and handle the screen if necessary
MVMCoreErrorObject *error = [MVMCoreErrorObject createErrorObjectForErrorInfo:loadObject.responseInfoMap location:[[MVMCoreLoadHandler sharedGlobal] errorLocationForRequest:loadObject]];
MVMCoreErrorObject *error = [[MVMCoreLoadHandler sharedGlobal] attachLoadInformation:loadObject toError:[MVMCoreErrorObject createErrorObjectForErrorInfo:loadObject.responseInfoMap location:[[MVMCoreLoadHandler sharedGlobal] errorLocationForRequest:loadObject]]];
[MVMCoreLoadRequestOperation loadAbortedWithError:error loadObject:loadObject];
} else {
@ -579,7 +653,7 @@
} else {
// Check for controller specific errors.
BOOL shouldContinue;
MVMCoreErrorObject *error = [MVMCoreErrorObject createErrorObjectForErrorInfo:loadObject.responseInfoMap location:[[MVMCoreLoadHandler sharedGlobal] errorLocationForRequest:loadObject]];
MVMCoreErrorObject *error = [[MVMCoreLoadHandler sharedGlobal] attachLoadInformation:loadObject toError:[MVMCoreErrorObject createErrorObjectForErrorInfo:loadObject.responseInfoMap location:[[MVMCoreLoadHandler sharedGlobal] errorLocationForRequest:loadObject]]];
if ([loadObject.delegateObject.loadDelegate respondsToSelector:@selector(checkForDelegateSpecificErrors:loadObject:completionHandler:)]) {
shouldContinue = [loadObject.delegateObject.loadDelegate checkForDelegateSpecificErrors:error loadObject:loadObject completionHandler:completionHandler];
} else {
@ -611,16 +685,30 @@
}
if (obj && [obj isKindOfClass:[NSDictionary class]]) {
NSDictionary *responseInfo = [obj dict:KeyResponseInfo];
if (![ValueTypeSuccess isEqualToString:[responseInfo string:KeyType]]) {
errorObject = [[MVMCoreErrorObject alloc] initWithTitle:[responseInfo stringForKey:KeyErrorHeading] message:[responseInfo stringForKey:KeyUserMessage] messageToLog:[responseInfo stringForKey:KeyMessage] code:[[responseInfo string:KeyCode] integerValue] domain:ErrorDomainServer location:[[MVMCoreLoadHandler sharedGlobal] errorLocationForRequest:loadObject]];
//Response Info is missing but errorObject should be created with generic message + code + domain
if (responseInfo == nil) {
errorObject = [[MVMCoreLoadHandler sharedGlobal]
errorForLoadObject:loadObject
withTitle:nil
message:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorCritical]
messageToLog:[NSString stringWithFormat:@"Module %@ is missing a %@ object.", key, KeyResponseInfo]
code:ErrorCodeJSONNotDictionary
domain:ErrorDomainServer];
} else if (![ValueTypeSuccess isEqualToString:[responseInfo string:KeyType]]) {
errorObject = [[MVMCoreLoadHandler sharedGlobal] attachLoadInformation:loadObject toError:
[[MVMCoreErrorObject alloc]
initWithTitle:[responseInfo stringForKey:KeyErrorHeading]
message:[responseInfo stringForKey:KeyUserMessage]
messageToLog:[responseInfo stringForKey:KeyMessage]
code:[[responseInfo string:KeyCode] integerValue]
domain:ErrorDomainServer
location:[[MVMCoreLoadHandler sharedGlobal] errorLocationForRequest:loadObject]]];
}
// Caches each dictionary from the array.
[[MVMCoreCache sharedCache] addModuleToCache:obj module:key queue:nil waitUntilFinished:YES completionBlock:NULL];
} else {
errorObject = [[MVMCoreErrorObject alloc] initWithTitle:nil message:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorCritical] code:ErrorCodeJSONNotDictionary domain:ErrorDomainNative location:[[MVMCoreLoadHandler sharedGlobal] errorLocationForRequest:loadObject]];
errorObject = [[MVMCoreLoadHandler sharedGlobal] errorForLoadObject:loadObject withTitle:nil message:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorCritical] code:ErrorCodeJSONNotDictionary domain:ErrorDomainSystem];
}
if (errorObject) {
@ -663,15 +751,15 @@
if (pageType) {
[[MVMCoreCache sharedCache] addPageToCache:obj pageType:pageType queue:nil waitUntilFinished:YES completionBlock:NULL];
} else {
errorObject = [[MVMCoreErrorObject alloc] initWithTitle:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorTitle] message:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorCritical] code:ErrorCodeNoPageType domain:ErrorDomainNative location:[[MVMCoreLoadHandler sharedGlobal] errorLocationForRequest:loadObject]];
errorObject = [[MVMCoreLoadHandler sharedGlobal] errorForLoadObject:loadObject withTitle:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorTitle] message:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorCritical] code:ErrorCodeNoPageType domain:ErrorDomainNative];
}
} else {
errorObject = [[MVMCoreErrorObject alloc] initWithTitle:nil message:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorCritical] code:ErrorCodeJSONNotDictionary domain:ErrorDomainNative location:[[MVMCoreLoadHandler sharedGlobal] errorLocationForRequest:loadObject]];
errorObject = [[MVMCoreLoadHandler sharedGlobal] errorForLoadObject:loadObject withTitle:nil message:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorCritical] code:ErrorCodeJSONNotDictionary domain:ErrorDomainNative];
}
// Logs the error.
if (errorObject) {
[MVMCoreLoggingHandler addErrorToLog:errorObject];
[[MVMCoreLoggingHandler sharedLoggingHandler]addErrorToLog:errorObject];
}
}];
@ -705,12 +793,15 @@
// Allows the view controller to handle specific errors (such as ensure it has all the required data).
shouldContinue = [viewController shouldFinishProcessingLoad:loadObject error:&error];
if (error) {
error = [[MVMCoreLoadHandler sharedGlobal] attachLoadInformation:loadObject toError:error];
}
if (!shouldContinue) {
viewController = nil;
}
} else {
// Couldn't initialize view controller, serious error.
error = [[MVMCoreErrorObject alloc] initWithTitle:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorTitle] message:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorCritical] code:ErrorCodeInitViewController domain:ErrorDomainNative location:[[MVMCoreLoadHandler sharedGlobal] errorLocationForRequest:loadObject]];
error = [[MVMCoreLoadHandler sharedGlobal] errorForLoadObject:loadObject withTitle:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorTitle] message:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorCritical] code:ErrorCodeInitViewController domain:ErrorDomainNative];
}
[MVMCoreLoadRequestOperation handleShouldContinue:shouldContinue error:error loadObject:loadObject errorBlock:NULL continueBlock:^{
@ -728,7 +819,7 @@
}
// Once displyed, we are finished.
[MVMCoreActionUtility displayViewController:viewController forLoadObject:loadObject presentationDelegate:loadObject.operation completionHandler:^{
[loadObject.operation displayWithViewController:viewController loadObject:loadObject completionHandler:^{
[MVMCoreLoadRequestOperation loadFinished:loadObject loadedViewController:viewController errorObject:error];
}];
}
@ -739,17 +830,19 @@
return;
}
// Logs the error.
if (error.logError) {
[MVMCoreLoggingHandler addErrorToLog:error];
}
MVMCoreLog(@"Error: %@ %@ %@ %@ %@",[error stringErrorCode], error.domain, error.location,error.messageToDisplay, error.messageToLog);
MVMCoreNetworkLog(@"Error: %@ %@ %@ %@ %@",[error stringErrorCode], error.domain, error.location,error.messageToDisplay, error.messageToLog);
if (showAlertForErrorIfApplicable && (!loadObject.operation.backgroundLoad || loadObject.requestParameters.allowAlertsIfBackgroundRequest) && !loadObject.requestParameters.handleErrorsSilently && !error.silentError && !error.errorScreenError) {
// Show alert for error.
[MVMCoreLoadRequestOperation createAndShowAlertForLoadObject:loadObject error:error delegateObject:loadObject.operation.delegateObject];
} else {
error.silentError = !error.errorScreenError && !error.nativeDrivenErrorScreen;
}
// Logs the error. If its a native driven error screen postpone until the native screen is define with its messaging.
if (error.logError && !error.nativeDrivenErrorScreen) {
[[MVMCoreLoggingHandler sharedLoggingHandler]addErrorToLog:error];
}
}
@ -798,7 +891,8 @@
//make post load calls function
[MVMCoreLoadRequestOperation loadPostCallActions:loadObject];
[MVMCoreLoadRequestOperation loadPostAction:loadObject delegateObject:delegateObject];
loadObject.error = errorObject;
loadObject.operation.error = errorObject;
[loadObject.operation markAsFinished];
}
@ -841,86 +935,4 @@
}
}
#pragma mark - Presentation Delegate
- (void)navigationController:(UINavigationController *)navigationController prepareDisplayForViewController:(UIViewController *)viewController {
if ([self.delegateObject.presentationDelegate respondsToSelector:@selector(navigationController:prepareDisplayForViewController:)]) {
[self.delegateObject.presentationDelegate navigationController:navigationController prepareDisplayForViewController:viewController];
}
}
- (void)navigationController:(UINavigationController *)navigationController willDisplayViewController:(UIViewController *)viewController {
// stop any loading animation we may have started if we are about to display
if (!self.backgroundLoad && !self.requestParameters.noloadingOverlay) {
[[MVMCoreLoadingOverlayHandler sharedLoadingOverlay] stopLoading:NO];
}
if ([self.delegateObject.presentationDelegate respondsToSelector:@selector(navigationController:willDisplayViewController:)]) {
[self.delegateObject.presentationDelegate navigationController:navigationController willDisplayViewController:viewController];
}
}
- (void)navigationController:(UINavigationController *)navigationController displayedViewController:(UIViewController *)viewController {
if ([self.delegateObject.presentationDelegate respondsToSelector:@selector(navigationController:displayedViewController:)]) {
[self.delegateObject.presentationDelegate navigationController:navigationController displayedViewController:viewController];
}
}
- (nullable id <UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC {
if (self.delegateObject.presentationDelegate && [self.delegateObject.presentationDelegate respondsToSelector:@selector(navigationController:animationControllerForOperation:fromViewController:toViewController:)]) {
return [self.delegateObject.presentationDelegate navigationController:navigationController animationControllerForOperation:operation fromViewController:fromVC toViewController:toVC];
} else {
return nil;
}
}
- (nullable id <UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController interactionControllerForAnimationController:(id<UIViewControllerAnimatedTransitioning>)animationController {
if (self.delegateObject.presentationDelegate && [self.delegateObject.presentationDelegate respondsToSelector:@selector(navigationController:interactionControllerForAnimationController:)]) {
return [self.delegateObject.presentationDelegate navigationController:navigationController interactionControllerForAnimationController:animationController];
} else {
return nil;
}
}
- (void)viewController:(UIViewController *)presentingViewController willPresentViewController:(UIViewController *)presentedViewController {
if ([self.delegateObject.presentationDelegate respondsToSelector:@selector(viewController:willPresentViewController:)]) {
[self.delegateObject.presentationDelegate viewController:presentingViewController willPresentViewController:presentedViewController];
}
}
- (void)viewController:(UIViewController *)presentingViewController didPresentViewController:(UIViewController *)presentedViewController {
if ([self.delegateObject.presentationDelegate respondsToSelector:@selector(viewController:didPresentViewController:)]) {
[self.delegateObject.presentationDelegate viewController:presentingViewController didPresentViewController:presentedViewController];
}
}
#pragma mark - Deprecated
- (void)setDelegateObject:(DelegateObject *)delegateObject {
_delegateObject = delegateObject;
_delegate = delegateObject.loadDelegate;
}
- (void)setDelegate:(NSObject<MVMCoreLoadDelegateProtocol,MVMCorePresentationDelegateProtocol,MVMCoreActionDelegateProtocol> *)delegate {
_delegate = delegate;
if ([delegate respondsToSelector:@selector(delegateObject)]) {
_delegateObject = [delegate performSelector:@selector(delegateObject)];
} else {
_delegateObject = [DelegateObject createWithDelegateForAll:delegate];
}
}
- (nullable instancetype)initWithRequestParameters:(nullable MVMCoreRequestParameters *)requestParameters dataForPage:(nullable NSDictionary *)dataForPage delegate:(nullable NSObject<MVMCoreLoadDelegateProtocol,MVMCorePresentationDelegateProtocol,MVMCoreActionDelegateProtocol>*)delegate backgroundLoad:(BOOL)backgroundLoad {
if (self = [super init]) {
self.requestParameters = requestParameters;
self.dataForPage = dataForPage;
self.delegate = delegate;
self.backgroundLoad = backgroundLoad;
}
return self;
}
@end

View File

@ -9,6 +9,7 @@
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <MVMCore/MVMCoreSessionObject.h>
// The loading style.
// MFLoadStyleDefault: This means it has not been explicitely set by the developer. Standard push.
@ -78,8 +79,13 @@ typedef NS_ENUM(NSInteger, MFLoadStyle) {
// Determines how it is loaded.
@property (nonatomic) MFLoadStyle loadStyle;
/// Determines if we should search the stack for a controller with the same pageType or just load a new controller with style. Default true
@property (nonatomic) BOOL replaceViewIfOnStackElseLoadWithStyle;
/// Determines if, when replaceViewIfOnStackElseLoadWithStyle is true, we should create a new controller or only pop back to the existing controller. Default true
@property (nonatomic) BOOL replaceViewControllerIfOnStackGoToOnly;
// A flag for if a tab was pressed to cause this load. This will ensure that we do not load a new tab page.
@property (nonatomic) BOOL tabWasPressed;
@ -100,6 +106,9 @@ typedef NS_ENUM(NSInteger, MFLoadStyle) {
/// A flag for if it should be a background request or not.
@property (assign, nonatomic) BOOL backgroundRequest;
//Unique Identifier for event tracking
@property (nullable, strong, nonatomic) NSString *identifier;
// Creates an object with the given page type and extra parameters. Adds the extra parameters to the standard request parameters. Will add any modules needed by the page type by default.
- (nullable instancetype)initWithPageType:(nonnull NSString *)pageType extraParameters:(nullable NSDictionary *)extraParameters;
@ -124,4 +133,7 @@ typedef NS_ENUM(NSInteger, MFLoadStyle) {
/// Returns optional and required modules
- (nullable NSArray<NSString *> *)allModules;
/// Resolves the URL given the session object and the current request parameters.
- (nonnull NSURL *)resolveURL:(nonnull MVMCoreSessionObject *)sessionObject;
@end

View File

@ -10,9 +10,12 @@
#import "NSDictionary+MFConvenience.h"
#import "MVMCoreJSONConstants.h"
#import "MVMCoreViewControllerMappingObject.h"
#import "MVMCoreConstants.h"
@interface MVMCoreRequestParameters ()
@property (nonatomic, strong, nullable) NSURL *determinedURL;
- (nullable instancetype)initWithExtraParameters:(nullable NSDictionary *)extraParameters;
@end
@ -26,6 +29,8 @@
// Default load style.
self.loadStyle = MFLoadStyleDefault;
self.replaceViewIfOnStackElseLoadWithStyle = YES;
self.replaceViewControllerIfOnStackGoToOnly = YES;
self.identifier = [[NSUUID UUID] UUIDString];
}
return self;
}
@ -86,6 +91,56 @@
return self;
}
- (void)setAlternateBaseURL:(NSURL *)alternateBaseURL {
_alternateBaseURL = alternateBaseURL;
_URL = self.determinedURL; // Reset resolution when changed.
}
- (void)setPageType:(NSString *)pageType {
_pageType = pageType;
_URL = self.determinedURL; // Reset resolution when changed.
}
- (void)setContextRoot:(NSString *)contextRoot {
_contextRoot = contextRoot;
_URL = self.determinedURL; // Reset resolution when changed.
}
- (void)setURL:(NSURL *)URL {
self.determinedURL = URL; // If set directly, this becomes the ultimate URL.
_URL = URL;
}
- (NSURL *)resolveURL:(MVMCoreSessionObject *)sessionObject {
if (self.URL) {
// Previously resovled.
return self.URL;
}
NSURL *url;
if (self.alternateBaseURL) {
url = self.alternateBaseURL;
} else {
url = sessionObject.baseURL ?: [NSURL URLWithString:URLProdPostpayBase];
}
// Appends the context root.
if (self.contextRoot) {
url = [url URLByAppendingPathComponent:self.contextRoot];
} else if (sessionObject.contextRoot) {
url = [url URLByAppendingPathComponent:[MVMCoreSessionObject sharedGlobal].contextRoot];
}
// Appends the page type
if (self.pageType) {
url = [url URLByAppendingPathComponent:self.pageType];
}
_URL = url;
return url;
}
- (void)addRequestParameters:(nonnull NSDictionary *)parameters {
if ([parameters count] > 0) {
@ -126,6 +181,7 @@
- (id)copyWithZone:(nullable NSZone *)zone {
MVMCoreRequestParameters *copyObject = [[MVMCoreRequestParameters alloc] init];
copyObject.identifier = [self.identifier copy];
copyObject.pageType = [self.pageType copy];
copyObject.parentPageType = self.parentPageType;
copyObject.optionalModules = [self.optionalModules copy];
@ -134,6 +190,7 @@
copyObject.contextRoot = [self.contextRoot copy];
copyObject.loadStyle = self.loadStyle;
copyObject.replaceViewIfOnStackElseLoadWithStyle = self.replaceViewIfOnStackElseLoadWithStyle;
copyObject.replaceViewControllerIfOnStackGoToOnly = self.replaceViewControllerIfOnStackGoToOnly;
copyObject.noViewControllerToLoad = self.noViewControllerToLoad;
copyObject.dontDisplayViewController = self.dontDisplayViewController;
copyObject.noloadingOverlay = self.noloadingOverlay;
@ -152,6 +209,8 @@
copyObject.customTimeoutTime = self.customTimeoutTime;
copyObject.backgroundRequest = self.backgroundRequest;
copyObject.URL = self.URL;
copyObject.determinedURL = self.determinedURL;
copyObject.actionMap = self.actionMap;
return copyObject;
}

View File

@ -34,7 +34,6 @@ FOUNDATION_EXPORT const unsigned char MVMCoreVersionString[];
#import <MVMCore/MVMCoreGetterUtility.h>
#import <MVMCore/MVMCoreErrorObject.h>
#import <MVMCore/MVMCoreOperation.h>
#import <MVMCore/MVMCoreObject.h>
#import <MVMCore/MVMCoreBlockOperation.h>
#import <MVMCore/Reachability.h>
@ -56,17 +55,9 @@ FOUNDATION_EXPORT const unsigned char MVMCoreVersionString[];
// Presentation Handling
#import <MVMCore/MVMCorePresentationDelegateProtocol.h>
#import <MVMCore/MVMCoreNavigationHandler.h>
#import <MVMCore/MVMCoreNavigationObject.h>
#import <MVMCore/MVMCoreDismissViewControllerOperation.h>
#import <MVMCore/MVMCorePresentAnimationOperation.h>
#import <MVMCore/MVMCorePresentViewControllerOperation.h>
#import <MVMCore/MVMCoreNavigationOperation.h>
#import <MVMCore/MVMCoreViewControllerAnimatedTransitioning.h>
#import <MVMCore/MVMCoreAlertController.h>
// Action Handling
#import <MVMCore/MVMCoreActionHandler.h>
#import <MVMCore/MVMCoreActionDelegateProtocol.h>
#import <MVMCore/MVMCoreActionUtility.h>
@ -76,12 +67,8 @@ FOUNDATION_EXPORT const unsigned char MVMCoreVersionString[];
#import <MVMCore/MVMCoreViewManagerViewControllerProtocol.h>
#import <MVMCore/MVMCoreViewManagerViewControllerProtocolHelper.h>
#import <MVMCore/MVMCoreViewProtocol.h>
#import <MVMCore/MVMCoreLoggingDelegateProtocol.h>
// Other Handlers and Protocols
#import <MVMCore/MVMCoreLoggingHandler.h>
// Singletons
#import <MVMCore/MVMCoreCache.h>
#import <MVMCore/MVMCoreSessionTimeHandler.h>
#import <MVMCore/MVMCoreSessionObject.h>
#import <MVMCore/MVMCoreLoggingHandlerHelper.h>

View File

@ -41,4 +41,12 @@
/// Checks to see if the operation has content to show.
- (BOOL)hasContentToShow:(nonnull MVMCoreLoadObject *)loadObject error:(nullable MVMCoreErrorObject *)error;
/// Notifies the delegate we are about to process the load object.
- (void)willProcessLoadObject:(nonnull MVMCoreLoadObject *)loadObject;
#if ENABLE_HARD_CODED_RESPONSE
- (nullable NSDictionary *)getJSONForRequestParameters:(nonnull MVMCoreRequestParameters *)requestParameters;
- (nonnull NSDictionary *)modifyJSON:(nonnull NSDictionary *)json;
#endif
@end

View File

@ -1,31 +0,0 @@
//
// MVMCoreLoggingDelegateProtocol.h
// MVMCore
//
// Created by Pfeil, Scott Robert on 11/28/17.
// Copyright © 2017 myverizon. All rights reserved.
//
#import <UIKit/UIKit.h>
@class MVMCoreAlertController;
@protocol MVMCoreLoggingDelegateProtocol <NSObject>
@optional
// Can be used to log different actions performed by the core.
- (void)handleDebugMessage:(nullable NSString *)message;
// Can be used to log different actions performed by the core.
- (void)logWithObject:(nullable id)object withName:(nullable NSString *)name withExtraInfo:(nullable NSDictionary *)extra;
// Can be used to choose how to log error objects.
- (void)addErrorToLog:(nonnull MVMCoreErrorObject *)errorObject;
// Log that the load has finished.
- (void)logLoadFinished:(nullable MVMCoreLoadObject *)loadObject loadedViewController:(nullable UIViewController <MVMCoreViewControllerProtocol> *)loadedViewController error:(nullable MVMCoreErrorObject *)error;
// Log alert
- (void)logAlertForAlertController:(nullable MVMCoreAlertController *)alertController;
@end

View File

@ -0,0 +1,27 @@
//
// MVMCoreLoggingDelegateProtocol.swift
// MVMCore
//
// Created by Nandhini Rajendran on 13/10/23.
// Copyright © 2023 myverizon. All rights reserved.
//
public protocol MVMCoreLoggingDelegateProtocol {
/// Can be used to log different actions performed by the core.
func handleDebugMessage(_ message: String?)
/// Can be used to log a message under a particular cagetory.
func handleDebugMessage(_ message: String, category: String?)
/// Can be used to choose how to log error objects.
func addError(toLog errorObject: MVMCoreErrorObject)
/// Log that the load has finished.
func logLoadFinished(_ loadObject: MVMCoreLoadObject?, loadedViewController: MVMCoreViewControllerProtocol?, error: MVMCoreErrorObject?)
}
public extension MVMCoreLoggingDelegateProtocol {
func addError(toLog errorObject: MVMCoreErrorObject) {}
func logLoadFinished(_ loadObject: MVMCoreLoadObject?, loadedViewController: MVMCoreViewControllerProtocol?, error: MVMCoreErrorObject?) {}
}

View File

@ -17,6 +17,11 @@
// Returns if the manage currently contains the page with the page type.
- (BOOL)containsPageWithPageType:(nullable NSString *)pageType;
- (nullable NSArray*)getAccessibilityElements; //AccessibilityElements that are owned by Manager.
/// Attempt to navigate to the controller. Return the controller that we navigated to if successful.
- (void)navigateToViewControllerOfPageType:(nonnull NSString *)pageType controllerType:(_Nullable Class)controllerType completionHandler:(void (^ __nullable)(UIViewController * _Nullable viewController))completionHandler;
@optional
/// Notifies the manager that the controller received new data.

View File

@ -7,7 +7,7 @@
//
public protocol ActionModelProtocol: ModelProtocol {
public protocol ActionModelProtocol: ModelProtocol, CustomDebugStringConvertible {
var actionType: String { get }
var extraParameters: JSONValueDictionary? { get set }
@ -33,4 +33,15 @@ public extension ActionModelProtocol {
static var categoryName: String {
return "\(ActionModelProtocol.self)"
}
var debugDescription: String {
return actionType
}
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

@ -1,40 +0,0 @@
//
// ActionModel.swift
// MVMCore
//
// Created by Suresh, Kamlesh on 10/3/19.
// Copyright © 2019 Suresh, Kamlesh. All rights reserved.
//
@objcMembers open class ActionOpenPageModel: ActionModelProtocol, ActionOpenPageProtocol, ClientParameterActionProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public static var identifier: String = "openPage"
public var actionType: String = ActionOpenPageModel.identifier
public var pageType: String
public var baseURL: String?
public var appContext: String?
public var requestURL: String?
public var extraParameters: JSONValueDictionary?
public var analyticsData: JSONValueDictionary?
public var presentationStyle: String?
public var tabBarIndex: Int?
public var background: Bool?
public var clientParameters: ClientParameterModel?
//--------------------------------------------------
// MARK: - Initialzier
//--------------------------------------------------
public init(pageType: String, presentationStyle: String? = nil, extraParameters: JSONValueDictionary? = nil, analyticsData: JSONValueDictionary? = nil, tabBarIndex: Int? = nil, background: Bool? = nil) {
self.pageType = pageType
self.presentationStyle = presentationStyle
self.extraParameters = extraParameters
self.analyticsData = analyticsData
self.tabBarIndex = tabBarIndex
self.background = background
}
}

View File

@ -1,43 +0,0 @@
//
// ActionOpenUrlModel.swift
// MVMCore
//
// Created by Suresh, Kamlesh on 12/16/19.
// Copyright © 2019 myverizon. All rights reserved.
//
@objcMembers public class ActionOpenUrlModel: ActionModelProtocol, ClientParameterActionProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public static var identifier: String = "openURL"
public var actionType: String = ActionOpenUrlModel.identifier
// TODO: decode into url once action handler is re-written
public var browserUrl: String
public var extraParameters: JSONValueDictionary?
public var analyticsData: JSONValueDictionary?
public var clientParameters: ClientParameterModel?
public var appURL: String?
//TODO: Should be removed in future releases. This should be MF specific.
//Missing params
public var openOauthWebView: Bool?
public var showNativeNavigation: Bool?
public var openInWebview: Bool?
public var customUserAgent: String?
public var postRequest: Bool?
public var dontShowProgress: Bool?
public var headerParameters: JSONValueDictionary?
public var enableNativeScroll: Bool?
public var hideUrl: Bool?
//--------------------------------------------------
// MARK: - Initialzier
//--------------------------------------------------
public init(browserUrl: String) {
self.browserUrl = browserUrl
}
}

View File

@ -29,4 +29,11 @@ public class ActionRunJavaScriptModel: 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 jsCallback == model.jsCallback
&& extraParameters == model.extraParameters
&& analyticsData == model.analyticsData
}
}

View File

@ -1,33 +0,0 @@
//
// ActionShareModel.swift
// MVMCore
//
// Created by Kevin Christiano on 2/18/20.
// Copyright © 2020 myverizon. All rights reserved.
//
@objcMembers public class ActionShareModel: ActionModelProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
public static var identifier: String = "share"
public var actionType: String = ActionShareModel.identifier
public var sharedType: String
public var sharedText: String
public var extraParameters: JSONValueDictionary?
public var analyticsData: JSONValueDictionary?
//--------------------------------------------------
// MARK: - Initializer
//--------------------------------------------------
public init(sharedText: String, sharedType: String, _ extraParameters: JSONValueDictionary? = nil, _ analyticsData: JSONValueDictionary? = nil) {
self.sharedType = sharedType
self.sharedText = sharedText
self.extraParameters = extraParameters
self.analyticsData = analyticsData
}
}

View File

@ -6,16 +6,39 @@
// Copyright © 2021 myverizon. All rights reserved.
//
@objcMembers open class ClientParameterHandler: NSObject {
/// Sample clientParameters
///{
/// "timeout": 30,
/// "list": [
/// {
/// "type": "currentLocation",
/// "inputParameters": {
/// "accuracy": 10,
/// "timeThreshold": 600
/// }
/// }
/// ]
///}
/// completionHandler can return flat dictinary or a map. It depends on the paramters handler
var parameterHandlerList: [ClientParameterProtocol] = []
let parametersWorkQueue = DispatchQueue(label: "com.mva.clientparameter")
let group = DispatchGroup()
@objc open class ClientParameterHandler: NSObject {
open func createParametersHandler(_ clientParameterModel: ClientParameterModelProtocol) -> ClientParameterProtocol? {
public static let DefaultTimeout = 30.0
open func createParametersHandler(_ clientParameterModel: ClientParameterModelProtocol) -> (any ClientParameterProtocol)? {
do {
let parameterType = try ModelRegistry.getHandler(clientParameterModel) as! ClientParameterProtocol.Type
return parameterType.init(clientParameterModel)
//Ensure the handlerType return will be initable using ClientParameterHandler
guard let handlerType = try ModelRegistry.getHandler(clientParameterModel) as? AnyClientParameterProtocol.Type else { throw ClientParameterError.castingError }
//init the handler
let handler = try handlerType.init(clientParameterModel: clientParameterModel)
//Cast from AnyClientParameterProtocol to AnyClientParameterProtocol, if not throw
guard let castedHandler = handler as? any ClientParameterProtocol else { throw ClientParameterError.castingError }
//Return the any ClientParameterProtocol
return castedHandler
} catch {
if let errorObject = MVMCoreErrorObject.createErrorObject(for: error, location: #function) {
MVMCoreLoggingHandler.shared()?.addError(toLog: errorObject)
@ -23,90 +46,113 @@
return nil
}
}
func getClientParameterModel(_ clientParameters: [String: Any]) throws -> ClientParameterModel? {
open func getClientParameterModel(_ clientParameters: [String: Any]) throws -> ClientParameterModel? {
let data = try JSONSerialization.data(withJSONObject: clientParameters)
return try JSONDecoder().decode(ClientParameterModel.self, from: data)
return try JSONDecoder.create().decode(ClientParameterModel.self, from: data)
}
/// Sample clientParameters
///{
/// "timeout": 30,
/// "list": [
/// {
/// "type": "currentLocation",
/// "inputParameters": {
/// "accuracy": 10,
/// "timeThreshold": 600
/// }
/// }
/// ]
///}
/// completionHandler can return flat dictinary or a map. It depends on the paramters handler
open func getParameters(with clientParameters: [String: Any], requestParameters: [String: Any], completionHandler:@escaping ([String: Any]?) -> ()) throws {
@objc
open func getParameters(with clientParameters: [String: Any], requestParameters: [String: Any], actionId: String, completionHandler:@escaping ([String: Any]?) -> ()) throws {
guard let clientParameterModel = try getClientParameterModel(clientParameters) else {
completionHandler(nil)
return
}
let timeout = clientParameterModel.timeout ?? 30.0
getParameters(with: clientParameterModel, requestParameters: requestParameters, actionId: actionId, completionHandler: completionHandler)
}
open func getParameters(with model: ClientParameterModel, requestParameters: [String: Any], actionId: String) async -> [String: AnyHashable] {
await withCheckedContinuation { continuation in
getParameters(with: model, requestParameters: requestParameters, actionId: actionId) { parameters in
continuation.resume(returning: parameters)
}
}
}
private func getParameters(with model: ClientParameterModel, requestParameters: [String: Any], actionId: String, completionHandler:@escaping ([String: AnyHashable]) -> ()) {
let parametersWorkQueue = DispatchQueue(label: "com.mva.clientparameter")
let group = DispatchGroup()
let timeout = model.timeout ?? Self.DefaultTimeout
let parameterHandlerList = model.list.compactMap { createParametersHandler($0) }
let requestUUID = (0..<parameterHandlerList.count).map { _ in UUID().uuidString }
var returnedList = [[String: AnyHashable]?](repeating: nil, count: parameterHandlerList.count)
// Dispatch setup on queue to ensure setup is complete before completion callbacks.
// Don't use [weak self]. Object is deallocated in the dispatch queue.
parametersWorkQueue.async(group: group, qos: .userInitiated) {
// Create the handler list so that same object can be used when merging. Merging needs default value in case of timeout
for parameterModel in clientParameterModel.list {
if let parameterHandler = self.createParametersHandler(parameterModel) {
self.parameterHandlerList.append(parameterHandler)
}
}
var returnedList = [[String: AnyHashable]?](repeating: nil, count: self.parameterHandlerList.count)
var mergedParametersList: [String: AnyHashable] {
var parametersList: [String: AnyHashable] = [:]
for (index, item) in returnedList.enumerated() {
let parameter = item ?? self.parameterHandlerList[index].valueOnTimeout()
parametersList = parametersList.merging(parameter) { (_, new) in new }
return returnedList.enumerated().map { (index, element) -> [String: AnyHashable] in
guard let parameter = element else {
let handler = parameterHandlerList[index]
MVMCoreLoggingHandler.shared()?.logCoreEvent(.clientParameterTimeout(
name: handler.clientParameterModel.type,
uuid: requestUUID[index],
actionId: actionId))
return handler.valueOnTimeout()
}
return parameter
}.reduce(into: [String: AnyHashable]()) { partialResult, next in
partialResult.merge(next) { first, last in first }
}
return parametersList
}
// Setup completion handlers. Barriered to ensure one happens after the other.
var complete = false
let timeoutWorkItem = DispatchWorkItem(qos: .userInitiated) {
completionHandler(mergedParametersList);
let params = mergedParametersList
completionHandler(params);
complete = true
}
let completionWorkItem = DispatchWorkItem(qos: .userInitiated) {
timeoutWorkItem.cancel()
if !complete { // In the case of firing after timeout.
completionHandler(mergedParametersList);
let params = mergedParametersList
completionHandler(params);
complete = true
}
}
// Setup timeout.
self.parametersWorkQueue.asyncAfter(deadline: .now() + .seconds(Int(timeout)), execute: timeoutWorkItem)
parametersWorkQueue.asyncAfter(deadline: .now() + .seconds(Int(timeout)), execute: timeoutWorkItem)
// Setup the parameter execution.
for (index, parameterHandler) in self.parameterHandlerList.enumerated() {
self.group.enter()
parameterHandler.fetchClientParameters(requestParameters: requestParameters,
for (index, parameterHandler) in parameterHandlerList.enumerated() {
let parameterType = parameterHandler.clientParameterModel.type
MVMCoreLoggingHandler.shared()?.logCoreEvent(.clientParameterStartFetch(name: parameterType, uuid: requestUUID[index], actionId: actionId))
group.enter()
parameterHandler.fetchClientParametersBridge(requestParameters: requestParameters,
timingOutIn: timeout) { (receivedParameter) in
// Queue the results for merge.
self.parametersWorkQueue.async {
parametersWorkQueue.async {
guard !complete else {
MVMCoreLoggingHandler.logDebugMessage(withDelegate: "Client \(parameterType) responded after task completion.")
return
}
guard returnedList[index] == nil else {
MVMCoreLoggingHandler.shared()?.addError(toLog: MVMCoreErrorObject(title: nil, message: "Client parameter \(parameterType) has already executed. The completion handler should only be called once!", code: ErrorCode.default.rawValue, domain: ErrorDomainNative, location: String(describing: ClientParameterHandler.self))!)
return
}
MVMCoreLoggingHandler.shared()?.logCoreEvent(.clientParameterFetchComplete(name: parameterType, uuid: requestUUID[index], actionId: actionId))
returnedList[index] = receivedParameter
self.group.leave() // Leaving is only done after setup (barriered).
group.leave() // Leaving is only done after setup (barriered).
}
}
}
// Callback when all parameters have been merged.
self.group.notify(queue: self.parametersWorkQueue, work: completionWorkItem);
group.notify(queue: parametersWorkQueue, work: completionWorkItem);
}
}
}
fileprivate extension ClientParameterProtocol {
func fetchClientParametersBridge(requestParameters: [String: Any], timingOutIn timeout: TimeInterval, completion: @escaping ([String: AnyHashable]?) -> ()) {
Task {
let parameters = await fetchClientParameters(requestParameters: requestParameters, timingOutIn: timeout)
completion(parameters)
}
}
}

View File

@ -8,7 +8,8 @@
import Foundation
public class ClientParameterModel: Codable {
public class ClientParameterModel: Equatable, Codable {
var timeout: Double?
var list: [ClientParameterModelProtocol]
@ -16,6 +17,11 @@ public class ClientParameterModel: Codable {
case timeout
case list
}
public init(list: [ClientParameterModelProtocol], timeout: Double? = nil) {
self.timeout = timeout
self.list = list
}
required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
@ -28,4 +34,9 @@ public class ClientParameterModel: Codable {
try container.encodeIfPresent(timeout, forKey: .timeout)
try container.encodeModels(list, forKey: .list)
}
public static func == (lhs: ClientParameterModel, rhs: ClientParameterModel) -> Bool {
return lhs.list.isEqual(to: rhs.list)
&& lhs.timeout == rhs.timeout
}
}

View File

@ -8,8 +8,13 @@
import Foundation
/// A protocol defining models for client parameter fetching handlers.
public protocol ClientParameterModelProtocol: ModelProtocol {
/// The type of client parameter.
var type: String { get }
/// A unique identifier for this instance.
var id: String { get }
}
public extension ClientParameterModelProtocol {
@ -25,4 +30,9 @@ public extension ClientParameterModelProtocol {
static var categoryName: String {
return "\(ClientParameterModelProtocol.self)"
}
func isEqual(to model: any ModelProtocol) -> Bool {
guard let model = model as? Self else { return false }
return type == model.type
}
}

View File

@ -8,34 +8,50 @@
import Foundation
public protocol ClientParameterProtocol: ModelHandlerProtocol {
static var name: String { get }
/// Errors used for ClientParamter
public enum ClientParameterError: Error {
case castingError
case modelMismatch(message: String)
}
init(_ clientParameterModel: ClientParameterModelProtocol)
public protocol AnyClientParameterProtocol {
/// Original init using a ClientParameterModelProtocol to get around the self - associatedType issues with ClientParameterProtocol
/// - Parameter clientParameterModel: any Model using the ClientParameterModelProtocol
init(clientParameterModel: ClientParameterModelProtocol) throws
}
/// A protocol defining client parameter fetching handlers.
public protocol ClientParameterProtocol<Model>: ModelHandlerProtocol, AnyClientParameterProtocol {
var clientParameterModel: ClientParameterModelProtocol { get set }
associatedtype Model: ClientParameterModelProtocol
var clientParameterModel: Model { get set }
init(clientParameterModel: Model)
func fetchClientParameters(requestParameters: [String: Any], timingOutIn timeout: Double, completionHandler:@escaping ([String: AnyHashable]?) -> ())
func fetchClientParameters(requestParameters: [String: Any], timingOutIn timeout: TimeInterval) async -> [String: AnyHashable]
/// Default parameter for timeout scenarios. It will use the protocol extension method bydefault. Can override to send custom values.
func valueOnTimeout() -> [String: AnyHashable]
}
public extension ClientParameterProtocol {
func valueOnTimeout() -> [String: AnyHashable] {
return [Self.name: "failed_to_collect"]
/// Helper init to convert protocol to specific model. Default Implementation should never be overridden
init(clientParameterModel: ClientParameterModelProtocol) throws {
// Cast the clientParameterModel to ensure it matches the asscociatedType Model assigned to this Handler.
guard let castedModel = clientParameterModel as? Model else {
let message = "Expected \(Model.self) but received \(clientParameterModel.type)"
throw ClientParameterError.modelMismatch(message: message)
}
// Call init for the Handler Class and pass in the casted Model.
self.init(clientParameterModel: castedModel)
}
/// The handler should call this method to pass the parameter back to the caller.
func returnParameters(_ isFlatMap: Bool, _ parameter: [String: AnyHashable]?, completionHandler: @escaping ([String: AnyHashable]?) -> ()) {
guard let parameter = parameter else {
return completionHandler(nil)
}
if isFlatMap {
completionHandler(parameter)
} else {
completionHandler([Self.name: parameter])
}
func valueOnTimeout() -> [String: AnyHashable] {
return [clientParameterModel.type: "failed_to_collect"]
}
/// Convenience function to format the return parameters consistently.
func formatReturnParameters(_ parameter: AnyHashable) -> [String: AnyHashable] {
return [clientParameterModel.type: parameter]
}
}

View File

@ -0,0 +1,113 @@
//
// Decoder+UserInfo.swift
// MVMCore
//
// Created by Matt Bruce on 5/10/22.
// Copyright © 2022 myverizon. All rights reserved.
//
import Foundation
extension CodingUserInfoKey {
public static let delegateObjectKey = CodingUserInfoKey(rawValue: "delegateObject")!
public static let contextKey = CodingUserInfoKey(rawValue: "context")!
}
// MARK: - DelegateObject
public extension JSONDecoder {
/// Adds a delegate object to the decoder for use in the model initializers.
func add<T: DelegateObject>(delegateObject: T) {
add(value: delegateObject, for: .delegateObjectKey)
}
}
public extension Decoder {
/// Gets a delegate object from the decoder for use in the model initializers. Had to be added before decode.
func get<T: DelegateObject>() throws -> T? {
return userInfo[.delegateObjectKey] as? T
}
}
// MARK: - DecodingContext
/// Class used to be added into the Decoder's userInfo object to store
/// key/value pairs to be used within the Decoding process.
public class DecodingContext {
/// Key/Value store
fileprivate var userInfo: [String: Any] = [:]
public init(){ }
/// Used to access value
/// - Parameter key: key for value
/// - Returns: value returns if the key exists
public func value(forKey key: String) -> Any? {
return userInfo[key]
}
}
extension Decoder {
///wrapping getter to call internal userInfo for this object
public var context: DecodingContext? {
userInfo[.contextKey] as? DecodingContext
}
/// Gets Typed value for key in the context
/// - Parameter key: Identifier
/// - Returns: Typed value
public func getContext<T>(key: String) throws -> T? {
context?.userInfo[key] as? T
}
/// Sets value for key in the context
/// - Parameters:
/// - value: Object
/// - key: Identifier
public func setContext(value: Any, for key: String) {
context?.userInfo[key] = value
}
/// Removes value for key in the context
/// - Parameter key: Identifier
public func removeContext(for key: String) {
context?.userInfo.removeValue(forKey: key)
}
/// This is a wrapping function that is meant to be used along with a "decode" method. It will save a key/value pair locally
/// and then this key/value pair is removed immediately after the completion handler is executed so that no other classes
/// will mistakenly use this value.
/// - Parameters:
/// - value: Object that you are wanting to save
/// - key: Identifier to get the Value
/// - completion: Code that will run after the value is set
public func setContext(value: Any, for key: String, completion: (() throws -> Void)) throws {
setContext(value: value, for: key)
try completion()
removeContext(for: key)
}
}
extension JSONDecoder {
/// Adds a key/value to the decoder for use in the model initializers.
func add(value: Any, for key: CodingUserInfoKey) {
userInfo.updateValue(value, forKey: key)
}
/// Helper method to initialize a JSONDecoder
/// - Parameter delegateObject: Delegate Object
/// - Returns: JSONDecoder
public class func create(with delegateObject: DelegateObject? = nil) -> JSONDecoder {
let decoder = JSONDecoder()
decoder.add(value: DecodingContext(), for: .contextKey)
if let delegateObject = delegateObject {
decoder.add(value: delegateObject, for: .delegateObjectKey)
}
return decoder
}
///wrapping getter to call internal userInfo for this object
public var context: DecodingContext? {
get { return userInfo[.contextKey] as? DecodingContext }
}
}

View File

@ -16,7 +16,7 @@ extension JSONDecoder: AnyDecoder {}
extension PropertyListDecoder: AnyDecoder {}
extension Data {
public func decode<T: Decodable>(using decoder: AnyDecoder = JSONDecoder(), delegateObject: DelegateObject? = nil) throws -> T {
public func decode<T: Decodable>(using decoder: AnyDecoder = JSONDecoder.create(), delegateObject: DelegateObject? = nil) throws -> T {
if let decoder = decoder as? JSONDecoder {
return try decoder.decode(T.self, from: self, delegateObject: delegateObject)
} else {
@ -25,6 +25,19 @@ extension Data {
}
}
extension JSONDecoder {
/// Decodes a top-level value of the given type from the given JSON representation, and adds the delegate object if provided.
func decode<T>(_ type: T.Type, from data: Data, delegateObject: DelegateObject?) throws -> T where T : Decodable {
if context == nil {
add(value: DecodingContext(), for: .contextKey)
}
if let delegateObject = delegateObject {
add(value: delegateObject, for: .delegateObjectKey)
}
return try decode(T.self, from: data)
}
}
extension KeyedDecodingContainerProtocol {
public func decode<T: Decodable>(forKey key: Key) throws -> T {
return try decode(T.self, forKey: key)
@ -42,7 +55,8 @@ extension Decodable {
public static func decode(jsonDict: [String: Any], delegateObject: DelegateObject? = nil) throws -> Self {
let jsonData = try JSONSerialization.data(withJSONObject: jsonDict)
do {
return try jsonData.decode(delegateObject: delegateObject)
let decoder = JSONDecoder.create(with: delegateObject)
return try jsonData.decode(using: decoder)
} catch {
throw JSONError.other(error: error)
}
@ -64,35 +78,3 @@ extension Decodable {
}
}
}
public enum DecoderKeyError: Error {
case createKey
}
public extension JSONDecoder {
/// Adds a delegate object to the decoder for use in the model initializers.
func add<T: DelegateObject>(delegateObject: T) throws {
guard let key = CodingUserInfoKey(rawValue: "delegateObject") else {
throw DecoderKeyError.createKey
}
userInfo.updateValue(delegateObject, forKey: key)
}
/// Decodes a top-level value of the given type from the given JSON representation, and adds the delegate object if provided.
func decode<T>(_ type: T.Type, from data: Data, delegateObject: DelegateObject?) throws -> T where T : Decodable {
if let delegateObject = delegateObject {
try add(delegateObject: delegateObject)
}
return try decode(T.self, from: data)
}
}
public extension Decoder {
/// Gets a delegate object from the decoder for use in the model initializers. Had to be added before decode.
func get<T: DelegateObject>() throws -> T? {
guard let key = CodingUserInfoKey(rawValue: "delegateObject") else {
throw DecoderKeyError.createKey
}
return userInfo[key] as? T
}
}

View File

@ -25,9 +25,27 @@ extension Encodable {
return (try? JSONSerialization.jsonObject(with: data, options: .allowFragments)).flatMap { $0 as? JSONDictionary }
}
public func toJSONString() -> String? {
public func toJSONAny() throws -> [String: Any] {
let data = try self.encode()
let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments)
guard let jsonAny = json as? [String: Any] else {
throw JSONError.error(message: "JSON Dictionary not found")
}
return jsonAny
}
public func toJSONArray() throws -> [Any] {
let data = try self.encode()
let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments)
guard let jsonArray = json as? [Any] else {
throw JSONError.error(message: "JSON Array not found")
}
return jsonArray
}
public func toJSONString(options: JSONSerialization.WritingOptions = .prettyPrinted) -> String? {
guard let json = self.toJSON(),
let data = try? JSONSerialization.data(withJSONObject: json, options: .prettyPrinted),
let data = try? JSONSerialization.data(withJSONObject: json, options: options),
let string = String(data: data, encoding: .utf8) else {
return nil
}

View File

@ -8,11 +8,80 @@
import Foundation
public typealias JSONArray = [[String: Any]]
public typealias JSONArray = [AnyHashable]
public typealias JSONDictionary = [String: AnyHashable]
public enum JSONError: Error {
case pathNotFound
case data(path: String)
case other(error: Error)
case error(message: String)
}
extension JSONError: LocalizedError, CustomStringConvertible {
public var description: String {
switch self {
case .pathNotFound:
return "JSON path not found"
case .data(path: let path):
return "JSON data in \(path) is corrupt"
case .other(error: let error):
if let decodingError = error as? DecodingError {
// the only way to get the decoding error description and details...
return (decodingError as NSError).description
}
return error.localizedDescription
case .error(message: let message):
return message
}
}
// Shown to customers.
public var errorDescription: String? {
return MVMCoreGetterUtility.hardcodedString(withKey: HardcodedErrorUnableToProcess)
}
}
extension JSONDictionary {
public func toJSONString(options: JSONSerialization.WritingOptions = []) throws -> String {
let data = try JSONSerialization.data(withJSONObject: self, options: options)
guard let string = String(data: data, encoding: .utf8) else {
throw JSONError.error(message: "Failed to convert data to string")
}
return string
}
public func toUrlQueryItems(shouldRemoveDefaultEncoding: Bool = false) throws -> [URLQueryItem] {
var queryItems: [URLQueryItem] = []
for (key, value) in self {
var valueString: String
if let value = value as? JSONDictionary {
valueString = try value.toJSONString()
} else if let value = value as? JSONArray {
valueString = try value.toJSONString()
} else {
valueString = String(describing: value.base)
if shouldRemoveDefaultEncoding {
guard let encodedValue = valueString.removingPercentEncoding else { throw JSONError.error(message:"query item failed: \(key) value \(value.base)") }
valueString = encodedValue
}
}
let queryItem = URLQueryItem(name: key, value: valueString)
queryItems.append(queryItem)
}
return queryItems
}
}
extension JSONArray {
public func toJSONString(options: JSONSerialization.WritingOptions = []) throws -> String {
let data = try JSONSerialization.data(withJSONObject: self, options: options)
guard let string = String(data: data, encoding: .utf8) else {
throw JSONError.error(message: "Failed to convert data to string")
}
return string
}
}

View File

@ -13,6 +13,7 @@ public typealias JSONValueDictionary = [String: JSONValue]
public enum JSONValueError: Error {
case encode
case TypeMismatch
}
extension Optional {
@ -68,6 +69,38 @@ public enum JSONValue: Codable, Equatable {
case .null: break
}
}
public var base: Any {
switch self {
case .string(let string): return string
case .int(let int): return int
case .double(let double): return double
case .bool(let bool): return bool
case .object(let object): return try! object.toJSONAny()
case .array(let array): return try! array.toJSONArray()
case .null: return NSNull()
}
}
public func value<T>() throws -> T {
guard let base = self.base as? T else {
throw JSONValueError.TypeMismatch
}
return base
}
private func value<T>(type: T.Type) throws -> T {
let base: T = try value()
return base
}
public func toString() throws -> String { try value(type: String.self) }
public func toDouble() throws -> Double { try value(type: Double.self) }
public func toInt() throws -> Int { try value(type: Int.self) }
public func toBool() throws -> Bool { try value(type: Bool.self) }
public func toArray<T>(of type: T.Type) throws -> [T]{ try value(type: [T].self) }
public func toObject<T>(of type: T.Type) throws -> T { try value(type: T.self) }
}
public func ==(lhs: JSONValue, rhs: JSONValue) -> Bool {
@ -112,10 +145,55 @@ extension JSONValue: ExpressibleByDictionaryLiteral {
}
}
extension Dictionary where Key == String, Value == Any {
public func toJSONValue() throws -> [String: JSONValue] {
extension Array where Element == Any {
public func toJSONValue() throws -> JSONValue {
let data = try JSONSerialization.data(withJSONObject: self, options: .prettyPrinted)
return try JSONDecoder().decode([String:JSONValue].self, from: data)
return try JSONDecoder().decode(JSONValue.self, from: data)
}
}
extension Array where Element == AnyHashable {
public func toJSONValue() throws -> JSONValue {
let data = try JSONSerialization.data(withJSONObject: self, options: .prettyPrinted)
return try JSONDecoder().decode(JSONValue.self, from: data)
}
}
extension Array where Element == JSONValue {
public func toJSONArray() throws -> [Any] {
let encoded = try JSONEncoder().encode(self)
guard let json = try JSONSerialization.jsonObject(with: encoded, options: .mutableContainers) as? [Any] else {
throw JSONValueError.encode
}
return json
}
}
extension Dictionary where Key == String, Value == Any {
public func toJSONValue() throws -> JSONValue {
let data = try JSONSerialization.data(withJSONObject: self, options: .prettyPrinted)
return try JSONDecoder().decode(JSONValue.self, from: data)
}
}
extension Dictionary where Key == String, Value == AnyHashable {
public func toJSONValue() throws -> JSONValue {
let data = try JSONSerialization.data(withJSONObject: self, options: .prettyPrinted)
return try JSONDecoder().decode(JSONValue.self, from: data)
}
}
extension Dictionary where Key == String, Value == Any {
public func toJSONValueDictionary() throws -> JSONValueDictionary {
let data = try JSONSerialization.data(withJSONObject: self, options: .prettyPrinted)
return try JSONDecoder().decode(JSONValueDictionary.self, from: data)
}
}
extension Dictionary where Key == String, Value == AnyHashable {
public func toJSONValueDictionary() throws -> JSONValueDictionary {
let data = try JSONSerialization.data(withJSONObject: self, options: .prettyPrinted)
return try JSONDecoder().decode(JSONValueDictionary.self, from: data)
}
}

View File

@ -8,7 +8,7 @@
import Foundation
public protocol ModelProtocol: Codable {
public protocol ModelProtocol: ModelComparisonProtocol, Codable {
/// The key name of the molecule
static var identifier: String { get }
@ -50,3 +50,102 @@ extension ModelProtocol {
try unkeyedContainer.encode(self)
}
}
public protocol ModelComparisonProtocol {
/// Shallow checks if the current model is equal to another model. Defaults to false unless implemented otherwise.
func isEqual(to model: ModelComparisonProtocol) -> Bool
}
extension ModelComparisonProtocol {
public func isEqual(to model: ModelComparisonProtocol) -> Bool {
return false
}
}
public extension Optional {
/// Checks if the current model is equal to another model.
func isEqual(to model: ModelComparisonProtocol?) -> Bool {
guard let self = self as? ModelComparisonProtocol else {
return model == nil
}
guard let model = model else {
return false
}
return self.isEqual(to: model)
}
}
public extension Collection {
/// Checks if all the models in the given collection match another given collection.
func isEqual(to models: [ModelComparisonProtocol]) -> Bool {
guard count == models.count, let self = self as? [ModelComparisonProtocol] else { return false }
return models.indices.allSatisfy { index in
self[index].isEqual(to: models[index])
}
}
}
public extension Optional where Wrapped: Collection {
/// Checks if the current model is equal to another model.
func isEqual(to models: [ModelComparisonProtocol]?) -> Bool {
guard let self = self as? [ModelComparisonProtocol] else {
return models == nil
}
guard let models = models else {
return false
}
return self.isEqual(to: models)
}
}
public extension Optional {
/// Checks if
func matchExistence(with anotherOptional: Optional) -> Bool {
switch(self) {
case .none:
return anotherOptional == nil
case .some(_):
return anotherOptional != nil
}
}
}
func == (lhs: (any ModelComparisonProtocol)?, rhs: (any ModelComparisonProtocol)?) -> Bool {
switch (lhs, rhs) {
case (.some(let lhs), .some(let rhs)):
return lhs.isEqual(to: rhs)
case (.none, .none):
return true
default:
return false
}
}
func != (lhs: (any ModelComparisonProtocol)?, rhs: (any ModelComparisonProtocol)?) -> Bool {
return !(lhs == rhs)
}
func == (lhs: [any ModelComparisonProtocol]?, rhs: [any ModelComparisonProtocol]?) -> Bool {
switch (lhs, rhs) {
case (.some(let lhs), .some(let rhs)):
return lhs == rhs
case (.none, .none):
return true
default:
return false
}
}
func != (lhs: [any ModelComparisonProtocol]?, rhs: [any ModelComparisonProtocol]?) -> Bool {
return !(lhs == rhs)
}
func == (lhs: [any ModelComparisonProtocol], rhs: [any ModelComparisonProtocol]) -> Bool {
return lhs.elementsEqual(rhs, by: { (lhsElement, rhsElement) -> Bool in
return lhsElement == rhsElement
})
}
func != (lhs: [any ModelComparisonProtocol], rhs: [any ModelComparisonProtocol]) -> Bool {
return !(lhs == rhs)
}

View File

@ -40,9 +40,9 @@ public struct ModelRegistry {
/// - Parameters:
/// - handler: The handling class taking an object of ModelHandlerProtocol.self which is used to register
/// - model: The data object of ModelProtocol.self which is used to register
public static func register<H: ModelHandlerProtocol, M: ModelProtocol>(handler: H.Type, for model: M.Type) {
public static func register<H: ModelHandlerProtocol, M: ModelProtocol>(handler: H.Type, for model: M.Type, allowsReplace: Bool = false) {
do {
try throwable_register(handler: handler, model: model)
try throwable_register(handler: handler, model: model, allowsReplace: allowsReplace)
} catch {
handleError(error)
}
@ -50,9 +50,9 @@ public struct ModelRegistry {
/// A convenience wrapping function where error handling is managed within the class.
/// - Parameter type: Takes an object of ModelProtocol.self which is used to register
public static func register<M: ModelProtocol>(_ type: M.Type) {
public static func register<M: ModelProtocol>(_ type: M.Type, allowsReplace: Bool = false) {
do {
try throwable_register(type: type)
try throwable_register(type: type, allowsReplace: allowsReplace)
} catch {
handleError(error)
}
@ -103,7 +103,7 @@ public struct ModelRegistry {
errorObject.title = "Unknown Model Registry Error"
}
MVMCoreLoggingHandler.addError(toLog: errorObject)
MVMCoreLoggingHandler.shared()?.addError(toLog: errorObject)
#if DEBUG
triggerCrashInDebug()
#endif
@ -124,9 +124,9 @@ public struct ModelRegistry {
/// - handler: The handling class taking an object of ModelHandlerProtocol.self which is used to register
/// - model: The data object of ModelProtocol.self which is used to register
/// - Throws: An Error object of `ModelRegistry.Error`
public static func throwable_register<H: ModelHandlerProtocol, M: ModelProtocol>(handler: H.Type, model: M.Type) throws {
public static func throwable_register<H: ModelHandlerProtocol, M: ModelProtocol>(handler: H.Type, model: M.Type, allowsReplace: Bool = false) throws {
// Register the type
try self.throwable_register(type: model)
try self.throwable_register(type: model, allowsReplace: allowsReplace)
// Get the key for the handler
let key = model.identifier
@ -136,24 +136,31 @@ public struct ModelRegistry {
// Check to ensure the Category/Container combination doesn't exist.
if category.handlerTypes[key] != nil {
throw ModelRegistry.Error.duplicateRegistration(message: "ModelHandlerProtocol: \(String(describing: handler)) already exists in Category: \(category.name)")
} else {
category.handlerTypes[key] = handler
if allowsReplace {
MVMCoreLoggingHandler.logDebugMessage(withDelegate: "Duplicate Registration: writing over \(category.handlerTypes[key]!) with \(handler)")
} else {
throw ModelRegistry.Error.duplicateRegistration(message: "ModelHandlerProtocol: \(String(describing: handler)) already exists in Category: \(category.name)")
}
}
category.handlerTypes[key] = handler
categories[category.name] = category
}
/// Registers models for Atomic use.
/// - Parameter type: Takes an object of ModelProtocol.self which is used to register
/// - Throws: An Error object of `ModelRegistry.Error`
public static func throwable_register<M: ModelProtocol>(type: M.Type) throws {
public static func throwable_register<M: ModelProtocol>(type: M.Type, allowsReplace: Bool = false) throws {
// Get the category for the ModelProtocol
var category = getCategory(for: type)
// Check to ensure the Category/Type combination doesn't exist.
if category.instanceTypes[M.identifier] != nil {
throw ModelRegistry.Error.duplicateRegistration(message: "ModelProtocol: \(M.identifier) already exists in Category: \(M.categoryName)")
if allowsReplace {
MVMCoreLoggingHandler.logDebugMessage(withDelegate: "Duplicate Registration: writing over \(category.instanceTypes[M.identifier]!) with \(type)")
} else {
throw ModelRegistry.Error.duplicateRegistration(message: "ModelProtocol: \(M.identifier) already exists in Category: \(M.categoryName)")
}
}
category.instanceTypes[M.identifier] = type
@ -204,7 +211,7 @@ public struct ModelRegistry {
public static func getCodingKey<T>(for type: T.Type) throws -> AnyCodingKey {
guard let category = getCategory(for: type) else {
throw ModelRegistry.Error.decoderOther(message: "decodeModelsIfPresent only works for objects implementing the ModelProtocol protocol")
throw ModelRegistry.Error.decoderOther(message: "Category hasnt been registered for the CodingKey for this type: \(String(describing: type.self))")
}
return AnyCodingKey(category.codingKey)

View File

@ -12,18 +12,18 @@
open class func registerActions() {
ModelRegistry.register(ActionRunJavaScriptModel.self)
ModelRegistry.register(ActionOpenPageModel.self)
ModelRegistry.register(ActionOpenUrlModel.self)
ModelRegistry.register(ActionCallModel.self)
ModelRegistry.register(ActionBackModel.self)
ModelRegistry.register(ActionShareModel.self)
ModelRegistry.register(ActionRestartModel.self)
ModelRegistry.register(ActionPreviousSubmitModel.self)
ModelRegistry.register(ActionCancelModel.self)
ModelRegistry.register(ActionSettingModel.self)
ModelRegistry.register(ActionNoopModel.self)
ModelRegistry.register(ActionActionsModel.self)
ModelRegistry.register(ActionOpenSMSModel.self)
ModelRegistry.register(ActionContactModel.self)
ModelRegistry.register(handler: ActionOpenPageHandler.self, for: ActionOpenPageModel.self)
ModelRegistry.register(handler: ActionOpenUrlHandler.self, for: ActionOpenUrlModel.self)
ModelRegistry.register(handler: ActionCallHandler.self, for: ActionCallModel.self)
ModelRegistry.register(handler: ActionBackHandler.self, for: ActionBackModel.self)
ModelRegistry.register(handler: ActionShareHandler.self, for: ActionShareModel.self)
ModelRegistry.register(handler: ActionRestartHandler.self, for: ActionRestartModel.self)
ModelRegistry.register(handler: ActionPreviousSubmitHandler.self, for: ActionPreviousSubmitModel.self)
ModelRegistry.register(handler: ActionCancelHandler.self, for: ActionCancelModel.self)
ModelRegistry.register(handler: ActionSettingHandler.self, for: ActionSettingModel.self)
ModelRegistry.register(handler: ActionNoopHandler.self, for: ActionNoopModel.self)
ModelRegistry.register(handler: ActionActionsHandler.self, for: ActionActionsModel.self)
ModelRegistry.register(handler: ActionOpenSMSHandler.self, for: ActionOpenSMSModel.self)
ModelRegistry.register(handler: ActionContactHandler.self, for: ActionContactModel.self)
}
}

View File

@ -0,0 +1,106 @@
//
// Cache.swift
// JSONCreator
//
// Created by Matt Bruce on 3/20/24.
// Copyright © 2024 Verizon Wireless. All rights reserved.
//
import Foundation
public enum CacheError: Error {
case serializationFailed
case deserializationFailed
case dataNotFound
case dataExpired
case saveFailed(Error)
case loadFailed(Error)
}
public class CachedData: Codable {
public var data: [String: AnyHashable]
public var expirationDate: Date
enum CodingKeys: CodingKey {
case data, expirationDate
}
public init(data: [String: AnyHashable], expirationDate: Date) {
self.data = data
self.expirationDate = expirationDate
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(expirationDate, forKey: .expirationDate)
let dataAsData = try JSONSerialization.data(withJSONObject: data, options: [])
try container.encode(dataAsData, forKey: .data)
}
required public init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
expirationDate = try values.decode(Date.self, forKey: .expirationDate)
let dataAsData = try values.decode(Data.self, forKey: .data)
guard let jsonData = try JSONSerialization.jsonObject(with: dataAsData, options: []) as? [String: AnyHashable] else {
throw CacheError.deserializationFailed
}
data = jsonData
}
}
@objc public class PersistentCacheManager: NSObject {
@objc public static let shared = PersistentCacheManager()
private let fileManager = FileManager.default
@objc public lazy var cacheDirectory = { fileManager.urls(for: .cachesDirectory, in: .userDomainMask).first!.appendingPathComponent("Atomic")}()
private override init() {}
@objc public func save(data: [String: AnyHashable], forKey key: String, path: URL, expirationDate: Date) throws {
let cachedData = CachedData(data: data, expirationDate: expirationDate)
do {
try FileManager.default.createDirectory(atPath: path.deletingLastPathComponent().relativePath, withIntermediateDirectories: true, attributes: [.protectionKey: FileProtectionType.complete])
let dataToSave = try JSONEncoder().encode(cachedData)
try dataToSave.write(to: path, options: [.atomic, .completeFileProtection])
MVMCoreLoggingHandler.logDebugMessage(withDelegate: "CACHEDFEED: SAVED TO PERSISTENT CACHE, key:\(key), path:\(path)")
} catch is EncodingError {
throw CacheError.serializationFailed
} catch {
throw CacheError.saveFailed(error)
}
}
@objc public func load(forKey key: String, path: URL) throws -> [String: AnyHashable] {
do {
let data = try Data(contentsOf: path)
let decodedCachedData = try JSONDecoder().decode(CachedData.self, from: data)
if Date() < decodedCachedData.expirationDate {
MVMCoreLoggingHandler.logDebugMessage(withDelegate: "CACHEDFEED: LOADED FROM PERSISTENT CACHE, key:\(key), path:\(path)")
return decodedCachedData.data
} else {
MVMCoreLoggingHandler.logDebugMessage(withDelegate: "CACHEDFEED: EXPIRED, key:\(key), path:\(path)")
throw CacheError.dataExpired
}
} catch {
// Remove item from the cache on any failure.
try fileManager.removeItem(at: path)
switch error {
case is DecodingError:
throw CacheError.deserializationFailed
default:
throw CacheError.loadFailed(error)
}
}
}
@objc public func remove(forKey key: String) throws {
let filePath = self.filePath(forKey: key)
try fileManager.removeItem(at: filePath)
}
@objc public func removeAll() throws {
try FileManager.default.removeItem(at: cacheDirectory)
}
private func filePath(forKey key: String) -> URL {
return cacheDirectory.appendingPathComponent("\(key).json")
}
}

View File

@ -12,6 +12,9 @@
#import <AVKit/AVKit.h>
@class MVMCoreErrorObject;
extern NSString * _Nonnull const KeyCachePolicy;
extern NSString * _Nonnull const KeyCacheExpiry;
//block returned when getting image
//parameters are UIImage object for the image, NSData for gif images, UIImage object for the image, A BOOL to indicate if it is a fall back image.
typedef void(^MVMCoreGetImageBlock)(UIImage * _Nullable, NSData * _Nullable, BOOL);
@ -31,10 +34,28 @@ typedef void(^MVMCoreGetImageBlock)(UIImage * _Nullable, NSData * _Nullable, BOO
#pragma mark - Page and Module Handling
// Checks the set of pageTypes to be cached for the given pageType.
- (BOOL)shouldCacheJSONWithPageType:(nonnull NSString *)pageType;
- (BOOL)shouldCachePageJSON:(nonnull NSDictionary *)jsonDictionary pageType:(nonnull NSString *)pageType;
// Checks the set of modules to be cached for the given module
- (BOOL)shouldCacheJSONWithModule:(nonnull NSString *)module;
- (BOOL)shouldCacheModuleJSON:(nonnull NSDictionary *)jsonDictionary moduleName:(nonnull NSString *)moduleName;
/// Returns if the json is expired or not.
- (BOOL)isJSONExpired:(nonnull NSDictionary *)jsonDictionary;
/// Returns the expiry time for the object.
- (nonnull NSDate *)getExpirationDateForJSON:(nonnull NSDictionary *)jsonDictionary;
/// Checks if the page is to be persistently cached.
- (BOOL)shouldPersistentlyCachePage:(nonnull NSDictionary *)jsonDictionary pageType:(nonnull NSString *)pageType;
/// Checks if the module is to be persistently cached.
- (BOOL)shouldPersistentlyCacheModule:(nonnull NSDictionary *)jsonDictionary module:(nonnull NSString *)module;
/// Can override the path for the page to be cached. Currently Cache/Atomic/Pages/pageType
- (nullable NSURL *)getPathForPersistentCachePage:(nonnull NSString *)pageType;
/// Can override the path for the page to be cached. Currently Cache/Atomic/Modules/moduleName
- (nullable NSURL *)getPathForPersistentCacheModule:(nonnull NSString *)moduleName;
// For pages external to the mobile first framework to be added to the list to not cache
- (void)addPageTypesToNotCache:(nullable NSArray <NSString *>*)array;
@ -53,6 +74,12 @@ typedef void(^MVMCoreGetImageBlock)(UIImage * _Nullable, NSData * _Nullable, BOO
// Gets a json dictionary from the cache with all the requested modules. Pass in the block that you want to run once the dictionary is received. This will be run on a background thread.
- (void)fetchJSONForModules:(nullable NSArray *)modules completionHandler:(nonnull void (^)(NSDictionary * _Nullable jsonDictionary))completionHandler;
/// Returns a page JSON from the persistent cache.
- (NSDictionary * _Nullable)fetchPageFromPersistentCache:(nonnull NSString *)pageType;
/// Returns a module JSON from the persistent cache.
- (NSDictionary * _Nullable)fetchModuleFromPersistentCache:(nonnull NSString *)moduleName;
#pragma mark - Advanced Fetch
// Pass in the block that you want to run once the dictionary is received and which queue to run it on. Pass in if you'd like the current thread to wait.
@ -75,6 +102,12 @@ typedef void(^MVMCoreGetImageBlock)(UIImage * _Nullable, NSData * _Nullable, BOO
// Adds a json dictionary to the cache by modules.
- (void)addModulesToCache:(nonnull NSDictionary *)jsonDictionary;
/// Adds the json to the persistent cache by pageType.
- (void)addPageToPersistentCache:(nonnull NSDictionary *)jsonDictionary pageType:(nonnull NSString *)pageType expirationDate:(nonnull NSDate *)expirationDate;
/// Adds the json to the persistent cache by module.
- (void)addModuleToPersistentCache:(nonnull NSDictionary *)jsonDictionary moduleName:(nonnull NSString *)moduleName expirationDate:(nonnull NSDate *)expirationDate;
#pragma mark - Advanced Insertion
// Adds a json dictionary to the cache by pageType. Pass in the block that you want to run once the dictionary is received and which queue to run it on. Pass in if you'd like the current thread to wait.
@ -111,6 +144,15 @@ typedef void(^MVMCoreGetImageBlock)(UIImage * _Nullable, NSData * _Nullable, BOO
// Removes the json for modules. Pass in the block that you want to run once the dictionary is received and which queue to run it on.
- (void)removeJSONForModules:(nonnull NSArray *)modules queue:(nullable NSOperationQueue *)queue waitUntilFinished:(BOOL)waitUntilFinished completionBlock:(nullable void (^)(void))completionBlock;
/// Clears the persistent JSON cache
- (void)clearPersistentJSONCache;
// Removes a json dictionary from the cache by pageType.
- (void)removePersistentJSONCacheForPageType:(nonnull NSString *)pageType pageJSON:(nonnull NSDictionary *)jsonDictionary;
// Removes a json dictionary from the cache by moduleType.
- (void)removePersistentModuleCacheForModule:(nonnull NSString *)moduleType moduleJSON:(nonnull NSDictionary *)jsonDictionary;
#pragma mark Image Functions
/// Register a bundle as one to search for images in.

View File

@ -9,14 +9,16 @@
#import "MVMCoreCache.h"
#import <MVMCore/NSDictionary+MFConvenience.h>
#import "MVMCoreErrorObject.h"
#import "MVMCoreLoggingHandler.h"
#import <MVMCore/MVMCore-Swift.h>
#import "MVMCoreGetterUtility.h"
#import "MVMCoreObject.h"
#import "MVMCoreConstants.h"
#import "MVMCoreActionUtility.h"
#import "MVMCoreLoggingHandler.h"
#import "MVMCoreDispatchUtility.h"
#import "MVMCoreErrorConstants.h"
#import "MVMCoreLoggingHandlerHelper.h"
NSString * _Nonnull const KeyCachePolicy = @"cachePolicy";
NSString * _Nonnull const KeyCacheExpiry = @"expiry";
@interface MVMCoreCache ()
@ -92,12 +94,55 @@ static NSString * const STATIC_CACHE_COMPONENT = @"StaticCache.txt";
return _modulesToNotCache;
}
- (BOOL)shouldCacheJSONWithPageType:(nonnull NSString *)pageType {
return ![self.pageTypesToNotCache containsObject:pageType];
- (BOOL)shouldCachePageJSON:(nonnull NSDictionary *)jsonDictionary pageType:(nonnull NSString *)pageType {
if ([self.pageTypesToNotCache containsObject:pageType]) { return NO; }
NSNumber *shouldCache = [jsonDictionary optionalNumberForKey:@"cache"];
return shouldCache == nil || shouldCache.boolValue;
}
- (BOOL)shouldCacheJSONWithModule:(nonnull NSString *)module {
return ![self.modulesToNotCache containsObject:module];
- (BOOL)shouldCacheModuleJSON:(nonnull NSDictionary *)jsonDictionary moduleName:(nonnull NSString *)moduleName {
if ([self.modulesToNotCache containsObject:moduleName]) { return NO; }
NSNumber *shouldCache = [jsonDictionary optionalNumberForKey:@"cache"];
return shouldCache == nil || shouldCache.boolValue;
}
- (BOOL)isJSONExpired:(nonnull NSDictionary *)jsonDictionary {
NSDate *expirationDate = [self getExpirationDateForJSON:jsonDictionary];
NSDate *now = [NSDate date];
if ([now compare:expirationDate] == NSOrderedDescending) {
[MVMCoreLoggingHandler logDebugMessageWithDelegate:[NSString stringWithFormat:@"CACHEDFEED: NEW DATA ALREADY EXPIRED %@ now:%@ expirationDate:%@",jsonDictionary,now,expirationDate]];
}
return [now compare:expirationDate] == NSOrderedDescending;
}
- (nonnull NSDate *)getExpirationDateForJSON:(nonnull NSDictionary *)jsonDictionary {
NSDictionary *cachePolicy = [jsonDictionary dict:KeyCachePolicy];
NSTimeInterval interval = [[cachePolicy string:KeyCacheExpiry] doubleValue] / 1000;
return [NSDate dateWithTimeIntervalSince1970:interval];
}
- (BOOL)shouldPersistentlyCacheJSON:(nonnull NSDictionary *)jsonDictionary {
NSDictionary *cachePolicy = [jsonDictionary dict:KeyCachePolicy];
if (!cachePolicy || ![cachePolicy boolForKey:@"persist"]) {
return NO;
}
return ![self isJSONExpired:jsonDictionary];
}
- (BOOL)shouldPersistentlyCachePage:(nonnull NSDictionary *)jsonDictionary pageType:(nonnull NSString *)pageType {
return [self shouldPersistentlyCacheJSON:jsonDictionary];
}
- (BOOL)shouldPersistentlyCacheModule:(nonnull NSDictionary *)jsonDictionary module:(nonnull NSString *)module {
return [self shouldPersistentlyCacheJSON:jsonDictionary];
}
- (nullable NSURL *)getPathForPersistentCachePage:(nonnull NSString *)pageType {
return [[[[PersistentCacheManager shared].cacheDirectory URLByAppendingPathComponent:@"Pages"] URLByAppendingPathComponent:pageType] URLByAppendingPathExtension:@"json"];
}
- (nullable NSURL *)getPathForPersistentCacheModule:(nonnull NSString *)moduleName {
return [[[[PersistentCacheManager shared].cacheDirectory URLByAppendingPathComponent:@"Modules"] URLByAppendingPathComponent:moduleName]URLByAppendingPathExtension:@"json"];
}
- (void)addPageTypesToNotCache:(nullable NSArray <NSString *>*)array {
@ -126,6 +171,24 @@ static NSString * const STATIC_CACHE_COMPONENT = @"StaticCache.txt";
[self fetchJSONForModules:modules queue:self.completionQueue waitUntilFinished:NO completionHandler:completionHandler];
}
- (NSDictionary * _Nullable)fetchPageFromPersistentCache:(nonnull NSString *)pageType {
NSError *error = nil;
return [[PersistentCacheManager shared] loadForKey:pageType path:[self getPathForPersistentCachePage:pageType] error:&error];
}
- (NSDictionary * _Nullable)fetchModuleFromPersistentCache:(nonnull NSString *)moduleName {
NSError *error = nil;
return [[PersistentCacheManager shared] loadForKey:moduleName path:[self getPathForPersistentCacheModule:moduleName] error:&error];
}
- (void)removePersistentJSONCacheForPageType:(nonnull NSString *)pageType pageJSON:(nonnull NSDictionary *)jsonDictionary {
[[PersistentCacheManager shared] removeForKey:pageType error:nil];
}
- (void)removePersistentModuleCacheForModule:(nonnull NSString *)moduleType moduleJSON:(nonnull NSDictionary *)jsonDictionary {
[[PersistentCacheManager shared] removeForKey:moduleType error:nil];
}
#pragma mark - Advanced Fetch
- (void)fetchJSONForPageType:(nullable NSString *)pageType queue:(nullable NSOperationQueue *)queue waitUntilFinished:(BOOL)waitUntilFinished completionHandler:(nonnull void (^)(NSDictionary * _Nullable jsonDictionary))completionHandler {
@ -141,6 +204,9 @@ static NSString * const STATIC_CACHE_COMPONENT = @"StaticCache.txt";
// First checks the cache by page type.
dictionary = [weakSelf.pageTypeCache objectForKey:pageType];
if (!dictionary) {
dictionary = [self fetchPageFromPersistentCache:pageType];
}
} else {
// If no pagetype, return whole cache
@ -177,6 +243,11 @@ static NSString * const STATIC_CACHE_COMPONENT = @"StaticCache.txt";
NSDictionary *moduleDictionary = [weakSelf.moduleCache objectForKey:module];
if (moduleDictionary) {
[modulesDictionary setObject:moduleDictionary forKey:module];
} else {
moduleDictionary = [self fetchModuleFromPersistentCache:module];
if (moduleDictionary) {
[modulesDictionary setObject:moduleDictionary forKey:module];
}
}
}
@ -207,16 +278,37 @@ static NSString * const STATIC_CACHE_COMPONENT = @"StaticCache.txt";
[self addModulesToCache:jsonDictionary queue:nil waitUntilFinished:NO completionBlock:NULL];
}
- (void)addPageToPersistentCache:(nonnull NSDictionary *)jsonDictionary pageType:(nonnull NSString *)pageType expirationDate:(nonnull NSDate *)expirationDate {
NSError *error = nil;
[[PersistentCacheManager shared] saveWithData:jsonDictionary forKey:pageType path:[self getPathForPersistentCachePage:pageType] expirationDate:expirationDate error:&error];
if (error) {
[[MVMCoreLoggingHandler sharedLoggingHandler] addErrorToLog:[MVMCoreErrorObject createErrorObjectForNSError:error location:[NSString stringWithFormat:@"%s_%@",__PRETTY_FUNCTION__,pageType]]];
}
}
- (void)addModuleToPersistentCache:(nonnull NSDictionary *)jsonDictionary moduleName:(nonnull NSString *)moduleName expirationDate:(nonnull NSDate *)expirationDate {
NSError *error = nil;
[[PersistentCacheManager shared] saveWithData:jsonDictionary forKey:moduleName path:[self getPathForPersistentCacheModule:moduleName] expirationDate:expirationDate error:&error];
if (error) {
[[MVMCoreLoggingHandler sharedLoggingHandler] addErrorToLog:[MVMCoreErrorObject createErrorObjectForNSError:error location:[NSString stringWithFormat:@"%s_%@",__PRETTY_FUNCTION__,moduleName]]];
}
}
#pragma mark - Advanced Insertion
- (void)addPageToCache:(nonnull NSDictionary *)jsonDictionary pageType:(nonnull NSString *)pageType queue:(nullable NSOperationQueue *)queue waitUntilFinished:(BOOL)waitUntilFinished completionBlock:(nullable void (^)(void))completionBlock {
if (![self shouldCachePageJSON:jsonDictionary pageType:pageType]) {
if (completionBlock) {
completionBlock();
}
return;
}
NSBlockOperation *addOperation = [[NSBlockOperation alloc] init];
__weak NSBlockOperation *weakOperation = addOperation;
__weak typeof(self) weakSelf = self;
[addOperation addExecutionBlock:^{
if (!weakOperation.isCancelled && [[MVMCoreCache sharedCache] shouldCacheJSONWithPageType:pageType]) {
if (!weakOperation.isCancelled) {
// There must be a dictionary and page type to cache.
if (jsonDictionary && pageType) {
@ -228,10 +320,13 @@ static NSString * const STATIC_CACHE_COMPONENT = @"StaticCache.txt";
}
// Adds json to cache with page type key.
NSNumber *shouldCache = [jsonDictionary optionalNumberForKey:@"cache"];
if (shouldCache == nil || shouldCache.boolValue) {
[weakSelf.pageTypeCache setObject:jsonDictionary forKey:pageType];
[weakSelf.pageTypeCache setObject:jsonDictionary forKey:pageType];
if (![self shouldPersistentlyCachePage:jsonDictionary pageType:pageType]) {
[self removePersistentJSONCacheForPageType:pageType pageJSON:jsonDictionary];
return;
}
[self addPageToPersistentCache:jsonDictionary pageType:pageType expirationDate:[self getExpirationDateForJSON:jsonDictionary]];
}
}
if (completionBlock) {
@ -242,11 +337,12 @@ static NSString * const STATIC_CACHE_COMPONENT = @"StaticCache.txt";
}
- (void)addModuleToCache:(nonnull NSDictionary *)jsonDictionary module:(nonnull NSString *)module queue:(nullable NSOperationQueue *)queue waitUntilFinished:(BOOL)waitUntilFinished completionBlock:(nullable void (^)(void))completionBlock {
[self addModulesToCache:@{module:jsonDictionary} queue:queue waitUntilFinished:waitUntilFinished completionBlock:completionBlock];
}
- (void)addModulesToCache:(nonnull NSDictionary *)jsonDictionary queue:(nullable NSOperationQueue *)queue waitUntilFinished:(BOOL)waitUntilFinished completionBlock:(nullable void (^)(void))completionBlock {
if (![self shouldCacheModuleJSON:jsonDictionary moduleName:module]) {
if (completionBlock) {
completionBlock();
}
return;
}
NSBlockOperation *addOperation = [[NSBlockOperation alloc] init];
__weak NSBlockOperation *weakOperation = addOperation;
__weak typeof(self) weakSelf = self;
@ -254,23 +350,19 @@ static NSString * const STATIC_CACHE_COMPONENT = @"StaticCache.txt";
if (!weakOperation.isCancelled) {
[jsonDictionary enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
if (!weakSelf.moduleCache) {
if ([[MVMCoreCache sharedCache] shouldCacheJSONWithModule:key]) {
if (!weakSelf.moduleCache) {
// Create the cache if necessary.
weakSelf.moduleCache = [NSMutableDictionary dictionary];
}
// Adds json to cache with page type key.
NSNumber *shouldCache = [jsonDictionary optionalNumberForKey:@"cache"];
if (shouldCache == nil || shouldCache.boolValue) {
[weakSelf.moduleCache setObject:obj forKey:key];
}
}
}];
// Create the cache if necessary.
weakSelf.moduleCache = [NSMutableDictionary dictionary];
}
[weakSelf.moduleCache setObject:jsonDictionary forKey:module];
if (![self shouldPersistentlyCacheModule:jsonDictionary module:module]) {
[self removePersistentModuleCacheForModule:module moduleJSON:jsonDictionary];
return;
}
[self addModuleToPersistentCache:jsonDictionary moduleName:module expirationDate:[self getExpirationDateForJSON:jsonDictionary]];
}
if (completionBlock) {
[(queue ?: weakSelf.completionQueue) addOperations:@[[NSBlockOperation blockOperationWithBlock:completionBlock]] waitUntilFinished:waitUntilFinished];
@ -279,6 +371,28 @@ static NSString * const STATIC_CACHE_COMPONENT = @"StaticCache.txt";
[self.moduleQueue addOperations:@[addOperation] waitUntilFinished:waitUntilFinished];
}
- (void)addModulesToCache:(nonnull NSDictionary *)jsonDictionary queue:(nullable NSOperationQueue *)queue waitUntilFinished:(BOOL)waitUntilFinished completionBlock:(nullable void (^)(void))completionBlock {
[jsonDictionary enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
if (![obj isKindOfClass:[NSDictionary class]]) {
MVMCoreErrorObject *error = [[MVMCoreErrorObject alloc]
initWithTitle:nil
messageToLog:[NSString stringWithFormat:@"Invalid module format. Cannot cache %@ as it's not an object", key]
code:ErrorCodeJSONNotDictionary
domain:ErrorDomainSystem
location:NSStringFromClass([self class])];
[MVMCoreLoggingHandler.sharedLoggingHandler addErrorToLog:error];
return;
}
[self addModuleToCache:obj module:key];
}];
__weak typeof(self) weakSelf = self;
[self.moduleQueue addOperations:@[[NSBlockOperation blockOperationWithBlock:^{
if (completionBlock) {
[(queue ?: weakSelf.completionQueue) addOperations:@[[NSBlockOperation blockOperationWithBlock:completionBlock]] waitUntilFinished:waitUntilFinished];
}
}]] waitUntilFinished:waitUntilFinished];
}
#pragma mark - Simple Deletion
- (void)removeJSONForPageType:(nonnull NSString *)pageType {
@ -293,6 +407,10 @@ static NSString * const STATIC_CACHE_COMPONENT = @"StaticCache.txt";
[self removeJSONForModules:modules queue:nil waitUntilFinished:NO completionBlock:NULL];
}
- (void)clearPersistentJSONCache {
[[PersistentCacheManager shared] removeAllAndReturnError:nil];
}
- (void)clearMFCache {
[self.pageTypeQueue cancelAllOperations];
[self.moduleQueue cancelAllOperations];
@ -330,6 +448,7 @@ static NSString * const STATIC_CACHE_COMPONENT = @"StaticCache.txt";
}
}];
[self.pageTypeQueue addOperations:@[removeOperation] waitUntilFinished:waitUntilFinished];
[[PersistentCacheManager shared] removeForKey:pageType error:nil];
}
- (void)removeJSONForModule:(nonnull NSString *)module queue:(nullable NSOperationQueue *)queue waitUntilFinished:(BOOL)waitUntilFinished completionBlock:(nullable void (^)(void))completionBlock {
@ -353,6 +472,7 @@ static NSString * const STATIC_CACHE_COMPONENT = @"StaticCache.txt";
}
}];
[self.moduleQueue addOperations:@[removeOperation] waitUntilFinished:waitUntilFinished];
[[PersistentCacheManager shared] removeForKey:module error:nil];
}
- (void)removeJSONForModules:(nonnull NSArray *)modules queue:(nullable NSOperationQueue *)queue waitUntilFinished:(BOOL)waitUntilFinished completionBlock:(nullable void (^)(void))completionBlock {
@ -372,6 +492,7 @@ static NSString * const STATIC_CACHE_COMPONENT = @"StaticCache.txt";
// Removes json from cache with module key.
[weakSelf.moduleCache removeObjectForKey:obj];
}
[[PersistentCacheManager shared] removeForKey:obj error:nil];
}
}];
if (completionBlock) {
@ -592,6 +713,10 @@ static NSString * const STATIC_CACHE_COMPONENT = @"StaticCache.txt";
//system stores cache based datatask and check cache based on response,
//need to manually store cache for response
[sharedCache storeCachedResponse:cachedReponse forRequest:request];
} else if (error) {
[[MVMCoreLoggingHandler sharedLoggingHandler]addErrorToLog:[MVMCoreErrorObject createErrorObjectForNSError:error location:@"MVMCoreCache->downloadImage"]];
} else {
[[MVMCoreLoggingHandler sharedLoggingHandler]addErrorToLog:[[MVMCoreErrorObject alloc] initWithTitle:nil messageToLog:[NSString stringWithFormat:@"Failed to download image %@", request.URL.absoluteString] code:0 domain:ErrorDomainSystem location:@"MVMCoreCache->downloadImage"]];
}
if (isGif) {
[self checkImage:nil imageData:data fallbackImage:fallbackImageName completionHandler:completionHandler];

View File

@ -0,0 +1,187 @@
//
// MVMCoreEvent.swift
// MVMCore
//
// https://oneconfluence.verizon.com/display/MFD/NewRelic+Client+Event+Logging
//
// Created by Kyle on 8/29/22.
// Copyright © 2022 myverizon. All rights reserved.
//
import Foundation
/// A list of possible events from the app.
public enum MVMCoreEvent {
// ----------------------------
// MARK: Action Events
// ----------------------------
/// Failed to decode the action payload.
case actionFailedToDecode(
pageType: String,
error: Error?
)
/// Could not find the action specified.
case actionNotFound(
name: String,
pageType: String
)
/// The core action handler was invoked and is in progress.
case actionInvoked(
name: String,
pageType: String,
uuid: String,
model: ActionModelProtocol
)
/// The core action handler failed to complete the action.
case actionFailed(
name: String,
pageType: String,
uuid: String,
model: ActionModelProtocol,
error: Error?
)
/// The core action handler completed an action.
case actionComplete(
name: String,
pageType: String,
uuid: String,
model: ActionModelProtocol
)
// ----------------------------
// MARK: ClientParameter Events
// ----------------------------
/// Could not find the client parameter specified.
case clientParameterNotFound(
name: String,
actionId: String
)
/// The client parameter handler was invoked and is in progress.
case clientParameterStartFetch(
name: String,
uuid: String,
actionId: String
)
/// The client perameter handler timed out and is returning a default value.
case clientParameterTimeout(
name: String,
uuid: String,
actionId: String
)
/// The client paramter fetch completed.
case clientParameterFetchComplete(
name: String,
uuid: String,
actionId: String
)
case pageStarted(
pageType: String,
requestUUID: String
)
case pageLoadStarted(
pageType: String,
requestUUID: String,
requestURL: String
)
case pageLoadComplete(
pageType: String,
requestUUID: String,
serverProcessingTime: String,
requestURL: String,
isFromCache: Bool
)
case pageProcessingComplete(
pageType: String,
requestUUID: String,
webUrl: String?
)
case pageRenderComplete(
pageType: String,
requestUUID: String,
templateName: String?,
controllerName: String,
error: String?
)
public enum EventType: String {
case action
case clientParameter
case pageLoad
public var notification: Notification.Name {
return Notification.Name(rawValue: rawValue)
}
}
public var type: EventType {
switch self {
case .actionFailedToDecode: return .action
case .actionNotFound: return .action
case .actionInvoked: return .action
case .actionFailed: return .action
case .actionComplete: return .action
case .clientParameterNotFound: return .clientParameter
case .clientParameterStartFetch: return .clientParameter
case .clientParameterTimeout: return .clientParameter
case .clientParameterFetchComplete: return .clientParameter
case .pageStarted, .pageLoadStarted, .pageLoadComplete, .pageProcessingComplete, .pageRenderComplete: return .pageLoad
}
}
public var name: String {
let name = String(describing: self)
if let attribIndex = name.firstIndex(of: "(") {
return String(name[..<attribIndex])
}
return name
}
public var notification: Notification.Name {
return Notification.Name(rawValue: type.rawValue)
}
}
public extension MVMCoreLoggingHandler {
func logCoreEvent(_ event: MVMCoreEvent, at timestamp: Int64 = Date.unixMillisecondsNow()) {
recordEvent(event.type.rawValue, attributes: ["timestamp": timestamp, "event": event])
}
}
@objc public extension MVMCoreLoggingHandler {
@objc func pageStarted(for pageType: String, requestUUID: String) {
logCoreEvent(.pageStarted(pageType: pageType, requestUUID: requestUUID))
}
@objc func logPageLoadStarted(for pageType: String, requestUUID: String, requestURL: String) {
logCoreEvent(.pageLoadStarted(pageType: pageType, requestUUID: requestUUID, requestURL: requestURL))
}
@objc func logPageLoadComplete(for pageType: String, serverProcessingTime: String, requestURL: String, requestUUID: String, isFromCache: Bool) {
logCoreEvent(.pageLoadComplete(pageType: pageType, requestUUID: requestUUID, serverProcessingTime: serverProcessingTime, requestURL: requestURL, isFromCache: isFromCache))
}
@objc func logPageProcessingComplete(for pageType: String, requestUUID: String, webUrl: String?) {
logCoreEvent(.pageProcessingComplete(pageType: pageType, requestUUID: requestUUID, webUrl: webUrl))
}
@objc func logPageRenderComplete(for pageType: String, requestUUID: String, templateName: String?, controllerName: String, error: String?) {
logCoreEvent(.pageRenderComplete(pageType: pageType, requestUUID: requestUUID, templateName: templateName, controllerName: controllerName, error: error))
}
}

View File

@ -7,9 +7,31 @@
//
import Foundation
import os
@objc public extension MVMCoreLoggingHandler {
@objc func print(with message: String) {
Swift.print(message)
public protocol CoreLogging {
static var loggingCategory: String? { get }
var loggingPrefix: String { get }
}
public extension CoreLogging {
static var loggingCategory: String? { return nil }
var loggingPrefix: String {
return ""
}
static func debugLog(_ string: String) {
#if LOGGING
MVMCoreLoggingHandler.shared()?.handleDebugMessage(string, category: loggingCategory)
#endif
}
func debugLog(_ string: String) {
#if LOGGING
MVMCoreLoggingHandler.shared()?.handleDebugMessage("\(loggingPrefix)\(string)", category: Self.loggingCategory)
#endif
}
}

View File

@ -1,32 +0,0 @@
//
// MVMCoreLoggingHandler.h
// MVMCore
//
// Created by Pfeil, Scott Robert on 11/28/17.
// Copyright © 2017 myverizon. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <MVMCore/MVMCoreErrorObject.h>
#import <MVMCore/MVMCoreViewControllerProtocol.h>
#import <MVMCore/MVMCoreLoadObject.h>
#import <MVMCore/MVMCoreLoggingDelegateProtocol.h>
@class MVMCoreAlertController;
#define MVMCoreLog(fmt, ...) \
[MVMCoreLoggingHandler logDebugMessageWithDelegate:[NSString stringWithFormat:(@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__]];
@interface MVMCoreLoggingHandler : NSObject <MVMCoreLoggingDelegateProtocol>
+ (nullable instancetype)sharedLoggingHandler;
+ (void)addErrorToLog:(nonnull MVMCoreErrorObject *)errorObject;
+ (void)logDebugMessageWithDelegate:(nullable NSString *)message;
+ (void)logWithDelegateWithObject:(nullable id)object withName:(nullable NSString *)name withExtraInfo:(nullable NSDictionary *)extra;
+ (void)logWithDelegateLoadFinished:(nullable MVMCoreLoadObject *)loadObject loadedViewController:(nullable UIViewController <MVMCoreViewControllerProtocol> *)loadedViewController error:(nullable MVMCoreErrorObject *)error;
+ (void)logAlertForAlertController:(nullable MVMCoreAlertController *)alertController;
#pragma mark MVMCoreLoggingDelegateProtocol
- (void)handleDebugMessage:(nullable NSString *)message;
@end

View File

@ -1,62 +0,0 @@
//
// MVMCoreLoggingHandler.m
// MVMCore
//
// Created by Pfeil, Scott Robert on 11/28/17.
// Copyright © 2017 myverizon. All rights reserved.
//
#import "MVMCoreLoggingHandler.h"
#import "MVMCoreObject.h"
#import "MVMCoreActionUtility.h"
#import <MVMCore/MVMCore-Swift.h>
@implementation MVMCoreLoggingHandler
+ (nullable instancetype)sharedLoggingHandler {
if ([MVMCoreObject sharedInstance].loggingDelegate && [MVMCoreActionUtility classIsInstanceTypeOfClass:[MVMCoreObject sharedInstance].loggingDelegate.class otherClass:self throwException:NO]) {
return (MVMCoreLoggingHandler *)[MVMCoreObject sharedInstance].loggingDelegate;
} else {
return nil;
}
}
+ (void)addErrorToLog:(nonnull MVMCoreErrorObject *)errorObject {
if (errorObject && [[MVMCoreObject sharedInstance].loggingDelegate respondsToSelector:@selector(addErrorToLog:)]) {
[[MVMCoreObject sharedInstance].loggingDelegate addErrorToLog:errorObject];
}
}
+ (void)logDebugMessageWithDelegate:(nullable NSString *)message {
if (message && [[MVMCoreObject sharedInstance].loggingDelegate respondsToSelector:@selector(handleDebugMessage:)]) {
[[MVMCoreObject sharedInstance].loggingDelegate handleDebugMessage:message];
}
}
+ (void)logWithDelegateWithObject:(id)object withName:(nullable NSString *)name withExtraInfo:(nullable NSDictionary *)extra {
if ([[MVMCoreObject sharedInstance].loggingDelegate respondsToSelector:@selector(logWithObject:withName:withExtraInfo:)]) {
[[MVMCoreObject sharedInstance].loggingDelegate logWithObject:object withName:name withExtraInfo:extra];
}
}
+ (void)logWithDelegateLoadFinished:(nullable MVMCoreLoadObject *)loadObject loadedViewController:(nullable UIViewController <MVMCoreViewControllerProtocol> *)loadedViewController error:(nullable MVMCoreErrorObject *)error {
if ([[MVMCoreObject sharedInstance].loggingDelegate respondsToSelector:@selector(logLoadFinished:loadedViewController:error:)]) {
[[MVMCoreObject sharedInstance].loggingDelegate logLoadFinished:loadObject loadedViewController:loadedViewController error:error];
}
}
+ (void)logAlertForAlertController:(nullable MVMCoreAlertController *)alertController {
if ([[MVMCoreObject sharedInstance].loggingDelegate respondsToSelector:@selector(logAlertForAlertController:)]) {
[[MVMCoreObject sharedInstance].loggingDelegate logAlertForAlertController:alertController];
}
}
#pragma mark - logging delegate
- (void)handleDebugMessage:(nullable NSString *)message {
#ifdef DEBUG
[self printWith:message];
#endif
}
@end

View File

@ -0,0 +1,105 @@
//
// MVMCoreLoggingHandler.swift
// MVMCore
//
// Created by Nandhini Rajendran on 22/09/23.
// Copyright © 2023 myverizon. All rights reserved.
//
import Foundation
import os
@objc open class MVMCoreLoggingHandler: NSObject, MVMCoreLoggingDelegateProtocol {
public static let standardCategory = "General"
private let logger = Logger(subsystem: "MVMCoreLogging", category: standardCategory)
private var loggerCache = [String: Logger]()
open func getLogger(category: String?) -> Logger {
if let category {
if let logger = loggerCache[category] {
return logger
} else {
let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: category)
loggerCache[category] = logger
return logger
}
}
return logger
}
@objc(sharedLoggingHandler)
public static func shared() -> Self? {
return MVMCoreActionUtility.initializerClassCheck(MVMCoreObject.sharedInstance()?.loggingDelegate as? NSObject, classToVerify: self) as? Self
}
@objc public class func logDebugMessage(withDelegate message: String) {
MVMCoreObject.sharedInstance()?.loggingDelegate?.handleDebugMessage(message)
}
@objc(logWithDelegateLoadFinished:loadedViewController:error:)
public class func log(withDelegateLoadFinished loadObject: MVMCoreLoadObject?, loadedViewController: UIViewController?, error: MVMCoreErrorObject?) {
MVMCoreObject.sharedInstance()?.loggingDelegate?.logLoadFinished(loadObject, loadedViewController: loadedViewController as? MVMCoreViewControllerProtocol, error: error)
}
open func recordEvent(_ name: String, attributes: [String : Any]?) {}
// MARK: - logging delegate
@objc open func handleDebugMessage(_ message: String?) {
#if LOGGING
guard let message = message else { return }
guard message.count < 1024 else {
logger.debug("\(message.prefix(300), privacy: .public)... <stdio>") // Send initial log to console.
print(message) // Print the whole on stdout.
return
}
logger.debug("\(message, privacy: .public)") // Assume that becaues this is a LOGGING build we want these messages to be unmasked.
// TODO: How do we split the messaging by Library and Subsystem?
#endif
}
@objc open func handleDebugMessage(_ message: String, category: String?) {
#if LOGGING
guard message.count < 1024 else {
getLogger(category: category).debug("\(message.prefix(300), privacy: .public)... <stdio>") // Send initial log to console.
print(message) // Print the whole on stdout.
return
}
getLogger(category: category).debug("\(message, privacy: .public)") // Assume that becaues this is a LOGGING build we want these messages to be unmasked.
#endif
}
open func handleWarningMessage(_ message: String, category: String?) {
#if LOGGING
guard message.count < 1024 else {
getLogger(category: category).warning("\(message.prefix(300), privacy: .public)... <stdio>") // Send initial log to console.
print(message) // Print the whole on stdout.
return
}
getLogger(category: category).warning("\(message, privacy: .public)") // Assume that becaues this is a LOGGING build we want these messages to be unmasked.
#endif
}
open func handleErrorMessage(_ message: String, category: String?) {
#if LOGGING
guard message.count < 1024 else {
getLogger(category: category).error("\(message.prefix(300), privacy: .public)... <stdio>") // Send initial log to console.
print(message) // Print the whole on stdout.
return
}
getLogger(category: category).error("\(message, privacy: .public)") // Assume that becaues this is a LOGGING build we want these messages to be unmasked.
#endif
}
@objc(addErrorToLog:)
open func addError(toLog errorObject: MVMCoreErrorObject) {
if errorObject.silentError {
handleWarningMessage(errorObject.messageToLog ?? errorObject.messageToDisplay ?? "Some error occurred.", category: "Handled Exception")
} else {
handleErrorMessage(errorObject.messageToLog ?? errorObject.messageToDisplay ?? "Some error occurred.", category: "Handled Exception")
}
}
open func logLoadFinished(_ loadObject: MVMCoreLoadObject?, loadedViewController: MVMCoreViewControllerProtocol?, error: MVMCoreErrorObject?) {}
}

View File

@ -0,0 +1,18 @@
//
// MVMCoreLoggingHandlerHelper.h
// MVMCore
//
// Created by Nandhini Rajendran on 18/12/23.
// Copyright © 2023 myverizon. All rights reserved.
//
#ifndef MVMCoreLoggingHandlerHelper_h
#define MVMCoreLoggingHandlerHelper_h
#define MVMCoreLog(fmt, ...) \
[MVMCoreLoggingHandler logDebugMessageWithDelegate:[NSString stringWithFormat:(@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__]];
#define MVMCoreNetworkLog(fmt, ...) \
[MVMCoreLoggingHandler.sharedLoggingHandler handleDebugMessage:[NSString stringWithFormat:(@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__] category: @"Network"];
#endif

View File

@ -1,21 +0,0 @@
//
// MVMCoreDismissViewControllerOperation.h
// myverizon
//
// Created by Scott Pfeil on 9/28/15.
// Copyright © 2015 Verizon Wireless. All rights reserved.
//
// Operation for dismissing an alert view controller. Needs to be added to the main queue
#import "MVMCoreOperation.h"
#import <UIKit/UIKit.h>
@interface MVMCoreDismissViewControllerOperation : MVMCoreOperation
// Goes up the presentation chain to only dismiss the top presented.
- (nullable instancetype)initAndDismissTopViewController:(nullable UIViewController *)viewController animated:(BOOL)animated;
// Dismiss the passed in view controller.
- (nullable instancetype)initAndDismissViewController:(nullable UIViewController *)viewController animated:(BOOL)animated;
@end

View File

@ -1,91 +0,0 @@
//
// MVMCoreDismissViewControllerOperation.m
// myverizon
//
// Created by Scott Pfeil on 9/28/15.
// Copyright © 2015 Verizon Wireless. All rights reserved.
//
#import "MVMCoreDismissViewControllerOperation.h"
#import "MVMCoreConstants.h"
typedef NS_ENUM(NSInteger, DismissType) {
DismissTypeTop = 0,
DismissTypeSpecific
};
@interface MVMCoreDismissViewControllerOperation ()
@property (nullable, strong, nonatomic) UIViewController *viewController;
@property (nonatomic) BOOL animate;
@property (nonatomic) DismissType type;
@end
@implementation MVMCoreDismissViewControllerOperation
- (nullable instancetype)initAndDismissTopViewController:(nullable UIViewController *)viewController animated:(BOOL)animated {
if (self = [super init]) {
self.viewController = viewController;
self.animate = animated;
self.type = DismissTypeTop;
}
return self;
}
- (nullable instancetype)initAndDismissViewController:(nullable UIViewController *)viewController animated:(BOOL)animated {
if (self = [super init]) {
self.viewController = viewController;
self.animate = animated;
self.type = DismissTypeSpecific;
}
return self;
}
- (void)main {
// Always check for cancellation before launching the task.
if ([self checkAndHandleForCancellation]) {
return;
}
switch (self.type) {
case DismissTypeTop:
{
// Gets the top most presented.
UIViewController *controllerToDismiss = self.viewController;
while (controllerToDismiss.presentedViewController) {
controllerToDismiss = controllerToDismiss.presentedViewController;
}
[self dismissViewController:controllerToDismiss];
}
break;
case DismissTypeSpecific:
{
if (self.viewController.presentingViewController) {
[self dismissViewController:self.viewController.presentingViewController];
} else {
[self dismissViewController:self.viewController];
}
}
break;
default:
break;
}
}
- (void)dismissViewController:(nonnull UIViewController *)viewController {
if (viewController.presentedViewController || viewController.presentingViewController) {
[viewController dismissViewControllerAnimated:self.animate completion:^{
[self markAsFinished];
// Notify that page has changed
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:MVMCoreNotificationViewControllerChanged object:nil];
});
}];
} else {
[self markAsFinished];
}
}
@end

View File

@ -1,153 +0,0 @@
//
// MVMCoreNavigationHandler.h
// myverizon
//
// Created by Scott Pfeil on 11/18/15.
// Copyright © 2015 Verizon Wireless. All rights reserved.
//
// This class should be used to handle all navigation and presentation for mvm.
#import <Foundation/Foundation.h>
#import <MVMCore/MVMCorePresentationDelegateProtocol.h>
@class MVMCoreOperation;
@class MVMCoreNavigationObject;
@class MVMCoreLoadObject;
@interface MVMCoreNavigationHandler : NSObject <UINavigationControllerDelegate>
// Returns the shared instance of this singleton
+ (nullable instancetype)sharedNavigationHandler;
// Can set the view controller to present on... will use MF if nil.
@property (nullable, nonatomic, weak) UIViewController *viewControllerToPresentOn;
// reference to main navigation controller
@property (nullable, weak, nonatomic) UINavigationController *navigationController;
/// A list of possible delegates looking for information.
@property (nonnull, strong, nonatomic) NSHashTable<MVMCorePresentationDelegateProtocol> *delegates;
// Will navigate appropriately based on the load style
- (void)navigateWithLoadObject:(nullable MVMCoreLoadObject *)loadObject viewController:(nonnull UIViewController *)viewController delegate:(nullable NSObject<MVMCorePresentationDelegateProtocol>*)delegate completionHandler:(nullable void (^)(void))completionBlock;
// Perform navigation with object.
- (void)startNavigationWithNavigationObject:(nonnull MVMCoreNavigationObject *)navigationObject delegate:(nullable NSObject<MVMCorePresentationDelegateProtocol>*)delegate completionHandler:(nullable void (^)(void))completionBlock;
// pops or dimisses as needed
- (void)removeCurrentViewController;
#pragma mark - Delegate Handling
/// Adds a listener for navigation delegate functions
- (void)addDelegate:(nonnull id <MVMCorePresentationDelegateProtocol>)delegate;
/// Removes a listener for navigation delegate functions
- (void)removeDelegate:(nullable id <MVMCorePresentationDelegateProtocol>)delegate;
#pragma mark - Navigation Simple
// Uses the default navigation controller in app delegate
// Use this to push.
- (void)pushViewController:(nonnull UIViewController *)viewController animated:(BOOL)animated;
// Use this to replace the top view controller.
- (void)replaceTopViewControllerWithViewController:(nonnull UIViewController *)viewController animated:(BOOL)animated;
// Use this to replace all the view controllers after the root with the passed in view controller.
- (void)replaceAfterRoot:(nonnull UIViewController *)viewController animated:(BOOL)animated;
// Use this to set the navigation stack.
- (void)setViewControllers:(nonnull NSArray *)viewControllers animated:(BOOL)animated;
// Use this to pop.
- (void)popTopViewControllerAnimated:(BOOL)animated;
// Use this to pop a specific view controller.
- (void)popViewController:(nonnull UIViewController *)viewController animated:(BOOL)animated;
// Use this to pop to a specific view controller in the stack.
- (void)popToViewController:(nonnull UIViewController *)viewController animated:(BOOL)animated;
// Use this to pop to a view controller of a specific class in the stack.
- (void)popToInstanceOfClass:(nonnull Class)viewControllerClass animated:(BOOL)animated;
// Use this to pop to a view controller of a specific page type in the stack.
- (void)popToViewControllerWithPageType:(nonnull NSString *)pageType animated:(BOOL)animated;
// Use this to pop to the root of the stack.
- (void)popToRootAnimated:(BOOL)animated;
// Adds the navigation operation to the queue.
- (void)addNavigationOperation:(nonnull MVMCoreOperation *)operation;
// Removes all queued up items.
- (void)cancelNavigation;
#pragma mark - Navigation Extra
// Use this to push.
- (void)pushViewController:(nonnull UIViewController *)viewController navigationController:(nullable UINavigationController *)navigationController animated:(BOOL)animated delegate:(nullable NSObject<MVMCorePresentationDelegateProtocol>*)delegate replaceInStack:(BOOL)replaceInStack completionHandler:(nullable void (^)(void))completionBlock;
// Use this to replace the top view controller.
- (void)replaceTopViewControllerWithViewController:(nonnull UIViewController *)viewController navigationController:(nullable UINavigationController *)navigationController animated:(BOOL)animated delegate:(nullable NSObject<MVMCorePresentationDelegateProtocol>*)delegate replaceInStack:(BOOL)replaceInStack completionHandler:(nullable void (^)(void))completionBlock;
// Use this to replace all the view controllers after the root with the passed in view controller. If no navigation controller is provided, will use the main one in app delegate.
- (void)replaceAfterRoot:(nonnull UIViewController *)viewController navigationController:(nullable UINavigationController *)navigationController animated:(BOOL)animated delegate:(nullable NSObject<MVMCorePresentationDelegateProtocol>*)delegate replaceInStack:(BOOL)replaceInStack completionHandler:(nullable void (^)(void))completionBlock;
// Use this to set the navigation stack. If no navigation controller is provided, will use the main one in app delegate.
- (void)setViewControllers:(nonnull NSArray *)viewControllers navigationController:(nullable UINavigationController *)navigationController animated:(BOOL)animated delegate:(nullable NSObject<MVMCorePresentationDelegateProtocol>*)delegate replaceInStack:(BOOL)replaceInStack completionHandler:(nullable void (^)(void))completionBlock;
// Use this to pop. If no navigation controller is provided, will use the main one in app delegate.
- (void)popTopViewControllerAnimated:(BOOL)animated navigationController:(nullable UINavigationController *)navigationController delegate:(nullable NSObject<MVMCorePresentationDelegateProtocol>*)delegate completionHandler:(nullable void (^)(void))completionBlock;
// Use this to pop a specific view controller. If no navigation controller is provided, will use the main one in app delegate.
- (void)popViewController:(nonnull UIViewController *)viewController navigationController:(nullable UINavigationController *)navigationController animated:(BOOL)animated delegate:(nullable NSObject<MVMCorePresentationDelegateProtocol>*)delegate completionHandler:(nullable void (^)(void))completionBlock;
// Use this to pop to a specific view controller in the stack. If no navigation controller is provided, will use the main one in app delegate.
- (void)popToViewController:(nonnull UIViewController *)viewController navigationController:(nullable UINavigationController *)navigationController animated:(BOOL)animated delegate:(nullable NSObject<MVMCorePresentationDelegateProtocol>*)delegate completionHandler:(nullable void (^)(void))completionBlock;
// Use this to pop to a view controller of a specific class in the stack. If no navigation controller is provided, will use the main one in app delegate.
- (void)popToInstanceOfClass:(nonnull Class)viewControllerClass navigationController:(nullable UINavigationController *)navigationController animated:(BOOL)animated delegate:(nullable NSObject<MVMCorePresentationDelegateProtocol>*)delegate completionHandler:(nullable void (^)(void))completionBlock;
// Use this to pop to a view controller of a specific pageType in the stack. If no navigation controller is provided, will use the main one in app delegate.
- (void)popToViewControllerWithPageType:(nonnull NSString *)pageType navigationController:(nullable UINavigationController *)navigationController animated:(BOOL)animated delegate:(nullable NSObject<MVMCorePresentationDelegateProtocol>*)delegate completionHandler:(nullable void (^)(void))completionBlock;
// Use this to pop to the root of the stack. If no navigation controller is provided, will use the main one in app delegate.
- (void)popToRootAnimated:(BOOL)animated navigationController:(nullable UINavigationController *)navigationController delegate:(nullable NSObject<MVMCorePresentationDelegateProtocol>*)delegate completionHandler:(nullable void (^)(void))completionBlock;
/// Returns the view controllers of the navigation controller. Takes into account navigation controller animation states.
- (nullable NSArray<UIViewController *> *)getViewControllersForNavigationController:(nullable UINavigationController *)navigationController;
#pragma mark - Presentation Simple
// Use this to present.
- (void)presentViewController:(nonnull UIViewController *)viewController animated:(BOOL)animated;
// Use this to dismiss.
- (void)dismissTopViewControllerAnimated:(BOOL)animated;
// Use this to dismiss a specific view controller and any it may be presenting.
- (void)dismissViewController:(nonnull UIViewController *)viewController animated:(BOOL)animated;
// Use this to dismiss all presented view controllers stacked on the bottom one.
- (void)dismissToBottom:(BOOL)animated;
// Removes all queued up items.
- (void)cancelPresentation;
#pragma mark - Presentation Extra
// Use this to present.
- (void)presentViewController:(nonnull UIViewController *)viewController animated:(BOOL)animated delegate:(nullable NSObject<MVMCorePresentationDelegateProtocol>*)delegate completionHandler:(nullable void (^)(void))completionBlock;
// Use this to dismiss.
- (void)dismissTopViewControllerAnimated:(BOOL)animated delegate:(nullable NSObject<MVMCorePresentationDelegateProtocol>*)delegate completionHandler:(nullable void (^)(void))completionBlock;
// Use this to dismiss a specific view controller and any it may be presenting.
- (void)dismissViewController:(nonnull UIViewController *)viewController animated:(BOOL)animated delegate:(nullable NSObject<MVMCorePresentationDelegateProtocol>*)delegate completionHandler:(nullable void (^)(void))completionBlock;
// Use this to dismiss all presented view controllers stacked on the bottom one.
- (void)dismissToBottom:(BOOL)animated delegate:(nullable NSObject<MVMCorePresentationDelegateProtocol>*)delegate completionHandler:(nullable void (^)(void))completionBlock;
@end

View File

@ -1,355 +0,0 @@
//
// MVMCoreNavigationHandler.m
// myverizon
//
// Created by Scott Pfeil on 11/18/15.
// Copyright © 2015 Verizon Wireless. All rights reserved.
//
#import "MVMCoreNavigationHandler.h"
#import "MVMCoreNavigationOperation.h"
#import "MVMCorePresentViewControllerOperation.h"
#import "MVMCoreDismissViewControllerOperation.h"
#import "MVMCoreNavigationObject.h"
#import "MVMCoreLoadObject.h"
#import "MVMCoreObject.h"
#import "MVMCoreRequestParameters.h"
#import "MVMCoreErrorConstants.h"
#import "MVMCoreLoggingHandler.h"
#import "MVMCoreLoadingOverlayHandler.h"
#import "MVMCoreDispatchUtility.h"
@interface MVMCoreNavigationHandler ()
@property (strong, nonatomic) NSOperationQueue *navigationQueue;
@property (strong, nonatomic) NSOperationQueue *presentationQueue;
@end
@implementation MVMCoreNavigationHandler
+ (nullable instancetype)sharedNavigationHandler {
static dispatch_once_t once;
static id sharedInstance;
dispatch_once(&once, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
- (instancetype)init {
if (self = [super init]) {
self.navigationQueue = [[NSOperationQueue alloc] init];
self.navigationQueue.maxConcurrentOperationCount = 1;
self.presentationQueue = [[NSOperationQueue alloc] init];
self.presentationQueue.maxConcurrentOperationCount = 1;
self.delegates = (NSHashTable <MVMCorePresentationDelegateProtocol>*)[NSHashTable weakObjectsHashTable];
}
return self;
}
#pragma mark - Delegate Handling
- (void)addDelegate:(nonnull id <MVMCorePresentationDelegateProtocol>)delegate {
[self.delegates addObject:delegate];
}
- (void)removeDelegate:(nullable id <MVMCorePresentationDelegateProtocol>)delegate {
[self.delegates removeObject:delegate];
}
#pragma mark - Navigation Helpers
- (void)navigateWithLoadObject:(nullable MVMCoreLoadObject *)loadObject viewController:(nonnull UIViewController *)viewController delegate:(nullable NSObject<MVMCorePresentationDelegateProtocol>*)delegate completionHandler:(nullable void (^)(void))completionBlock {
BOOL shouldAnimate = !loadObject.requestParameters.shouldNotAnimatePush;
switch (loadObject.requestParameters.loadStyle) {
case MFLoadStyleReplaceCurrent:
{
// Replace current screen.
[[MVMCoreNavigationHandler sharedNavigationHandler] replaceTopViewControllerWithViewController:viewController navigationController:loadObject.requestParameters.navigationController animated:shouldAnimate delegate:delegate replaceInStack:loadObject.requestParameters.replaceViewIfOnStackElseLoadWithStyle completionHandler:completionBlock];
}
break;
case MFLoadStyleOnTopOfRoot:
{
// Pushes ater the root.
[[MVMCoreNavigationHandler sharedNavigationHandler] replaceAfterRoot:viewController navigationController:loadObject.requestParameters.navigationController animated:shouldAnimate delegate:delegate replaceInStack:loadObject.requestParameters.replaceViewIfOnStackElseLoadWithStyle completionHandler:completionBlock];
}
break;
case MFLoadStyleBecomeRoot:
{
// Loads as root the root.
NSArray *replaceViewControllers = @[viewController];
[[MVMCoreNavigationHandler sharedNavigationHandler] setViewControllers:replaceViewControllers navigationController:loadObject.requestParameters.navigationController animated:shouldAnimate delegate:delegate replaceInStack:loadObject.requestParameters.replaceViewIfOnStackElseLoadWithStyle completionHandler:completionBlock];
}
break;
case MFLoadStylePresent:
{
// Present as modal.
[[MVMCoreNavigationHandler sharedNavigationHandler] presentViewController:viewController animated:shouldAnimate delegate:delegate completionHandler:completionBlock];
}
break;
default:
{
// Just pushes.
[[MVMCoreNavigationHandler sharedNavigationHandler] pushViewController:viewController navigationController:loadObject.requestParameters.navigationController animated:shouldAnimate delegate:delegate replaceInStack:loadObject.requestParameters.replaceViewIfOnStackElseLoadWithStyle completionHandler:completionBlock];
}
break;
}
}
- (void)startNavigationWithNavigationObject:(MVMCoreNavigationObject *)navigationObject delegate:(nullable NSObject<MVMCorePresentationDelegateProtocol>*)delegate completionHandler:(nullable void (^)(void))completionBlock {
// In case it takes some time to happen.
[[MVMCoreLoadingOverlayHandler sharedLoadingOverlay] startLoading];
navigationObject.stopLoadingOverlay = YES;
MVMCoreNavigationOperation *navigationOperation = [[MVMCoreNavigationOperation alloc] initWithNavigationObject:navigationObject];
navigationOperation.delegate = delegate;
navigationOperation.completionBlock = completionBlock;
[self.navigationQueue addOperation:navigationOperation];
}
- (void)removeCurrentViewController {
[MVMCoreDispatchUtility performBlockOnMainThread:^{
// presentedViewController must be used on main thread
if (self.viewControllerToPresentOn.presentedViewController) {
[[MVMCoreNavigationHandler sharedNavigationHandler] dismissTopViewControllerAnimated:YES];
} else {
[[MVMCoreNavigationHandler sharedNavigationHandler] popTopViewControllerAnimated:YES];
}
}];
}
#pragma mark - Navigation Simple
- (void)pushViewController:(nonnull UIViewController *)viewController animated:(BOOL)animated {
MVMCoreNavigationObject *navigationObject = [[MVMCoreNavigationObject alloc] initWithViewController:viewController navigationController:nil viewControllers:nil animated:animated tryToReplaceFirst:NO navigationType:NavigationTypePush];
[self startNavigationWithNavigationObject:navigationObject delegate:nil completionHandler:NULL];
}
- (void)replaceTopViewControllerWithViewController:(nonnull UIViewController *)viewController animated:(BOOL)animated {
MVMCoreNavigationObject *navigationObject = [[MVMCoreNavigationObject alloc] initWithViewController:viewController navigationController:nil viewControllers:nil animated:animated tryToReplaceFirst:NO navigationType:NavigationTypeReplaceTop];
[self startNavigationWithNavigationObject:navigationObject delegate:nil completionHandler:NULL];
}
- (void)replaceAfterRoot:(nonnull UIViewController *)viewController animated:(BOOL)animated {
MVMCoreNavigationObject *navigationObject = [[MVMCoreNavigationObject alloc] initWithViewController:viewController navigationController:nil viewControllers:nil animated:animated tryToReplaceFirst:NO navigationType:NavigationTypeReplaceAfterRoot];
[self startNavigationWithNavigationObject:navigationObject delegate:nil completionHandler:NULL];
}
- (void)setViewControllers:(nonnull NSArray *)viewControllers animated:(BOOL)animated {
MVMCoreNavigationObject *navigationObject = [[MVMCoreNavigationObject alloc] initWithViewController:nil navigationController:nil viewControllers:viewControllers animated:animated tryToReplaceFirst:NO navigationType:NavigationTypeSet];
[self startNavigationWithNavigationObject:navigationObject delegate:nil completionHandler:NULL];
}
- (void)popTopViewControllerAnimated:(BOOL)animated {
MVMCoreNavigationObject *navigationObject = [[MVMCoreNavigationObject alloc] initWithViewController:nil navigationController:nil viewControllers:nil animated:animated tryToReplaceFirst:NO navigationType:NavigationTypePop];
[self startNavigationWithNavigationObject:navigationObject delegate:nil completionHandler:NULL];
}
- (void)popViewController:(nonnull UIViewController *)viewController animated:(BOOL)animated {
MVMCoreNavigationObject *navigationObject = [[MVMCoreNavigationObject alloc] initWithViewController:viewController navigationController:nil viewControllers:nil animated:animated tryToReplaceFirst:NO navigationType:NavigationTypePopSpecific];
[self startNavigationWithNavigationObject:navigationObject delegate:nil completionHandler:NULL];
}
- (void)popToViewController:(nonnull UIViewController *)viewController animated:(BOOL)animated {
MVMCoreNavigationObject *navigationObject = [[MVMCoreNavigationObject alloc] initWithViewController:viewController navigationController:nil viewControllers:nil animated:animated tryToReplaceFirst:NO navigationType:NavigationTypePopTo];
[self startNavigationWithNavigationObject:navigationObject delegate:nil completionHandler:NULL];
}
- (void)popToInstanceOfClass:(nonnull Class)viewControllerClass animated:(BOOL)animated {
MVMCoreNavigationObject *navigationObject = [[MVMCoreNavigationObject alloc] initWithViewController:nil navigationController:nil viewControllers:nil animated:animated tryToReplaceFirst:NO navigationType:NavigationTypePopTo];
navigationObject.classToPopTo = viewControllerClass;
[self startNavigationWithNavigationObject:navigationObject delegate:nil completionHandler:NULL];
}
- (void)popToViewControllerWithPageType:(nonnull NSString *)pageType animated:(BOOL)animated {
MVMCoreNavigationObject *navigationObject = [[MVMCoreNavigationObject alloc] initWithViewController:nil navigationController:nil viewControllers:nil animated:animated tryToReplaceFirst:NO navigationType:NavigationTypePopTo];
navigationObject.pageTypeToPopTo = pageType;
[self startNavigationWithNavigationObject:navigationObject delegate:nil completionHandler:NULL];
}
- (void)popToRootAnimated:(BOOL)animated {
MVMCoreNavigationObject *navigationObject = [[MVMCoreNavigationObject alloc] initWithViewController:nil navigationController:nil viewControllers:nil animated:animated tryToReplaceFirst:NO navigationType:NavigationTypePopToRoot];
[self startNavigationWithNavigationObject:navigationObject delegate:nil completionHandler:NULL];
}
- (void)addNavigationOperation:(nonnull MVMCoreOperation *)operation {
[self.navigationQueue addOperation:operation];
}
- (void)cancelNavigation {
[self.navigationQueue cancelAllOperations];
}
#pragma mark - Navigation Extra
- (void)pushViewController:(nonnull UIViewController *)viewController navigationController:(nullable UINavigationController *)navigationController animated:(BOOL)animated delegate:(nullable NSObject<MVMCorePresentationDelegateProtocol>*)delegate replaceInStack:(BOOL)replaceInStack completionHandler:(nullable void (^)(void))completionBlock {
MVMCoreNavigationObject *navigationObject = [[MVMCoreNavigationObject alloc] initWithViewController:viewController navigationController:navigationController viewControllers:nil animated:animated tryToReplaceFirst:replaceInStack navigationType:NavigationTypePush];
[self startNavigationWithNavigationObject:navigationObject delegate:delegate completionHandler:completionBlock];
}
- (void)replaceTopViewControllerWithViewController:(nonnull UIViewController *)viewController navigationController:(nullable UINavigationController *)navigationController animated:(BOOL)animated delegate:(nullable NSObject<MVMCorePresentationDelegateProtocol>*)delegate replaceInStack:(BOOL)replaceInStack completionHandler:(nullable void (^)(void))completionBlock {
MVMCoreNavigationObject *navigationObject = [[MVMCoreNavigationObject alloc] initWithViewController:viewController navigationController:navigationController viewControllers:nil animated:animated tryToReplaceFirst:replaceInStack navigationType:NavigationTypeReplaceTop];
[self startNavigationWithNavigationObject:navigationObject delegate:delegate completionHandler:completionBlock];
}
- (void)replaceAfterRoot:(nonnull UIViewController *)viewController navigationController:(nullable UINavigationController *)navigationController animated:(BOOL)animated delegate:(nullable NSObject<MVMCorePresentationDelegateProtocol>*)delegate replaceInStack:(BOOL)replaceInStack completionHandler:(nullable void (^)(void))completionBlock {
MVMCoreNavigationObject *navigationObject = [[MVMCoreNavigationObject alloc] initWithViewController:viewController navigationController:navigationController viewControllers:nil animated:animated tryToReplaceFirst:replaceInStack navigationType:NavigationTypeReplaceAfterRoot];
[self startNavigationWithNavigationObject:navigationObject delegate:delegate completionHandler:completionBlock];
}
- (void)setViewControllers:(nonnull NSArray *)viewControllers navigationController:(nullable UINavigationController *)navigationController animated:(BOOL)animated delegate:(nullable NSObject<MVMCorePresentationDelegateProtocol>*)delegate replaceInStack:(BOOL)replaceInStack completionHandler:(nullable void (^)(void))completionBlock {
MVMCoreNavigationObject *navigationObject = [[MVMCoreNavigationObject alloc] initWithViewController:nil navigationController:navigationController viewControllers:viewControllers animated:animated tryToReplaceFirst:replaceInStack navigationType:NavigationTypeSet];
[self startNavigationWithNavigationObject:navigationObject delegate:delegate completionHandler:completionBlock];
}
- (void)popTopViewControllerAnimated:(BOOL)animated navigationController:(nullable UINavigationController *)navigationController delegate:(nullable NSObject<MVMCorePresentationDelegateProtocol>*)delegate completionHandler:(nullable void (^)(void))completionBlock {
MVMCoreNavigationObject *navigationObject = [[MVMCoreNavigationObject alloc] initWithViewController:nil navigationController:navigationController viewControllers:nil animated:animated tryToReplaceFirst:NO navigationType:NavigationTypePop];
[self startNavigationWithNavigationObject:navigationObject delegate:delegate completionHandler:completionBlock];
}
- (void)popViewController:(nonnull UIViewController *)viewController navigationController:(nullable UINavigationController *)navigationController animated:(BOOL)animated delegate:(nullable NSObject<MVMCorePresentationDelegateProtocol>*)delegate completionHandler:(nullable void (^)(void))completionBlock {
MVMCoreNavigationObject *navigationObject = [[MVMCoreNavigationObject alloc] initWithViewController:viewController navigationController:navigationController viewControllers:nil animated:animated tryToReplaceFirst:NO navigationType:NavigationTypePopSpecific];
[self startNavigationWithNavigationObject:navigationObject delegate:delegate completionHandler:completionBlock];
}
- (void)popToViewController:(nonnull UIViewController *)viewController navigationController:(nullable UINavigationController *)navigationController animated:(BOOL)animated delegate:(nullable NSObject<MVMCorePresentationDelegateProtocol>*)delegate completionHandler:(nullable void (^)(void))completionBlock {
MVMCoreNavigationObject *navigationObject = [[MVMCoreNavigationObject alloc] initWithViewController:viewController navigationController:navigationController viewControllers:nil animated:animated tryToReplaceFirst:NO navigationType:NavigationTypePopTo];
[self startNavigationWithNavigationObject:navigationObject delegate:delegate completionHandler:completionBlock];
}
- (void)popToInstanceOfClass:(nonnull Class)viewControllerClass navigationController:(nullable UINavigationController *)navigationController animated:(BOOL)animated delegate:(nullable NSObject<MVMCorePresentationDelegateProtocol>*)delegate completionHandler:(nullable void (^)(void))completionBlock {
MVMCoreNavigationObject *navigationObject = [[MVMCoreNavigationObject alloc] initWithViewController:nil navigationController:navigationController viewControllers:nil animated:animated tryToReplaceFirst:NO navigationType:NavigationTypePopTo];
navigationObject.classToPopTo = viewControllerClass;
[self startNavigationWithNavigationObject:navigationObject delegate:delegate completionHandler:completionBlock];
}
- (void)popToViewControllerWithPageType:(nonnull NSString *)pageType navigationController:(nullable UINavigationController *)navigationController animated:(BOOL)animated delegate:(nullable NSObject<MVMCorePresentationDelegateProtocol>*)delegate completionHandler:(nullable void (^)(void))completionBlock {
MVMCoreNavigationObject *navigationObject = [[MVMCoreNavigationObject alloc] initWithViewController:nil navigationController:navigationController viewControllers:nil animated:animated tryToReplaceFirst:NO navigationType:NavigationTypePopTo];
navigationObject.pageTypeToPopTo = pageType;
[self startNavigationWithNavigationObject:navigationObject delegate:delegate completionHandler:completionBlock];
}
- (void)popToRootAnimated:(BOOL)animated navigationController:(nullable UINavigationController *)navigationController delegate:(nullable NSObject<MVMCorePresentationDelegateProtocol>*)delegate completionHandler:(nullable void (^)(void))completionBlock {
MVMCoreNavigationObject *navigationObject = [[MVMCoreNavigationObject alloc] initWithViewController:nil navigationController:navigationController viewControllers:nil animated:animated tryToReplaceFirst:NO navigationType:NavigationTypePopToRoot];
[self startNavigationWithNavigationObject:navigationObject delegate:delegate completionHandler:completionBlock];
}
- (nullable NSArray<UIViewController *> *)getViewControllersForNavigationController:(nullable UINavigationController *)navigationController {
// Check if we are currently animating.
NSInteger index = [self.navigationQueue.operations indexOfObjectPassingTest:^BOOL(__kindof MVMCoreNavigationOperation * _Nonnull operation, NSUInteger idx, BOOL * _Nonnull stop) {
return operation.isExecuting && [operation isKindOfClass:[MVMCoreNavigationOperation class]];
}];
if (index != NSNotFound) {
// Test above ensures we have an MVMCoreNavigationOperation. There are situations where block operations are submitted to the queue to be executed.
MVMCoreNavigationOperation *operation = [self.navigationQueue.operations objectAtIndex:index];
if (operation.navigationObject.navigationController == navigationController && operation.futureViewControllers) {
// Return the future state if animating.
return operation.futureViewControllers;
}
}
return navigationController.viewControllers;
}
#pragma mark - Presentation Simple
- (void)presentViewController:(nonnull UIViewController *)viewController animated:(BOOL)animated {
[self presentViewController:viewController animated:animated delegate:nil completionHandler:NULL];
}
- (void)dismissTopViewControllerAnimated:(BOOL)animated {
[self dismissTopViewControllerAnimated:animated delegate:nil completionHandler:NULL];
}
- (void)dismissViewController:(nonnull UIViewController *)viewController animated:(BOOL)animated {
[self dismissViewController:viewController animated:animated delegate:nil completionHandler:NULL];
}
- (void)dismissToBottom:(BOOL)animated {
[self dismissToBottom:animated delegate:nil completionHandler:NULL];
}
- (void)cancelPresentation {
[self.presentationQueue cancelAllOperations];
}
#pragma mark - Presentation Extra
- (void)presentViewController:(nonnull UIViewController *)viewController animated:(BOOL)animated delegate:(nullable NSObject<MVMCorePresentationDelegateProtocol>*)delegate completionHandler:(nullable void (^)(void))completionBlock {
[MVMCoreDispatchUtility performBlockOnMainThread:^{
UIViewController *controllerToPresentOn = self.viewControllerToPresentOn ?: [UIApplication sharedApplication].keyWindow.rootViewController;
if (!controllerToPresentOn) {
// Log if we are attempting to add an alert to nothing.
MVMCoreErrorObject *error = [[MVMCoreErrorObject alloc] initWithTitle:nil message:@"The viewControllerToPresent on property is nil and an attempt was made to present." code:ErrorCodeNoViewControllerToPresentOn domain:ErrorDomainNative location:[NSString stringWithFormat:@"ViewController:%@|Delegate:%@",viewController.description,delegate]];
[MVMCoreLoggingHandler addErrorToLog:error];
} else {
MVMCorePresentViewControllerOperation *operation = [[MVMCorePresentViewControllerOperation alloc] initWithPresentingViewController:controllerToPresentOn presentedViewController:viewController animated:animated];
operation.delegate = delegate;
operation.completionBlock = completionBlock;
[self.presentationQueue addOperation:operation];
}
}];
}
- (void)dismissTopViewControllerAnimated:(BOOL)animated delegate:(nullable NSObject<MVMCorePresentationDelegateProtocol>*)delegate completionHandler:(nullable void (^)(void))completionBlock {
[MVMCoreDispatchUtility performBlockOnMainThread:^{
// Dismiss on the main navigation controller.
UIViewController *controllerToPresentOn = self.viewControllerToPresentOn ?: [UIApplication sharedApplication].keyWindow.rootViewController;
MVMCoreDismissViewControllerOperation *operation = [[MVMCoreDismissViewControllerOperation alloc] initAndDismissTopViewController:controllerToPresentOn animated:animated];
operation.completionBlock = completionBlock;
[[NSOperationQueue mainQueue] addOperation:operation];
}];
}
- (void)dismissViewController:(nonnull UIViewController *)viewController animated:(BOOL)animated delegate:(nullable NSObject<MVMCorePresentationDelegateProtocol>*)delegate completionHandler:(nullable void (^)(void))completionBlock {
MVMCoreDismissViewControllerOperation *operation = [[MVMCoreDismissViewControllerOperation alloc] initAndDismissViewController:viewController animated:animated];
operation.completionBlock = completionBlock;
[[NSOperationQueue mainQueue] addOperation:operation];
}
- (void)dismissToBottom:(BOOL)animated delegate:(nullable NSObject<MVMCorePresentationDelegateProtocol>*)delegate completionHandler:(nullable void (^)(void))completionBlock {
[MVMCoreDispatchUtility performBlockOnMainThread:^{
// Dismiss on the main navigation controller.
UIViewController *controllerToPresentOn = self.viewControllerToPresentOn ?: [UIApplication sharedApplication].keyWindow.rootViewController;
MVMCoreDismissViewControllerOperation *operation = [[MVMCoreDismissViewControllerOperation alloc] initAndDismissViewController:controllerToPresentOn animated:animated];
operation.completionBlock = completionBlock;
[[NSOperationQueue mainQueue] addOperation:operation];
}];
}
@end

View File

@ -1,27 +0,0 @@
//
// MVMCoreNavigationObject.h
// mobilefirst
//
// Created by Scott Pfeil on 4/22/16.
// Copyright © 2016 Verizon Wireless. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <MVMCore/MVMCoreConstants.h>
@interface MVMCoreNavigationObject : NSObject
@property (nullable, strong, nonatomic) UIViewController *viewController;
@property (nullable, strong, nonatomic) UINavigationController *navigationController;
@property (nullable, strong, nonatomic) NSArray *viewControllers;
@property (nullable, strong, nonatomic) Class classToPopTo;
@property (nullable, strong, nonatomic) NSString *pageTypeToPopTo;
@property (nonatomic) NavigationType navigationType;
@property (nonatomic) BOOL animated;
@property (nonatomic) BOOL tryToReplaceFirst;
@property (nonatomic) BOOL stopLoadingOverlay;
- (nullable instancetype)initWithViewController:(nullable UIViewController *)viewController navigationController:(nullable UINavigationController *)navigationController viewControllers:(nullable NSArray *)viewControllers animated:(BOOL)animated tryToReplaceFirst:(BOOL)tryToReplaceFirst navigationType:(NavigationType)navigationType;
@end

View File

@ -1,31 +0,0 @@
//
// MVMCoreNavigationObject.m
// mobilefirst
//
// Created by Scott Pfeil on 4/22/16.
// Copyright © 2016 Verizon Wireless. All rights reserved.
//
#import "MVMCoreNavigationObject.h"
#import "MVMCoreNavigationHandler.h"
@implementation MVMCoreNavigationObject
- (nullable instancetype)initWithViewController:(nullable UIViewController *)viewController navigationController:(nullable UINavigationController *)navigationController viewControllers:(nullable NSArray *)viewControllers animated:(BOOL)animated tryToReplaceFirst:(BOOL)tryToReplaceFirst navigationType:(NavigationType)navigationType {
if (self = [super init]) {
self.viewController = viewController;
UINavigationController *navigationToUse = navigationController ?: [MVMCoreNavigationHandler sharedNavigationHandler].navigationController;
self.navigationController = navigationToUse;
self.viewControllers = viewControllers;
self.animated = animated;
self.tryToReplaceFirst = tryToReplaceFirst;
self.navigationType = navigationType;
}
return self;
}
@end

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