Compare commits
417 Commits
bugfix/Act
...
develop
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3e1581e28e | ||
|
|
8f2483eb1b | ||
|
|
12d17dbca8 | ||
|
|
c360c75512 | ||
|
|
d57a86e140 | ||
|
|
214ccfd8f6 | ||
|
|
31aa1d6df7 | ||
|
|
817d7900f4 | ||
|
|
4b35a8bb2d | ||
|
|
a29fa60e5e | ||
|
|
3103f8dd89 | ||
|
|
2b36711bca | ||
|
|
a570f3c0e6 | ||
|
|
038fb8cdf7 | ||
|
|
dd2b0f9de5 | ||
|
|
d61cb6cfb9 | ||
|
|
cf3d7810d4 | ||
|
|
3c8af09752 | ||
|
|
b219f3f75d | ||
|
|
fba2e80b8a | ||
|
|
460aa06678 | ||
|
|
c18ce5e811 | ||
|
|
4bf30550ef | ||
|
|
317815d44a | ||
|
|
3054f7e62d | ||
|
|
25e05c6c53 | ||
|
|
a1c6332131 | ||
|
|
9744fc5333 | ||
|
|
8a92c9cdd3 | ||
|
|
a00eff7cf1 | ||
|
|
0104570bc9 | ||
|
|
134ce14e5a | ||
|
|
220b8530da | ||
|
|
05df4ad6ef | ||
|
|
8f88e94ed8 | ||
|
|
d2572c4543 | ||
|
|
71689b957b | ||
|
|
009bb01e1b | ||
|
|
4bded0a433 | ||
|
|
20d4d323e0 | ||
|
|
62a5799312 | ||
|
|
e8552b0aa2 | ||
|
|
dde3e565a3 | ||
|
|
62b7955406 | ||
|
|
a5763d4516 | ||
|
|
9ff641060e | ||
|
|
85747b146e | ||
|
|
9b718ce0d4 | ||
|
|
39a8451314 | ||
|
|
c38030bdb8 | ||
|
|
09ff3b6457 | ||
|
|
a428d5f7ce | ||
|
|
fe7e98f615 | ||
|
|
f7a348a8b0 | ||
|
|
58f7abb5fc | ||
|
|
262881f52b | ||
|
|
c4b6122d4c | ||
|
|
0f89fb51d2 | ||
|
|
c63a7f6d90 | ||
|
|
fac3e77984 | ||
|
|
f6f272f727 | ||
|
|
19c277d68e | ||
|
|
64aba6a100 | ||
|
|
25b79530eb | ||
|
|
8235aff75f | ||
|
|
d08a8f6782 | ||
|
|
4fc4aa21f3 | ||
|
|
4bdd93dbe5 | ||
|
|
3b410fb522 | ||
|
|
c90f267599 | ||
|
|
f89bad1c7a | ||
|
|
54e2ecb313 | ||
|
|
b9097361ab | ||
|
|
a16e09c569 | ||
|
|
84f4a1ac46 | ||
|
|
8c32dbbd7d | ||
|
|
c636cc1ca4 | ||
|
|
d46093887c | ||
|
|
03f81ca9fc | ||
|
|
0c8012d40f | ||
|
|
1e487dd58b | ||
|
|
c8cabfaee1 | ||
|
|
402708ecdc | ||
|
|
bed4b5c837 | ||
|
|
e741805f35 | ||
|
|
d394bbea0e | ||
|
|
c59dd70348 | ||
|
|
6db21b612d | ||
|
|
fc0bd385c6 | ||
|
|
94b2f5b1e3 | ||
|
|
0b23bd8e93 | ||
|
|
10b569e3a9 | ||
|
|
a0b8459a79 | ||
|
|
3bde28c2d2 | ||
|
|
606dbf6131 | ||
|
|
1efd261de3 | ||
|
|
4552a57ea2 | ||
|
|
ec610690fb | ||
|
|
b0bc8994ee | ||
|
|
c89efeb3e7 | ||
|
|
98f55d4bc5 | ||
|
|
fb090fee64 | ||
|
|
7b61615d39 | ||
|
|
435b5a4c97 | ||
|
|
d91dbbd460 | ||
|
|
84b00f7d19 | ||
|
|
d7db83583f | ||
|
|
3e8cd2a6e8 | ||
|
|
47286a9e35 | ||
|
|
27233a39a2 | ||
|
|
7ccb191f6e | ||
|
|
a8606e6641 | ||
|
|
0316828728 | ||
|
|
62ffdd605a | ||
|
|
15f1be66fe | ||
|
|
f5e8c0b2e6 | ||
|
|
e04bd2cefe | ||
|
|
9ef78a9c15 | ||
|
|
6d169ea203 | ||
|
|
7e02aa17b6 | ||
|
|
b70220902a | ||
|
|
3ea582efc9 | ||
|
|
2e7fd9ddd4 | ||
|
|
ab43e791cf | ||
|
|
b8f785fbc2 | ||
|
|
dd0688985e | ||
|
|
c53bbd254b | ||
|
|
291cf99604 | ||
|
|
293c3bf864 | ||
|
|
64e5f9eb3d | ||
|
|
9549dca564 | ||
|
|
641ebcac7f | ||
|
|
f64ba3aff4 | ||
|
|
89a6c7e204 | ||
|
|
7a8500153f | ||
|
|
3cab2464be | ||
|
|
48efbc73bf | ||
|
|
77ab27d79d | ||
|
|
f7ca8da8f9 | ||
|
|
2a438e68a7 | ||
|
|
fc0075a92d | ||
|
|
def76778e5 | ||
|
|
c5dab7d70d | ||
|
|
d44235bd03 | ||
|
|
48de2b1869 | ||
|
|
1e8f7f417e | ||
|
|
3dc05bea61 | ||
|
|
31b5dc2171 | ||
|
|
a8f3407ed8 | ||
|
|
f2df0f52e6 | ||
|
|
223ff22612 | ||
|
|
5a8147655b | ||
|
|
b1e4c55281 | ||
|
|
db9bd9e3b3 | ||
|
|
51597121bd | ||
|
|
a94cc27168 | ||
|
|
a5d237df8b | ||
|
|
e5402bb6eb | ||
|
|
c93fe59b5c | ||
|
|
975ee661fb | ||
|
|
3d4f8938dc | ||
|
|
79915b3f6f | ||
|
|
20d6149918 | ||
|
|
ba8f0b90ca | ||
|
|
d6096c7ee5 | ||
|
|
46bcd6618d | ||
|
|
3459e067b3 | ||
|
|
e942bbfe15 | ||
|
|
f340ac61c7 | ||
|
|
e31fe71fae | ||
|
|
9419fd51a2 | ||
|
|
dc0be54444 | ||
|
|
4542e82060 | ||
|
|
2af3badb4b | ||
|
|
66693289ed | ||
|
|
99da8d56d5 | ||
|
|
a5be9469ee | ||
|
|
296b1df0e9 | ||
|
|
034133e4a5 | ||
|
|
fe5dc7c6b7 | ||
|
|
9d88dd70af | ||
|
|
f2a5586061 | ||
|
|
64535c6b21 | ||
|
|
2a8bf6d695 | ||
|
|
8b912d5d87 | ||
|
|
6877763d07 | ||
|
|
a4e0203de5 | ||
|
|
2300678d96 | ||
|
|
30a8f48f4d | ||
|
|
1aed90a1fe | ||
|
|
985d01842d | ||
|
|
fd27a82e5c | ||
|
|
5493c32682 | ||
|
|
3bccc503cf | ||
|
|
28842d673e | ||
|
|
24ddfbfd34 | ||
|
|
890a8c7fe2 | ||
|
|
eafd275527 | ||
|
|
5becbbb7f1 | ||
|
|
d86462427a | ||
|
|
2466d06698 | ||
|
|
674cff506d | ||
|
|
25394dc640 | ||
|
|
05289f88aa | ||
|
|
3b315096cc | ||
|
|
ce246523ac | ||
|
|
7426e5956e | ||
|
|
5091d82962 | ||
|
|
3383d71c19 | ||
|
|
53634fcaa1 | ||
|
|
30f7737b4c | ||
|
|
cba4af9ce8 | ||
|
|
a5c5397c92 | ||
|
|
3af64af961 | ||
|
|
c21e4b680b | ||
|
|
17025101bc | ||
|
|
cdff607cf1 | ||
|
|
87135f31ed | ||
|
|
e6ca9ec67d | ||
|
|
6372fcb56d | ||
|
|
3d1f1617c5 | ||
|
|
85f7096499 | ||
|
|
27f138d6c1 | ||
|
|
ba8621cea1 | ||
|
|
c10cb0792e | ||
|
|
cbb17edcf9 | ||
|
|
e14c01e0d4 | ||
|
|
6a0be99ce2 | ||
|
|
519093a24f | ||
|
|
10db5ff1ba | ||
|
|
14af9f2d5f | ||
|
|
bc46ff3174 | ||
|
|
f0f842f87e | ||
|
|
38cb3eb80e | ||
|
|
e3cbc7a7cd | ||
|
|
15ca6142fe | ||
|
|
3c9786b4d6 | ||
|
|
01b14b02e4 | ||
|
|
f93e1866c1 | ||
|
|
11d635fdd4 | ||
|
|
40741deac3 | ||
|
|
5ee5c39ff8 | ||
|
|
14b0dc2c3e | ||
|
|
8ab9609724 | ||
|
|
a07807e693 | ||
|
|
ab0c13efaf | ||
|
|
4799c3fcbb | ||
|
|
85ebbdf44c | ||
|
|
cb401ee3f0 | ||
|
|
7a38ecf62b | ||
|
|
3b85ca1ff8 | ||
|
|
56857f187b | ||
|
|
52883a534b | ||
|
|
a74aa6ef2d | ||
|
|
5006517bb1 | ||
|
|
6d9da1f958 | ||
|
|
74c16205e1 | ||
|
|
e26a09e1ec | ||
|
|
3e9d66e5e0 | ||
|
|
08a1718f11 | ||
|
|
1f377dfb51 | ||
|
|
16d169c46c | ||
|
|
80512a0b8a | ||
|
|
c7bfda216a | ||
|
|
aa1be3f1c5 | ||
|
|
920b975294 | ||
|
|
3f59a1c9fe | ||
|
|
6874424dd1 | ||
|
|
8e586e5f01 | ||
|
|
9243b8e285 | ||
|
|
11728703ce | ||
|
|
a8b5db4d28 | ||
|
|
d7b80e87ed | ||
|
|
9aaeb1d266 | ||
|
|
ee98b9fe5f | ||
|
|
217cceb84b | ||
|
|
2b09f58686 | ||
|
|
8dd0aebf7e | ||
|
|
85dcc57513 | ||
|
|
130208a080 | ||
|
|
45b89ca7d3 | ||
|
|
cdd2eb2f04 | ||
|
|
0340f9dda6 | ||
|
|
4f1cbf6c61 | ||
|
|
de280960f7 | ||
|
|
c95def255b | ||
|
|
afead9710d | ||
|
|
ec70621ea0 | ||
|
|
89d9809b9e | ||
|
|
f8dec38c13 | ||
|
|
793e64143d | ||
|
|
3ecd769f1c | ||
|
|
645d304907 | ||
|
|
3abf053e4e | ||
|
|
b5e579f59a | ||
|
|
61ce51cefd | ||
|
|
3b18e3dd55 | ||
|
|
13e03375d4 | ||
|
|
05f6ed1013 | ||
|
|
343020ad20 | ||
|
|
aff3d52fe8 | ||
|
|
e7e829bb44 | ||
|
|
d747980805 | ||
|
|
dfb58e04b6 | ||
|
|
55d6df4e25 | ||
|
|
571d55aebd | ||
|
|
068714a001 | ||
|
|
dcbaa316ac | ||
|
|
3739812379 | ||
|
|
c4f8bd955b | ||
|
|
27c239cab2 | ||
|
|
17b2a4368f | ||
|
|
5c53466dac | ||
|
|
0196d5c190 | ||
|
|
e6164026f6 | ||
|
|
4d72b31a51 | ||
|
|
bf14282eb5 | ||
|
|
dcc81a2c08 | ||
|
|
36ec79f353 | ||
|
|
cbb5ccded8 | ||
|
|
e6dca10d87 | ||
|
|
b62a67fcc7 | ||
|
|
a0f2111a51 | ||
|
|
71b2146862 | ||
|
|
064fd5d621 | ||
|
|
d09834f19c | ||
|
|
f123be046c | ||
|
|
90adc247d1 | ||
|
|
606fd93fc3 | ||
|
|
9bb56d09db | ||
|
|
27c5be0415 | ||
|
|
ec8552ea12 | ||
|
|
8bfea9b093 | ||
|
|
9ffb6f044d | ||
|
|
ded68fe51f | ||
|
|
863a9fbbe5 | ||
|
|
80a257c066 | ||
|
|
a7d6fff40e | ||
|
|
a5f5ed3cd1 | ||
|
|
aaa2bb664e | ||
|
|
0a9aca1a98 | ||
|
|
83a814ddb1 | ||
|
|
07bb18fe75 | ||
|
|
e9b8ccec18 | ||
|
|
22f2b18057 | ||
|
|
8fb9f7e605 | ||
|
|
1b4a673802 | ||
|
|
dfaa2b0364 | ||
|
|
5979945304 | ||
|
|
1031443180 | ||
|
|
463756fa75 | ||
|
|
61a54e831f | ||
|
|
9d4caedbe5 | ||
|
|
d2a1e316ba | ||
|
|
fa6f79f3d0 | ||
|
|
acf5aae880 | ||
|
|
05a549c633 | ||
|
|
88f8ee0859 | ||
|
|
5ca22837bf | ||
|
|
464df10708 | ||
|
|
71fb70c6eb | ||
|
|
c84f9b5388 | ||
|
|
f2bde996a8 | ||
|
|
2db6fb923c | ||
|
|
f69dd7339c | ||
|
|
506717d682 | ||
|
|
071cb16870 | ||
|
|
9e9421f66a | ||
|
|
9bb90b2153 | ||
|
|
a7e32f3ca4 | ||
|
|
3f0450547a | ||
|
|
1718f87f40 | ||
|
|
cb053464b5 | ||
|
|
129159a9a2 | ||
|
|
ce0d984c0b | ||
|
|
a4770c4c79 | ||
|
|
51580bdbd0 | ||
|
|
a05da2695b | ||
|
|
c21858c48c | ||
|
|
e19ed416bb | ||
|
|
edeaefc346 | ||
|
|
374c83bddd | ||
|
|
c093a224b4 | ||
|
|
ef59c73a5b | ||
|
|
f4b9245a51 | ||
|
|
fa43578968 | ||
|
|
ba9dab019f | ||
|
|
1866c0c28a | ||
|
|
30d4c7730f | ||
|
|
e89c10daae | ||
|
|
7f57d493f6 | ||
|
|
3e06f6ee44 | ||
|
|
4fa85ecc34 | ||
|
|
e0d3bfb9e3 | ||
|
|
d3d198b007 | ||
|
|
40c365829a | ||
|
|
306e66a3b2 | ||
|
|
f2d824f829 | ||
|
|
c21b677048 | ||
|
|
a2d9196bca | ||
|
|
6fe6d6ea8b | ||
|
|
1dcdc12919 | ||
|
|
0711efee00 | ||
|
|
b63e60e58a | ||
|
|
247adceb98 | ||
|
|
5d4995322b | ||
|
|
324be22ad2 | ||
|
|
11888424f6 | ||
|
|
80be78a401 | ||
|
|
64f6624e00 | ||
|
|
cc06f93e50 | ||
|
|
35b96b2fde | ||
|
|
c93bb7f0f6 | ||
|
|
f569d5279d | ||
|
|
b03532a364 | ||
|
|
d3bf9481fc | ||
|
|
d1ea9518a0 |
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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"
|
||||
|
||||
51
MVMCore/MVMCore/ActionHandling/ActionActionsHandler.swift
Normal file
51
MVMCore/MVMCore/ActionHandling/ActionActionsHandler.swift
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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)]"
|
||||
}
|
||||
}
|
||||
26
MVMCore/MVMCore/ActionHandling/ActionBackHandler.swift
Normal file
26
MVMCore/MVMCore/ActionHandling/ActionBackHandler.swift
Normal 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)
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
19
MVMCore/MVMCore/ActionHandling/ActionCallHandler.swift
Normal file
19
MVMCore/MVMCore/ActionHandling/ActionCallHandler.swift
Normal 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)")
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
20
MVMCore/MVMCore/ActionHandling/ActionCancelHandler.swift
Normal file
20
MVMCore/MVMCore/ActionHandling/ActionCancelHandler.swift
Normal 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 {
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
126
MVMCore/MVMCore/ActionHandling/ActionContactHandler.swift
Normal file
126
MVMCore/MVMCore/ActionHandling/ActionContactHandler.swift
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
27
MVMCore/MVMCore/ActionHandling/ActionDelegateProtocol.swift
Normal file
27
MVMCore/MVMCore/ActionHandling/ActionDelegateProtocol.swift
Normal 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)
|
||||
}
|
||||
}
|
||||
15
MVMCore/MVMCore/ActionHandling/ActionNoopHandler.swift
Normal file
15
MVMCore/MVMCore/ActionHandling/ActionNoopHandler.swift
Normal 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 {}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
127
MVMCore/MVMCore/ActionHandling/ActionOpenPageHandler.swift
Normal file
127
MVMCore/MVMCore/ActionHandling/ActionOpenPageHandler.swift
Normal 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)
|
||||
}
|
||||
}
|
||||
145
MVMCore/MVMCore/ActionHandling/ActionOpenPageModel.swift
Normal file
145
MVMCore/MVMCore/ActionHandling/ActionOpenPageModel.swift
Normal 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)"
|
||||
}
|
||||
}
|
||||
}
|
||||
33
MVMCore/MVMCore/ActionHandling/ActionOpenSMSHandler.swift
Normal file
33
MVMCore/MVMCore/ActionHandling/ActionOpenSMSHandler.swift
Normal 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)
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
96
MVMCore/MVMCore/ActionHandling/ActionOpenUrlHandler.swift
Normal file
96
MVMCore/MVMCore/ActionHandling/ActionOpenUrlHandler.swift
Normal 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)
|
||||
}
|
||||
}
|
||||
72
MVMCore/MVMCore/ActionHandling/ActionOpenUrlModel.swift
Normal file
72
MVMCore/MVMCore/ActionHandling/ActionOpenUrlModel.swift
Normal 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
|
||||
}
|
||||
}
|
||||
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
42
MVMCore/MVMCore/ActionHandling/ActionRestartHandler.swift
Normal file
42
MVMCore/MVMCore/ActionHandling/ActionRestartHandler.swift
Normal 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()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
17
MVMCore/MVMCore/ActionHandling/ActionSettingHandler.swift
Normal file
17
MVMCore/MVMCore/ActionHandling/ActionSettingHandler.swift
Normal 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)
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
54
MVMCore/MVMCore/ActionHandling/ActionShareHandler.swift
Normal file
54
MVMCore/MVMCore/ActionHandling/ActionShareHandler.swift
Normal 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
|
||||
}
|
||||
}
|
||||
131
MVMCore/MVMCore/ActionHandling/ActionShareModel.swift
Normal file
131
MVMCore/MVMCore/ActionHandling/ActionShareModel.swift
Normal 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
|
||||
}
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
@ -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
|
||||
228
MVMCore/MVMCore/ActionHandling/MVMCoreActionHandler.swift
Normal file
228
MVMCore/MVMCore/ActionHandling/MVMCoreActionHandler.swift
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
58
MVMCore/MVMCore/ActionHandling/OpenURLOptionsModel.swift
Normal file
58
MVMCore/MVMCore/ActionHandling/OpenURLOptionsModel.swift
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -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
|
||||
@ -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
|
||||
16
MVMCore/MVMCore/Categories/Collection+Safe.swift
Normal file
16
MVMCore/MVMCore/Categories/Collection+Safe.swift
Normal 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
|
||||
}
|
||||
}
|
||||
20
MVMCore/MVMCore/Categories/Date+Extension.swift
Normal file
20
MVMCore/MVMCore/Categories/Date+Extension.swift
Normal 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)
|
||||
}
|
||||
}
|
||||
@ -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> {
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -40,5 +40,6 @@ typedef NS_ENUM(NSInteger, ErrorCode) {
|
||||
ErrorCodeSSL,//23
|
||||
ErrorCodeNoViewControllerToPresentOn,//24
|
||||
ErrorCodeNoErrorPageSent, //25
|
||||
ErrorCodeFontNotFound //26
|
||||
ErrorCodeFontNotFound, //26
|
||||
ErrorCodePoorPerformance //27
|
||||
};
|
||||
|
||||
@ -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";
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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";
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -11,7 +11,6 @@
|
||||
#import <MVMCore/MVMCoreViewControllerProtocol.h>
|
||||
@class MVMCoreRequestParameters;
|
||||
@class MVMCoreErrorObject;
|
||||
@class MVMCoreAlertObject;
|
||||
@class MVMCoreLoadObject;
|
||||
|
||||
@protocol MVMCoreLoadDelegateProtocol
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
22
MVMCore/MVMCore/LoadHandling/MVMCoreLoadHandler.swift
Normal file
22
MVMCore/MVMCore/LoadHandling/MVMCoreLoadHandler.swift
Normal 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)
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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))
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
@ -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?) {}
|
||||
}
|
||||
@ -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.
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@ -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]
|
||||
}
|
||||
}
|
||||
|
||||
113
MVMCore/MVMCore/Models/Extensions/Decoder+UserInfo.swift
Normal file
113
MVMCore/MVMCore/Models/Extensions/Decoder+UserInfo.swift
Normal 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 }
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
@ -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 hasn’t been registered for the CodingKey for this type: \(String(describing: type.self))")
|
||||
}
|
||||
|
||||
return AnyCodingKey(category.codingKey)
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
106
MVMCore/MVMCore/OtherHandlers/MVMCoreCache+Extension.swift
Normal file
106
MVMCore/MVMCore/OtherHandlers/MVMCoreCache+Extension.swift
Normal 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")
|
||||
}
|
||||
}
|
||||
@ -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.
|
||||
|
||||
@ -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];
|
||||
|
||||
187
MVMCore/MVMCore/OtherHandlers/MVMCoreEvent.swift
Normal file
187
MVMCore/MVMCore/OtherHandlers/MVMCoreEvent.swift
Normal 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))
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
@ -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
|
||||
105
MVMCore/MVMCore/OtherHandlers/MVMCoreLoggingHandler.swift
Normal file
105
MVMCore/MVMCore/OtherHandlers/MVMCoreLoggingHandler.swift
Normal 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?) {}
|
||||
}
|
||||
18
MVMCore/MVMCore/OtherHandlers/MVMCoreLoggingHandlerHelper.h
Normal file
18
MVMCore/MVMCore/OtherHandlers/MVMCoreLoggingHandlerHelper.h
Normal 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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
Loading…
Reference in New Issue
Block a user