From 86f7701c2ea393dfe055c585e9290f1b62a6fefa Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Tue, 13 Jun 2023 09:52:41 -0500 Subject: [PATCH 01/12] updated images for vector Signed-off-by: Matt Bruce --- .../Icons.xcassets/CreditCard/amex.imageset/Contents.json | 3 +++ .../CreditCard/credit-card.imageset/Contents.json | 3 +++ .../CreditCard/dinersClub-inverted.imageset/Contents.json | 3 +++ .../CreditCard/dinersClub.imageset/Contents.json | 3 +++ .../Icons.xcassets/CreditCard/discover.imageset/Contents.json | 3 +++ .../CreditCard/generic-inverted.imageset/Contents.json | 3 +++ .../Icons.xcassets/CreditCard/generic.imageset/Contents.json | 3 +++ .../Icons.xcassets/CreditCard/jcb.imageset/Contents.json | 3 +++ .../CreditCard/mastercard.imageset/Contents.json | 3 +++ .../CreditCard/placeholder-inverted.imageset/Contents.json | 3 +++ .../CreditCard/placeholder.imageset/Contents.json | 3 +++ .../CreditCard/securityCode-inverted.imageset/Contents.json | 3 +++ .../CreditCard/securityCode.imageset/Contents.json | 3 +++ .../securityCodeAmex-inverted.imageset/Contents.json | 3 +++ .../CreditCard/securityCodeAmex.imageset/Contents.json | 3 +++ .../CreditCard/visa-inverted.imageset/Contents.json | 3 +++ .../Icons.xcassets/CreditCard/visa.imageset/Contents.json | 3 +++ .../Restricted/checkmark-alt-bold.imageset/Contents.json | 3 +++ .../Restricted/checkmark-alt.imageset/Contents.json | 3 +++ .../Restricted/checkmark-bold.imageset/Contents.json | 3 +++ .../Icons.xcassets/Restricted/checkmark.imageset/Contents.json | 3 +++ .../Restricted/close-bold.imageset/Contents.json | 3 +++ .../Icons.xcassets/Restricted/close.imageset/Contents.json | 3 +++ .../Restricted/down-caret-bold.imageset/Contents.json | 3 +++ .../Restricted/down-caret.imageset/Contents.json | 3 +++ .../Restricted/error-bold.imageset/Contents.json | 3 +++ .../Icons.xcassets/Restricted/error.imageset/Contents.json | 3 +++ .../Icons.xcassets/Restricted/info-bold.imageset/Contents.json | 3 +++ .../Icons.xcassets/Restricted/info.imageset/Contents.json | 3 +++ .../Restricted/left-arrow.imageset/Contents.json | 3 +++ .../Restricted/left-caret-bold.imageset/Contents.json | 3 +++ .../Restricted/left-caret.imageset/Contents.json | 3 +++ .../Restricted/multiple-documents.imageset/Contents.json | 3 +++ .../Restricted/pagination-left-arrow.imageset/Contents.json | 3 +++ .../Restricted/pagination-left-caret.imageset/Contents.json | 3 +++ .../Restricted/pagination-right-arrow.imageset/Contents.json | 3 +++ .../Restricted/pagination-right-caret.imageset/Contents.json | 3 +++ .../Restricted/right-arrow.imageset/Contents.json | 3 +++ .../Restricted/right-caret-bold.imageset/Contents.json | 3 +++ .../Restricted/right-caret.imageset/Contents.json | 3 +++ .../Restricted/warning-bold.imageset/Contents.json | 3 +++ .../Icons.xcassets/Restricted/warning.imageset/Contents.json | 3 +++ 42 files changed, 126 insertions(+) diff --git a/VDS/SupportingFiles/Icons.xcassets/CreditCard/amex.imageset/Contents.json b/VDS/SupportingFiles/Icons.xcassets/CreditCard/amex.imageset/Contents.json index 610ffbd7..d806b247 100644 --- a/VDS/SupportingFiles/Icons.xcassets/CreditCard/amex.imageset/Contents.json +++ b/VDS/SupportingFiles/Icons.xcassets/CreditCard/amex.imageset/Contents.json @@ -8,5 +8,8 @@ "info" : { "author" : "xcode", "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true } } diff --git a/VDS/SupportingFiles/Icons.xcassets/CreditCard/credit-card.imageset/Contents.json b/VDS/SupportingFiles/Icons.xcassets/CreditCard/credit-card.imageset/Contents.json index df2d7bca..24a71037 100644 --- a/VDS/SupportingFiles/Icons.xcassets/CreditCard/credit-card.imageset/Contents.json +++ b/VDS/SupportingFiles/Icons.xcassets/CreditCard/credit-card.imageset/Contents.json @@ -8,5 +8,8 @@ "info" : { "author" : "xcode", "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true } } diff --git a/VDS/SupportingFiles/Icons.xcassets/CreditCard/dinersClub-inverted.imageset/Contents.json b/VDS/SupportingFiles/Icons.xcassets/CreditCard/dinersClub-inverted.imageset/Contents.json index b4949ace..01c460d2 100644 --- a/VDS/SupportingFiles/Icons.xcassets/CreditCard/dinersClub-inverted.imageset/Contents.json +++ b/VDS/SupportingFiles/Icons.xcassets/CreditCard/dinersClub-inverted.imageset/Contents.json @@ -8,5 +8,8 @@ "info" : { "author" : "xcode", "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true } } diff --git a/VDS/SupportingFiles/Icons.xcassets/CreditCard/dinersClub.imageset/Contents.json b/VDS/SupportingFiles/Icons.xcassets/CreditCard/dinersClub.imageset/Contents.json index 6a22c2dd..32adfd39 100644 --- a/VDS/SupportingFiles/Icons.xcassets/CreditCard/dinersClub.imageset/Contents.json +++ b/VDS/SupportingFiles/Icons.xcassets/CreditCard/dinersClub.imageset/Contents.json @@ -8,5 +8,8 @@ "info" : { "author" : "xcode", "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true } } diff --git a/VDS/SupportingFiles/Icons.xcassets/CreditCard/discover.imageset/Contents.json b/VDS/SupportingFiles/Icons.xcassets/CreditCard/discover.imageset/Contents.json index ae99049b..28cfbca3 100644 --- a/VDS/SupportingFiles/Icons.xcassets/CreditCard/discover.imageset/Contents.json +++ b/VDS/SupportingFiles/Icons.xcassets/CreditCard/discover.imageset/Contents.json @@ -8,5 +8,8 @@ "info" : { "author" : "xcode", "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true } } diff --git a/VDS/SupportingFiles/Icons.xcassets/CreditCard/generic-inverted.imageset/Contents.json b/VDS/SupportingFiles/Icons.xcassets/CreditCard/generic-inverted.imageset/Contents.json index 49581273..28c8b212 100644 --- a/VDS/SupportingFiles/Icons.xcassets/CreditCard/generic-inverted.imageset/Contents.json +++ b/VDS/SupportingFiles/Icons.xcassets/CreditCard/generic-inverted.imageset/Contents.json @@ -8,5 +8,8 @@ "info" : { "author" : "xcode", "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true } } diff --git a/VDS/SupportingFiles/Icons.xcassets/CreditCard/generic.imageset/Contents.json b/VDS/SupportingFiles/Icons.xcassets/CreditCard/generic.imageset/Contents.json index b0026068..a647b1a8 100644 --- a/VDS/SupportingFiles/Icons.xcassets/CreditCard/generic.imageset/Contents.json +++ b/VDS/SupportingFiles/Icons.xcassets/CreditCard/generic.imageset/Contents.json @@ -8,5 +8,8 @@ "info" : { "author" : "xcode", "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true } } diff --git a/VDS/SupportingFiles/Icons.xcassets/CreditCard/jcb.imageset/Contents.json b/VDS/SupportingFiles/Icons.xcassets/CreditCard/jcb.imageset/Contents.json index 5798433a..8a4c248a 100644 --- a/VDS/SupportingFiles/Icons.xcassets/CreditCard/jcb.imageset/Contents.json +++ b/VDS/SupportingFiles/Icons.xcassets/CreditCard/jcb.imageset/Contents.json @@ -8,5 +8,8 @@ "info" : { "author" : "xcode", "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true } } diff --git a/VDS/SupportingFiles/Icons.xcassets/CreditCard/mastercard.imageset/Contents.json b/VDS/SupportingFiles/Icons.xcassets/CreditCard/mastercard.imageset/Contents.json index 3ee10a5c..e5a22fd7 100644 --- a/VDS/SupportingFiles/Icons.xcassets/CreditCard/mastercard.imageset/Contents.json +++ b/VDS/SupportingFiles/Icons.xcassets/CreditCard/mastercard.imageset/Contents.json @@ -8,5 +8,8 @@ "info" : { "author" : "xcode", "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true } } diff --git a/VDS/SupportingFiles/Icons.xcassets/CreditCard/placeholder-inverted.imageset/Contents.json b/VDS/SupportingFiles/Icons.xcassets/CreditCard/placeholder-inverted.imageset/Contents.json index caf02da3..5b516479 100644 --- a/VDS/SupportingFiles/Icons.xcassets/CreditCard/placeholder-inverted.imageset/Contents.json +++ b/VDS/SupportingFiles/Icons.xcassets/CreditCard/placeholder-inverted.imageset/Contents.json @@ -8,5 +8,8 @@ "info" : { "author" : "xcode", "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true } } diff --git a/VDS/SupportingFiles/Icons.xcassets/CreditCard/placeholder.imageset/Contents.json b/VDS/SupportingFiles/Icons.xcassets/CreditCard/placeholder.imageset/Contents.json index d039c34d..9b2b69ae 100644 --- a/VDS/SupportingFiles/Icons.xcassets/CreditCard/placeholder.imageset/Contents.json +++ b/VDS/SupportingFiles/Icons.xcassets/CreditCard/placeholder.imageset/Contents.json @@ -8,5 +8,8 @@ "info" : { "author" : "xcode", "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true } } diff --git a/VDS/SupportingFiles/Icons.xcassets/CreditCard/securityCode-inverted.imageset/Contents.json b/VDS/SupportingFiles/Icons.xcassets/CreditCard/securityCode-inverted.imageset/Contents.json index 2c8a3508..248b9279 100644 --- a/VDS/SupportingFiles/Icons.xcassets/CreditCard/securityCode-inverted.imageset/Contents.json +++ b/VDS/SupportingFiles/Icons.xcassets/CreditCard/securityCode-inverted.imageset/Contents.json @@ -8,5 +8,8 @@ "info" : { "author" : "xcode", "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true } } diff --git a/VDS/SupportingFiles/Icons.xcassets/CreditCard/securityCode.imageset/Contents.json b/VDS/SupportingFiles/Icons.xcassets/CreditCard/securityCode.imageset/Contents.json index 21980ced..b7838a59 100644 --- a/VDS/SupportingFiles/Icons.xcassets/CreditCard/securityCode.imageset/Contents.json +++ b/VDS/SupportingFiles/Icons.xcassets/CreditCard/securityCode.imageset/Contents.json @@ -8,5 +8,8 @@ "info" : { "author" : "xcode", "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true } } diff --git a/VDS/SupportingFiles/Icons.xcassets/CreditCard/securityCodeAmex-inverted.imageset/Contents.json b/VDS/SupportingFiles/Icons.xcassets/CreditCard/securityCodeAmex-inverted.imageset/Contents.json index 4bc9d730..39edd17c 100644 --- a/VDS/SupportingFiles/Icons.xcassets/CreditCard/securityCodeAmex-inverted.imageset/Contents.json +++ b/VDS/SupportingFiles/Icons.xcassets/CreditCard/securityCodeAmex-inverted.imageset/Contents.json @@ -8,5 +8,8 @@ "info" : { "author" : "xcode", "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true } } diff --git a/VDS/SupportingFiles/Icons.xcassets/CreditCard/securityCodeAmex.imageset/Contents.json b/VDS/SupportingFiles/Icons.xcassets/CreditCard/securityCodeAmex.imageset/Contents.json index c4dc8123..24cb9017 100644 --- a/VDS/SupportingFiles/Icons.xcassets/CreditCard/securityCodeAmex.imageset/Contents.json +++ b/VDS/SupportingFiles/Icons.xcassets/CreditCard/securityCodeAmex.imageset/Contents.json @@ -8,5 +8,8 @@ "info" : { "author" : "xcode", "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true } } diff --git a/VDS/SupportingFiles/Icons.xcassets/CreditCard/visa-inverted.imageset/Contents.json b/VDS/SupportingFiles/Icons.xcassets/CreditCard/visa-inverted.imageset/Contents.json index f1e909a2..8f71dfc4 100644 --- a/VDS/SupportingFiles/Icons.xcassets/CreditCard/visa-inverted.imageset/Contents.json +++ b/VDS/SupportingFiles/Icons.xcassets/CreditCard/visa-inverted.imageset/Contents.json @@ -8,5 +8,8 @@ "info" : { "author" : "xcode", "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true } } diff --git a/VDS/SupportingFiles/Icons.xcassets/CreditCard/visa.imageset/Contents.json b/VDS/SupportingFiles/Icons.xcassets/CreditCard/visa.imageset/Contents.json index 680fa238..87260339 100644 --- a/VDS/SupportingFiles/Icons.xcassets/CreditCard/visa.imageset/Contents.json +++ b/VDS/SupportingFiles/Icons.xcassets/CreditCard/visa.imageset/Contents.json @@ -8,5 +8,8 @@ "info" : { "author" : "xcode", "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true } } diff --git a/VDS/SupportingFiles/Icons.xcassets/Restricted/checkmark-alt-bold.imageset/Contents.json b/VDS/SupportingFiles/Icons.xcassets/Restricted/checkmark-alt-bold.imageset/Contents.json index efc51701..f2f866f7 100644 --- a/VDS/SupportingFiles/Icons.xcassets/Restricted/checkmark-alt-bold.imageset/Contents.json +++ b/VDS/SupportingFiles/Icons.xcassets/Restricted/checkmark-alt-bold.imageset/Contents.json @@ -8,5 +8,8 @@ "info" : { "author" : "xcode", "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true } } diff --git a/VDS/SupportingFiles/Icons.xcassets/Restricted/checkmark-alt.imageset/Contents.json b/VDS/SupportingFiles/Icons.xcassets/Restricted/checkmark-alt.imageset/Contents.json index 50ccb6e9..cae26f91 100644 --- a/VDS/SupportingFiles/Icons.xcassets/Restricted/checkmark-alt.imageset/Contents.json +++ b/VDS/SupportingFiles/Icons.xcassets/Restricted/checkmark-alt.imageset/Contents.json @@ -8,5 +8,8 @@ "info" : { "author" : "xcode", "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true } } diff --git a/VDS/SupportingFiles/Icons.xcassets/Restricted/checkmark-bold.imageset/Contents.json b/VDS/SupportingFiles/Icons.xcassets/Restricted/checkmark-bold.imageset/Contents.json index 14a052ea..4dab2e00 100644 --- a/VDS/SupportingFiles/Icons.xcassets/Restricted/checkmark-bold.imageset/Contents.json +++ b/VDS/SupportingFiles/Icons.xcassets/Restricted/checkmark-bold.imageset/Contents.json @@ -8,5 +8,8 @@ "info" : { "author" : "xcode", "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true } } diff --git a/VDS/SupportingFiles/Icons.xcassets/Restricted/checkmark.imageset/Contents.json b/VDS/SupportingFiles/Icons.xcassets/Restricted/checkmark.imageset/Contents.json index 6b69c1c8..bb8da90b 100644 --- a/VDS/SupportingFiles/Icons.xcassets/Restricted/checkmark.imageset/Contents.json +++ b/VDS/SupportingFiles/Icons.xcassets/Restricted/checkmark.imageset/Contents.json @@ -8,5 +8,8 @@ "info" : { "author" : "xcode", "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true } } diff --git a/VDS/SupportingFiles/Icons.xcassets/Restricted/close-bold.imageset/Contents.json b/VDS/SupportingFiles/Icons.xcassets/Restricted/close-bold.imageset/Contents.json index f7e08c7b..5fa7f126 100644 --- a/VDS/SupportingFiles/Icons.xcassets/Restricted/close-bold.imageset/Contents.json +++ b/VDS/SupportingFiles/Icons.xcassets/Restricted/close-bold.imageset/Contents.json @@ -8,5 +8,8 @@ "info" : { "author" : "xcode", "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true } } diff --git a/VDS/SupportingFiles/Icons.xcassets/Restricted/close.imageset/Contents.json b/VDS/SupportingFiles/Icons.xcassets/Restricted/close.imageset/Contents.json index 308f9c8f..d6edae4a 100644 --- a/VDS/SupportingFiles/Icons.xcassets/Restricted/close.imageset/Contents.json +++ b/VDS/SupportingFiles/Icons.xcassets/Restricted/close.imageset/Contents.json @@ -8,5 +8,8 @@ "info" : { "author" : "xcode", "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true } } diff --git a/VDS/SupportingFiles/Icons.xcassets/Restricted/down-caret-bold.imageset/Contents.json b/VDS/SupportingFiles/Icons.xcassets/Restricted/down-caret-bold.imageset/Contents.json index 97881155..752ccaed 100644 --- a/VDS/SupportingFiles/Icons.xcassets/Restricted/down-caret-bold.imageset/Contents.json +++ b/VDS/SupportingFiles/Icons.xcassets/Restricted/down-caret-bold.imageset/Contents.json @@ -8,5 +8,8 @@ "info" : { "author" : "xcode", "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true } } diff --git a/VDS/SupportingFiles/Icons.xcassets/Restricted/down-caret.imageset/Contents.json b/VDS/SupportingFiles/Icons.xcassets/Restricted/down-caret.imageset/Contents.json index fca125b2..1376a186 100644 --- a/VDS/SupportingFiles/Icons.xcassets/Restricted/down-caret.imageset/Contents.json +++ b/VDS/SupportingFiles/Icons.xcassets/Restricted/down-caret.imageset/Contents.json @@ -8,5 +8,8 @@ "info" : { "author" : "xcode", "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true } } diff --git a/VDS/SupportingFiles/Icons.xcassets/Restricted/error-bold.imageset/Contents.json b/VDS/SupportingFiles/Icons.xcassets/Restricted/error-bold.imageset/Contents.json index 90962db0..1abe2a2d 100644 --- a/VDS/SupportingFiles/Icons.xcassets/Restricted/error-bold.imageset/Contents.json +++ b/VDS/SupportingFiles/Icons.xcassets/Restricted/error-bold.imageset/Contents.json @@ -8,5 +8,8 @@ "info" : { "author" : "xcode", "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true } } diff --git a/VDS/SupportingFiles/Icons.xcassets/Restricted/error.imageset/Contents.json b/VDS/SupportingFiles/Icons.xcassets/Restricted/error.imageset/Contents.json index a2f87247..bd94a6e4 100644 --- a/VDS/SupportingFiles/Icons.xcassets/Restricted/error.imageset/Contents.json +++ b/VDS/SupportingFiles/Icons.xcassets/Restricted/error.imageset/Contents.json @@ -8,5 +8,8 @@ "info" : { "author" : "xcode", "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true } } diff --git a/VDS/SupportingFiles/Icons.xcassets/Restricted/info-bold.imageset/Contents.json b/VDS/SupportingFiles/Icons.xcassets/Restricted/info-bold.imageset/Contents.json index ffefe268..4dee1808 100644 --- a/VDS/SupportingFiles/Icons.xcassets/Restricted/info-bold.imageset/Contents.json +++ b/VDS/SupportingFiles/Icons.xcassets/Restricted/info-bold.imageset/Contents.json @@ -8,5 +8,8 @@ "info" : { "author" : "xcode", "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true } } diff --git a/VDS/SupportingFiles/Icons.xcassets/Restricted/info.imageset/Contents.json b/VDS/SupportingFiles/Icons.xcassets/Restricted/info.imageset/Contents.json index adcd08a2..32919952 100644 --- a/VDS/SupportingFiles/Icons.xcassets/Restricted/info.imageset/Contents.json +++ b/VDS/SupportingFiles/Icons.xcassets/Restricted/info.imageset/Contents.json @@ -8,5 +8,8 @@ "info" : { "author" : "xcode", "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true } } diff --git a/VDS/SupportingFiles/Icons.xcassets/Restricted/left-arrow.imageset/Contents.json b/VDS/SupportingFiles/Icons.xcassets/Restricted/left-arrow.imageset/Contents.json index 5b9739ba..1496eefd 100644 --- a/VDS/SupportingFiles/Icons.xcassets/Restricted/left-arrow.imageset/Contents.json +++ b/VDS/SupportingFiles/Icons.xcassets/Restricted/left-arrow.imageset/Contents.json @@ -8,5 +8,8 @@ "info" : { "author" : "xcode", "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true } } diff --git a/VDS/SupportingFiles/Icons.xcassets/Restricted/left-caret-bold.imageset/Contents.json b/VDS/SupportingFiles/Icons.xcassets/Restricted/left-caret-bold.imageset/Contents.json index 1e4c1c7e..d8517e5a 100644 --- a/VDS/SupportingFiles/Icons.xcassets/Restricted/left-caret-bold.imageset/Contents.json +++ b/VDS/SupportingFiles/Icons.xcassets/Restricted/left-caret-bold.imageset/Contents.json @@ -8,5 +8,8 @@ "info" : { "author" : "xcode", "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true } } diff --git a/VDS/SupportingFiles/Icons.xcassets/Restricted/left-caret.imageset/Contents.json b/VDS/SupportingFiles/Icons.xcassets/Restricted/left-caret.imageset/Contents.json index 7dcf67e0..388b021c 100644 --- a/VDS/SupportingFiles/Icons.xcassets/Restricted/left-caret.imageset/Contents.json +++ b/VDS/SupportingFiles/Icons.xcassets/Restricted/left-caret.imageset/Contents.json @@ -8,5 +8,8 @@ "info" : { "author" : "xcode", "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true } } diff --git a/VDS/SupportingFiles/Icons.xcassets/Restricted/multiple-documents.imageset/Contents.json b/VDS/SupportingFiles/Icons.xcassets/Restricted/multiple-documents.imageset/Contents.json index a8edc344..a32733a4 100644 --- a/VDS/SupportingFiles/Icons.xcassets/Restricted/multiple-documents.imageset/Contents.json +++ b/VDS/SupportingFiles/Icons.xcassets/Restricted/multiple-documents.imageset/Contents.json @@ -8,5 +8,8 @@ "info" : { "author" : "xcode", "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true } } diff --git a/VDS/SupportingFiles/Icons.xcassets/Restricted/pagination-left-arrow.imageset/Contents.json b/VDS/SupportingFiles/Icons.xcassets/Restricted/pagination-left-arrow.imageset/Contents.json index 84274b84..6944ac1a 100644 --- a/VDS/SupportingFiles/Icons.xcassets/Restricted/pagination-left-arrow.imageset/Contents.json +++ b/VDS/SupportingFiles/Icons.xcassets/Restricted/pagination-left-arrow.imageset/Contents.json @@ -8,5 +8,8 @@ "info" : { "author" : "xcode", "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true } } diff --git a/VDS/SupportingFiles/Icons.xcassets/Restricted/pagination-left-caret.imageset/Contents.json b/VDS/SupportingFiles/Icons.xcassets/Restricted/pagination-left-caret.imageset/Contents.json index b7e824be..6fd7077b 100644 --- a/VDS/SupportingFiles/Icons.xcassets/Restricted/pagination-left-caret.imageset/Contents.json +++ b/VDS/SupportingFiles/Icons.xcassets/Restricted/pagination-left-caret.imageset/Contents.json @@ -8,5 +8,8 @@ "info" : { "author" : "xcode", "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true } } diff --git a/VDS/SupportingFiles/Icons.xcassets/Restricted/pagination-right-arrow.imageset/Contents.json b/VDS/SupportingFiles/Icons.xcassets/Restricted/pagination-right-arrow.imageset/Contents.json index 67994793..82073c3d 100644 --- a/VDS/SupportingFiles/Icons.xcassets/Restricted/pagination-right-arrow.imageset/Contents.json +++ b/VDS/SupportingFiles/Icons.xcassets/Restricted/pagination-right-arrow.imageset/Contents.json @@ -8,5 +8,8 @@ "info" : { "author" : "xcode", "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true } } diff --git a/VDS/SupportingFiles/Icons.xcassets/Restricted/pagination-right-caret.imageset/Contents.json b/VDS/SupportingFiles/Icons.xcassets/Restricted/pagination-right-caret.imageset/Contents.json index ac5bf0f8..f13140e6 100644 --- a/VDS/SupportingFiles/Icons.xcassets/Restricted/pagination-right-caret.imageset/Contents.json +++ b/VDS/SupportingFiles/Icons.xcassets/Restricted/pagination-right-caret.imageset/Contents.json @@ -8,5 +8,8 @@ "info" : { "author" : "xcode", "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true } } diff --git a/VDS/SupportingFiles/Icons.xcassets/Restricted/right-arrow.imageset/Contents.json b/VDS/SupportingFiles/Icons.xcassets/Restricted/right-arrow.imageset/Contents.json index de24a6e9..36cbff60 100644 --- a/VDS/SupportingFiles/Icons.xcassets/Restricted/right-arrow.imageset/Contents.json +++ b/VDS/SupportingFiles/Icons.xcassets/Restricted/right-arrow.imageset/Contents.json @@ -8,5 +8,8 @@ "info" : { "author" : "xcode", "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true } } diff --git a/VDS/SupportingFiles/Icons.xcassets/Restricted/right-caret-bold.imageset/Contents.json b/VDS/SupportingFiles/Icons.xcassets/Restricted/right-caret-bold.imageset/Contents.json index 9c8e052c..e57ccc0d 100644 --- a/VDS/SupportingFiles/Icons.xcassets/Restricted/right-caret-bold.imageset/Contents.json +++ b/VDS/SupportingFiles/Icons.xcassets/Restricted/right-caret-bold.imageset/Contents.json @@ -8,5 +8,8 @@ "info" : { "author" : "xcode", "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true } } diff --git a/VDS/SupportingFiles/Icons.xcassets/Restricted/right-caret.imageset/Contents.json b/VDS/SupportingFiles/Icons.xcassets/Restricted/right-caret.imageset/Contents.json index 616090e3..1e745e81 100644 --- a/VDS/SupportingFiles/Icons.xcassets/Restricted/right-caret.imageset/Contents.json +++ b/VDS/SupportingFiles/Icons.xcassets/Restricted/right-caret.imageset/Contents.json @@ -8,5 +8,8 @@ "info" : { "author" : "xcode", "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true } } diff --git a/VDS/SupportingFiles/Icons.xcassets/Restricted/warning-bold.imageset/Contents.json b/VDS/SupportingFiles/Icons.xcassets/Restricted/warning-bold.imageset/Contents.json index 079e7cc3..55dd1b81 100644 --- a/VDS/SupportingFiles/Icons.xcassets/Restricted/warning-bold.imageset/Contents.json +++ b/VDS/SupportingFiles/Icons.xcassets/Restricted/warning-bold.imageset/Contents.json @@ -8,5 +8,8 @@ "info" : { "author" : "xcode", "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true } } diff --git a/VDS/SupportingFiles/Icons.xcassets/Restricted/warning.imageset/Contents.json b/VDS/SupportingFiles/Icons.xcassets/Restricted/warning.imageset/Contents.json index b9aa7c20..86da0a6d 100644 --- a/VDS/SupportingFiles/Icons.xcassets/Restricted/warning.imageset/Contents.json +++ b/VDS/SupportingFiles/Icons.xcassets/Restricted/warning.imageset/Contents.json @@ -8,5 +8,8 @@ "info" : { "author" : "xcode", "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true } } From d7cad3372744f1b2939c87170ee772143c0ad909 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Wed, 14 Jun 2023 08:17:42 -0500 Subject: [PATCH 02/12] refactored dropshadow Signed-off-by: Matt Bruce --- .../Icon/ButtonIcon/ButtonIcon.swift | 43 +++++++++++-------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift b/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift index 57e5c7f6..12db5a56 100644 --- a/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift +++ b/VDS/Components/Icon/ButtonIcon/ButtonIcon.swift @@ -172,13 +172,13 @@ open class ButtonIcon: Control { SurfaceColorConfiguration(VDSColor.backgroundPrimaryLight, .clear).eraseToAnyColorable() }() var shadowColorConfiguration: AnyColorable = { - SurfaceColorConfiguration(VDSColor.backgroundPrimaryLight, .clear).eraseToAnyColorable() + SurfaceColorConfiguration(VDSColor.paletteBlack, .clear).eraseToAnyColorable() }() - var shadowOpacity: CGFloat = 0.5 - var shadowOffset: CGSize = .init(width: 1, height: 1) + var shadowOpacity: CGFloat = 0.16 + var shadowOffset: CGSize = .init(width: 0, height: 2) var shadowRadius: CGFloat = 2 } - + private struct HighContrastConfiguration: Configuration { var kind: Kind = .highContrast var surfaceType: SurfaceType = .colorFill @@ -280,7 +280,6 @@ open class ButtonIcon: Control { } else { icon.reset() } - setNeedsLayout() } @@ -316,26 +315,15 @@ open class ButtonIcon: Control { if let borderable = currentConfig as? Borderable { layer.borderColor = borderable.borderColorConfiguration.getColor(self).cgColor layer.borderWidth = borderable.borderWidth - icon.layer.borderWidth = borderable.borderWidth } else { layer.borderColor = nil layer.borderWidth = 0 - icon.layer.borderWidth = 0 } if let dropshadowable = currentConfig as? Dropshadowable { - layer.masksToBounds = false - layer.shadowColor = dropshadowable.shadowColorConfiguration.getColor(self).cgColor - layer.shadowOpacity = Float(dropshadowable.shadowOpacity) - layer.shadowOffset = dropshadowable.shadowOffset - layer.shadowRadius = dropshadowable.shadowRadius - layer.shadowPath = UIBezierPath(rect: bounds).cgPath - layer.shouldRasterize = true - layer.rasterizationScale = UIScreen.main.scale + addDropShadow(config: dropshadowable) } else { - layer.shadowOpacity = 0 - layer.shadowRadius = 0 - layer.shadowPath = nil + removeDropShadow() } } @@ -360,6 +348,25 @@ extension ButtonIcon: AppleGuidlinesTouchable { } +extension UIView { + fileprivate func addDropShadow(config: Dropshadowable) { + layer.masksToBounds = false + layer.shadowColor = config.shadowColorConfiguration.getColor(self).cgColor + layer.shadowOpacity = Float(config.shadowOpacity) + layer.shadowOffset = config.shadowOffset + layer.shadowRadius = config.shadowRadius + layer.shouldRasterize = true + layer.rasterizationScale = UIScreen.main.scale + layer.shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: layer.cornerRadius).cgPath + } + + fileprivate func removeDropShadow() { + layer.shadowOpacity = 0 + layer.shadowRadius = 0 + layer.shadowPath = nil + } +} + private protocol Borderable { var borderWidth: CGFloat { get set } var borderColorConfiguration: AnyColorable { get set } From ce340fa34eaf12c1501ae905a3edbc7c2d0ab78d Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 15 Jun 2023 10:26:40 -0500 Subject: [PATCH 03/12] added extension methods for anchoring Signed-off-by: Matt Bruce --- VDS/Extensions/UIView.swift | 484 +++++++++++++++++++++++++++++++++--- 1 file changed, 447 insertions(+), 37 deletions(-) diff --git a/VDS/Extensions/UIView.swift b/VDS/Extensions/UIView.swift index 327849fc..792834ef 100644 --- a/VDS/Extensions/UIView.swift +++ b/VDS/Extensions/UIView.swift @@ -10,56 +10,203 @@ import UIKit import VDSFormControlsTokens extension UIView { - public func pin(_ view: UIView, with edges: UIEdgeInsets = UIEdgeInsets.zero) { - leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: edges.left).isActive = true - trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -edges.right).isActive = true - topAnchor.constraint(equalTo: view.topAnchor, constant: edges.top).isActive = true - bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -edges.bottom).isActive = true + public enum ConstraintIdentifier: CustomStringConvertible { + case leading, trailing, top, bottom, height, width + case custom(String) + + public var description: String { + switch self { + case .leading: return "leading" + case .trailing: return "trailing" + case .top: return "top" + case .bottom: return "bottom" + case .height: return "height" + case .width: return "width" + case .custom(let identifier): return identifier + } + } } - + + public enum ConstraintType { + case equal, lessThanOrEqual, greaterThanOrEqual + } + + public var _topConstraint: NSLayoutConstraint? { constraint(with: .top)} + public var _leadingConstraint: NSLayoutConstraint? { constraint(with: .leading)} + public var _trailingConstraint: NSLayoutConstraint? { constraint(with: .trailing)} + public var _bottomConstraint: NSLayoutConstraint? { constraint(with: .bottom)} + public var _widthConstraint: NSLayoutConstraint? { constraint(with: .width)} + public var _heightConstraint: NSLayoutConstraint? { constraint(with: .height)} + + public func constraint(with identifier: ConstraintIdentifier) -> NSLayoutConstraint? { + return constraint(with: identifier.description) + } + + public func constraint(with identifier: String) -> NSLayoutConstraint? { + return constraints.first { $0.identifier == identifier } + } + + public func removeConstraint(edges: [UIRectEdge]) { + let topConstraint: NSLayoutConstraint? = constraint(with: .top) + let leadingConstraint: NSLayoutConstraint? = constraint(with: .leading) + let trailingConstraint: NSLayoutConstraint? = constraint(with: .trailing) + let bottomConstraint: NSLayoutConstraint? = constraint(with: .bottom) + + edges.forEach { edge in + switch edge { + case .all: + if let leadingConstraint { + removeConstraint(leadingConstraint) + } + if let trailingConstraint { + removeConstraint(trailingConstraint) + } + if let topConstraint { + removeConstraint(topConstraint) + } + if let bottomConstraint { + removeConstraint(bottomConstraint) + } + case .left: + if let leadingConstraint { + removeConstraint(leadingConstraint) + } + case .right: + if let trailingConstraint { + removeConstraint(trailingConstraint) + } + case .top: + if let topConstraint { + removeConstraint(topConstraint) + } + case .bottom: + if let bottomConstraint { + removeConstraint(bottomConstraint) + } + default: + break + } + } + } +} + +//-------------------------------------------------- +// MARK: - Pinning +//-------------------------------------------------- +extension UIView { + public func pin(_ view: UIView, with edges: UIEdgeInsets = UIEdgeInsets.zero) { + leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: edges.left, identifier: ConstraintIdentifier.leading.description).isActive = true + trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -edges.right, identifier: ConstraintIdentifier.trailing.description).isActive = true + topAnchor.constraint(equalTo: view.topAnchor, constant: edges.top, identifier: ConstraintIdentifier.top.description).isActive = true + bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -edges.bottom, identifier: ConstraintIdentifier.bottom.description).isActive = true + } + public func pinToSuperView(_ edges: UIEdgeInsets = UIEdgeInsets.zero) { if let superview { pin(superview, with: edges) } } +} + +//-------------------------------------------------- +// MARK: - HeightAnchor +//-------------------------------------------------- +extension UIView { + + @discardableResult + public func height(_ constant: CGFloat, type: ConstraintType = .equal) -> Self { + switch type { + case .equal: + height(constant) + + case .lessThanOrEqual: + heightLessThanEqualTo(constant) + + case .greaterThanOrEqual: + heightGreaterThanEqualTo(constant) + } + return self + } @discardableResult public func height(_ constant: CGFloat) -> Self { - heightAnchor.constraint(equalToConstant: constant).isActive = true + heightAnchor.constraint(equalToConstant: constant, identifier: ConstraintIdentifier.height.description).isActive = true return self } - - @discardableResult - public func heightGreaterThanEqual(_ constant: CGFloat) -> Self { - heightAnchor.constraint(greaterThanOrEqualToConstant: constant).isActive = true - return self - } - - @discardableResult - public func heightLessThanEqual(_ constant: CGFloat) -> Self { - heightAnchor.constraint(lessThanOrEqualToConstant: constant).isActive = true - return self - } - - @discardableResult - public func width(_ constant: CGFloat) -> Self { - widthAnchor.constraint(equalToConstant: constant).isActive = true - return self - } - @discardableResult - public func widthGreaterThanEqual(_ constant: CGFloat) -> Self { - widthAnchor.constraint(greaterThanOrEqualToConstant: constant).isActive = true + public func heightGreaterThanEqualTo(_ constant: CGFloat) -> Self { + heightAnchor.constraint(greaterThanOrEqualToConstant: constant, identifier: ConstraintIdentifier.height.description).isActive = true return self } - + @discardableResult - public func widthLessThanEqual(_ constant: CGFloat) -> Self { - widthAnchor.constraint(lessThanOrEqualToConstant: constant).isActive = true + public func heightLessThanEqualTo(_ constant: CGFloat) -> Self { + heightAnchor.constraint(lessThanOrEqualToConstant: constant, identifier: ConstraintIdentifier.height.description).isActive = true return self } + +} +//-------------------------------------------------- +// MARK: - WidthAnchor +//-------------------------------------------------- +extension UIView { + + @discardableResult + public func width(_ constant: CGFloat, type: ConstraintType = .equal) -> Self { + switch type { + case .equal: + width(constant) + + case .lessThanOrEqual: + widthLessThanEqualTo(constant) + + case .greaterThanOrEqual: + widthGreaterThanEqualTo(constant) + } + return self + } + + @discardableResult + public func width(_ constant: CGFloat) -> Self { + widthAnchor.constraint(equalToConstant: constant, identifier: ConstraintIdentifier.width.description).isActive = true + return self + } + + @discardableResult + public func widthGreaterThanEqualTo(_ constant: CGFloat) -> Self { + widthAnchor.constraint(greaterThanOrEqualToConstant: constant, identifier: ConstraintIdentifier.width.description).isActive = true + return self + } + + @discardableResult + public func widthLessThanEqualTo(_ constant: CGFloat) -> Self { + widthAnchor.constraint(lessThanOrEqualToConstant: constant, identifier: ConstraintIdentifier.width.description).isActive = true + return self + } +} + +//-------------------------------------------------- +// MARK: - TopAnchor +//-------------------------------------------------- +extension UIView { + + @discardableResult + public func pinTop(_ anchor: NSLayoutYAxisAnchor? = nil, _ constant: CGFloat = 0.0, _ type: ConstraintType = .equal) -> Self { + switch type { + case .equal: + pinTop(anchor, constant) + + case .lessThanOrEqual: + pinTopLessThanOrEqualTo(anchor, constant) + + case .greaterThanOrEqual: + pinTopGreaterThanOrEqualTo(anchor, constant) + } + return self + } + @discardableResult public func pinTop(_ constant: CGFloat = 0.0) -> Self { return pinTop(nil, constant) @@ -69,11 +216,49 @@ extension UIView { public func pinTop(_ anchor: NSLayoutYAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self { let found: NSLayoutYAxisAnchor? = anchor ?? superview?.topAnchor if let found { - topAnchor.constraint(equalTo: found, constant: constant).isActive = true + topAnchor.constraint(equalTo: found, constant: constant, identifier: ConstraintIdentifier.top.description).isActive = true } return self } + + @discardableResult + public func pinTopLessThanOrEqualTo(_ anchor: NSLayoutYAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self { + let found: NSLayoutYAxisAnchor? = anchor ?? superview?.topAnchor + if let found { + topAnchor.constraint(lessThanOrEqualTo: found, constant: constant, identifier: ConstraintIdentifier.top.description).isActive = true + } + return self + } + + @discardableResult + public func pinTopGreaterThanOrEqualTo(_ anchor: NSLayoutYAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self { + let found: NSLayoutYAxisAnchor? = anchor ?? superview?.topAnchor + if let found { + topAnchor.constraint(greaterThanOrEqualTo: found, constant: constant, identifier: ConstraintIdentifier.top.description).isActive = true + } + return self + } +} +//-------------------------------------------------- +// MARK: - BottomAnchor +//-------------------------------------------------- +extension UIView { + @discardableResult + public func pinBottom(_ anchor: NSLayoutYAxisAnchor? = nil, _ constant: CGFloat = 0.0, _ type: ConstraintType = .equal) -> Self { + switch type { + case .equal: + pinBottom(anchor, constant) + + case .lessThanOrEqual: + pinBottomLessThanOrEqualTo(anchor, constant) + + case .greaterThanOrEqual: + pinBottomGreaterThanOrEqualTo(anchor, constant) + } + return self + } + @discardableResult public func pinBottom(_ constant: CGFloat = 0.0) -> Self { return pinBottom(nil, constant) @@ -83,7 +268,45 @@ extension UIView { public func pinBottom(_ anchor: NSLayoutYAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self { let found: NSLayoutYAxisAnchor? = anchor ?? superview?.bottomAnchor if let found { - bottomAnchor.constraint(equalTo: found, constant: -constant).isActive = true + bottomAnchor.constraint(equalTo: found, constant: -constant, identifier: ConstraintIdentifier.bottom.description).isActive = true + } + return self + } + + @discardableResult + public func pinBottomLessThanOrEqualTo(_ anchor: NSLayoutYAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self { + let found: NSLayoutYAxisAnchor? = anchor ?? superview?.bottomAnchor + if let found { + bottomAnchor.constraint(lessThanOrEqualTo: found, constant: -constant, identifier: ConstraintIdentifier.bottom.description).isActive = true + } + return self + } + + @discardableResult + public func pinBottomGreaterThanOrEqualTo(_ anchor: NSLayoutYAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self { + let found: NSLayoutYAxisAnchor? = anchor ?? superview?.bottomAnchor + if let found { + bottomAnchor.constraint(greaterThanOrEqualTo: found, constant: -constant, identifier: ConstraintIdentifier.bottom.description).isActive = true + } + return self + } +} + +//-------------------------------------------------- +// MARK: - LeadingAnchor +//-------------------------------------------------- +extension UIView { + @discardableResult + public func pinLeading(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0, _ type: ConstraintType = .equal) -> Self { + switch type { + case .equal: + pinLeading(anchor, constant) + + case .lessThanOrEqual: + pinLeadingLessThanOrEqualTo(anchor, constant) + + case .greaterThanOrEqual: + pinLeadingGreaterThanOrEqualTo(anchor, constant) } return self } @@ -92,16 +315,55 @@ extension UIView { public func pinLeading(_ constant: CGFloat = 0.0) -> Self { return pinLeading(nil, constant) } - + @discardableResult public func pinLeading(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self { let found: NSLayoutXAxisAnchor? = anchor ?? superview?.leadingAnchor if let found { - leadingAnchor.constraint(equalTo: found, constant: constant).isActive = true + leadingAnchor.constraint(equalTo: found, constant: constant, identifier: ConstraintIdentifier.leading.description).isActive = true } return self } + + @discardableResult + public func pinLeadingLessThanOrEqualTo(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self { + let found: NSLayoutXAxisAnchor? = anchor ?? superview?.leadingAnchor + if let found { + leadingAnchor.constraint(lessThanOrEqualTo: found, constant: constant, identifier: ConstraintIdentifier.leading.description).isActive = true + } + return self + } + + @discardableResult + public func pinLeadingGreaterThanOrEqualTo(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self { + let found: NSLayoutXAxisAnchor? = anchor ?? superview?.leadingAnchor + if let found { + leadingAnchor.constraint(greaterThanOrEqualTo: found, constant: constant, identifier: ConstraintIdentifier.leading.description).isActive = true + } + return self + } +} +//-------------------------------------------------- +// MARK: - TrailingAnchor +//-------------------------------------------------- +extension UIView { + + @discardableResult + public func pinTrailing(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0, _ type: ConstraintType = .equal) -> Self { + switch type { + case .equal: + pinTrailing(anchor, constant) + + case .lessThanOrEqual: + pinTrailingLessThanOrEqualTo(anchor, constant) + + case .greaterThanOrEqual: + pinLeadingGreaterThanOrEqualTo(anchor, constant) + } + return self + } + @discardableResult public func pinTrailing(_ constant: CGFloat = 0.0) -> Self { return pinTrailing(nil, constant) @@ -111,13 +373,33 @@ extension UIView { public func pinTrailing(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self { let found: NSLayoutXAxisAnchor? = anchor ?? superview?.trailingAnchor if let found { - trailingAnchor.constraint(equalTo: found, constant: -constant).isActive = true + trailingAnchor.constraint(equalTo: found, constant: -constant, identifier: ConstraintIdentifier.trailing.description).isActive = true + } + return self + } + + @discardableResult + public func pinTrailingLessThanOrEqualTo(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self { + let found: NSLayoutXAxisAnchor? = anchor ?? superview?.trailingAnchor + if let found { + trailingAnchor.constraint(lessThanOrEqualTo: found, constant: -constant, identifier: ConstraintIdentifier.trailing.description).isActive = true } return self } + @discardableResult + public func pinTrailingGreaterThanOrEqualTo(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self { + let found: NSLayoutXAxisAnchor? = anchor ?? superview?.trailingAnchor + if let found { + trailingAnchor.constraint(greaterThanOrEqualTo: found, constant: -constant, identifier: ConstraintIdentifier.trailing.description).isActive = true + } + return self + } } +//-------------------------------------------------- +// MARK: - Debug Borders +//-------------------------------------------------- extension UIView { internal func removeDebugBorder() { @@ -174,6 +456,9 @@ extension UIView { } } +//-------------------------------------------------- +// MARK: - CALayer +//-------------------------------------------------- extension CALayer { func remove(layerName: String) { guard let sublayers = sublayers else { @@ -188,7 +473,9 @@ extension CALayer { } } - +//-------------------------------------------------- +// MARK: - Borders +//-------------------------------------------------- extension UIView { public func addBorder(side: UIRectEdge, width: CGFloat, color: UIColor, offset: CGFloat = 0) { @@ -239,3 +526,126 @@ extension UIView { } } } + +//-------------------------------------------------- +// MARK: - NSLayoutAnchor +//-------------------------------------------------- +extension NSLayoutAnchor { + // These methods return an inactive constraint of the form thisAnchor = otherAnchor. + @discardableResult + @objc public func constraint(equalTo anchor: NSLayoutAnchor, identifier: String) -> NSLayoutConstraint { + let constraint = self.constraint(equalTo: anchor) + constraint.identifier = identifier + return constraint + } + + @discardableResult + @objc public func constraint(greaterThanOrEqualTo anchor: NSLayoutAnchor, identifier: String) -> NSLayoutConstraint { + let constraint = self.constraint(greaterThanOrEqualTo: anchor) + constraint.identifier = identifier + return constraint + } + + @discardableResult + @objc public func constraint(lessThanOrEqualTo anchor: NSLayoutAnchor, identifier: String) -> NSLayoutConstraint { + let constraint = self.constraint(lessThanOrEqualTo: anchor) + constraint.identifier = identifier + return constraint + } + + + @discardableResult + @objc public func constraint(equalTo anchor: NSLayoutAnchor, constant: CGFloat, identifier: String) -> NSLayoutConstraint { + let constraint = self.constraint(equalTo: anchor, constant: constant) + constraint.identifier = identifier + return constraint + } + + @discardableResult + @objc public func constraint(greaterThanOrEqualTo anchor: NSLayoutAnchor, constant: CGFloat, identifier: String) -> NSLayoutConstraint { + let constraint = self.constraint(greaterThanOrEqualTo: anchor, constant: constant) + constraint.identifier = identifier + return constraint + } + + @discardableResult + @objc public func constraint(lessThanOrEqualTo anchor: NSLayoutAnchor, constant: CGFloat, identifier: String) -> NSLayoutConstraint { + let constraint = self.constraint(lessThanOrEqualTo: anchor, constant: constant) + constraint.identifier = identifier + return constraint + } +} + +//-------------------------------------------------- +// MARK: - NSLayoutDimension +//-------------------------------------------------- +extension NSLayoutDimension { + // These methods return an inactive constraint of the form thisVariable = constant. + @discardableResult + @objc public func constraint(equalToConstant c: CGFloat, identifier: String) -> NSLayoutConstraint { + let lc = constraint(equalToConstant: c) + lc.identifier = identifier + return lc + } + + @discardableResult + @objc public func constraint(greaterThanOrEqualToConstant c: CGFloat, identifier: String) -> NSLayoutConstraint { + let lc = constraint(greaterThanOrEqualToConstant: c) + lc.identifier = identifier + return lc + } + + @discardableResult + @objc public func constraint(lessThanOrEqualToConstant c: CGFloat, identifier: String) -> NSLayoutConstraint { + let lc = constraint(lessThanOrEqualToConstant: c) + lc.identifier = identifier + return lc + } + + + // These methods return an inactive constraint of the form thisAnchor = otherAnchor * multiplier. + @discardableResult + @objc public func constraint(equalTo anchor: NSLayoutDimension, multiplier m: CGFloat, identifier: String) -> NSLayoutConstraint { + let lc = constraint(equalTo: anchor, multiplier: m) + lc.identifier = identifier + return lc + } + + @discardableResult + @objc public func constraint(greaterThanOrEqualTo anchor: NSLayoutDimension, multiplier m: CGFloat, identifier: String) -> NSLayoutConstraint { + let lc = constraint(greaterThanOrEqualTo: anchor ,multiplier: m) + lc.identifier = identifier + return lc + } + + @discardableResult + @objc public func constraint(lessThanOrEqualTo anchor: NSLayoutDimension, multiplier m: CGFloat, identifier: String) -> NSLayoutConstraint { + let lc = constraint(lessThanOrEqualTo: anchor, multiplier: m) + lc.identifier = identifier + return lc + } + + + // These methods return an inactive constraint of the form thisAnchor = otherAnchor * multiplier + constant. + @discardableResult + @objc public func constraint(equalTo anchor: NSLayoutDimension, multiplier m: CGFloat, constant c: CGFloat, identifier: String) -> NSLayoutConstraint { + let lc = constraint(equalTo: anchor, multiplier: m, constant: c) + lc.identifier = identifier + return lc + } + + @discardableResult + @objc public func constraint(greaterThanOrEqualTo anchor: NSLayoutDimension, multiplier m: CGFloat, constant c: CGFloat, identifier: String) -> NSLayoutConstraint { + let lc = constraint(greaterThanOrEqualTo: anchor, multiplier: m, constant: c) + lc.identifier = identifier + return lc + } + + @discardableResult + @objc public func constraint(lessThanOrEqualTo anchor: NSLayoutDimension, multiplier m: CGFloat, constant c: CGFloat, identifier: String) -> NSLayoutConstraint { + let lc = constraint(lessThanOrEqualTo: anchor, multiplier: m, constant: c) + lc.identifier = identifier + return lc + } + +} From 342357820f7331d65c55306757c6b28c8d2b9e5e Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 15 Jun 2023 10:39:42 -0500 Subject: [PATCH 04/12] refactored out extensions into files Signed-off-by: Matt Bruce --- VDS.xcodeproj/project.pbxproj | 12 ++ VDS/Extensions/NSLayoutAnchor.swift | 58 ++++++ VDS/Extensions/NSLayoutDimension.swift | 84 ++++++++ VDS/Extensions/UIView+CALayer.swift | 140 ++++++++++++++ VDS/Extensions/UIView.swift | 253 ------------------------- 5 files changed, 294 insertions(+), 253 deletions(-) create mode 100644 VDS/Extensions/NSLayoutAnchor.swift create mode 100644 VDS/Extensions/NSLayoutDimension.swift create mode 100644 VDS/Extensions/UIView+CALayer.swift diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index 10ade0c0..d5893104 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -106,6 +106,9 @@ EAC925842911C63100091998 /* Colorable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAA5EEDF28F49DB3003B3210 /* Colorable.swift */; }; EAC9258C2911C9DE00091998 /* InputField.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC925872911C9DE00091998 /* InputField.swift */; }; EAC9258F2911C9DE00091998 /* EntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC9258B2911C9DE00091998 /* EntryField.swift */; }; + EAD062A72A3B67770015965D /* UIView+CALayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD062A62A3B67770015965D /* UIView+CALayer.swift */; }; + EAD062A92A3B67B10015965D /* NSLayoutAnchor.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD062A82A3B67B10015965D /* NSLayoutAnchor.swift */; }; + EAD062AB2A3B67D00015965D /* NSLayoutDimension.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD062AA2A3B67D00015965D /* NSLayoutDimension.swift */; }; EAD8D2C128BFDE8B006EB6A6 /* UIGestureRecognizer+Publisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD8D2C028BFDE8B006EB6A6 /* UIGestureRecognizer+Publisher.swift */; }; EAF1FE9929D4850E00101452 /* Clickable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF1FE9829D4850E00101452 /* Clickable.swift */; }; EAF1FE9B29DB1A6000101452 /* Changeable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF1FE9A29DB1A6000101452 /* Changeable.swift */; }; @@ -237,6 +240,9 @@ EAC925822911B35300091998 /* TextLinkCaret.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextLinkCaret.swift; sourceTree = ""; }; EAC925872911C9DE00091998 /* InputField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InputField.swift; sourceTree = ""; }; EAC9258B2911C9DE00091998 /* EntryField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EntryField.swift; sourceTree = ""; }; + EAD062A62A3B67770015965D /* UIView+CALayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+CALayer.swift"; sourceTree = ""; }; + EAD062A82A3B67B10015965D /* NSLayoutAnchor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSLayoutAnchor.swift; sourceTree = ""; }; + EAD062AA2A3B67D00015965D /* NSLayoutDimension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSLayoutDimension.swift; sourceTree = ""; }; EAD8D2C028BFDE8B006EB6A6 /* UIGestureRecognizer+Publisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIGestureRecognizer+Publisher.swift"; sourceTree = ""; }; EAF1FE9829D4850E00101452 /* Clickable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Clickable.swift; sourceTree = ""; }; EAF1FE9A29DB1A6000101452 /* Changeable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Changeable.swift; sourceTree = ""; }; @@ -429,12 +435,15 @@ EAF7F0992899B17200B287F5 /* CATransaction.swift */, EA33622D2891EA3C0071C351 /* DispatchQueue+Once.swift */, EABFEB632A26473700C4C106 /* NSAttributedString.swift */, + EAD062A82A3B67B10015965D /* NSLayoutAnchor.swift */, + EAD062AA2A3B67D00015965D /* NSLayoutDimension.swift */, EAB2376529E9952D00AABE9A /* UIApplication.swift */, EA3361A7288B23300071C351 /* UIColor.swift */, EA81410F2A127066004F60D2 /* UIColor+VDSColor.swift */, EA33623D2892EE950071C351 /* UIDevice.swift */, EAF7F0B6289C12A600B287F5 /* UITapGestureRecognizer.swift */, EAB5FED329267EB300998C17 /* UIView.swift */, + EAD062A62A3B67770015965D /* UIView+CALayer.swift */, EAB5FF0029424ACB00998C17 /* UIControl.swift */, EA985C662970C21600F2FF2E /* VDSLayout.swift */, ); @@ -884,6 +893,7 @@ EA33624728931B050071C351 /* Initable.swift in Sources */, EAF7F0A4289B017C00B287F5 /* LabelAttributeModel.swift in Sources */, EA5F86D02A1F936100BC83E4 /* TabsContainer.swift in Sources */, + EAD062A92A3B67B10015965D /* NSLayoutAnchor.swift in Sources */, EAF7F0B1289B177F00B287F5 /* ColorLabelAttribute.swift in Sources */, EAC9258F2911C9DE00091998 /* EntryField.swift in Sources */, EAB1D2EA28AE84AA00DAE764 /* UIControlPublisher.swift in Sources */, @@ -927,6 +937,7 @@ EAB2376629E9952D00AABE9A /* UIApplication.swift in Sources */, EAB5FED429267EB300998C17 /* UIView.swift in Sources */, EAB2376829E9992800AABE9A /* TooltipAlertViewController.swift in Sources */, + EAD062AB2A3B67D00015965D /* NSLayoutDimension.swift in Sources */, EA33623E2892EE950071C351 /* UIDevice.swift in Sources */, EA985C692971B90B00F2FF2E /* IconSize.swift in Sources */, EA985C672970C21600F2FF2E /* VDSLayout.swift in Sources */, @@ -941,6 +952,7 @@ EA1F266628B945070033E859 /* RadioSwatchGroup.swift in Sources */, EA596ABF2A16B4F500300C4B /* Tabs.swift in Sources */, EAC71A212A2E1DC000E47A9F /* SelectorItemBase.swift in Sources */, + EAD062A72A3B67770015965D /* UIView+CALayer.swift in Sources */, EA985BEC2968A91200F2FF2E /* TitleLockupTitleModel.swift in Sources */, 5FC35BE328D51405004EBEAC /* Button.swift in Sources */, ); diff --git a/VDS/Extensions/NSLayoutAnchor.swift b/VDS/Extensions/NSLayoutAnchor.swift new file mode 100644 index 00000000..21c526e6 --- /dev/null +++ b/VDS/Extensions/NSLayoutAnchor.swift @@ -0,0 +1,58 @@ +// +// NSLayoutAnchor.swift +// VDS +// +// Created by Matt Bruce on 6/15/23. +// + +import Foundation +import UIKit + +//-------------------------------------------------- +// MARK: - NSLayoutAnchor +//-------------------------------------------------- +extension NSLayoutAnchor { + // These methods return an inactive constraint of the form thisAnchor = otherAnchor. + @discardableResult + @objc public func constraint(equalTo anchor: NSLayoutAnchor, identifier: String) -> NSLayoutConstraint { + let constraint = self.constraint(equalTo: anchor) + constraint.identifier = identifier + return constraint + } + + @discardableResult + @objc public func constraint(greaterThanOrEqualTo anchor: NSLayoutAnchor, identifier: String) -> NSLayoutConstraint { + let constraint = self.constraint(greaterThanOrEqualTo: anchor) + constraint.identifier = identifier + return constraint + } + + @discardableResult + @objc public func constraint(lessThanOrEqualTo anchor: NSLayoutAnchor, identifier: String) -> NSLayoutConstraint { + let constraint = self.constraint(lessThanOrEqualTo: anchor) + constraint.identifier = identifier + return constraint + } + + + @discardableResult + @objc public func constraint(equalTo anchor: NSLayoutAnchor, constant: CGFloat, identifier: String) -> NSLayoutConstraint { + let constraint = self.constraint(equalTo: anchor, constant: constant) + constraint.identifier = identifier + return constraint + } + + @discardableResult + @objc public func constraint(greaterThanOrEqualTo anchor: NSLayoutAnchor, constant: CGFloat, identifier: String) -> NSLayoutConstraint { + let constraint = self.constraint(greaterThanOrEqualTo: anchor, constant: constant) + constraint.identifier = identifier + return constraint + } + + @discardableResult + @objc public func constraint(lessThanOrEqualTo anchor: NSLayoutAnchor, constant: CGFloat, identifier: String) -> NSLayoutConstraint { + let constraint = self.constraint(lessThanOrEqualTo: anchor, constant: constant) + constraint.identifier = identifier + return constraint + } +} diff --git a/VDS/Extensions/NSLayoutDimension.swift b/VDS/Extensions/NSLayoutDimension.swift new file mode 100644 index 00000000..d8eacf79 --- /dev/null +++ b/VDS/Extensions/NSLayoutDimension.swift @@ -0,0 +1,84 @@ +// +// NSLayoutDimension.swift +// VDS +// +// Created by Matt Bruce on 6/15/23. +// + +import Foundation +import UIKit + +//-------------------------------------------------- +// MARK: - NSLayoutDimension +//-------------------------------------------------- +extension NSLayoutDimension { + // These methods return an inactive constraint of the form thisVariable = constant. + @discardableResult + @objc public func constraint(equalToConstant c: CGFloat, identifier: String) -> NSLayoutConstraint { + let lc = constraint(equalToConstant: c) + lc.identifier = identifier + return lc + } + + @discardableResult + @objc public func constraint(greaterThanOrEqualToConstant c: CGFloat, identifier: String) -> NSLayoutConstraint { + let lc = constraint(greaterThanOrEqualToConstant: c) + lc.identifier = identifier + return lc + } + + @discardableResult + @objc public func constraint(lessThanOrEqualToConstant c: CGFloat, identifier: String) -> NSLayoutConstraint { + let lc = constraint(lessThanOrEqualToConstant: c) + lc.identifier = identifier + return lc + } + + + // These methods return an inactive constraint of the form thisAnchor = otherAnchor * multiplier. + @discardableResult + @objc public func constraint(equalTo anchor: NSLayoutDimension, multiplier m: CGFloat, identifier: String) -> NSLayoutConstraint { + let lc = constraint(equalTo: anchor, multiplier: m) + lc.identifier = identifier + return lc + } + + @discardableResult + @objc public func constraint(greaterThanOrEqualTo anchor: NSLayoutDimension, multiplier m: CGFloat, identifier: String) -> NSLayoutConstraint { + let lc = constraint(greaterThanOrEqualTo: anchor ,multiplier: m) + lc.identifier = identifier + return lc + } + + @discardableResult + @objc public func constraint(lessThanOrEqualTo anchor: NSLayoutDimension, multiplier m: CGFloat, identifier: String) -> NSLayoutConstraint { + let lc = constraint(lessThanOrEqualTo: anchor, multiplier: m) + lc.identifier = identifier + return lc + } + + + // These methods return an inactive constraint of the form thisAnchor = otherAnchor * multiplier + constant. + @discardableResult + @objc public func constraint(equalTo anchor: NSLayoutDimension, multiplier m: CGFloat, constant c: CGFloat, identifier: String) -> NSLayoutConstraint { + let lc = constraint(equalTo: anchor, multiplier: m, constant: c) + lc.identifier = identifier + return lc + } + + @discardableResult + @objc public func constraint(greaterThanOrEqualTo anchor: NSLayoutDimension, multiplier m: CGFloat, constant c: CGFloat, identifier: String) -> NSLayoutConstraint { + let lc = constraint(greaterThanOrEqualTo: anchor, multiplier: m, constant: c) + lc.identifier = identifier + return lc + } + + @discardableResult + @objc public func constraint(lessThanOrEqualTo anchor: NSLayoutDimension, multiplier m: CGFloat, constant c: CGFloat, identifier: String) -> NSLayoutConstraint { + let lc = constraint(lessThanOrEqualTo: anchor, multiplier: m, constant: c) + lc.identifier = identifier + return lc + } + +} + diff --git a/VDS/Extensions/UIView+CALayer.swift b/VDS/Extensions/UIView+CALayer.swift new file mode 100644 index 00000000..2ad15363 --- /dev/null +++ b/VDS/Extensions/UIView+CALayer.swift @@ -0,0 +1,140 @@ +// +// UIView+CALayer.swift +// VDS +// +// Created by Matt Bruce on 6/15/23. +// + +import Foundation +import UIKit +import VDSFormControlsTokens + +//-------------------------------------------------- +// MARK: - Debug Borders +//-------------------------------------------------- +extension UIView { + + internal func removeDebugBorder() { + layer.remove(layerName: "debug") + } + + internal func addDebugBorder(color: UIColor = .red) { + //ensure you remove existing + removeDebugBorder() + + //add bounds border + let borderLayer = CALayer() + borderLayer.name = "debugAreaLayer" + borderLayer.frame = bounds + borderLayer.bounds = bounds + borderLayer.borderWidth = VDSFormControls.widthBorder + borderLayer.borderColor = color.cgColor + layer.addSublayer(borderLayer) + + //add touchborder if applicable + if type(of: self) is AppleGuidlinesTouchable.Type { + let faultToleranceX: CGFloat = max((45 - bounds.size.width) / 2.0, 0) + let faultToleranceY: CGFloat = max((45 - bounds.size.height) / 2.0, 0) + + let touchableAreaPath = UIBezierPath(rect: bounds.insetBy(dx: -faultToleranceX, dy: -faultToleranceY)) + let touchLayer = CAShapeLayer() + touchLayer.path = touchableAreaPath.cgPath + touchLayer.strokeColor = color.cgColor + touchLayer.fillColor = UIColor.clear.cgColor + touchLayer.lineWidth = VDSFormControls.widthBorder + touchLayer.opacity = 1.0 + touchLayer.name = "debugTouchableAreaLayer" + touchLayer.zPosition = 100 + touchLayer.frame = bounds + touchLayer.bounds = bounds + layer.addSublayer(touchLayer) + } + } + + public var hasDebugBorder: Bool { + guard let layers = layer.sublayers else { return false } + return layers.compactMap{$0.name}.filter{$0.hasPrefix("debug")}.count > 0 + } + + public func debugBorder(show shouldShow: Bool = true, color: UIColor = .red) { + if shouldShow { + addDebugBorder(color: color) + } else { + removeDebugBorder() + } + if let view = self as? Handlerable { + view.updateView() + } + } +} + +//-------------------------------------------------- +// MARK: - CALayer +//-------------------------------------------------- +extension CALayer { + func remove(layerName: String) { + guard let sublayers = sublayers else { + return + } + + sublayers.forEach({ layer in + if layer.name?.hasPrefix(layerName) ?? false { + layer.removeFromSuperlayer() + } + }) + } +} + +//-------------------------------------------------- +// MARK: - Borders +//-------------------------------------------------- +extension UIView { + + public func addBorder(side: UIRectEdge, width: CGFloat, color: UIColor, offset: CGFloat = 0) { + let layerName = borderLayerName(for: side) + layer.remove(layerName: layerName) + + let borderLayer = CALayer() + borderLayer.backgroundColor = color.cgColor + borderLayer.name = layerName + + switch side { + case .left: + borderLayer.frame = CGRect(x: 0, y: 0, width: width, height: frame.height) + case .right: + borderLayer.frame = CGRect(x: frame.width - width - offset, y: 0, width: width, height: frame.height) + case .top: + borderLayer.frame = CGRect(x: 0, y: 0, width: frame.width, height: width) + case .bottom: + borderLayer.frame = CGRect(x: 0, y: frame.height - width - offset, width: frame.width, height: width) + default: + break + } + + layer.addSublayer(borderLayer) + } + + public func removeBorders() { + layer.borderWidth = 0 + layer.borderColor = nil + layer.remove(layerName: borderLayerName(for: .top)) + layer.remove(layerName: borderLayerName(for: .left)) + layer.remove(layerName: borderLayerName(for: .right)) + layer.remove(layerName: borderLayerName(for: .bottom)) + } + + private func borderLayerName(for side: UIRectEdge) -> String { + switch side { + case .left: + return "leftBorderLayer" + case .right: + return "rightBorderLayer" + case .top: + return "topBorderLayer" + case .bottom: + return "bottomBorderLayer" + default: + return "" + } + } +} diff --git a/VDS/Extensions/UIView.swift b/VDS/Extensions/UIView.swift index 792834ef..1196e5e6 100644 --- a/VDS/Extensions/UIView.swift +++ b/VDS/Extensions/UIView.swift @@ -396,256 +396,3 @@ extension UIView { return self } } - -//-------------------------------------------------- -// MARK: - Debug Borders -//-------------------------------------------------- -extension UIView { - - internal func removeDebugBorder() { - layer.remove(layerName: "debug") - } - - internal func addDebugBorder(color: UIColor = .red) { - //ensure you remove existing - removeDebugBorder() - - //add bounds border - let borderLayer = CALayer() - borderLayer.name = "debugAreaLayer" - borderLayer.frame = bounds - borderLayer.bounds = bounds - borderLayer.borderWidth = VDSFormControls.widthBorder - borderLayer.borderColor = color.cgColor - layer.addSublayer(borderLayer) - - //add touchborder if applicable - if type(of: self) is AppleGuidlinesTouchable.Type { - let faultToleranceX: CGFloat = max((45 - bounds.size.width) / 2.0, 0) - let faultToleranceY: CGFloat = max((45 - bounds.size.height) / 2.0, 0) - - let touchableAreaPath = UIBezierPath(rect: bounds.insetBy(dx: -faultToleranceX, dy: -faultToleranceY)) - let touchLayer = CAShapeLayer() - touchLayer.path = touchableAreaPath.cgPath - touchLayer.strokeColor = color.cgColor - touchLayer.fillColor = UIColor.clear.cgColor - touchLayer.lineWidth = VDSFormControls.widthBorder - touchLayer.opacity = 1.0 - touchLayer.name = "debugTouchableAreaLayer" - touchLayer.zPosition = 100 - touchLayer.frame = bounds - touchLayer.bounds = bounds - layer.addSublayer(touchLayer) - } - } - - public var hasDebugBorder: Bool { - guard let layers = layer.sublayers else { return false } - return layers.compactMap{$0.name}.filter{$0.hasPrefix("debug")}.count > 0 - } - - public func debugBorder(show shouldShow: Bool = true, color: UIColor = .red) { - if shouldShow { - addDebugBorder(color: color) - } else { - removeDebugBorder() - } - if let view = self as? Handlerable { - view.updateView() - } - } -} - -//-------------------------------------------------- -// MARK: - CALayer -//-------------------------------------------------- -extension CALayer { - func remove(layerName: String) { - guard let sublayers = sublayers else { - return - } - - sublayers.forEach({ layer in - if layer.name?.hasPrefix(layerName) ?? false { - layer.removeFromSuperlayer() - } - }) - } -} - -//-------------------------------------------------- -// MARK: - Borders -//-------------------------------------------------- -extension UIView { - - public func addBorder(side: UIRectEdge, width: CGFloat, color: UIColor, offset: CGFloat = 0) { - let layerName = borderLayerName(for: side) - layer.remove(layerName: layerName) - - let borderLayer = CALayer() - borderLayer.backgroundColor = color.cgColor - borderLayer.name = layerName - - switch side { - case .left: - borderLayer.frame = CGRect(x: 0, y: 0, width: width, height: frame.height) - case .right: - borderLayer.frame = CGRect(x: frame.width - width - offset, y: 0, width: width, height: frame.height) - case .top: - borderLayer.frame = CGRect(x: 0, y: 0, width: frame.width, height: width) - case .bottom: - borderLayer.frame = CGRect(x: 0, y: frame.height - width - offset, width: frame.width, height: width) - default: - break - } - - layer.addSublayer(borderLayer) - } - - public func removeBorders() { - layer.borderWidth = 0 - layer.borderColor = nil - layer.remove(layerName: borderLayerName(for: .top)) - layer.remove(layerName: borderLayerName(for: .left)) - layer.remove(layerName: borderLayerName(for: .right)) - layer.remove(layerName: borderLayerName(for: .bottom)) - } - - private func borderLayerName(for side: UIRectEdge) -> String { - switch side { - case .left: - return "leftBorderLayer" - case .right: - return "rightBorderLayer" - case .top: - return "topBorderLayer" - case .bottom: - return "bottomBorderLayer" - default: - return "" - } - } -} - -//-------------------------------------------------- -// MARK: - NSLayoutAnchor -//-------------------------------------------------- -extension NSLayoutAnchor { - // These methods return an inactive constraint of the form thisAnchor = otherAnchor. - @discardableResult - @objc public func constraint(equalTo anchor: NSLayoutAnchor, identifier: String) -> NSLayoutConstraint { - let constraint = self.constraint(equalTo: anchor) - constraint.identifier = identifier - return constraint - } - - @discardableResult - @objc public func constraint(greaterThanOrEqualTo anchor: NSLayoutAnchor, identifier: String) -> NSLayoutConstraint { - let constraint = self.constraint(greaterThanOrEqualTo: anchor) - constraint.identifier = identifier - return constraint - } - - @discardableResult - @objc public func constraint(lessThanOrEqualTo anchor: NSLayoutAnchor, identifier: String) -> NSLayoutConstraint { - let constraint = self.constraint(lessThanOrEqualTo: anchor) - constraint.identifier = identifier - return constraint - } - - - @discardableResult - @objc public func constraint(equalTo anchor: NSLayoutAnchor, constant: CGFloat, identifier: String) -> NSLayoutConstraint { - let constraint = self.constraint(equalTo: anchor, constant: constant) - constraint.identifier = identifier - return constraint - } - - @discardableResult - @objc public func constraint(greaterThanOrEqualTo anchor: NSLayoutAnchor, constant: CGFloat, identifier: String) -> NSLayoutConstraint { - let constraint = self.constraint(greaterThanOrEqualTo: anchor, constant: constant) - constraint.identifier = identifier - return constraint - } - - @discardableResult - @objc public func constraint(lessThanOrEqualTo anchor: NSLayoutAnchor, constant: CGFloat, identifier: String) -> NSLayoutConstraint { - let constraint = self.constraint(lessThanOrEqualTo: anchor, constant: constant) - constraint.identifier = identifier - return constraint - } -} - -//-------------------------------------------------- -// MARK: - NSLayoutDimension -//-------------------------------------------------- -extension NSLayoutDimension { - // These methods return an inactive constraint of the form thisVariable = constant. - @discardableResult - @objc public func constraint(equalToConstant c: CGFloat, identifier: String) -> NSLayoutConstraint { - let lc = constraint(equalToConstant: c) - lc.identifier = identifier - return lc - } - - @discardableResult - @objc public func constraint(greaterThanOrEqualToConstant c: CGFloat, identifier: String) -> NSLayoutConstraint { - let lc = constraint(greaterThanOrEqualToConstant: c) - lc.identifier = identifier - return lc - } - - @discardableResult - @objc public func constraint(lessThanOrEqualToConstant c: CGFloat, identifier: String) -> NSLayoutConstraint { - let lc = constraint(lessThanOrEqualToConstant: c) - lc.identifier = identifier - return lc - } - - - // These methods return an inactive constraint of the form thisAnchor = otherAnchor * multiplier. - @discardableResult - @objc public func constraint(equalTo anchor: NSLayoutDimension, multiplier m: CGFloat, identifier: String) -> NSLayoutConstraint { - let lc = constraint(equalTo: anchor, multiplier: m) - lc.identifier = identifier - return lc - } - - @discardableResult - @objc public func constraint(greaterThanOrEqualTo anchor: NSLayoutDimension, multiplier m: CGFloat, identifier: String) -> NSLayoutConstraint { - let lc = constraint(greaterThanOrEqualTo: anchor ,multiplier: m) - lc.identifier = identifier - return lc - } - - @discardableResult - @objc public func constraint(lessThanOrEqualTo anchor: NSLayoutDimension, multiplier m: CGFloat, identifier: String) -> NSLayoutConstraint { - let lc = constraint(lessThanOrEqualTo: anchor, multiplier: m) - lc.identifier = identifier - return lc - } - - - // These methods return an inactive constraint of the form thisAnchor = otherAnchor * multiplier + constant. - @discardableResult - @objc public func constraint(equalTo anchor: NSLayoutDimension, multiplier m: CGFloat, constant c: CGFloat, identifier: String) -> NSLayoutConstraint { - let lc = constraint(equalTo: anchor, multiplier: m, constant: c) - lc.identifier = identifier - return lc - } - - @discardableResult - @objc public func constraint(greaterThanOrEqualTo anchor: NSLayoutDimension, multiplier m: CGFloat, constant c: CGFloat, identifier: String) -> NSLayoutConstraint { - let lc = constraint(greaterThanOrEqualTo: anchor, multiplier: m, constant: c) - lc.identifier = identifier - return lc - } - - @discardableResult - @objc public func constraint(lessThanOrEqualTo anchor: NSLayoutDimension, multiplier m: CGFloat, constant c: CGFloat, identifier: String) -> NSLayoutConstraint { - let lc = constraint(lessThanOrEqualTo: anchor, multiplier: m, constant: c) - lc.identifier = identifier - return lc - } - -} From c8e9ab75c2a63bfcb504b8a293ecc74fc653e4e9 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 15 Jun 2023 12:42:36 -0500 Subject: [PATCH 05/12] refactored even more Signed-off-by: Matt Bruce --- VDS/Extensions/UIView.swift | 397 ++++++++++++++++-------------------- 1 file changed, 172 insertions(+), 225 deletions(-) diff --git a/VDS/Extensions/UIView.swift b/VDS/Extensions/UIView.swift index 1196e5e6..f53336a2 100644 --- a/VDS/Extensions/UIView.swift +++ b/VDS/Extensions/UIView.swift @@ -10,101 +10,31 @@ import UIKit import VDSFormControlsTokens extension UIView { - public enum ConstraintIdentifier: CustomStringConvertible { - case leading, trailing, top, bottom, height, width - case custom(String) - - public var description: String { - switch self { - case .leading: return "leading" - case .trailing: return "trailing" - case .top: return "top" - case .bottom: return "bottom" - case .height: return "height" - case .width: return "width" - case .custom(let identifier): return identifier - } - } - } - - public enum ConstraintType { - case equal, lessThanOrEqual, greaterThanOrEqual - } - - public var _topConstraint: NSLayoutConstraint? { constraint(with: .top)} - public var _leadingConstraint: NSLayoutConstraint? { constraint(with: .leading)} - public var _trailingConstraint: NSLayoutConstraint? { constraint(with: .trailing)} - public var _bottomConstraint: NSLayoutConstraint? { constraint(with: .bottom)} - public var _widthConstraint: NSLayoutConstraint? { constraint(with: .width)} - public var _heightConstraint: NSLayoutConstraint? { constraint(with: .height)} - - public func constraint(with identifier: ConstraintIdentifier) -> NSLayoutConstraint? { - return constraint(with: identifier.description) - } public func constraint(with identifier: String) -> NSLayoutConstraint? { return constraints.first { $0.identifier == identifier } } - - public func removeConstraint(edges: [UIRectEdge]) { - let topConstraint: NSLayoutConstraint? = constraint(with: .top) - let leadingConstraint: NSLayoutConstraint? = constraint(with: .leading) - let trailingConstraint: NSLayoutConstraint? = constraint(with: .trailing) - let bottomConstraint: NSLayoutConstraint? = constraint(with: .bottom) - - edges.forEach { edge in - switch edge { - case .all: - if let leadingConstraint { - removeConstraint(leadingConstraint) - } - if let trailingConstraint { - removeConstraint(trailingConstraint) - } - if let topConstraint { - removeConstraint(topConstraint) - } - if let bottomConstraint { - removeConstraint(bottomConstraint) - } - case .left: - if let leadingConstraint { - removeConstraint(leadingConstraint) - } - case .right: - if let trailingConstraint { - removeConstraint(trailingConstraint) - } - case .top: - if let topConstraint { - removeConstraint(topConstraint) - } - case .bottom: - if let bottomConstraint { - removeConstraint(bottomConstraint) - } - default: - break - } - } - } } //-------------------------------------------------- // MARK: - Pinning //-------------------------------------------------- extension UIView { - public func pin(_ view: UIView, with edges: UIEdgeInsets = UIEdgeInsets.zero) { - leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: edges.left, identifier: ConstraintIdentifier.leading.description).isActive = true - trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -edges.right, identifier: ConstraintIdentifier.trailing.description).isActive = true - topAnchor.constraint(equalTo: view.topAnchor, constant: edges.top, identifier: ConstraintIdentifier.top.description).isActive = true - bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -edges.bottom, identifier: ConstraintIdentifier.bottom.description).isActive = true + @discardableResult + public func pin(_ view: UIView, with edges: UIEdgeInsets = UIEdgeInsets.zero) -> Self { + pinLeading(view.leadingAnchor, edges.left) + pinTrailing(view.trailingAnchor, edges.right) + pinTop(view.topAnchor, edges.top) + pinBottom(view.bottomAnchor, edges.bottom) + return self } - public func pinToSuperView(_ edges: UIEdgeInsets = UIEdgeInsets.zero) { + @discardableResult + public func pinToSuperView(_ edges: UIEdgeInsets = UIEdgeInsets.zero) -> Self { if let superview { pin(superview, with: edges) } + return self } } @@ -114,38 +44,38 @@ extension UIView { extension UIView { @discardableResult - public func height(_ constant: CGFloat, type: ConstraintType = .equal) -> Self { - switch type { - case .equal: - height(constant) - - case .lessThanOrEqual: - heightLessThanEqualTo(constant) - - case .greaterThanOrEqual: - heightGreaterThanEqualTo(constant) - } + public func height(_ constant: CGFloat) -> Self { + height(constant: constant) return self } - @discardableResult - public func height(_ constant: CGFloat) -> Self { - heightAnchor.constraint(equalToConstant: constant, identifier: ConstraintIdentifier.height.description).isActive = true - return self - } - @discardableResult public func heightGreaterThanEqualTo(_ constant: CGFloat) -> Self { - heightAnchor.constraint(greaterThanOrEqualToConstant: constant, identifier: ConstraintIdentifier.height.description).isActive = true + heightGreaterThanEqualTo(constant: constant) return self } @discardableResult public func heightLessThanEqualTo(_ constant: CGFloat) -> Self { - heightAnchor.constraint(lessThanOrEqualToConstant: constant, identifier: ConstraintIdentifier.height.description).isActive = true + heightLessThanEqualTo(constant: constant) return self } + @discardableResult + public func height(constant: CGFloat) -> NSLayoutConstraint { + heightAnchor.constraint(equalToConstant: constant).activate() + } + + @discardableResult + public func heightGreaterThanEqualTo(constant: CGFloat) -> NSLayoutConstraint { + heightAnchor.constraint(greaterThanOrEqualToConstant: constant).activate() + } + + @discardableResult + public func heightLessThanEqualTo(constant: CGFloat) -> NSLayoutConstraint { + heightAnchor.constraint(lessThanOrEqualToConstant: constant).activate() + } + } //-------------------------------------------------- @@ -153,38 +83,38 @@ extension UIView { //-------------------------------------------------- extension UIView { - @discardableResult - public func width(_ constant: CGFloat, type: ConstraintType = .equal) -> Self { - switch type { - case .equal: - width(constant) - - case .lessThanOrEqual: - widthLessThanEqualTo(constant) - - case .greaterThanOrEqual: - widthGreaterThanEqualTo(constant) - } - return self - } - @discardableResult public func width(_ constant: CGFloat) -> Self { - widthAnchor.constraint(equalToConstant: constant, identifier: ConstraintIdentifier.width.description).isActive = true + width(constant: constant) return self } @discardableResult public func widthGreaterThanEqualTo(_ constant: CGFloat) -> Self { - widthAnchor.constraint(greaterThanOrEqualToConstant: constant, identifier: ConstraintIdentifier.width.description).isActive = true + widthGreaterThanEqualTo(constant: constant) return self } @discardableResult public func widthLessThanEqualTo(_ constant: CGFloat) -> Self { - widthAnchor.constraint(lessThanOrEqualToConstant: constant, identifier: ConstraintIdentifier.width.description).isActive = true + widthLessThanEqualTo(constant: constant) return self } + + @discardableResult + public func width(constant: CGFloat) -> NSLayoutConstraint { + widthAnchor.constraint(equalToConstant: constant).activate() + } + + @discardableResult + public func widthGreaterThanEqualTo(constant: CGFloat) -> NSLayoutConstraint { + widthAnchor.constraint(greaterThanOrEqualToConstant: constant).activate() + } + + @discardableResult + public func widthLessThanEqualTo(constant: CGFloat) -> NSLayoutConstraint { + widthAnchor.constraint(lessThanOrEqualToConstant: constant).activate() + } } //-------------------------------------------------- @@ -192,21 +122,6 @@ extension UIView { //-------------------------------------------------- extension UIView { - @discardableResult - public func pinTop(_ anchor: NSLayoutYAxisAnchor? = nil, _ constant: CGFloat = 0.0, _ type: ConstraintType = .equal) -> Self { - switch type { - case .equal: - pinTop(anchor, constant) - - case .lessThanOrEqual: - pinTopLessThanOrEqualTo(anchor, constant) - - case .greaterThanOrEqual: - pinTopGreaterThanOrEqualTo(anchor, constant) - } - return self - } - @discardableResult public func pinTop(_ constant: CGFloat = 0.0) -> Self { return pinTop(nil, constant) @@ -214,51 +129,49 @@ extension UIView { @discardableResult public func pinTop(_ anchor: NSLayoutYAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self { - let found: NSLayoutYAxisAnchor? = anchor ?? superview?.topAnchor - if let found { - topAnchor.constraint(equalTo: found, constant: constant, identifier: ConstraintIdentifier.top.description).isActive = true - } + pinTop(anchor: anchor, constant: constant) return self } @discardableResult public func pinTopLessThanOrEqualTo(_ anchor: NSLayoutYAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self { - let found: NSLayoutYAxisAnchor? = anchor ?? superview?.topAnchor - if let found { - topAnchor.constraint(lessThanOrEqualTo: found, constant: constant, identifier: ConstraintIdentifier.top.description).isActive = true - } + pinBottomLessThanOrEqualTo(anchor: anchor, constant: constant) return self } @discardableResult public func pinTopGreaterThanOrEqualTo(_ anchor: NSLayoutYAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self { - let found: NSLayoutYAxisAnchor? = anchor ?? superview?.topAnchor - if let found { - topAnchor.constraint(greaterThanOrEqualTo: found, constant: constant, identifier: ConstraintIdentifier.top.description).isActive = true - } + pinTopGreaterThanOrEqualTo(anchor: anchor, constant: constant) return self } + + @discardableResult + public func pinTop(anchor: NSLayoutYAxisAnchor?, constant: CGFloat) -> NSLayoutConstraint? { + let found: NSLayoutYAxisAnchor? = anchor ?? superview?.topAnchor + guard let found else { return nil } + return topAnchor.constraint(equalTo: found, constant: constant).activate() + } + + @discardableResult + public func pinTopLessThanOrEqualTo(anchor: NSLayoutYAxisAnchor?, constant: CGFloat) -> NSLayoutConstraint? { + let found: NSLayoutYAxisAnchor? = anchor ?? superview?.topAnchor + guard let found else { return nil } + return topAnchor.constraint(lessThanOrEqualTo: found, constant: constant).activate() + } + + @discardableResult + public func pinTopGreaterThanOrEqualTo(anchor: NSLayoutYAxisAnchor?, constant: CGFloat) -> NSLayoutConstraint? { + let found: NSLayoutYAxisAnchor? = anchor ?? superview?.topAnchor + guard let found else { return nil } + return topAnchor.constraint(greaterThanOrEqualTo: found, constant: constant).activate() + } + } //-------------------------------------------------- // MARK: - BottomAnchor //-------------------------------------------------- extension UIView { - @discardableResult - public func pinBottom(_ anchor: NSLayoutYAxisAnchor? = nil, _ constant: CGFloat = 0.0, _ type: ConstraintType = .equal) -> Self { - switch type { - case .equal: - pinBottom(anchor, constant) - - case .lessThanOrEqual: - pinBottomLessThanOrEqualTo(anchor, constant) - - case .greaterThanOrEqual: - pinBottomGreaterThanOrEqualTo(anchor, constant) - } - return self - } - @discardableResult public func pinBottom(_ constant: CGFloat = 0.0) -> Self { return pinBottom(nil, constant) @@ -266,50 +179,48 @@ extension UIView { @discardableResult public func pinBottom(_ anchor: NSLayoutYAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self { - let found: NSLayoutYAxisAnchor? = anchor ?? superview?.bottomAnchor - if let found { - bottomAnchor.constraint(equalTo: found, constant: -constant, identifier: ConstraintIdentifier.bottom.description).isActive = true - } + pinBottom(anchor: anchor, constant: constant) return self } @discardableResult public func pinBottomLessThanOrEqualTo(_ anchor: NSLayoutYAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self { - let found: NSLayoutYAxisAnchor? = anchor ?? superview?.bottomAnchor - if let found { - bottomAnchor.constraint(lessThanOrEqualTo: found, constant: -constant, identifier: ConstraintIdentifier.bottom.description).isActive = true - } + pinBottomLessThanOrEqualTo(anchor: anchor, constant: constant) return self } @discardableResult public func pinBottomGreaterThanOrEqualTo(_ anchor: NSLayoutYAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self { - let found: NSLayoutYAxisAnchor? = anchor ?? superview?.bottomAnchor - if let found { - bottomAnchor.constraint(greaterThanOrEqualTo: found, constant: -constant, identifier: ConstraintIdentifier.bottom.description).isActive = true - } + pinBottomGreaterThanOrEqualTo(anchor: anchor, constant: constant) return self } + + @discardableResult + public func pinBottom(anchor: NSLayoutYAxisAnchor?, constant: CGFloat) -> NSLayoutConstraint? { + let found: NSLayoutYAxisAnchor? = anchor ?? superview?.bottomAnchor + guard let found else { return nil } + return bottomAnchor.constraint(equalTo: found, constant: -constant).activate() + } + + @discardableResult + public func pinBottomLessThanOrEqualTo(anchor: NSLayoutYAxisAnchor?, constant: CGFloat) -> NSLayoutConstraint? { + let found: NSLayoutYAxisAnchor? = anchor ?? superview?.bottomAnchor + guard let found else { return nil } + return bottomAnchor.constraint(lessThanOrEqualTo: found, constant: -constant).activate() + } + + @discardableResult + public func pinBottomGreaterThanOrEqualTo(anchor: NSLayoutYAxisAnchor?, constant: CGFloat) -> NSLayoutConstraint? { + let found: NSLayoutYAxisAnchor? = anchor ?? superview?.bottomAnchor + guard let found else { return nil } + return bottomAnchor.constraint(greaterThanOrEqualTo: found, constant: -constant).activate() + } } //-------------------------------------------------- // MARK: - LeadingAnchor //-------------------------------------------------- extension UIView { - @discardableResult - public func pinLeading(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0, _ type: ConstraintType = .equal) -> Self { - switch type { - case .equal: - pinLeading(anchor, constant) - - case .lessThanOrEqual: - pinLeadingLessThanOrEqualTo(anchor, constant) - - case .greaterThanOrEqual: - pinLeadingGreaterThanOrEqualTo(anchor, constant) - } - return self - } @discardableResult public func pinLeading(_ constant: CGFloat = 0.0) -> Self { @@ -318,30 +229,42 @@ extension UIView { @discardableResult public func pinLeading(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self { - let found: NSLayoutXAxisAnchor? = anchor ?? superview?.leadingAnchor - if let found { - leadingAnchor.constraint(equalTo: found, constant: constant, identifier: ConstraintIdentifier.leading.description).isActive = true - } + pinLeading(anchor: anchor, constant: constant) return self } @discardableResult public func pinLeadingLessThanOrEqualTo(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self { - let found: NSLayoutXAxisAnchor? = anchor ?? superview?.leadingAnchor - if let found { - leadingAnchor.constraint(lessThanOrEqualTo: found, constant: constant, identifier: ConstraintIdentifier.leading.description).isActive = true - } + pinLeadingLessThanOrEqualTo(anchor: anchor, constant: constant) return self } @discardableResult public func pinLeadingGreaterThanOrEqualTo(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self { - let found: NSLayoutXAxisAnchor? = anchor ?? superview?.leadingAnchor - if let found { - leadingAnchor.constraint(greaterThanOrEqualTo: found, constant: constant, identifier: ConstraintIdentifier.leading.description).isActive = true - } + pinLeadingGreaterThanOrEqualTo(anchor: anchor, constant: constant) return self } + + @discardableResult + public func pinLeading(anchor: NSLayoutXAxisAnchor?, constant: CGFloat) -> NSLayoutConstraint? { + let found: NSLayoutXAxisAnchor? = anchor ?? superview?.leadingAnchor + guard let found else { return nil } + return leadingAnchor.constraint(equalTo: found, constant: constant).activate() + } + + @discardableResult + public func pinLeadingLessThanOrEqualTo(anchor: NSLayoutXAxisAnchor?, constant: CGFloat) -> NSLayoutConstraint? { + let found: NSLayoutXAxisAnchor? = anchor ?? superview?.leadingAnchor + guard let found else { return nil } + return leadingAnchor.constraint(lessThanOrEqualTo: found, constant: constant).activate() + } + + @discardableResult + public func pinLeadingGreaterThanOrEqualTo(anchor: NSLayoutXAxisAnchor?, constant: CGFloat) -> NSLayoutConstraint? { + let found: NSLayoutXAxisAnchor? = anchor ?? superview?.leadingAnchor + guard let found else { return nil } + return leadingAnchor.constraint(greaterThanOrEqualTo: found, constant: constant).activate() + } } //-------------------------------------------------- @@ -349,50 +272,74 @@ extension UIView { //-------------------------------------------------- extension UIView { - @discardableResult - public func pinTrailing(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0, _ type: ConstraintType = .equal) -> Self { - switch type { - case .equal: - pinTrailing(anchor, constant) - - case .lessThanOrEqual: - pinTrailingLessThanOrEqualTo(anchor, constant) - - case .greaterThanOrEqual: - pinLeadingGreaterThanOrEqualTo(anchor, constant) - } - return self - } - @discardableResult public func pinTrailing(_ constant: CGFloat = 0.0) -> Self { - return pinTrailing(nil, constant) + pinTrailing(nil, constant) } @discardableResult public func pinTrailing(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self { - let found: NSLayoutXAxisAnchor? = anchor ?? superview?.trailingAnchor - if let found { - trailingAnchor.constraint(equalTo: found, constant: -constant, identifier: ConstraintIdentifier.trailing.description).isActive = true - } + pinTrailing(anchor: anchor, constant: constant) return self } @discardableResult public func pinTrailingLessThanOrEqualTo(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self { - let found: NSLayoutXAxisAnchor? = anchor ?? superview?.trailingAnchor - if let found { - trailingAnchor.constraint(lessThanOrEqualTo: found, constant: -constant, identifier: ConstraintIdentifier.trailing.description).isActive = true - } + pinTrailingLessThanOrEqualTo(anchor: anchor, constant: constant) return self } @discardableResult public func pinTrailingGreaterThanOrEqualTo(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self { - let found: NSLayoutXAxisAnchor? = anchor ?? superview?.trailingAnchor - if let found { - trailingAnchor.constraint(greaterThanOrEqualTo: found, constant: -constant, identifier: ConstraintIdentifier.trailing.description).isActive = true - } + pinTrailingGreaterThanOrEqualTo(anchor: anchor, constant: constant) return self } + + @discardableResult + public func pinTrailing(anchor: NSLayoutXAxisAnchor?, constant: CGFloat) -> NSLayoutConstraint? { + let found: NSLayoutXAxisAnchor? = anchor ?? superview?.trailingAnchor + guard let found else { return nil } + return trailingAnchor.constraint(equalTo: found, constant: -constant).activate() + } + + @discardableResult + public func pinTrailingLessThanOrEqualTo(anchor: NSLayoutXAxisAnchor?, constant: CGFloat) -> NSLayoutConstraint? { + let found: NSLayoutXAxisAnchor? = anchor ?? superview?.trailingAnchor + guard let found else { return nil } + return trailingAnchor.constraint(lessThanOrEqualTo: found, constant: -constant).activate() + } + + @discardableResult + public func pinTrailingGreaterThanOrEqualTo(anchor: NSLayoutXAxisAnchor?, constant: CGFloat) -> NSLayoutConstraint? { + let found: NSLayoutXAxisAnchor? = anchor ?? superview?.trailingAnchor + guard let found else { return nil } + return trailingAnchor.constraint(greaterThanOrEqualTo: found, constant: -constant).activate() + } +} + +extension NSLayoutConstraint { + + @discardableResult + public func activate() -> Self{ + isActive = true + return self + } + + @discardableResult + public func deactivate() -> Self{ + isActive = false + return self + } + + public class Container { + public var topConstraint: NSLayoutConstraint? + public var leadingConstraint: NSLayoutConstraint? + public var trailingConstraint: NSLayoutConstraint? + public var bottomConstraint: NSLayoutConstraint? + public var widthConstraint: NSLayoutConstraint? + public var heightConstraint: NSLayoutConstraint? + + public init(){} + } + } From 52fac7ce930f4ed26ddc3b3749ba76528617a796 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 15 Jun 2023 12:48:18 -0500 Subject: [PATCH 06/12] added back default Signed-off-by: Matt Bruce --- VDS/Extensions/UIView.swift | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/VDS/Extensions/UIView.swift b/VDS/Extensions/UIView.swift index f53336a2..517ef104 100644 --- a/VDS/Extensions/UIView.swift +++ b/VDS/Extensions/UIView.swift @@ -146,21 +146,21 @@ extension UIView { } @discardableResult - public func pinTop(anchor: NSLayoutYAxisAnchor?, constant: CGFloat) -> NSLayoutConstraint? { + public func pinTop(anchor: NSLayoutYAxisAnchor?, constant: CGFloat = 0.0) -> NSLayoutConstraint? { let found: NSLayoutYAxisAnchor? = anchor ?? superview?.topAnchor guard let found else { return nil } return topAnchor.constraint(equalTo: found, constant: constant).activate() } @discardableResult - public func pinTopLessThanOrEqualTo(anchor: NSLayoutYAxisAnchor?, constant: CGFloat) -> NSLayoutConstraint? { + public func pinTopLessThanOrEqualTo(anchor: NSLayoutYAxisAnchor?, constant: CGFloat = 0.0) -> NSLayoutConstraint? { let found: NSLayoutYAxisAnchor? = anchor ?? superview?.topAnchor guard let found else { return nil } return topAnchor.constraint(lessThanOrEqualTo: found, constant: constant).activate() } @discardableResult - public func pinTopGreaterThanOrEqualTo(anchor: NSLayoutYAxisAnchor?, constant: CGFloat) -> NSLayoutConstraint? { + public func pinTopGreaterThanOrEqualTo(anchor: NSLayoutYAxisAnchor?, constant: CGFloat = 0.0) -> NSLayoutConstraint? { let found: NSLayoutYAxisAnchor? = anchor ?? superview?.topAnchor guard let found else { return nil } return topAnchor.constraint(greaterThanOrEqualTo: found, constant: constant).activate() @@ -196,21 +196,21 @@ extension UIView { } @discardableResult - public func pinBottom(anchor: NSLayoutYAxisAnchor?, constant: CGFloat) -> NSLayoutConstraint? { + public func pinBottom(anchor: NSLayoutYAxisAnchor?, constant: CGFloat = 0.0) -> NSLayoutConstraint? { let found: NSLayoutYAxisAnchor? = anchor ?? superview?.bottomAnchor guard let found else { return nil } return bottomAnchor.constraint(equalTo: found, constant: -constant).activate() } @discardableResult - public func pinBottomLessThanOrEqualTo(anchor: NSLayoutYAxisAnchor?, constant: CGFloat) -> NSLayoutConstraint? { + public func pinBottomLessThanOrEqualTo(anchor: NSLayoutYAxisAnchor?, constant: CGFloat = 0.0) -> NSLayoutConstraint? { let found: NSLayoutYAxisAnchor? = anchor ?? superview?.bottomAnchor guard let found else { return nil } return bottomAnchor.constraint(lessThanOrEqualTo: found, constant: -constant).activate() } @discardableResult - public func pinBottomGreaterThanOrEqualTo(anchor: NSLayoutYAxisAnchor?, constant: CGFloat) -> NSLayoutConstraint? { + public func pinBottomGreaterThanOrEqualTo(anchor: NSLayoutYAxisAnchor?, constant: CGFloat = 0.0) -> NSLayoutConstraint? { let found: NSLayoutYAxisAnchor? = anchor ?? superview?.bottomAnchor guard let found else { return nil } return bottomAnchor.constraint(greaterThanOrEqualTo: found, constant: -constant).activate() @@ -246,21 +246,21 @@ extension UIView { } @discardableResult - public func pinLeading(anchor: NSLayoutXAxisAnchor?, constant: CGFloat) -> NSLayoutConstraint? { + public func pinLeading(anchor: NSLayoutXAxisAnchor?, constant: CGFloat = 0.0) -> NSLayoutConstraint? { let found: NSLayoutXAxisAnchor? = anchor ?? superview?.leadingAnchor guard let found else { return nil } return leadingAnchor.constraint(equalTo: found, constant: constant).activate() } @discardableResult - public func pinLeadingLessThanOrEqualTo(anchor: NSLayoutXAxisAnchor?, constant: CGFloat) -> NSLayoutConstraint? { + public func pinLeadingLessThanOrEqualTo(anchor: NSLayoutXAxisAnchor?, constant: CGFloat = 0.0) -> NSLayoutConstraint? { let found: NSLayoutXAxisAnchor? = anchor ?? superview?.leadingAnchor guard let found else { return nil } return leadingAnchor.constraint(lessThanOrEqualTo: found, constant: constant).activate() } @discardableResult - public func pinLeadingGreaterThanOrEqualTo(anchor: NSLayoutXAxisAnchor?, constant: CGFloat) -> NSLayoutConstraint? { + public func pinLeadingGreaterThanOrEqualTo(anchor: NSLayoutXAxisAnchor?, constant: CGFloat = 0.0) -> NSLayoutConstraint? { let found: NSLayoutXAxisAnchor? = anchor ?? superview?.leadingAnchor guard let found else { return nil } return leadingAnchor.constraint(greaterThanOrEqualTo: found, constant: constant).activate() @@ -296,21 +296,21 @@ extension UIView { } @discardableResult - public func pinTrailing(anchor: NSLayoutXAxisAnchor?, constant: CGFloat) -> NSLayoutConstraint? { + public func pinTrailing(anchor: NSLayoutXAxisAnchor?, constant: CGFloat = 0.0) -> NSLayoutConstraint? { let found: NSLayoutXAxisAnchor? = anchor ?? superview?.trailingAnchor guard let found else { return nil } return trailingAnchor.constraint(equalTo: found, constant: -constant).activate() } @discardableResult - public func pinTrailingLessThanOrEqualTo(anchor: NSLayoutXAxisAnchor?, constant: CGFloat) -> NSLayoutConstraint? { + public func pinTrailingLessThanOrEqualTo(anchor: NSLayoutXAxisAnchor?, constant: CGFloat = 0.0) -> NSLayoutConstraint? { let found: NSLayoutXAxisAnchor? = anchor ?? superview?.trailingAnchor guard let found else { return nil } return trailingAnchor.constraint(lessThanOrEqualTo: found, constant: -constant).activate() } @discardableResult - public func pinTrailingGreaterThanOrEqualTo(anchor: NSLayoutXAxisAnchor?, constant: CGFloat) -> NSLayoutConstraint? { + public func pinTrailingGreaterThanOrEqualTo(anchor: NSLayoutXAxisAnchor?, constant: CGFloat = 0.0) -> NSLayoutConstraint? { let found: NSLayoutXAxisAnchor? = anchor ?? superview?.trailingAnchor guard let found else { return nil } return trailingAnchor.constraint(greaterThanOrEqualTo: found, constant: -constant).activate() From 00edeac169f8d5f97cc7896b7a1c5dcf34e68d2e Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 15 Jun 2023 13:21:09 -0500 Subject: [PATCH 07/12] initial component just copied badge for ease Signed-off-by: Matt Bruce --- VDS.xcodeproj/project.pbxproj | 12 ++ .../BadgeIndicator/BadgeIndicator.swift | 144 ++++++++++++++++++ 2 files changed, 156 insertions(+) create mode 100644 VDS/Components/BadgeIndicator/BadgeIndicator.swift diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index d5893104..1f086e68 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -109,6 +109,7 @@ EAD062A72A3B67770015965D /* UIView+CALayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD062A62A3B67770015965D /* UIView+CALayer.swift */; }; EAD062A92A3B67B10015965D /* NSLayoutAnchor.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD062A82A3B67B10015965D /* NSLayoutAnchor.swift */; }; EAD062AB2A3B67D00015965D /* NSLayoutDimension.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD062AA2A3B67D00015965D /* NSLayoutDimension.swift */; }; + EAD062B02A3B873E0015965D /* BadgeIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD062AF2A3B873E0015965D /* BadgeIndicator.swift */; }; EAD8D2C128BFDE8B006EB6A6 /* UIGestureRecognizer+Publisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD8D2C028BFDE8B006EB6A6 /* UIGestureRecognizer+Publisher.swift */; }; EAF1FE9929D4850E00101452 /* Clickable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF1FE9829D4850E00101452 /* Clickable.swift */; }; EAF1FE9B29DB1A6000101452 /* Changeable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF1FE9A29DB1A6000101452 /* Changeable.swift */; }; @@ -243,6 +244,7 @@ EAD062A62A3B67770015965D /* UIView+CALayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+CALayer.swift"; sourceTree = ""; }; EAD062A82A3B67B10015965D /* NSLayoutAnchor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSLayoutAnchor.swift; sourceTree = ""; }; EAD062AA2A3B67D00015965D /* NSLayoutDimension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSLayoutDimension.swift; sourceTree = ""; }; + EAD062AF2A3B873E0015965D /* BadgeIndicator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BadgeIndicator.swift; sourceTree = ""; }; EAD8D2C028BFDE8B006EB6A6 /* UIGestureRecognizer+Publisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIGestureRecognizer+Publisher.swift"; sourceTree = ""; }; EAF1FE9829D4850E00101452 /* Clickable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Clickable.swift; sourceTree = ""; }; EAF1FE9A29DB1A6000101452 /* Changeable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Changeable.swift; sourceTree = ""; }; @@ -400,6 +402,7 @@ EA33619D288B1E330071C351 /* Components */ = { isa = PBXGroup; children = ( + EAD062AE2A3B87210015965D /* BadgeIndicator */, EA4DB2FE28DCBC1900103EE3 /* Badge */, EA0FC2BE2912D18200DF80B4 /* Buttons */, EAF7F092289985E200B287F5 /* Checkbox */, @@ -695,6 +698,14 @@ path = EntryField; sourceTree = ""; }; + EAD062AE2A3B87210015965D /* BadgeIndicator */ = { + isa = PBXGroup; + children = ( + EAD062AF2A3B873E0015965D /* BadgeIndicator.swift */, + ); + path = BadgeIndicator; + sourceTree = ""; + }; EAF7F092289985E200B287F5 /* Checkbox */ = { isa = PBXGroup; children = ( @@ -927,6 +938,7 @@ EA336171288B19200071C351 /* VDS.docc in Sources */, EA985BF02968A93600F2FF2E /* TitleLockupEyebrowModel.swift in Sources */, EA5E30532950DDA60082B959 /* TitleLockup.swift in Sources */, + EAD062B02A3B873E0015965D /* BadgeIndicator.swift in Sources */, EAA5EEB528ECBFB4003B3210 /* ImageLabelAttribute.swift in Sources */, EAB5FF0129424ACB00998C17 /* UIControl.swift in Sources */, EA985BF5296C60C000F2FF2E /* Icon.swift in Sources */, diff --git a/VDS/Components/BadgeIndicator/BadgeIndicator.swift b/VDS/Components/BadgeIndicator/BadgeIndicator.swift new file mode 100644 index 00000000..68af0d22 --- /dev/null +++ b/VDS/Components/BadgeIndicator/BadgeIndicator.swift @@ -0,0 +1,144 @@ +// +// Badge.swift +// VDS +// +// Created by Matt Bruce on 9/22/22. +// + +import Foundation +import UIKit +import VDSColorTokens +import VDSFormControlsTokens +import Combine + +/// Badges are visual labels used to convey status or highlight supplemental information. +@objc(VDSBadgeIndicator) +open class BadgeIndicator: View { + //-------------------------------------------------- + // MARK: - Enums + //-------------------------------------------------- + public enum FillColor: String, CaseIterable { + case red, yellow, green, orange, blue, gray, grayLowContrast, black, white + } + + //-------------------------------------------------- + // MARK: - Public Properties + //-------------------------------------------------- + open var label = Label().with { + $0.setContentCompressionResistancePriority(.required, for: .vertical) + $0.adjustsFontSizeToFitWidth = false + $0.lineBreakMode = .byTruncatingTail + $0.textPosition = .left + $0.textStyle = .boldBodySmall + } + + open var fillColor: FillColor = .red { didSet { setNeedsUpdate() }} + + open var text: String = "" { didSet { setNeedsUpdate() }} + + open var maxWidth: CGFloat? { didSet { setNeedsUpdate() }} + + open var numberOfLines: Int = 1 { didSet { setNeedsUpdate() }} + + //-------------------------------------------------- + // MARK: - Constraints + //-------------------------------------------------- + private var maxWidthConstraint: NSLayoutConstraint? + private var minWidthConstraint: NSLayoutConstraint? + + //-------------------------------------------------- + // MARK: - Lifecycle + //-------------------------------------------------- + + open override func setup() { + super.setup() + + accessibilityElements = [label] + layer.cornerRadius = 2 + + addSubview(label) + label.pinToSuperView(.init(top: 2, + left: VDSLayout.Spacing.space1X.value, + bottom: 2, + right: VDSLayout.Spacing.space1X.value)) + + maxWidthConstraint = label.widthAnchor.constraint(lessThanOrEqualToConstant: 100) + minWidthConstraint = label.widthAnchor.constraint(greaterThanOrEqualToConstant: 23) + minWidthConstraint?.isActive = true + + } + + open override func reset() { + super.reset() + shouldUpdateView = false + label.reset() + label.lineBreakMode = .byTruncatingTail + label.textPosition = .left + label.textStyle = .boldBodySmall + fillColor = .red + text = "" + maxWidth = nil + numberOfLines = 1 + shouldUpdateView = true + setNeedsUpdate() + } + + //-------------------------------------------------- + // MARK: - Configuration + //-------------------------------------------------- + private var backgroundColorConfiguration: AnyColorable = { + let config = KeyedColorConfiguration(keyPath: \.fillColor) + config.setSurfaceColors(VDSColor.backgroundBrandhighlight, VDSColor.backgroundBrandhighlight, forKey: .red) + config.setSurfaceColors(VDSColor.paletteYellow53, VDSColor.paletteYellow53, forKey: .yellow) + config.setSurfaceColors(VDSColor.paletteGreen26, VDSColor.paletteGreen36, forKey: .green) + config.setSurfaceColors(VDSColor.paletteOrange41, VDSColor.paletteOrange58, forKey: .orange) + config.setSurfaceColors(VDSColor.paletteBlue38, VDSColor.paletteBlue46, forKey: .blue) + config.setSurfaceColors(VDSColor.backgroundPrimaryDark, VDSColor.backgroundPrimaryDark, forKey: .black) + config.setSurfaceColors(VDSColor.backgroundPrimaryLight, VDSColor.backgroundPrimaryLight, forKey: .white) + return config.eraseToAnyColorable() + }() + + private var textColorConfiguration = ViewColorConfiguration() + + public func updateTextColorConfig() { + textColorConfiguration.reset() + + switch fillColor { + + case .red, .black: + textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOndark, forDisabled: false) + textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOndark, forDisabled: true) + + case .yellow, .white: + textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOnlight, forDisabled: false) + textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOnlight, forDisabled: true) + + case .orange, .green, .blue: + textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOnlight, forDisabled: false) + textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOnlight, forDisabled: true) + } + } + + //-------------------------------------------------- + // MARK: - State + //-------------------------------------------------- + open override func updateView() { + updateTextColorConfig() + + backgroundColor = backgroundColorConfiguration.getColor(self) + + label.textColorConfiguration = textColorConfiguration.eraseToAnyColorable() + label.numberOfLines = numberOfLines + label.text = text + label.surface = surface + label.disabled = disabled + + if let maxWidth = maxWidth, let minWidth = minWidthConstraint?.constant, maxWidth > minWidth { + maxWidthConstraint?.constant = maxWidth + maxWidthConstraint?.isActive = true + } else { + maxWidthConstraint?.isActive = false + } + } +} + From bbdf496cda5bd10fe2d02ef996059acd8c908d8d Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 15 Jun 2023 18:50:30 -0500 Subject: [PATCH 08/12] added edgeInset Signed-off-by: Matt Bruce --- VDS/Components/Label/Label.swift | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/VDS/Components/Label/Label.swift b/VDS/Components/Label/Label.swift index c88ab853..c460530b 100644 --- a/VDS/Components/Label/Label.swift +++ b/VDS/Components/Label/Label.swift @@ -39,6 +39,14 @@ open class Label: UILabel, Handlerable, ViewProtocol, Resettable, UserInfoable { open var userInfo = [String: Primitive]() + open var edgeInset: UIEdgeInsets = .zero { + didSet { + setNeedsUpdate() + + } + + } + override open var text: String? { didSet { attributes = nil @@ -192,7 +200,16 @@ open class Label: UILabel, Handlerable, ViewProtocol, Resettable, UserInfoable { attributedString.addAttribute( .paragraphStyle, value: paragraph, range: entireRange) } } - + + open override func drawText(in rect: CGRect) { + super.drawText(in: rect.inset(by: edgeInset)) + } + + open override var intrinsicContentSize: CGSize { + let size = super.intrinsicContentSize + return CGSize(width: size.width + edgeInset.left + edgeInset.right, height: size.height + edgeInset.top + edgeInset.bottom) + } + //-------------------------------------------------- // MARK: - Actionable //-------------------------------------------------- From f8bffa7981657ca9d34ad02822d7b68404b6d0c6 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 15 Jun 2023 18:50:39 -0500 Subject: [PATCH 09/12] added color helper Signed-off-by: Matt Bruce --- VDS/Extensions/UIColor+VDSColor.swift | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/VDS/Extensions/UIColor+VDSColor.swift b/VDS/Extensions/UIColor+VDSColor.swift index ad05efc1..e06c4f50 100644 --- a/VDS/Extensions/UIColor+VDSColor.swift +++ b/VDS/Extensions/UIColor+VDSColor.swift @@ -119,4 +119,11 @@ extension UIColor { guard let _ = found else { return false} return true } + + public func toVDSColor() -> VDSColor? { + guard let hex = hexString else { return nil } + let found = VDSColor.allCases.first{ $0.uiColor.hexString == hex } + guard let found else { return nil} + return found + } } From e276087d217299f3167f65d4fabb125be4e9cf45 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 15 Jun 2023 18:51:09 -0500 Subject: [PATCH 10/12] updated typography to a struct instead of enum Signed-off-by: Matt Bruce --- .../TitleLockup/TitleLockupTextStyle.swift | 14 +- VDS/Typography/Typography.swift | 409 ++++++++++-------- 2 files changed, 242 insertions(+), 181 deletions(-) diff --git a/VDS/Components/TitleLockup/TitleLockupTextStyle.swift b/VDS/Components/TitleLockup/TitleLockupTextStyle.swift index e8dc0319..a09491ae 100644 --- a/VDS/Components/TitleLockup/TitleLockupTextStyle.swift +++ b/VDS/Components/TitleLockup/TitleLockupTextStyle.swift @@ -11,7 +11,7 @@ extension TitleLockup { //-------------------------------------------------- // MARK: - Enums //-------------------------------------------------- - public enum TitleTextStyle: String, EnumSubset { + public enum TitleTextStyle: String, CaseIterable { case featureMedium case boldFeatureMedium @@ -32,9 +32,14 @@ extension TitleLockup { case boldTitleSmall public var defaultValue: TextStyle {.boldFeatureXSmall } + + public var value: TextStyle { + TextStyle.textStyle(for: self.rawValue) ?? defaultValue + } + } - public enum OtherTextStyle: String, EnumSubset { + public enum OtherTextStyle: String, CaseIterable { case bodyLarge case boldBodyLarge case bodyMedium @@ -43,6 +48,9 @@ extension TitleLockup { case boldBodySmall public var defaultValue: TextStyle {.bodyLarge } + + public var value: TextStyle { + TextStyle.textStyle(for: self.rawValue) ?? defaultValue + } } - } diff --git a/VDS/Typography/Typography.swift b/VDS/Typography/Typography.swift index 0df38e84..8d815ad3 100644 --- a/VDS/Typography/Typography.swift +++ b/VDS/Typography/Typography.swift @@ -23,45 +23,230 @@ public enum TextPosition: String, CaseIterable { } } -public enum TextStyle: String, CaseIterable { +public struct TextStyle: Equatable { + public let rawValue: String + public let pointSize: CGFloat + public let lineHeight: CGFloat + public let letterSpacing: CGFloat + public let fontFace: Fonts - case featureXLarge - case boldFeatureXLarge - case featureLarge - case boldFeatureLarge - case featureMedium - case boldFeatureMedium - case featureSmall - case boldFeatureSmall - case featureXSmall - case boldFeatureXSmall - - case title2XLarge - case boldTitle2XLarge - case titleXLarge - case boldTitleXLarge - case titleLarge - case boldTitleLarge - case titleMedium - case boldTitleMedium - case titleSmall - case boldTitleSmall - - case bodyLarge - case boldBodyLarge - case bodyMedium - case boldBodyMedium - case bodySmall - case boldBodySmall - - case micro - case boldMicro - - public static var defaultStyle: TextStyle { - return .bodyLarge + public init(rawValue: String, fontFace: Fonts, pointSize: CGFloat, lineHeight: CGFloat, letterSpacing: CGFloat) { + self.rawValue = rawValue + self.fontFace = fontFace + self.pointSize = pointSize + self.lineHeight = lineHeight + self.letterSpacing = letterSpacing } } +//MARK: Definitions +extension TextStyle { + + // Static properties for different text styles + public static let featureXLarge = TextStyle(rawValue: "featureXLarge", + fontFace: .dsLight, + pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature144 : VDSTypography.fontSizeFeature96, + lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature136 : VDSTypography.lineHeightFeature88, + letterSpacing: 0.25) + + public static let boldFeatureXLarge = TextStyle(rawValue: "boldFeatureXLarge", + fontFace: .dsBold, + pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature144 : VDSTypography.fontSizeFeature96, + lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature136 : VDSTypography.lineHeightFeature88, + letterSpacing: 0.25) + + public static let featureLarge = TextStyle(rawValue: "featureLarge", + fontFace: .dsLight, + pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature128 : VDSTypography.fontSizeFeature80, + lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature120 : VDSTypography.lineHeightFeature76, + letterSpacing: 0.25) + + public static let boldFeatureLarge = TextStyle(rawValue: "boldFeatureLarge", + fontFace: .dsBold, + pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature128 : VDSTypography.fontSizeFeature80, + lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature120 : VDSTypography.lineHeightFeature76, + letterSpacing: 0.25) + + public static let featureMedium = TextStyle(rawValue: "featureMedium", + fontFace: .dsLight, + pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature96 : VDSTypography.fontSizeFeature64, + lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature88 : VDSTypography.lineHeightFeature64, + letterSpacing: 0.25) + + public static let boldFeatureMedium = TextStyle(rawValue: "boldFeatureMedium", + fontFace: .dsBold, + pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature96 : VDSTypography.fontSizeFeature64, + lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature88 : VDSTypography.lineHeightFeature64, + letterSpacing: 0.25) + + public static let featureSmall = TextStyle(rawValue: "featureSmall", + fontFace: .dsLight, + pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature80 : VDSTypography.fontSizeFeature48, + lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature76 : VDSTypography.lineHeightFeature48, + letterSpacing: 0.25) + + public static let boldFeatureSmall = TextStyle(rawValue: "boldFeatureSmall", + fontFace: .dsBold, + pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature80 : VDSTypography.fontSizeFeature48, + lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature76 : VDSTypography.lineHeightFeature48, + letterSpacing: 0.25) + + public static let featureXSmall = TextStyle(rawValue: "featureXSmall", + fontFace: .dsLight, + pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature64 : VDSTypography.fontSizeFeature40, + lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature64 : VDSTypography.lineHeightFeature40, + letterSpacing: 0.25) + + public static let boldFeatureXSmall = TextStyle(rawValue: "boldFeatureXSmall", + fontFace: .dsBold, + pointSize: UIDevice.isIPad ? VDSTypography.fontSizeFeature64 : VDSTypography.fontSizeFeature40, + lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightFeature64 : VDSTypography.lineHeightFeature40, + letterSpacing: 0.25) + + public static let title2XLarge = TextStyle(rawValue: "title2XLarge", + fontFace: .dsLight, + pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle64 : VDSTypography.fontSizeTitle40, + lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle64 : VDSTypography.lineHeightTitle40, + letterSpacing: 0.25) + + public static let boldTitle2XLarge = TextStyle(rawValue: "boldTitle2XLarge", + fontFace: .dsBold, + pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle64 : VDSTypography.fontSizeTitle40, + lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle64 : VDSTypography.lineHeightTitle40, + letterSpacing: 0.25) + + public static let titleXLarge = TextStyle(rawValue: "titleXLarge", + fontFace: .dsLight, + pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle48 : VDSTypography.fontSizeTitle32, + lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle48 : VDSTypography.lineHeightTitle36, + letterSpacing: 0.25) + + public static let boldTitleXLarge = TextStyle(rawValue: "boldTitleXLarge", + fontFace: .dsBold, + pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle48 : VDSTypography.fontSizeTitle32, + lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle48 : VDSTypography.lineHeightTitle36, + letterSpacing: 0.25) + + public static let titleLarge = TextStyle(rawValue: "titleLarge", + fontFace: .dsLight, + pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle32 : VDSTypography.fontSizeTitle24, + lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle36 : VDSTypography.lineHeightTitle28, + letterSpacing: 0.25) + + public static let boldTitleLarge = TextStyle(rawValue: "boldTitleLarge", + fontFace: .dsBold, + pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle32 : VDSTypography.fontSizeTitle24, + lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle36 : VDSTypography.lineHeightTitle28, + letterSpacing: 0.25) + + public static let titleMedium = TextStyle(rawValue: "titleMedium", + fontFace: .dsLight, + pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle24 : VDSTypography.fontSizeTitle20, + lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle28 : VDSTypography.lineHeightTitle24, + letterSpacing: 0.25) + + public static let boldTitleMedium = TextStyle(rawValue: "boldTitleMedium", + fontFace: .dsBold, + pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle24 : VDSTypography.fontSizeTitle20, + lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle28 : VDSTypography.lineHeightTitle24, + letterSpacing: 0.25) + + public static let titleSmall = TextStyle(rawValue: "titleSmall", + fontFace: .dsLight, + pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle20 : VDSTypography.fontSizeTitle16, + lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle24 : VDSTypography.lineHeightTitle20, + letterSpacing: 0.25) + + public static let boldTitleSmall = TextStyle(rawValue: "boldTitleSmall", + fontFace: .dsBold, + pointSize: UIDevice.isIPad ? VDSTypography.fontSizeTitle20 : VDSTypography.fontSizeTitle16, + lineHeight: UIDevice.isIPad ? VDSTypography.lineHeightTitle24 : VDSTypography.lineHeightTitle20, + letterSpacing: 0.25) + + public static let bodyLarge = TextStyle(rawValue: "bodyLarge", + fontFace: .dsRegular, + pointSize: VDSTypography.fontSizeBody16, + lineHeight: VDSTypography.lineHeightBody20, + letterSpacing: 0.5) + + public static let boldBodyLarge = TextStyle(rawValue: "boldBodyLarge", + fontFace: .dsBold, + pointSize: VDSTypography.fontSizeBody16, + lineHeight: VDSTypography.lineHeightBody20, + letterSpacing: 0.5) + + public static let bodyMedium = TextStyle(rawValue: "bodyMedium", + fontFace: .dsRegular, + pointSize: VDSTypography.fontSizeBody14, + lineHeight: VDSTypography.lineHeightBody18, + letterSpacing: 0.5) + + public static let boldBodyMedium = TextStyle(rawValue: "boldBodyMedium", + fontFace: .dsBold, + pointSize: VDSTypography.fontSizeBody14, + lineHeight: VDSTypography.lineHeightBody18, + letterSpacing: 0.5) + + public static let bodySmall = TextStyle(rawValue: "bodySmall", + fontFace: .dsRegular, + pointSize: VDSTypography.fontSizeBody12, + lineHeight: VDSTypography.lineHeightBody16, + letterSpacing: 0.25) + + public static let boldBodySmall = TextStyle(rawValue: "boldBodySmall", + fontFace: .dsBold, + pointSize: VDSTypography.fontSizeBody12, + lineHeight: VDSTypography.lineHeightBody16, + letterSpacing: 0.5) + + public static let micro = TextStyle(rawValue: "micro", + fontFace: .dsRegular, + pointSize: VDSTypography.fontSizeMicro11, + lineHeight: VDSTypography.lineHeightMicro16, + letterSpacing: 0.25) + + public static let boldMicro = TextStyle(rawValue: "boldMicro", + fontFace: .dsBold, + pointSize: VDSTypography.fontSizeMicro11, + lineHeight: VDSTypography.lineHeightMicro16, + letterSpacing: 0.5) + + public static var allCases: [TextStyle] { + return [ + featureXLarge, + boldFeatureXLarge, + featureLarge, + boldFeatureLarge, + featureMedium, + boldFeatureMedium, + featureSmall, + boldFeatureSmall, + featureXSmall, + boldFeatureXSmall, + title2XLarge, + boldTitle2XLarge, + titleXLarge, + boldTitleXLarge, + titleLarge, + boldTitleLarge, + titleMedium, + boldTitleMedium, + titleSmall, + boldTitleSmall, + bodyLarge, + boldBodyLarge, + bodyMedium, + boldBodyMedium, + bodySmall, + boldBodySmall, + micro, + boldMicro + ] + } + +} + + //MARK: FontCategory extension TextStyle { public enum FontCategory: String, CaseIterable { @@ -91,7 +276,8 @@ extension TextStyle { } else { styleName = "\(rawValue)\(fontSize?.rawValue ?? "")" } - guard let style = TextStyle(rawValue: styleName) else { + + guard let style = TextStyle.textStyle(for: styleName) else { return nil } return style @@ -111,102 +297,6 @@ extension TextStyle { } } -//MARK: PointSize -extension TextStyle { - public var pointSize: CGFloat { - switch self { - case .featureXLarge, .boldFeatureXLarge: - return UIDevice.isIPad ? VDSTypography.fontSizeFeature144 : VDSTypography.fontSizeFeature96 - case .featureLarge, .boldFeatureLarge: - return UIDevice.isIPad ? VDSTypography.fontSizeFeature128 : VDSTypography.fontSizeFeature80 - case .featureMedium, .boldFeatureMedium: - return UIDevice.isIPad ? VDSTypography.fontSizeFeature96 : VDSTypography.fontSizeFeature64 - case .featureSmall, .boldFeatureSmall: - return UIDevice.isIPad ? VDSTypography.fontSizeFeature80 : VDSTypography.fontSizeFeature48 - case .featureXSmall, .boldFeatureXSmall: - return UIDevice.isIPad ? VDSTypography.fontSizeFeature64 : VDSTypography.fontSizeFeature40 - case .title2XLarge, .boldTitle2XLarge: - return UIDevice.isIPad ? VDSTypography.fontSizeTitle64 : VDSTypography.fontSizeTitle40 - case .titleXLarge, .boldTitleXLarge: - return UIDevice.isIPad ? VDSTypography.fontSizeTitle48 : VDSTypography.fontSizeTitle32 - case .titleLarge, .boldTitleLarge: - return UIDevice.isIPad ? VDSTypography.fontSizeTitle32 : VDSTypography.fontSizeTitle24 - case .titleMedium, .boldTitleMedium: - return UIDevice.isIPad ? VDSTypography.fontSizeTitle24 : VDSTypography.fontSizeTitle20 - case .titleSmall, .boldTitleSmall: - return UIDevice.isIPad ? VDSTypography.fontSizeTitle20 : VDSTypography.fontSizeTitle16 - case .bodyLarge, .boldBodyLarge: - return VDSTypography.fontSizeBody16 - case .bodyMedium, .boldBodyMedium: - return VDSTypography.fontSizeBody14 - case .bodySmall, .boldBodySmall: - return VDSTypography.fontSizeBody12 - case .micro, .boldMicro: - return VDSTypography.fontSizeMicro11 - } - } -} - -//MARK: LineHeight -extension TextStyle { - public var lineHeight: CGFloat { - switch self { - case .featureXLarge, .boldFeatureXLarge: - return UIDevice.isIPad ? VDSTypography.lineHeightFeature136 : VDSTypography.lineHeightFeature88 - case .featureLarge, .boldFeatureLarge: - return UIDevice.isIPad ? VDSTypography.lineHeightFeature120 : VDSTypography.lineHeightFeature76 - case .featureMedium, .boldFeatureMedium: - return UIDevice.isIPad ? VDSTypography.lineHeightFeature88 : VDSTypography.lineHeightFeature64 - case .featureSmall, .boldFeatureSmall: - return UIDevice.isIPad ? VDSTypography.lineHeightFeature76 : VDSTypography.lineHeightFeature48 - case .featureXSmall, .boldFeatureXSmall: - return UIDevice.isIPad ? VDSTypography.lineHeightFeature64 : VDSTypography.lineHeightFeature40 - case .title2XLarge, .boldTitle2XLarge: - return UIDevice.isIPad ? VDSTypography.lineHeightTitle64 : VDSTypography.lineHeightTitle40 - case .titleXLarge, .boldTitleXLarge: - return UIDevice.isIPad ? VDSTypography.lineHeightTitle48 : VDSTypography.lineHeightTitle36 - case .titleLarge, .boldTitleLarge: - return UIDevice.isIPad ? VDSTypography.lineHeightTitle36 : VDSTypography.lineHeightTitle28 - case .titleMedium, .boldTitleMedium: - return UIDevice.isIPad ? VDSTypography.lineHeightTitle28 : VDSTypography.lineHeightTitle24 - case .titleSmall, .boldTitleSmall: - return UIDevice.isIPad ? VDSTypography.lineHeightTitle24 : VDSTypography.lineHeightTitle20 - case .bodyLarge, .boldBodyLarge: - return VDSTypography.lineHeightBody20 - case .bodyMedium, .boldBodyMedium: - return VDSTypography.lineHeightBody18 - case .bodySmall, .boldBodySmall: - return VDSTypography.lineHeightBody16 - case .micro, .boldMicro: - return VDSTypography.lineHeightMicro16 - } - } -} - -//MARK: LetterSpacing -extension TextStyle { - public var letterSpacing: CGFloat { - switch self { - case .featureXLarge, - .featureLarge, - .featureMedium, - .featureSmall, - .featureXSmall, - .title2XLarge, - .titleXLarge, - .titleLarge: - return 0.25 - - case .boldBodyLarge, .bodyLarge, - .boldBodyMedium, .bodyMedium: - return 0.5 - - default: - return 0.0 - } - } -} - //MARK: Alignments extension TextStyle { public var aligments: [TextPosition] { @@ -216,55 +306,9 @@ extension TextStyle { //MARK: Fonts extension TextStyle { - public var fontFace: Fonts { - switch self { - case .boldFeatureXLarge, - .boldFeatureLarge, - .boldFeatureMedium, - .boldFeatureSmall, - .boldFeatureXSmall, - .boldTitle2XLarge, - .boldTitleXLarge, - .boldTitleLarge, - .boldTitleMedium, - .boldTitleSmall, - .boldBodyLarge, - .boldBodyMedium: - return .dsBold - - case .featureXLarge, - .featureLarge, - .featureMedium, - .featureSmall, - .featureXSmall, - .title2XLarge, - .titleXLarge: - return .dsLight - - case .titleLarge, - .titleMedium, - .titleSmall, - .bodyLarge, - .bodyMedium: - return .dsRegular - - case .boldBodySmall, - .boldMicro: - return .txBold - - case .bodySmall, - .micro: - return .txRegular - } - } - public var font: UIFont { return fontFace.font(ofSize: pointSize) } - - public var superScriptFont: UIFont { - return fontFace.font(ofSize: pointSize / 2) - } } extension TextStyle { @@ -335,3 +379,12 @@ extension TextStyle: CustomDebugStringConvertible { "Name: \(self.rawValue) FontFace: \(font.fontName) FontWeight: \(self.rawValue.hasPrefix("bold") ? "bold" : "normal") PointSize: \(font.pointSize) LetterSpacing: \(letterSpacing) LineHeight: \(lineHeight)" } } + +extension TextStyle { + public static var defaultStyle: TextStyle { return bodyLarge } + + public static func textStyle(for name: String) -> TextStyle? { + guard let style = TextStyle.allCases.first(where: {$0.rawValue == name }) else { return nil } + return style + } +} From 3dc9fdfbb7a9f3ea4ba45e875dec6528c84f599f Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 15 Jun 2023 18:51:22 -0500 Subject: [PATCH 11/12] updated badgeIndicator to final for this release for now Signed-off-by: Matt Bruce --- .../BadgeIndicator/BadgeIndicator.swift | 246 +++++++++++++++--- 1 file changed, 214 insertions(+), 32 deletions(-) diff --git a/VDS/Components/BadgeIndicator/BadgeIndicator.swift b/VDS/Components/BadgeIndicator/BadgeIndicator.swift index 68af0d22..511f9b61 100644 --- a/VDS/Components/BadgeIndicator/BadgeIndicator.swift +++ b/VDS/Components/BadgeIndicator/BadgeIndicator.swift @@ -10,6 +10,7 @@ import UIKit import VDSColorTokens import VDSFormControlsTokens import Combine +import VDSTypographyTokens /// Badges are visual labels used to convey status or highlight supplemental information. @objc(VDSBadgeIndicator) @@ -21,6 +22,104 @@ open class BadgeIndicator: View { case red, yellow, green, orange, blue, gray, grayLowContrast, black, white } + public enum Kind: String, CaseIterable { + case simple, numbered + } + + public enum MaxDigits: String, CaseIterable { + case one + case two + case three + case four + case five + case six + + public var value: Int { + switch self { + case .two: + return 2 + case .one: + return 1 + case .three: + return 3 + case .four: + return 4 + case .five: + return 5 + case .six: + return 6 + } + } + } + + public enum TextSize: String, CaseIterable { + case xxlarge = "2XLarge" + case xlarge = "XLarge" + case large = "Large" + case medium = "Medium" + case small = "Small" + + public var minimumSize: CGFloat { + switch self { + case .xxlarge: + return 29 + case .xlarge: + return 24 + case .large: + return 20 + case .medium: + return 18 + case .small: + return 16 + } + } + + public var padding: CGFloat { + switch self { + case .xxlarge: + return 8 + case .xlarge: + return 6 + case .large: + return 6 + case .medium: + return 6 + case .small: + return 4 + } + } + + public var textStyle: TextStyle { + let style = TextStyle.bodySmall + var pointSize: CGFloat = VDSTypography.fontSizeBody12 + + switch self { + case .xxlarge: + pointSize = VDSTypography.fontSizeTitle24 + + case .xlarge: + pointSize = VDSTypography.fontSizeTitle20 + + case .large: + pointSize = VDSTypography.fontSizeBody16 + + case .medium: + pointSize = VDSTypography.fontSizeBody14 + + case .small: + pointSize = VDSTypography.fontSizeBody12 + + } + + return TextStyle(rawValue: "\(self.rawValue)BadgeIndicator", + fontFace: style.fontFace, + pointSize: pointSize, + lineHeight: style.lineHeight, + letterSpacing: style.letterSpacing) + } + + } + //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- @@ -28,24 +127,54 @@ open class BadgeIndicator: View { $0.setContentCompressionResistancePriority(.required, for: .vertical) $0.adjustsFontSizeToFitWidth = false $0.lineBreakMode = .byTruncatingTail - $0.textPosition = .left - $0.textStyle = .boldBodySmall + $0.textPosition = .center + $0.numberOfLines = 1 + } + + open var borderColorLight: UIColor? { + didSet { + if let borderColorLight { + borderColorConfiguration.lightColor = borderColorLight + } else { + borderColorConfiguration.lightColor = VDSColor.paletteWhite + } + setNeedsUpdate() + } + } + + open var borderColorDark: UIColor? { + didSet { + if let borderColorDark { + borderColorConfiguration.darkColor = borderColorDark + } else { + borderColorConfiguration.darkColor = VDSColor.paletteBlack + } + setNeedsUpdate() + } } open var fillColor: FillColor = .red { didSet { setNeedsUpdate() }} - open var text: String = "" { didSet { setNeedsUpdate() }} + open var number: Int? { didSet { setNeedsUpdate() }} - open var maxWidth: CGFloat? { didSet { setNeedsUpdate() }} + open var kind: Kind = .simple { didSet { setNeedsUpdate() }} + + open var leadingCharacter: String? { didSet { setNeedsUpdate() }} - open var numberOfLines: Int = 1 { didSet { setNeedsUpdate() }} - + open var textSize: TextSize = .xxlarge { didSet { setNeedsUpdate() }} + + open var hideDot: Bool = false { didSet { setNeedsUpdate() }} + + open var hideBorder: Bool = false { didSet { setNeedsUpdate() }} + + open var maxDigits: MaxDigits = .two { didSet { setNeedsUpdate() }} + //-------------------------------------------------- // MARK: - Constraints //-------------------------------------------------- - private var maxWidthConstraint: NSLayoutConstraint? - private var minWidthConstraint: NSLayoutConstraint? - + private var labelWidthConstraint: NSLayoutConstraint? + private var labelHeightConstraint: NSLayoutConstraint? + private var defaultBadgeSize: CGFloat = 16 //-------------------------------------------------- // MARK: - Lifecycle //-------------------------------------------------- @@ -54,18 +183,17 @@ open class BadgeIndicator: View { super.setup() accessibilityElements = [label] - layer.cornerRadius = 2 - + addSubview(label) - label.pinToSuperView(.init(top: 2, - left: VDSLayout.Spacing.space1X.value, - bottom: 2, - right: VDSLayout.Spacing.space1X.value)) - - maxWidthConstraint = label.widthAnchor.constraint(lessThanOrEqualToConstant: 100) - minWidthConstraint = label.widthAnchor.constraint(greaterThanOrEqualToConstant: 23) - minWidthConstraint?.isActive = true + label.pinToSuperView() + NSLayoutConstraint.activate([ + label.centerXAnchor.constraint(equalTo: centerXAnchor), + label.centerYAnchor.constraint(equalTo: centerYAnchor) + ]) + + labelWidthConstraint = label.widthGreaterThanEqualTo(constant: defaultBadgeSize).activate() + labelHeightConstraint = label.heightGreaterThanEqualTo(constant: defaultBadgeSize).activate() } open override func reset() { @@ -73,12 +201,9 @@ open class BadgeIndicator: View { shouldUpdateView = false label.reset() label.lineBreakMode = .byTruncatingTail - label.textPosition = .left - label.textStyle = .boldBodySmall + label.textPosition = .center fillColor = .red - text = "" - maxWidth = nil - numberOfLines = 1 + number = nil shouldUpdateView = true setNeedsUpdate() } @@ -86,6 +211,8 @@ open class BadgeIndicator: View { //-------------------------------------------------- // MARK: - Configuration //-------------------------------------------------- + private var borderColorConfiguration = SurfaceColorConfiguration(VDSColor.paletteWhite, VDSColor.paletteBlack) + private var backgroundColorConfiguration: AnyColorable = { let config = KeyedColorConfiguration(keyPath: \.fillColor) config.setSurfaceColors(VDSColor.backgroundBrandhighlight, VDSColor.backgroundBrandhighlight, forKey: .red) @@ -93,6 +220,8 @@ open class BadgeIndicator: View { config.setSurfaceColors(VDSColor.paletteGreen26, VDSColor.paletteGreen36, forKey: .green) config.setSurfaceColors(VDSColor.paletteOrange41, VDSColor.paletteOrange58, forKey: .orange) config.setSurfaceColors(VDSColor.paletteBlue38, VDSColor.paletteBlue46, forKey: .blue) + config.setSurfaceColors(VDSColor.paletteGray44, VDSColor.paletteGray65, forKey: .gray) + config.setSurfaceColors(VDSColor.paletteGray85, VDSColor.paletteGray20, forKey: .grayLowContrast) config.setSurfaceColors(VDSColor.backgroundPrimaryDark, VDSColor.backgroundPrimaryDark, forKey: .black) config.setSurfaceColors(VDSColor.backgroundPrimaryLight, VDSColor.backgroundPrimaryLight, forKey: .white) return config.eraseToAnyColorable() @@ -105,7 +234,7 @@ open class BadgeIndicator: View { switch fillColor { - case .red, .black: + case .red, .black, .gray, .grayLowContrast: textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOndark, forDisabled: false) textColorConfiguration.setSurfaceColors(VDSColor.elementsPrimaryOndark, VDSColor.elementsPrimaryOndark, forDisabled: true) @@ -126,18 +255,71 @@ open class BadgeIndicator: View { updateTextColorConfig() backgroundColor = backgroundColorConfiguration.getColor(self) - + + label.useAttributedText = true + label.edgeInset = .init(top: 0, left: textSize.padding, bottom: 0, right: textSize.padding) + label.font = textSize.textStyle.font + label.textColor = textColorConfiguration.getColor(self) label.textColorConfiguration = textColorConfiguration.eraseToAnyColorable() - label.numberOfLines = numberOfLines - label.text = text + label.text = getText() label.surface = surface label.disabled = disabled + label.sizeToFit() + setNeedsLayout() + layoutIfNeeded() + } + + private func getText() -> String { + let badgeCount = number ?? 0 + var text: String = "" + if kind == .numbered { + let maxBadgetCount = limitDigits(number: badgeCount, maxDigits: maxDigits.value) + + text = "\(maxBadgetCount)" + if maxDigits.value < "\(badgeCount)".count { + text = "\(maxBadgetCount)+" + } + if let leadingCharacter { + text = "\(leadingCharacter)\(text)" + } else { + text = "\(text)" + } + } + return text + } + + private func limitDigits(number: Int, maxDigits: Int) -> Int { + let maxNumber = Int(pow(10.0, Double(maxDigits))) - 1 + return min(number, maxNumber) + } + + open override func layoutSubviews() { + super.layoutSubviews() + labelWidthConstraint?.constant = textSize.minimumSize + labelHeightConstraint?.constant = textSize.minimumSize + layer.cornerRadius = frame.size.height / 2 - if let maxWidth = maxWidth, let minWidth = minWidthConstraint?.constant, maxWidth > minWidth { - maxWidthConstraint?.constant = maxWidth - maxWidthConstraint?.isActive = true + if hideBorder { + layer.borderWidth = 0 } else { - maxWidthConstraint?.isActive = false + layer.borderColor = borderColorConfiguration.getColor(surface).cgColor + layer.borderWidth = 1 + } + + layer.remove(layerName: "dot") + if kind == .simple && !hideDot { + let dotSize: CGFloat = bounds.width * 0.1875 + let dotLayer = CAShapeLayer() + dotLayer.name = "dot" + + let centerX = (bounds.width - dotSize) / 2.0 + let centerY = (bounds.width - dotSize) / 2.0 + + dotLayer.frame = .init(x: centerX, y: centerY, width: dotSize, height: dotSize) + dotLayer.path = UIBezierPath(ovalIn: .init(origin: .zero, size: .init(width: dotSize, height: dotSize))).cgPath + dotLayer.fillColor = textColorConfiguration.getColor(self).cgColor + + layer.addSublayer(dotLayer) } } } From 385ed1b216d510fd9f97df69e46a0850de547c17 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 15 Jun 2023 18:58:44 -0500 Subject: [PATCH 12/12] updated controller Signed-off-by: Matt Bruce --- VDS/Components/BadgeIndicator/BadgeIndicator.swift | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/VDS/Components/BadgeIndicator/BadgeIndicator.swift b/VDS/Components/BadgeIndicator/BadgeIndicator.swift index 511f9b61..0bafa46d 100644 --- a/VDS/Components/BadgeIndicator/BadgeIndicator.swift +++ b/VDS/Components/BadgeIndicator/BadgeIndicator.swift @@ -272,12 +272,15 @@ open class BadgeIndicator: View { private func getText() -> String { let badgeCount = number ?? 0 var text: String = "" - if kind == .numbered { + if kind == .numbered && badgeCount >= 0 { let maxBadgetCount = limitDigits(number: badgeCount, maxDigits: maxDigits.value) - - text = "\(maxBadgetCount)" + let formatter = NumberFormatter() + formatter.numberStyle = .decimal + text = formatter.string(from: .init(integerLiteral: maxBadgetCount))! if maxDigits.value < "\(badgeCount)".count { - text = "\(maxBadgetCount)+" + let formatter = NumberFormatter() + formatter.numberStyle = .decimal + text = "\(text)+" } if let leadingCharacter { text = "\(leadingCharacter)\(text)"