updated submodules
6
.gitmodules
vendored
@@ -31,9 +31,6 @@
|
|||||||
[submodule "Tweaks/iSponsorBlock"]
|
[submodule "Tweaks/iSponsorBlock"]
|
||||||
path = Tweaks/iSponsorBlock
|
path = Tweaks/iSponsorBlock
|
||||||
url = https://github.com/Galactic-Dev/iSponsorBlock.git
|
url = https://github.com/Galactic-Dev/iSponsorBlock.git
|
||||||
[submodule "Extensions"]
|
|
||||||
path = Extensions
|
|
||||||
url = https://github.com/CokePokes/YoutubeExtensions.git
|
|
||||||
[submodule "Tweaks/YTHoldForSpeed"]
|
[submodule "Tweaks/YTHoldForSpeed"]
|
||||||
path = Tweaks/YTHoldForSpeed
|
path = Tweaks/YTHoldForSpeed
|
||||||
url = https://github.com/arichorn/YTHoldForSpeed.git
|
url = https://github.com/arichorn/YTHoldForSpeed.git
|
||||||
@@ -43,3 +40,6 @@
|
|||||||
[submodule "Tweaks/YTLite"]
|
[submodule "Tweaks/YTLite"]
|
||||||
path = Tweaks/YTLite
|
path = Tweaks/YTLite
|
||||||
url = https://github.com/dayanch96/YTLite.git
|
url = https://github.com/dayanch96/YTLite.git
|
||||||
|
[submodule "Extensions"]
|
||||||
|
path = Extensions
|
||||||
|
url = https://github.com/CokePokes/YoutubeExtensions.git
|
||||||
|
1
Extensions
Submodule
2
Extensions/.gitattributes
vendored
@@ -1,2 +0,0 @@
|
|||||||
# Auto detect text files and perform LF normalization
|
|
||||||
* text=auto
|
|
1
Extensions/.gitignore
vendored
@@ -1 +0,0 @@
|
|||||||
.DS_Store
|
|
@@ -1,333 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>files</key>
|
|
||||||
<dict>
|
|
||||||
<key>Info.plist</key>
|
|
||||||
<data>
|
|
||||||
5KaPBsMVTGZfcc05Od8nGW6/EyQ=
|
|
||||||
</data>
|
|
||||||
<key>_locales/en/messages.json</key>
|
|
||||||
<data>
|
|
||||||
8cPkszxzYFSjhRWsf34A0AiHaPM=
|
|
||||||
</data>
|
|
||||||
<key>background.js</key>
|
|
||||||
<data>
|
|
||||||
tClFxbnUm0L65Qj+Qu8Fk9asL2o=
|
|
||||||
</data>
|
|
||||||
<key>content.js</key>
|
|
||||||
<data>
|
|
||||||
a6o4B4PMlrIOBXlniU2NS4D9SJE=
|
|
||||||
</data>
|
|
||||||
<key>embedded.mobileprovision</key>
|
|
||||||
<data>
|
|
||||||
dVGLS8Qpu/eCI1J5VCu9IfYq3Z4=
|
|
||||||
</data>
|
|
||||||
<key>images/cat_1.0.gif</key>
|
|
||||||
<data>
|
|
||||||
DtSTnvB7wRt647kM1b38KLfDfXA=
|
|
||||||
</data>
|
|
||||||
<key>images/icon-128.png</key>
|
|
||||||
<data>
|
|
||||||
rYa1lv1LgkO3fkP9h6gRSjlQgqk=
|
|
||||||
</data>
|
|
||||||
<key>images/icon-256.png</key>
|
|
||||||
<data>
|
|
||||||
05xbekvTg28KsH9RRIKQRL8tqQs=
|
|
||||||
</data>
|
|
||||||
<key>images/icon-48.png</key>
|
|
||||||
<data>
|
|
||||||
BWUZe8raKzOzA2cDWIYFoBPxxw8=
|
|
||||||
</data>
|
|
||||||
<key>images/icon-512.png</key>
|
|
||||||
<data>
|
|
||||||
shzpVHJMsAu4q820Fb+YzByiFhc=
|
|
||||||
</data>
|
|
||||||
<key>images/icon-64.png</key>
|
|
||||||
<data>
|
|
||||||
HZC4YIb4ZLg4lpjNAKFqSaka6r0=
|
|
||||||
</data>
|
|
||||||
<key>images/icon-96.png</key>
|
|
||||||
<data>
|
|
||||||
IPAOd1HfCtCI7ybhVhwA5TU/BZ8=
|
|
||||||
</data>
|
|
||||||
<key>images/toolbar-icon-16.png</key>
|
|
||||||
<data>
|
|
||||||
Bkb2Cy8VYIcWl7wFZ2HcWZcCoyA=
|
|
||||||
</data>
|
|
||||||
<key>images/toolbar-icon-19.png</key>
|
|
||||||
<data>
|
|
||||||
XLkdODJ73CVbwn/1LCAsfB6scPg=
|
|
||||||
</data>
|
|
||||||
<key>images/toolbar-icon-32.png</key>
|
|
||||||
<data>
|
|
||||||
0cQgf/z3urGdzsmtmc2Wnim1+lg=
|
|
||||||
</data>
|
|
||||||
<key>images/toolbar-icon-38.png</key>
|
|
||||||
<data>
|
|
||||||
eas7Tl3/r2JMZf6nK84ZjoBJrZo=
|
|
||||||
</data>
|
|
||||||
<key>images/toolbar-icon-48.png</key>
|
|
||||||
<data>
|
|
||||||
fxyz1xgkIR877Cf/7uYNUqXrxoM=
|
|
||||||
</data>
|
|
||||||
<key>images/toolbar-icon-72.png</key>
|
|
||||||
<data>
|
|
||||||
pHL3CJwjPY30T9sFvvcA2qlraBw=
|
|
||||||
</data>
|
|
||||||
<key>manifest.json</key>
|
|
||||||
<data>
|
|
||||||
b37QyqMYHlvlfOjbvJLOKeAM5Y4=
|
|
||||||
</data>
|
|
||||||
<key>popup.css</key>
|
|
||||||
<data>
|
|
||||||
mXR2qQxu+ceMOItNpc4aImux5wY=
|
|
||||||
</data>
|
|
||||||
<key>popup.html</key>
|
|
||||||
<data>
|
|
||||||
zTk6QImmvcZjMYLQY8ek+cqSEWg=
|
|
||||||
</data>
|
|
||||||
<key>popup.js</key>
|
|
||||||
<data>
|
|
||||||
grmSQBg1aRbGzHHjd3TWHS/HbOY=
|
|
||||||
</data>
|
|
||||||
</dict>
|
|
||||||
<key>files2</key>
|
|
||||||
<dict>
|
|
||||||
<key>_locales/en/messages.json</key>
|
|
||||||
<dict>
|
|
||||||
<key>hash2</key>
|
|
||||||
<data>
|
|
||||||
4pOaVgBrOGGIoI81XdEOZidIyW9peYtz85HIYX7d1QE=
|
|
||||||
</data>
|
|
||||||
</dict>
|
|
||||||
<key>background.js</key>
|
|
||||||
<dict>
|
|
||||||
<key>hash2</key>
|
|
||||||
<data>
|
|
||||||
2S7ONYvdkGsryEavyrR7nMCTwsjNGqMV2BSWIxWLSYg=
|
|
||||||
</data>
|
|
||||||
</dict>
|
|
||||||
<key>content.js</key>
|
|
||||||
<dict>
|
|
||||||
<key>hash2</key>
|
|
||||||
<data>
|
|
||||||
9CYz6yZ8bRI2JRzRwnn4DOGuPuy2GSsOudXSZU6s1po=
|
|
||||||
</data>
|
|
||||||
</dict>
|
|
||||||
<key>embedded.mobileprovision</key>
|
|
||||||
<dict>
|
|
||||||
<key>hash2</key>
|
|
||||||
<data>
|
|
||||||
4TQyzTTz0VYUTM0IXf2PMSufVEkzd4WlPWbwKMyfKfQ=
|
|
||||||
</data>
|
|
||||||
</dict>
|
|
||||||
<key>images/cat_1.0.gif</key>
|
|
||||||
<dict>
|
|
||||||
<key>hash2</key>
|
|
||||||
<data>
|
|
||||||
65Ql3FhfivRMoMifbuY5KK8I/1rZx/Zmmwsx1La4OyI=
|
|
||||||
</data>
|
|
||||||
</dict>
|
|
||||||
<key>images/icon-128.png</key>
|
|
||||||
<dict>
|
|
||||||
<key>hash2</key>
|
|
||||||
<data>
|
|
||||||
TV8I8bcVP9rAnVA4AJRAWtkJveIenMpYsd/7+rsMLzo=
|
|
||||||
</data>
|
|
||||||
</dict>
|
|
||||||
<key>images/icon-256.png</key>
|
|
||||||
<dict>
|
|
||||||
<key>hash2</key>
|
|
||||||
<data>
|
|
||||||
kksdsW0Y1svz0bT0i3UzQGBmBDxJGr2eTCZmaqTS+XM=
|
|
||||||
</data>
|
|
||||||
</dict>
|
|
||||||
<key>images/icon-48.png</key>
|
|
||||||
<dict>
|
|
||||||
<key>hash2</key>
|
|
||||||
<data>
|
|
||||||
mBNPpZ78p0eH4WsNdF/EXw/sFHq5f8PqERARlLulYbY=
|
|
||||||
</data>
|
|
||||||
</dict>
|
|
||||||
<key>images/icon-512.png</key>
|
|
||||||
<dict>
|
|
||||||
<key>hash2</key>
|
|
||||||
<data>
|
|
||||||
waQn18oFc3GbhXXm2HEn6xFQk3HKehp9crGljWAMsGQ=
|
|
||||||
</data>
|
|
||||||
</dict>
|
|
||||||
<key>images/icon-64.png</key>
|
|
||||||
<dict>
|
|
||||||
<key>hash2</key>
|
|
||||||
<data>
|
|
||||||
CJwxajQk49Cd0RfR22yEPO6pjDbg+Aa4Ocxi+812CiM=
|
|
||||||
</data>
|
|
||||||
</dict>
|
|
||||||
<key>images/icon-96.png</key>
|
|
||||||
<dict>
|
|
||||||
<key>hash2</key>
|
|
||||||
<data>
|
|
||||||
zuzRjCepizxOWXh9ftCPth38GUxy1Ea/4zS3dw19OXo=
|
|
||||||
</data>
|
|
||||||
</dict>
|
|
||||||
<key>images/toolbar-icon-16.png</key>
|
|
||||||
<dict>
|
|
||||||
<key>hash2</key>
|
|
||||||
<data>
|
|
||||||
xmXH4YHb+Pq/YuC1e8JLIun93LuM3+/8MvB3r8oTKls=
|
|
||||||
</data>
|
|
||||||
</dict>
|
|
||||||
<key>images/toolbar-icon-19.png</key>
|
|
||||||
<dict>
|
|
||||||
<key>hash2</key>
|
|
||||||
<data>
|
|
||||||
qSX/1Ux4BOUIhixJK5NkvyTomLwp0yISfsQ97uF8/5g=
|
|
||||||
</data>
|
|
||||||
</dict>
|
|
||||||
<key>images/toolbar-icon-32.png</key>
|
|
||||||
<dict>
|
|
||||||
<key>hash2</key>
|
|
||||||
<data>
|
|
||||||
pGDg4NcSdD5EQaZgaiwxNosbSEXmZnpRc79RfitKc1c=
|
|
||||||
</data>
|
|
||||||
</dict>
|
|
||||||
<key>images/toolbar-icon-38.png</key>
|
|
||||||
<dict>
|
|
||||||
<key>hash2</key>
|
|
||||||
<data>
|
|
||||||
BUU3dwrCSvNOiFkBQWdPkrwASjUvxSxbizW+Izt3LBA=
|
|
||||||
</data>
|
|
||||||
</dict>
|
|
||||||
<key>images/toolbar-icon-48.png</key>
|
|
||||||
<dict>
|
|
||||||
<key>hash2</key>
|
|
||||||
<data>
|
|
||||||
JLZV5da+fZkfw0m2KfMqHSixWBCJvZoUNlt3la7gm54=
|
|
||||||
</data>
|
|
||||||
</dict>
|
|
||||||
<key>images/toolbar-icon-72.png</key>
|
|
||||||
<dict>
|
|
||||||
<key>hash2</key>
|
|
||||||
<data>
|
|
||||||
TwM7A1Bkuv4C3SWorFNwG+w38mWo3TaMtglLdDXxcFw=
|
|
||||||
</data>
|
|
||||||
</dict>
|
|
||||||
<key>manifest.json</key>
|
|
||||||
<dict>
|
|
||||||
<key>hash2</key>
|
|
||||||
<data>
|
|
||||||
+nWdvS9ap7YzpjqKSWsGUHP5K2irkTGozQX/tI4WrYc=
|
|
||||||
</data>
|
|
||||||
</dict>
|
|
||||||
<key>popup.css</key>
|
|
||||||
<dict>
|
|
||||||
<key>hash2</key>
|
|
||||||
<data>
|
|
||||||
LIfF3an8mzKIMD8PDhKILnrZBhxxSTzoZQKyRiyWuB0=
|
|
||||||
</data>
|
|
||||||
</dict>
|
|
||||||
<key>popup.html</key>
|
|
||||||
<dict>
|
|
||||||
<key>hash2</key>
|
|
||||||
<data>
|
|
||||||
9Ro1fCC5Meq0eSNrYab7V3uc4tNvmwRqMsCb1757M6Q=
|
|
||||||
</data>
|
|
||||||
</dict>
|
|
||||||
<key>popup.js</key>
|
|
||||||
<dict>
|
|
||||||
<key>hash2</key>
|
|
||||||
<data>
|
|
||||||
ruLXAORE+vDoLKPGBSkl7hnXv8V+ZexCoX3KvJyHxBk=
|
|
||||||
</data>
|
|
||||||
</dict>
|
|
||||||
</dict>
|
|
||||||
<key>rules</key>
|
|
||||||
<dict>
|
|
||||||
<key>^.*</key>
|
|
||||||
<true/>
|
|
||||||
<key>^.*\.lproj/</key>
|
|
||||||
<dict>
|
|
||||||
<key>optional</key>
|
|
||||||
<true/>
|
|
||||||
<key>weight</key>
|
|
||||||
<real>1000</real>
|
|
||||||
</dict>
|
|
||||||
<key>^.*\.lproj/locversion.plist$</key>
|
|
||||||
<dict>
|
|
||||||
<key>omit</key>
|
|
||||||
<true/>
|
|
||||||
<key>weight</key>
|
|
||||||
<real>1100</real>
|
|
||||||
</dict>
|
|
||||||
<key>^Base\.lproj/</key>
|
|
||||||
<dict>
|
|
||||||
<key>weight</key>
|
|
||||||
<real>1010</real>
|
|
||||||
</dict>
|
|
||||||
<key>^version.plist$</key>
|
|
||||||
<true/>
|
|
||||||
</dict>
|
|
||||||
<key>rules2</key>
|
|
||||||
<dict>
|
|
||||||
<key>.*\.dSYM($|/)</key>
|
|
||||||
<dict>
|
|
||||||
<key>weight</key>
|
|
||||||
<real>11</real>
|
|
||||||
</dict>
|
|
||||||
<key>^(.*/)?\.DS_Store$</key>
|
|
||||||
<dict>
|
|
||||||
<key>omit</key>
|
|
||||||
<true/>
|
|
||||||
<key>weight</key>
|
|
||||||
<real>2000</real>
|
|
||||||
</dict>
|
|
||||||
<key>^.*</key>
|
|
||||||
<true/>
|
|
||||||
<key>^.*\.lproj/</key>
|
|
||||||
<dict>
|
|
||||||
<key>optional</key>
|
|
||||||
<true/>
|
|
||||||
<key>weight</key>
|
|
||||||
<real>1000</real>
|
|
||||||
</dict>
|
|
||||||
<key>^.*\.lproj/locversion.plist$</key>
|
|
||||||
<dict>
|
|
||||||
<key>omit</key>
|
|
||||||
<true/>
|
|
||||||
<key>weight</key>
|
|
||||||
<real>1100</real>
|
|
||||||
</dict>
|
|
||||||
<key>^Base\.lproj/</key>
|
|
||||||
<dict>
|
|
||||||
<key>weight</key>
|
|
||||||
<real>1010</real>
|
|
||||||
</dict>
|
|
||||||
<key>^Info\.plist$</key>
|
|
||||||
<dict>
|
|
||||||
<key>omit</key>
|
|
||||||
<true/>
|
|
||||||
<key>weight</key>
|
|
||||||
<real>20</real>
|
|
||||||
</dict>
|
|
||||||
<key>^PkgInfo$</key>
|
|
||||||
<dict>
|
|
||||||
<key>omit</key>
|
|
||||||
<true/>
|
|
||||||
<key>weight</key>
|
|
||||||
<real>20</real>
|
|
||||||
</dict>
|
|
||||||
<key>^embedded\.provisionprofile$</key>
|
|
||||||
<dict>
|
|
||||||
<key>weight</key>
|
|
||||||
<real>20</real>
|
|
||||||
</dict>
|
|
||||||
<key>^version\.plist$</key>
|
|
||||||
<dict>
|
|
||||||
<key>weight</key>
|
|
||||||
<real>20</real>
|
|
||||||
</dict>
|
|
||||||
</dict>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
@@ -1,10 +0,0 @@
|
|||||||
{
|
|
||||||
"extension_name": {
|
|
||||||
"message": "OpenYoutube",
|
|
||||||
"description": "The display name for the extension."
|
|
||||||
},
|
|
||||||
"extension_description": {
|
|
||||||
"message": "Displays an Open in Youtube alert for sideloaded YT",
|
|
||||||
"description": "Description of what the extension does."
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,6 +0,0 @@
|
|||||||
browser.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
|
||||||
console.log("Received request: ", request);
|
|
||||||
|
|
||||||
if (request.greeting === "hello")
|
|
||||||
sendResponse({ farewell: "goodbye" });
|
|
||||||
});
|
|
@@ -1,25 +0,0 @@
|
|||||||
browser.runtime.sendMessage({ greeting: "hello" }).then((response) => {
|
|
||||||
console.log("Received response: ", response);
|
|
||||||
});
|
|
||||||
|
|
||||||
browser.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
|
||||||
console.log("Received request: ", request);
|
|
||||||
});
|
|
||||||
|
|
||||||
function afterNavigate() {
|
|
||||||
if ('/watch' === location.pathname) {
|
|
||||||
window.location.href = `youtube://${window.location.pathname.slice(1)}${
|
|
||||||
window.location.search
|
|
||||||
}${window.location.hash}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(document.body || document.documentElement).addEventListener('transitionend',
|
|
||||||
function(/*TransitionEvent*/ event) {
|
|
||||||
if (event.propertyName === 'width' && event.target.id === 'progress') {
|
|
||||||
afterNavigate();
|
|
||||||
}
|
|
||||||
}, true);
|
|
||||||
// After page load
|
|
||||||
afterNavigate();
|
|
||||||
|
|
||||||
|
|
Before Width: | Height: | Size: 110 KiB |
Before Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 42 KiB |
Before Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 128 KiB |
Before Width: | Height: | Size: 5.0 KiB |
Before Width: | Height: | Size: 9.5 KiB |
Before Width: | Height: | Size: 454 B |
Before Width: | Height: | Size: 569 B |
Before Width: | Height: | Size: 919 B |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 2.1 KiB |
@@ -1,40 +0,0 @@
|
|||||||
{
|
|
||||||
"manifest_version": 2,
|
|
||||||
"default_locale": "en",
|
|
||||||
|
|
||||||
"name": "__MSG_extension_name__",
|
|
||||||
"description": "__MSG_extension_description__",
|
|
||||||
"version": "1.0",
|
|
||||||
|
|
||||||
"icons": {
|
|
||||||
"48": "images/icon-48.png",
|
|
||||||
"96": "images/icon-96.png",
|
|
||||||
"128": "images/icon-128.png",
|
|
||||||
"256": "images/icon-256.png",
|
|
||||||
"512": "images/icon-512.png"
|
|
||||||
},
|
|
||||||
|
|
||||||
"background": {
|
|
||||||
"scripts": [ "background.js" ],
|
|
||||||
"persistent": false
|
|
||||||
},
|
|
||||||
|
|
||||||
"content_scripts": [{
|
|
||||||
"js": [ "content.js" ],
|
|
||||||
"matches": [ "*://*.youtube.com/*" ]
|
|
||||||
}],
|
|
||||||
|
|
||||||
"browser_action": {
|
|
||||||
"default_popup": "popup.html",
|
|
||||||
"default_icon": {
|
|
||||||
"16": "images/toolbar-icon-16.png",
|
|
||||||
"19": "images/toolbar-icon-19.png",
|
|
||||||
"32": "images/toolbar-icon-32.png",
|
|
||||||
"38": "images/toolbar-icon-38.png",
|
|
||||||
"48": "images/toolbar-icon-48.png",
|
|
||||||
"72": "images/toolbar-icon-72.png"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
"permissions": [ ]
|
|
||||||
}
|
|
@@ -1,15 +0,0 @@
|
|||||||
:root {
|
|
||||||
color-scheme: light dark;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
width: 100px;
|
|
||||||
padding: 10px;
|
|
||||||
|
|
||||||
font-family: system-ui;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
|
||||||
/* Dark Mode styles go here. */
|
|
||||||
}
|
|
@@ -1,21 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<link rel="stylesheet" href="popup.css">
|
|
||||||
<script type="module" src="popup.js"></script>
|
|
||||||
</head>
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
background-image:url('images/cat_1.0.gif');
|
|
||||||
background-size:100%;
|
|
||||||
background-repeat: repeat-y;
|
|
||||||
background-attachment: fixed;
|
|
||||||
height:100%;
|
|
||||||
width:100%;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<body>
|
|
||||||
<strong>Extension made by @CokePokes</strong>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@@ -1 +0,0 @@
|
|||||||
console.log("Hello World!", browser);
|
|
@@ -1,20 +0,0 @@
|
|||||||
# YoutubeExtensions
|
|
||||||
appex extensions for sideloaded YT
|
|
||||||
|
|
||||||
|
|
||||||
What is this?
|
|
||||||
|
|
||||||
These plugins enable "Open In" for sideloaded Youtube without any need to download other Opener apps /Shortcuts.
|
|
||||||
|
|
||||||
|
|
||||||
How to install:
|
|
||||||
|
|
||||||
1. Download the .appex files here
|
|
||||||
2. Unzip Youtube.ipa & copy them to /Payload/Youtube.app/Plugins
|
|
||||||
3. Compress Payload folder & rename .zip to .ipa
|
|
||||||
4. Sign & Install onto device
|
|
||||||
5. Open YouTube once & then open Safari to enable the iOS 15 safari plugin [prompted always allow - do it]
|
|
||||||
6. Press the Share icon in Safari scroll app list > More > Enable Youtube
|
|
||||||
|
|
||||||
Done!
|
|
||||||
|
|
Before Width: | Height: | Size: 1.2 KiB |
@@ -1,157 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>files</key>
|
|
||||||
<dict>
|
|
||||||
<key>Base.lproj/MainInterface.storyboardc/Info.plist</key>
|
|
||||||
<data>
|
|
||||||
Bgt43YuQd48Y7NBkKAH/I1Nd+7Q=
|
|
||||||
</data>
|
|
||||||
<key>Base.lproj/MainInterface.storyboardc/UIViewController-j1y-V4-xli.nib</key>
|
|
||||||
<data>
|
|
||||||
t/rVTMy59WLCl0e0ydlT2JlJKIs=
|
|
||||||
</data>
|
|
||||||
<key>Base.lproj/MainInterface.storyboardc/j1y-V4-xli-view-wbc-yd-nQP.nib</key>
|
|
||||||
<data>
|
|
||||||
56s4vIzFNrq5HEvB3Mr6qnqVRFg=
|
|
||||||
</data>
|
|
||||||
<key>Info.plist</key>
|
|
||||||
<data>
|
|
||||||
7+n2S5sS/Ngeoe21gJMc6iC6+ac=
|
|
||||||
</data>
|
|
||||||
<key>embedded.mobileprovision</key>
|
|
||||||
<data>
|
|
||||||
dVGLS8Qpu/eCI1J5VCu9IfYq3Z4=
|
|
||||||
</data>
|
|
||||||
<key>icon.png</key>
|
|
||||||
<data>
|
|
||||||
/pip+c1EETgjhxNcOhgiyQxxzyU=
|
|
||||||
</data>
|
|
||||||
</dict>
|
|
||||||
<key>files2</key>
|
|
||||||
<dict>
|
|
||||||
<key>Base.lproj/MainInterface.storyboardc/Info.plist</key>
|
|
||||||
<dict>
|
|
||||||
<key>hash2</key>
|
|
||||||
<data>
|
|
||||||
Qnp5pVqL/lRCSEISDYZs1VBLxfcEnfpOzHg6WgcgLgk=
|
|
||||||
</data>
|
|
||||||
</dict>
|
|
||||||
<key>Base.lproj/MainInterface.storyboardc/UIViewController-j1y-V4-xli.nib</key>
|
|
||||||
<dict>
|
|
||||||
<key>hash2</key>
|
|
||||||
<data>
|
|
||||||
VpQww1vK2BoM0RIaiw/B/8JZ3kp5Pks5bM8Sjtjju9w=
|
|
||||||
</data>
|
|
||||||
</dict>
|
|
||||||
<key>Base.lproj/MainInterface.storyboardc/j1y-V4-xli-view-wbc-yd-nQP.nib</key>
|
|
||||||
<dict>
|
|
||||||
<key>hash2</key>
|
|
||||||
<data>
|
|
||||||
C87FO0vFlvhG8vp7+3v+EcR9kbOeu9v+mDLy/iU+6e8=
|
|
||||||
</data>
|
|
||||||
</dict>
|
|
||||||
<key>embedded.mobileprovision</key>
|
|
||||||
<dict>
|
|
||||||
<key>hash2</key>
|
|
||||||
<data>
|
|
||||||
4TQyzTTz0VYUTM0IXf2PMSufVEkzd4WlPWbwKMyfKfQ=
|
|
||||||
</data>
|
|
||||||
</dict>
|
|
||||||
<key>icon.png</key>
|
|
||||||
<dict>
|
|
||||||
<key>hash2</key>
|
|
||||||
<data>
|
|
||||||
mfufJ0CJyFLUpRnLC8q8awHkGqmWeQtRDgF5EBXKUQs=
|
|
||||||
</data>
|
|
||||||
</dict>
|
|
||||||
</dict>
|
|
||||||
<key>rules</key>
|
|
||||||
<dict>
|
|
||||||
<key>^.*</key>
|
|
||||||
<true/>
|
|
||||||
<key>^.*\.lproj/</key>
|
|
||||||
<dict>
|
|
||||||
<key>optional</key>
|
|
||||||
<true/>
|
|
||||||
<key>weight</key>
|
|
||||||
<real>1000</real>
|
|
||||||
</dict>
|
|
||||||
<key>^.*\.lproj/locversion.plist$</key>
|
|
||||||
<dict>
|
|
||||||
<key>omit</key>
|
|
||||||
<true/>
|
|
||||||
<key>weight</key>
|
|
||||||
<real>1100</real>
|
|
||||||
</dict>
|
|
||||||
<key>^Base\.lproj/</key>
|
|
||||||
<dict>
|
|
||||||
<key>weight</key>
|
|
||||||
<real>1010</real>
|
|
||||||
</dict>
|
|
||||||
<key>^version.plist$</key>
|
|
||||||
<true/>
|
|
||||||
</dict>
|
|
||||||
<key>rules2</key>
|
|
||||||
<dict>
|
|
||||||
<key>.*\.dSYM($|/)</key>
|
|
||||||
<dict>
|
|
||||||
<key>weight</key>
|
|
||||||
<real>11</real>
|
|
||||||
</dict>
|
|
||||||
<key>^(.*/)?\.DS_Store$</key>
|
|
||||||
<dict>
|
|
||||||
<key>omit</key>
|
|
||||||
<true/>
|
|
||||||
<key>weight</key>
|
|
||||||
<real>2000</real>
|
|
||||||
</dict>
|
|
||||||
<key>^.*</key>
|
|
||||||
<true/>
|
|
||||||
<key>^.*\.lproj/</key>
|
|
||||||
<dict>
|
|
||||||
<key>optional</key>
|
|
||||||
<true/>
|
|
||||||
<key>weight</key>
|
|
||||||
<real>1000</real>
|
|
||||||
</dict>
|
|
||||||
<key>^.*\.lproj/locversion.plist$</key>
|
|
||||||
<dict>
|
|
||||||
<key>omit</key>
|
|
||||||
<true/>
|
|
||||||
<key>weight</key>
|
|
||||||
<real>1100</real>
|
|
||||||
</dict>
|
|
||||||
<key>^Base\.lproj/</key>
|
|
||||||
<dict>
|
|
||||||
<key>weight</key>
|
|
||||||
<real>1010</real>
|
|
||||||
</dict>
|
|
||||||
<key>^Info\.plist$</key>
|
|
||||||
<dict>
|
|
||||||
<key>omit</key>
|
|
||||||
<true/>
|
|
||||||
<key>weight</key>
|
|
||||||
<real>20</real>
|
|
||||||
</dict>
|
|
||||||
<key>^PkgInfo$</key>
|
|
||||||
<dict>
|
|
||||||
<key>omit</key>
|
|
||||||
<true/>
|
|
||||||
<key>weight</key>
|
|
||||||
<real>20</real>
|
|
||||||
</dict>
|
|
||||||
<key>^embedded\.provisionprofile$</key>
|
|
||||||
<dict>
|
|
||||||
<key>weight</key>
|
|
||||||
<real>20</real>
|
|
||||||
</dict>
|
|
||||||
<key>^version\.plist$</key>
|
|
||||||
<dict>
|
|
||||||
<key>weight</key>
|
|
||||||
<real>20</real>
|
|
||||||
</dict>
|
|
||||||
</dict>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
@@ -1,7 +0,0 @@
|
|||||||
var GetURL = function() {};
|
|
||||||
GetURL.prototype = {
|
|
||||||
run: function(arguments) {
|
|
||||||
arguments.completionFunction({"URL": document.URL});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
var ExtensionPreprocessingJS = new GetURL;
|
|
1
Tweaks/Alderis
Submodule
16
Tweaks/Alderis/.gitignore
vendored
@@ -1,16 +0,0 @@
|
|||||||
# Crap
|
|
||||||
.DS_Store
|
|
||||||
|
|
||||||
# Xcode
|
|
||||||
*.pbxuser
|
|
||||||
!default.pbxuser
|
|
||||||
xcuserdata
|
|
||||||
*.xccheckout
|
|
||||||
*.xcuserstate
|
|
||||||
|
|
||||||
# Carthage
|
|
||||||
Carthage/
|
|
||||||
|
|
||||||
# Theos
|
|
||||||
.theos
|
|
||||||
packages/
|
|
@@ -1,36 +0,0 @@
|
|||||||
clean: true
|
|
||||||
author: HASHBANG Productions
|
|
||||||
author_url: https://hbang.github.io/
|
|
||||||
github_url: https://github.com/hbang/Alderis
|
|
||||||
root_url: https://hbang.github.io/Alderis/
|
|
||||||
dash_url: https://hbang.github.io/Alderis/docsets/Alderis.xml
|
|
||||||
documentation: info/*.md
|
|
||||||
hide_documentation_coverage: true
|
|
||||||
|
|
||||||
custom_categories:
|
|
||||||
- name: "Guides"
|
|
||||||
children:
|
|
||||||
- "Preference Bundles"
|
|
||||||
- "Migrating to 1.1"
|
|
||||||
|
|
||||||
- name: "Color Picker"
|
|
||||||
children:
|
|
||||||
- ColorPickerViewController
|
|
||||||
- ColorPickerConfiguration
|
|
||||||
- ColorPickerDelegate
|
|
||||||
- ColorPickerTab
|
|
||||||
|
|
||||||
- name: "UI Components"
|
|
||||||
children:
|
|
||||||
- ColorWell
|
|
||||||
|
|
||||||
- name: "Extensions"
|
|
||||||
children:
|
|
||||||
- UIColor
|
|
||||||
- ColorPropertyListValue
|
|
||||||
- String
|
|
||||||
- Array
|
|
||||||
|
|
||||||
- name: "Deprecated"
|
|
||||||
children:
|
|
||||||
- ColorPickerCircleView
|
|
@@ -1,61 +0,0 @@
|
|||||||
disabled_rules:
|
|
||||||
- trailing_comma
|
|
||||||
- nesting
|
|
||||||
- fallthrough
|
|
||||||
- shorthand_operator
|
|
||||||
- todo
|
|
||||||
- large_tuple
|
|
||||||
- identifier_name
|
|
||||||
- type_name
|
|
||||||
- type_body_length
|
|
||||||
# TODO: Why is vertical_parameter_alignment giving false positives?
|
|
||||||
- vertical_parameter_alignment
|
|
||||||
- vertical_parameter_alignment_on_call
|
|
||||||
# TODO: Enable when removing support for older Swift versions (<5.6)
|
|
||||||
- unavailable_condition
|
|
||||||
opt_in_rules:
|
|
||||||
- closure_end_indentation
|
|
||||||
- closure_spacing
|
|
||||||
- contains_over_first_not_nil
|
|
||||||
- empty_count
|
|
||||||
- explicit_init
|
|
||||||
- fatal_error_message
|
|
||||||
- first_where
|
|
||||||
- joined_default_parameter
|
|
||||||
- literal_expression_end_indentation
|
|
||||||
- overridden_super_call
|
|
||||||
- prohibited_super_call
|
|
||||||
- sorted_first_last
|
|
||||||
- unneeded_parentheses_in_closure_argument
|
|
||||||
- vertical_parameter_alignment_on_call
|
|
||||||
- yoda_condition
|
|
||||||
- nslocalizedstring_key
|
|
||||||
- unused_setter_value
|
|
||||||
custom_rules:
|
|
||||||
comment_whitespace:
|
|
||||||
name: "Comment Whitespace"
|
|
||||||
regex: //\S
|
|
||||||
match_kinds: comment
|
|
||||||
message: "Comments must begin with a whitespace character"
|
|
||||||
spaces_not_tabs:
|
|
||||||
name: "Tabs not Spaces"
|
|
||||||
regex: ^( )
|
|
||||||
message: "Use tabs instead of spaces"
|
|
||||||
point_zero:
|
|
||||||
name: "Point Zero"
|
|
||||||
regex: '(?<!iOS\s)(?<!macOS\s)(?<!\.)\b[\d_]+\.0\b'
|
|
||||||
match_kinds:
|
|
||||||
- number
|
|
||||||
- attribute.builtin
|
|
||||||
message: "Don't add a .0 to the end of floating point literals"
|
|
||||||
color_init:
|
|
||||||
name: "Color Initializer"
|
|
||||||
regex: 'UIColor\(red: (.+), green: \1, blue: \1, alpha: .+\)'
|
|
||||||
message: "Use UIColor(white:alpha:)"
|
|
||||||
force_try: warning
|
|
||||||
force_cast: warning
|
|
||||||
function_body_length: 200
|
|
||||||
line_length: 200
|
|
||||||
file_length: 450
|
|
||||||
cyclomatic_complexity: 12
|
|
||||||
function_parameter_count: 7
|
|
@@ -1,30 +0,0 @@
|
|||||||
Pod::Spec.new do |spec|
|
|
||||||
spec.name = "Alderis"
|
|
||||||
spec.version = "1.2.0"
|
|
||||||
spec.summary = "A fresh new color picker, with a gentle, fun, and dead simple user interface."
|
|
||||||
spec.description = <<-DESC
|
|
||||||
Alderis is a fresh new color picker, with a gentle, fun, and dead simple user
|
|
||||||
interface. It aims to incorporate the usual elements of a color picker, in a way
|
|
||||||
that users will find easy and fun to use.
|
|
||||||
|
|
||||||
The user can start by selecting a color they like on the initial color palette
|
|
||||||
tab, and either accept it, or refine it using the color wheel and adjustment
|
|
||||||
sliders found on the two other tabs.
|
|
||||||
DESC
|
|
||||||
spec.homepage = "https://github.com/hbang/Alderis"
|
|
||||||
spec.screenshots = "https://github.com/hbang/Alderis/raw/main/screenshots/alderis-1.jpg",
|
|
||||||
"https://github.com/hbang/Alderis/raw/main/screenshots/alderis-2.jpg",
|
|
||||||
"https://github.com/hbang/Alderis/raw/main/screenshots/alderis-3.jpg",
|
|
||||||
"https://github.com/hbang/Alderis/raw/main/screenshots/alderis-4.jpg"
|
|
||||||
spec.license = "Apache License, Version 2.0"
|
|
||||||
spec.author = "HASHBANG Productions"
|
|
||||||
spec.social_media_url = "https://twitter.com/hashbang"
|
|
||||||
|
|
||||||
spec.swift_versions = "5.0"
|
|
||||||
spec.platform = :ios, "12.0"
|
|
||||||
|
|
||||||
spec.source = { :git => "https://github.com/hbang/Alderis.git", :tag => "#{spec.version}" }
|
|
||||||
spec.requires_arc = true
|
|
||||||
spec.source_files = [ "Alderis/*.swift", "Alderis/*.h" ]
|
|
||||||
spec.resource_bundles = { "Alderis" => "Alderis/Assets-ios12.xcassets" }
|
|
||||||
end
|
|
@@ -1,482 +0,0 @@
|
|||||||
// !$*UTF8*$!
|
|
||||||
{
|
|
||||||
archiveVersion = 1;
|
|
||||||
classes = {
|
|
||||||
};
|
|
||||||
objectVersion = 52;
|
|
||||||
objects = {
|
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
|
||||||
4E1C741328266C5900227EC3 /* UIFontDescriptorAdditions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E1C741228266C5900227EC3 /* UIFontDescriptorAdditions.swift */; };
|
|
||||||
4E1C74172826C1F100227EC3 /* ColorPickerAccessibilityViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E1C74162826C1F100227EC3 /* ColorPickerAccessibilityViewController.swift */; };
|
|
||||||
4E1C741928276D5600227EC3 /* TextViewLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E1C741828276D5600227EC3 /* TextViewLabel.swift */; };
|
|
||||||
4E1C741B2827829E00227EC3 /* AccessibilityComplianceLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E1C741A2827829E00227EC3 /* AccessibilityComplianceLabel.swift */; };
|
|
||||||
4E1C741D2827882600227EC3 /* AccessibilityContrastSelector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E1C741C2827882600227EC3 /* AccessibilityContrastSelector.swift */; };
|
|
||||||
4E1C741F2827B3C800227EC3 /* UIFloat.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E1C741E2827B3C800227EC3 /* UIFloat.swift */; };
|
|
||||||
4E1C74212827B8F800227EC3 /* NSBeep.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E1C74202827B8F800227EC3 /* NSBeep.swift */; };
|
|
||||||
4E2E6C06282BD5990089E4FB /* GradientView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E2E6C05282BD5990089E4FB /* GradientView.swift */; };
|
|
||||||
569C25522427F57000022C60 /* ColorPickerTabViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 569C25512427F57000022C60 /* ColorPickerTabViewController.swift */; };
|
|
||||||
569C25582428346900022C60 /* ColorPickerMapSlider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 569C25572428346900022C60 /* ColorPickerMapSlider.swift */; };
|
|
||||||
56C74667242F722A003ED00A /* ColorPickerSlider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56C74666242F722A003ED00A /* ColorPickerSlider.swift */; };
|
|
||||||
56C74669242F75E3003ED00A /* ColorPickerNumericSlider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56C74668242F75E3003ED00A /* ColorPickerNumericSlider.swift */; };
|
|
||||||
94A2368C252B5951002B5D0B /* UIColorAdditions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94A2368B252B5951002B5D0B /* UIColorAdditions.swift */; };
|
|
||||||
CF73D33A241F9C23000B1B10 /* Alderis.h in Headers */ = {isa = PBXBuildFile; fileRef = CF73D338241F9C23000B1B10 /* Alderis.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
|
||||||
CF73D344241F9C31000B1B10 /* ColorWell.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF73D32D241E49EE000B1B10 /* ColorWell.swift */; };
|
|
||||||
CF73D345241F9C31000B1B10 /* ColorPickerMapViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CFE70280241CBDE700083903 /* ColorPickerMapViewController.swift */; };
|
|
||||||
CF73D346241F9C31000B1B10 /* ColorPickerSlidersViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CFE70282241CC88D00083903 /* ColorPickerSlidersViewController.swift */; };
|
|
||||||
CF73D347241F9C31000B1B10 /* ColorPickerWheelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CFE70288241D0E7300083903 /* ColorPickerWheelView.swift */; };
|
|
||||||
CF73D348241F9C31000B1B10 /* ColorPickerInnerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CFE7027B241A62ED00083903 /* ColorPickerInnerViewController.swift */; };
|
|
||||||
CF73D34A241F9C31000B1B10 /* ColorPickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CFE70273241A4C5500083903 /* ColorPickerViewController.swift */; };
|
|
||||||
CF73D34B241F9C31000B1B10 /* ColorPickerSwatchViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CFE7027E241B984600083903 /* ColorPickerSwatchViewController.swift */; };
|
|
||||||
CF73D34C241F9C4D000B1B10 /* Color.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF73D32B241E4720000B1B10 /* Color.swift */; };
|
|
||||||
CF73D351241F9FB3000B1B10 /* ColorPickerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF73D350241F9FB3000B1B10 /* ColorPickerDelegate.swift */; };
|
|
||||||
CF7750B72520D3B50069CC57 /* Assets.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF7750B62520D3B50069CC57 /* Assets.swift */; };
|
|
||||||
CF7750BE252203630069CC57 /* DialogButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF7750BD252203630069CC57 /* DialogButton.swift */; };
|
|
||||||
CF7750CF252433680069CC57 /* ColorPickerConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF7750CE252433680069CC57 /* ColorPickerConfiguration.swift */; };
|
|
||||||
CF7750D62524615D0069CC57 /* SeparatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF7750D52524615D0069CC57 /* SeparatorView.swift */; };
|
|
||||||
CF775122252852460069CC57 /* AlderisSDKCompatibility.h in Headers */ = {isa = PBXBuildFile; fileRef = CF775121252852110069CC57 /* AlderisSDKCompatibility.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
|
||||||
CF79DA31251723C500F17BCB /* BottomSheetTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF79DA30251723C500F17BCB /* BottomSheetTransition.swift */; };
|
|
||||||
CFAFFC9124277CEE005AD4C1 /* Assets-ios12.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CFAFFC9024277CEE005AD4C1 /* Assets-ios12.xcassets */; platformFilter = ios; };
|
|
||||||
/* End PBXBuildFile section */
|
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
|
||||||
4E1C741228266C5900227EC3 /* UIFontDescriptorAdditions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIFontDescriptorAdditions.swift; sourceTree = "<group>"; };
|
|
||||||
4E1C74162826C1F100227EC3 /* ColorPickerAccessibilityViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorPickerAccessibilityViewController.swift; sourceTree = "<group>"; };
|
|
||||||
4E1C741828276D5600227EC3 /* TextViewLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextViewLabel.swift; sourceTree = "<group>"; };
|
|
||||||
4E1C741A2827829E00227EC3 /* AccessibilityComplianceLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccessibilityComplianceLabel.swift; sourceTree = "<group>"; };
|
|
||||||
4E1C741C2827882600227EC3 /* AccessibilityContrastSelector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccessibilityContrastSelector.swift; sourceTree = "<group>"; };
|
|
||||||
4E1C741E2827B3C800227EC3 /* UIFloat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIFloat.swift; sourceTree = "<group>"; };
|
|
||||||
4E1C74202827B8F800227EC3 /* NSBeep.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSBeep.swift; sourceTree = "<group>"; };
|
|
||||||
4E2E6C05282BD5990089E4FB /* GradientView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GradientView.swift; sourceTree = "<group>"; };
|
|
||||||
569C25512427F57000022C60 /* ColorPickerTabViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorPickerTabViewController.swift; sourceTree = "<group>"; };
|
|
||||||
569C25572428346900022C60 /* ColorPickerMapSlider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorPickerMapSlider.swift; sourceTree = "<group>"; };
|
|
||||||
56C74666242F722A003ED00A /* ColorPickerSlider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorPickerSlider.swift; sourceTree = "<group>"; };
|
|
||||||
56C74668242F75E3003ED00A /* ColorPickerNumericSlider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorPickerNumericSlider.swift; sourceTree = "<group>"; };
|
|
||||||
94A2368B252B5951002B5D0B /* UIColorAdditions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIColorAdditions.swift; sourceTree = "<group>"; };
|
|
||||||
CF73D32B241E4720000B1B10 /* Color.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Color.swift; sourceTree = "<group>"; };
|
|
||||||
CF73D32D241E49EE000B1B10 /* ColorWell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorWell.swift; sourceTree = "<group>"; };
|
|
||||||
CF73D336241F9C23000B1B10 /* Alderis.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Alderis.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
|
||||||
CF73D338241F9C23000B1B10 /* Alderis.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Alderis.h; sourceTree = "<group>"; };
|
|
||||||
CF73D339241F9C23000B1B10 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
|
||||||
CF73D350241F9FB3000B1B10 /* ColorPickerDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorPickerDelegate.swift; sourceTree = "<group>"; };
|
|
||||||
CF7750B62520D3B50069CC57 /* Assets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Assets.swift; sourceTree = "<group>"; };
|
|
||||||
CF7750BD252203630069CC57 /* DialogButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DialogButton.swift; sourceTree = "<group>"; };
|
|
||||||
CF7750CE252433680069CC57 /* ColorPickerConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ColorPickerConfiguration.swift; sourceTree = "<group>"; };
|
|
||||||
CF7750D52524615D0069CC57 /* SeparatorView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SeparatorView.swift; sourceTree = "<group>"; };
|
|
||||||
CF775121252852110069CC57 /* AlderisSDKCompatibility.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AlderisSDKCompatibility.h; sourceTree = "<group>"; };
|
|
||||||
CF79DA30251723C500F17BCB /* BottomSheetTransition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BottomSheetTransition.swift; sourceTree = "<group>"; };
|
|
||||||
CFAFFC9024277CEE005AD4C1 /* Assets-ios12.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Assets-ios12.xcassets"; sourceTree = "<group>"; };
|
|
||||||
CFE70273241A4C5500083903 /* ColorPickerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorPickerViewController.swift; sourceTree = "<group>"; };
|
|
||||||
CFE7027B241A62ED00083903 /* ColorPickerInnerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorPickerInnerViewController.swift; sourceTree = "<group>"; };
|
|
||||||
CFE7027E241B984600083903 /* ColorPickerSwatchViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorPickerSwatchViewController.swift; sourceTree = "<group>"; };
|
|
||||||
CFE70280241CBDE700083903 /* ColorPickerMapViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorPickerMapViewController.swift; sourceTree = "<group>"; };
|
|
||||||
CFE70282241CC88D00083903 /* ColorPickerSlidersViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorPickerSlidersViewController.swift; sourceTree = "<group>"; };
|
|
||||||
CFE70288241D0E7300083903 /* ColorPickerWheelView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorPickerWheelView.swift; sourceTree = "<group>"; };
|
|
||||||
/* End PBXFileReference section */
|
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
|
||||||
CF73D333241F9C23000B1B10 /* Frameworks */ = {
|
|
||||||
isa = PBXFrameworksBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
/* End PBXFrameworksBuildPhase section */
|
|
||||||
|
|
||||||
/* Begin PBXGroup section */
|
|
||||||
CF39D435222BC07C001EF57F = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
CF73D337241F9C23000B1B10 /* Alderis */,
|
|
||||||
CF39D43F222BC07C001EF57F /* Products */,
|
|
||||||
);
|
|
||||||
indentWidth = 2;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
tabWidth = 2;
|
|
||||||
usesTabs = 1;
|
|
||||||
};
|
|
||||||
CF39D43F222BC07C001EF57F /* Products */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
CF73D336241F9C23000B1B10 /* Alderis.framework */,
|
|
||||||
);
|
|
||||||
name = Products;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
CF73D337241F9C23000B1B10 /* Alderis */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
CF73D338241F9C23000B1B10 /* Alderis.h */,
|
|
||||||
CF775121252852110069CC57 /* AlderisSDKCompatibility.h */,
|
|
||||||
CF7750B62520D3B50069CC57 /* Assets.swift */,
|
|
||||||
CF79DA30251723C500F17BCB /* BottomSheetTransition.swift */,
|
|
||||||
CF73D32B241E4720000B1B10 /* Color.swift */,
|
|
||||||
CFE70273241A4C5500083903 /* ColorPickerViewController.swift */,
|
|
||||||
CF7750CE252433680069CC57 /* ColorPickerConfiguration.swift */,
|
|
||||||
CF73D350241F9FB3000B1B10 /* ColorPickerDelegate.swift */,
|
|
||||||
CFE7027B241A62ED00083903 /* ColorPickerInnerViewController.swift */,
|
|
||||||
569C25512427F57000022C60 /* ColorPickerTabViewController.swift */,
|
|
||||||
56C74666242F722A003ED00A /* ColorPickerSlider.swift */,
|
|
||||||
CFE7027E241B984600083903 /* ColorPickerSwatchViewController.swift */,
|
|
||||||
569C25572428346900022C60 /* ColorPickerMapSlider.swift */,
|
|
||||||
CFE70280241CBDE700083903 /* ColorPickerMapViewController.swift */,
|
|
||||||
CFE70288241D0E7300083903 /* ColorPickerWheelView.swift */,
|
|
||||||
CFE70282241CC88D00083903 /* ColorPickerSlidersViewController.swift */,
|
|
||||||
56C74668242F75E3003ED00A /* ColorPickerNumericSlider.swift */,
|
|
||||||
4E1C74162826C1F100227EC3 /* ColorPickerAccessibilityViewController.swift */,
|
|
||||||
4E1C741A2827829E00227EC3 /* AccessibilityComplianceLabel.swift */,
|
|
||||||
4E1C741C2827882600227EC3 /* AccessibilityContrastSelector.swift */,
|
|
||||||
CF73D32D241E49EE000B1B10 /* ColorWell.swift */,
|
|
||||||
CF7750BD252203630069CC57 /* DialogButton.swift */,
|
|
||||||
CF7750D52524615D0069CC57 /* SeparatorView.swift */,
|
|
||||||
4E2E6C05282BD5990089E4FB /* GradientView.swift */,
|
|
||||||
94A2368B252B5951002B5D0B /* UIColorAdditions.swift */,
|
|
||||||
4E1C741228266C5900227EC3 /* UIFontDescriptorAdditions.swift */,
|
|
||||||
4E1C741E2827B3C800227EC3 /* UIFloat.swift */,
|
|
||||||
4E1C741828276D5600227EC3 /* TextViewLabel.swift */,
|
|
||||||
4E1C74202827B8F800227EC3 /* NSBeep.swift */,
|
|
||||||
CF73D339241F9C23000B1B10 /* Info.plist */,
|
|
||||||
CFAFFC9024277CEE005AD4C1 /* Assets-ios12.xcassets */,
|
|
||||||
);
|
|
||||||
path = Alderis;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
/* End PBXGroup section */
|
|
||||||
|
|
||||||
/* Begin PBXHeadersBuildPhase section */
|
|
||||||
CF73D331241F9C23000B1B10 /* Headers */ = {
|
|
||||||
isa = PBXHeadersBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
CF73D33A241F9C23000B1B10 /* Alderis.h in Headers */,
|
|
||||||
CF775122252852460069CC57 /* AlderisSDKCompatibility.h in Headers */,
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
/* End PBXHeadersBuildPhase section */
|
|
||||||
|
|
||||||
/* Begin PBXNativeTarget section */
|
|
||||||
CF73D335241F9C23000B1B10 /* Alderis */ = {
|
|
||||||
isa = PBXNativeTarget;
|
|
||||||
buildConfigurationList = CF73D340241F9C23000B1B10 /* Build configuration list for PBXNativeTarget "Alderis" */;
|
|
||||||
buildPhases = (
|
|
||||||
CF73D331241F9C23000B1B10 /* Headers */,
|
|
||||||
CF73D332241F9C23000B1B10 /* Sources */,
|
|
||||||
CF73D333241F9C23000B1B10 /* Frameworks */,
|
|
||||||
CF73D334241F9C23000B1B10 /* Resources */,
|
|
||||||
CF77511225281F7E0069CC57 /* SwiftLint */,
|
|
||||||
);
|
|
||||||
buildRules = (
|
|
||||||
);
|
|
||||||
dependencies = (
|
|
||||||
);
|
|
||||||
name = Alderis;
|
|
||||||
productName = Alderis;
|
|
||||||
productReference = CF73D336241F9C23000B1B10 /* Alderis.framework */;
|
|
||||||
productType = "com.apple.product-type.framework";
|
|
||||||
};
|
|
||||||
/* End PBXNativeTarget section */
|
|
||||||
|
|
||||||
/* Begin PBXProject section */
|
|
||||||
CF39D436222BC07C001EF57F /* Project object */ = {
|
|
||||||
isa = PBXProject;
|
|
||||||
attributes = {
|
|
||||||
LastUpgradeCheck = 1330;
|
|
||||||
ORGANIZATIONNAME = "HASHBANG Productions";
|
|
||||||
TargetAttributes = {
|
|
||||||
CF73D335241F9C23000B1B10 = {
|
|
||||||
CreatedOnToolsVersion = 11.3.1;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
buildConfigurationList = CF39D439222BC07C001EF57F /* Build configuration list for PBXProject "Alderis" */;
|
|
||||||
compatibilityVersion = "Xcode 9.3";
|
|
||||||
developmentRegion = en;
|
|
||||||
hasScannedForEncodings = 0;
|
|
||||||
knownRegions = (
|
|
||||||
en,
|
|
||||||
Base,
|
|
||||||
);
|
|
||||||
mainGroup = CF39D435222BC07C001EF57F;
|
|
||||||
productRefGroup = CF39D43F222BC07C001EF57F /* Products */;
|
|
||||||
projectDirPath = "";
|
|
||||||
projectRoot = "";
|
|
||||||
targets = (
|
|
||||||
CF73D335241F9C23000B1B10 /* Alderis */,
|
|
||||||
);
|
|
||||||
};
|
|
||||||
/* End PBXProject section */
|
|
||||||
|
|
||||||
/* Begin PBXResourcesBuildPhase section */
|
|
||||||
CF73D334241F9C23000B1B10 /* Resources */ = {
|
|
||||||
isa = PBXResourcesBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
CFAFFC9124277CEE005AD4C1 /* Assets-ios12.xcassets in Resources */,
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
/* End PBXResourcesBuildPhase section */
|
|
||||||
|
|
||||||
/* Begin PBXShellScriptBuildPhase section */
|
|
||||||
CF77511225281F7E0069CC57 /* SwiftLint */ = {
|
|
||||||
isa = PBXShellScriptBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
);
|
|
||||||
inputFileListPaths = (
|
|
||||||
);
|
|
||||||
inputPaths = (
|
|
||||||
);
|
|
||||||
name = SwiftLint;
|
|
||||||
outputFileListPaths = (
|
|
||||||
);
|
|
||||||
outputPaths = (
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
shellPath = /bin/sh;
|
|
||||||
shellScript = "export PATH=$PATH:/opt/homebrew/bin\nif which swiftlint >/dev/null; then\n\tswiftlint\nelse\n\techo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n";
|
|
||||||
};
|
|
||||||
/* End PBXShellScriptBuildPhase section */
|
|
||||||
|
|
||||||
/* Begin PBXSourcesBuildPhase section */
|
|
||||||
CF73D332241F9C23000B1B10 /* Sources */ = {
|
|
||||||
isa = PBXSourcesBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
CF73D34B241F9C31000B1B10 /* ColorPickerSwatchViewController.swift in Sources */,
|
|
||||||
CF7750BE252203630069CC57 /* DialogButton.swift in Sources */,
|
|
||||||
4E1C741928276D5600227EC3 /* TextViewLabel.swift in Sources */,
|
|
||||||
CF73D347241F9C31000B1B10 /* ColorPickerWheelView.swift in Sources */,
|
|
||||||
CF7750D62524615D0069CC57 /* SeparatorView.swift in Sources */,
|
|
||||||
CF73D34C241F9C4D000B1B10 /* Color.swift in Sources */,
|
|
||||||
94A2368C252B5951002B5D0B /* UIColorAdditions.swift in Sources */,
|
|
||||||
569C25582428346900022C60 /* ColorPickerMapSlider.swift in Sources */,
|
|
||||||
4E2E6C06282BD5990089E4FB /* GradientView.swift in Sources */,
|
|
||||||
CF73D344241F9C31000B1B10 /* ColorWell.swift in Sources */,
|
|
||||||
CF7750B72520D3B50069CC57 /* Assets.swift in Sources */,
|
|
||||||
CF73D348241F9C31000B1B10 /* ColorPickerInnerViewController.swift in Sources */,
|
|
||||||
56C74667242F722A003ED00A /* ColorPickerSlider.swift in Sources */,
|
|
||||||
4E1C74212827B8F800227EC3 /* NSBeep.swift in Sources */,
|
|
||||||
4E1C74172826C1F100227EC3 /* ColorPickerAccessibilityViewController.swift in Sources */,
|
|
||||||
4E1C741D2827882600227EC3 /* AccessibilityContrastSelector.swift in Sources */,
|
|
||||||
CF73D345241F9C31000B1B10 /* ColorPickerMapViewController.swift in Sources */,
|
|
||||||
CF79DA31251723C500F17BCB /* BottomSheetTransition.swift in Sources */,
|
|
||||||
4E1C741328266C5900227EC3 /* UIFontDescriptorAdditions.swift in Sources */,
|
|
||||||
CF73D34A241F9C31000B1B10 /* ColorPickerViewController.swift in Sources */,
|
|
||||||
CF7750CF252433680069CC57 /* ColorPickerConfiguration.swift in Sources */,
|
|
||||||
56C74669242F75E3003ED00A /* ColorPickerNumericSlider.swift in Sources */,
|
|
||||||
569C25522427F57000022C60 /* ColorPickerTabViewController.swift in Sources */,
|
|
||||||
4E1C741F2827B3C800227EC3 /* UIFloat.swift in Sources */,
|
|
||||||
CF73D351241F9FB3000B1B10 /* ColorPickerDelegate.swift in Sources */,
|
|
||||||
CF73D346241F9C31000B1B10 /* ColorPickerSlidersViewController.swift in Sources */,
|
|
||||||
4E1C741B2827829E00227EC3 /* AccessibilityComplianceLabel.swift in Sources */,
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
/* End PBXSourcesBuildPhase section */
|
|
||||||
|
|
||||||
/* Begin XCBuildConfiguration section */
|
|
||||||
CF39D452222BC07E001EF57F /* Debug */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
buildSettings = {
|
|
||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
|
||||||
CLANG_ANALYZER_NONNULL = YES;
|
|
||||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
|
||||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
|
||||||
CLANG_CXX_LIBRARY = "libc++";
|
|
||||||
CLANG_ENABLE_MODULES = YES;
|
|
||||||
CLANG_ENABLE_OBJC_ARC = YES;
|
|
||||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
|
||||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
|
||||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_COMMA = YES;
|
|
||||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
|
||||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
|
||||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
|
||||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
|
||||||
CLANG_WARN_EMPTY_BODY = YES;
|
|
||||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
|
||||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
|
||||||
CLANG_WARN_INT_CONVERSION = YES;
|
|
||||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
|
||||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
|
||||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
|
||||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
|
||||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
|
||||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
|
||||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
|
||||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
|
||||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
|
||||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
|
||||||
COPY_PHASE_STRIP = NO;
|
|
||||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
|
||||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
|
||||||
ENABLE_TESTABILITY = YES;
|
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
|
||||||
GCC_DYNAMIC_NO_PIC = NO;
|
|
||||||
GCC_NO_COMMON_BLOCKS = YES;
|
|
||||||
GCC_OPTIMIZATION_LEVEL = 0;
|
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
|
||||||
"DEBUG=1",
|
|
||||||
"$(inherited)",
|
|
||||||
);
|
|
||||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
|
||||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
|
||||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
|
||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
|
||||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
|
||||||
MTL_FAST_MATH = YES;
|
|
||||||
ONLY_ACTIVE_ARCH = YES;
|
|
||||||
SDKROOT = iphoneos;
|
|
||||||
};
|
|
||||||
name = Debug;
|
|
||||||
};
|
|
||||||
CF39D453222BC07E001EF57F /* Release */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
buildSettings = {
|
|
||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
|
||||||
CLANG_ANALYZER_NONNULL = YES;
|
|
||||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
|
||||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
|
||||||
CLANG_CXX_LIBRARY = "libc++";
|
|
||||||
CLANG_ENABLE_MODULES = YES;
|
|
||||||
CLANG_ENABLE_OBJC_ARC = YES;
|
|
||||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
|
||||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
|
||||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_COMMA = YES;
|
|
||||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
|
||||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
|
||||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
|
||||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
|
||||||
CLANG_WARN_EMPTY_BODY = YES;
|
|
||||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
|
||||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
|
||||||
CLANG_WARN_INT_CONVERSION = YES;
|
|
||||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
|
||||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
|
||||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
|
||||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
|
||||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
|
||||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
|
||||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
|
||||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
|
||||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
|
||||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
|
||||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
|
||||||
COPY_PHASE_STRIP = NO;
|
|
||||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
|
||||||
ENABLE_NS_ASSERTIONS = NO;
|
|
||||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
|
||||||
GCC_NO_COMMON_BLOCKS = YES;
|
|
||||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
|
||||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
|
||||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
|
||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
|
||||||
MTL_FAST_MATH = YES;
|
|
||||||
SDKROOT = iphoneos;
|
|
||||||
SWIFT_COMPILATION_MODE = wholemodule;
|
|
||||||
VALIDATE_PRODUCT = YES;
|
|
||||||
};
|
|
||||||
name = Release;
|
|
||||||
};
|
|
||||||
CF73D341241F9C23000B1B10 /* Debug */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
buildSettings = {
|
|
||||||
APPLICATION_EXTENSION_API_ONLY = YES;
|
|
||||||
BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
|
|
||||||
CURRENT_PROJECT_VERSION = 3;
|
|
||||||
DEFINES_MODULE = YES;
|
|
||||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
|
||||||
DYLIB_CURRENT_VERSION = 1;
|
|
||||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
|
||||||
INFOPLIST_FILE = Alderis/Info.plist;
|
|
||||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
|
||||||
"$(inherited)",
|
|
||||||
"@executable_path/Frameworks",
|
|
||||||
"@loader_path/Frameworks",
|
|
||||||
);
|
|
||||||
MARKETING_VERSION = 1.2;
|
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = ws.hbang.Alderis;
|
|
||||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
|
||||||
SKIP_INSTALL = NO;
|
|
||||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
|
||||||
SWIFT_VERSION = 5.0;
|
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
|
||||||
VERSIONING_SYSTEM = "apple-generic";
|
|
||||||
VERSION_INFO_PREFIX = "";
|
|
||||||
};
|
|
||||||
name = Debug;
|
|
||||||
};
|
|
||||||
CF73D342241F9C23000B1B10 /* Release */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
buildSettings = {
|
|
||||||
APPLICATION_EXTENSION_API_ONLY = YES;
|
|
||||||
BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
|
|
||||||
CURRENT_PROJECT_VERSION = 3;
|
|
||||||
DEFINES_MODULE = YES;
|
|
||||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
|
||||||
DYLIB_CURRENT_VERSION = 1;
|
|
||||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
|
||||||
INFOPLIST_FILE = Alderis/Info.plist;
|
|
||||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
|
||||||
"$(inherited)",
|
|
||||||
"@executable_path/Frameworks",
|
|
||||||
"@loader_path/Frameworks",
|
|
||||||
);
|
|
||||||
MARKETING_VERSION = 1.2;
|
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = ws.hbang.Alderis;
|
|
||||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
|
||||||
SKIP_INSTALL = NO;
|
|
||||||
SWIFT_COMPILATION_MODE = wholemodule;
|
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
|
||||||
SWIFT_VERSION = 5.0;
|
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
|
||||||
VERSIONING_SYSTEM = "apple-generic";
|
|
||||||
VERSION_INFO_PREFIX = "";
|
|
||||||
};
|
|
||||||
name = Release;
|
|
||||||
};
|
|
||||||
/* End XCBuildConfiguration section */
|
|
||||||
|
|
||||||
/* Begin XCConfigurationList section */
|
|
||||||
CF39D439222BC07C001EF57F /* Build configuration list for PBXProject "Alderis" */ = {
|
|
||||||
isa = XCConfigurationList;
|
|
||||||
buildConfigurations = (
|
|
||||||
CF39D452222BC07E001EF57F /* Debug */,
|
|
||||||
CF39D453222BC07E001EF57F /* Release */,
|
|
||||||
);
|
|
||||||
defaultConfigurationIsVisible = 0;
|
|
||||||
defaultConfigurationName = Release;
|
|
||||||
};
|
|
||||||
CF73D340241F9C23000B1B10 /* Build configuration list for PBXNativeTarget "Alderis" */ = {
|
|
||||||
isa = XCConfigurationList;
|
|
||||||
buildConfigurations = (
|
|
||||||
CF73D341241F9C23000B1B10 /* Debug */,
|
|
||||||
CF73D342241F9C23000B1B10 /* Release */,
|
|
||||||
);
|
|
||||||
defaultConfigurationIsVisible = 0;
|
|
||||||
defaultConfigurationName = Release;
|
|
||||||
};
|
|
||||||
/* End XCConfigurationList section */
|
|
||||||
};
|
|
||||||
rootObject = CF39D436222BC07C001EF57F /* Project object */;
|
|
||||||
}
|
|
@@ -1,7 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<Workspace
|
|
||||||
version = "1.0">
|
|
||||||
<FileRef
|
|
||||||
location = "self:Alderis Demo.xcodeproj">
|
|
||||||
</FileRef>
|
|
||||||
</Workspace>
|
|
@@ -1,8 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>IDEDidComputeMac32BitWarning</key>
|
|
||||||
<true/>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
@@ -1,67 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<Scheme
|
|
||||||
LastUpgradeVersion = "1330"
|
|
||||||
version = "1.3">
|
|
||||||
<BuildAction
|
|
||||||
parallelizeBuildables = "YES"
|
|
||||||
buildImplicitDependencies = "YES">
|
|
||||||
<BuildActionEntries>
|
|
||||||
<BuildActionEntry
|
|
||||||
buildForTesting = "YES"
|
|
||||||
buildForRunning = "YES"
|
|
||||||
buildForProfiling = "YES"
|
|
||||||
buildForArchiving = "YES"
|
|
||||||
buildForAnalyzing = "YES">
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "CF73D335241F9C23000B1B10"
|
|
||||||
BuildableName = "Alderis.framework"
|
|
||||||
BlueprintName = "Alderis"
|
|
||||||
ReferencedContainer = "container:Alderis.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</BuildActionEntry>
|
|
||||||
</BuildActionEntries>
|
|
||||||
</BuildAction>
|
|
||||||
<TestAction
|
|
||||||
buildConfiguration = "Debug"
|
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
|
||||||
<Testables>
|
|
||||||
</Testables>
|
|
||||||
</TestAction>
|
|
||||||
<LaunchAction
|
|
||||||
buildConfiguration = "Debug"
|
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
|
||||||
launchStyle = "0"
|
|
||||||
useCustomWorkingDirectory = "NO"
|
|
||||||
ignoresPersistentStateOnLaunch = "NO"
|
|
||||||
debugDocumentVersioning = "YES"
|
|
||||||
debugServiceExtension = "internal"
|
|
||||||
allowLocationSimulation = "YES">
|
|
||||||
</LaunchAction>
|
|
||||||
<ProfileAction
|
|
||||||
buildConfiguration = "Release"
|
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
|
||||||
savedToolIdentifier = ""
|
|
||||||
useCustomWorkingDirectory = "NO"
|
|
||||||
debugDocumentVersioning = "YES">
|
|
||||||
<MacroExpansion>
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "CF73D335241F9C23000B1B10"
|
|
||||||
BuildableName = "Alderis.framework"
|
|
||||||
BlueprintName = "Alderis"
|
|
||||||
ReferencedContainer = "container:Alderis.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</MacroExpansion>
|
|
||||||
</ProfileAction>
|
|
||||||
<AnalyzeAction
|
|
||||||
buildConfiguration = "Debug">
|
|
||||||
</AnalyzeAction>
|
|
||||||
<ArchiveAction
|
|
||||||
buildConfiguration = "Release"
|
|
||||||
revealArchiveInOrganizer = "YES">
|
|
||||||
</ArchiveAction>
|
|
||||||
</Scheme>
|
|
@@ -1,77 +0,0 @@
|
|||||||
//
|
|
||||||
// AccessibilityComplianceLabel.swift
|
|
||||||
// Alderis
|
|
||||||
//
|
|
||||||
// Created by Adam Demasi on 8/5/2022.
|
|
||||||
// Copyright © 2022 HASHBANG Productions. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import UIKit
|
|
||||||
|
|
||||||
internal class AccessibilityComplianceLabel: UIView {
|
|
||||||
|
|
||||||
var text: String {
|
|
||||||
get { label.text! }
|
|
||||||
set { label.text = newValue }
|
|
||||||
}
|
|
||||||
|
|
||||||
var isCompliant = false {
|
|
||||||
didSet { updateState() }
|
|
||||||
}
|
|
||||||
|
|
||||||
private let tickImage = Assets.systemImage(named: "checkmark.circle.fill")
|
|
||||||
private let crossImage = Assets.systemImage(named: "xmark.circle.fill")
|
|
||||||
|
|
||||||
private var imageView: UIImageView!
|
|
||||||
private var label: UILabel!
|
|
||||||
|
|
||||||
override init(frame: CGRect) {
|
|
||||||
super.init(frame: frame)
|
|
||||||
|
|
||||||
let font = UIFont.systemFont(ofSize: UIFloat(16), weight: .medium)
|
|
||||||
|
|
||||||
imageView = UIImageView()
|
|
||||||
if #available(iOS 13, *) {
|
|
||||||
imageView.preferredSymbolConfiguration = UIImage.SymbolConfiguration(font: font, scale: .small)
|
|
||||||
}
|
|
||||||
|
|
||||||
label = UILabel()
|
|
||||||
label.font = font
|
|
||||||
|
|
||||||
let stackView = UIStackView(arrangedSubviews: [imageView, label])
|
|
||||||
stackView.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
stackView.alignment = .center
|
|
||||||
stackView.spacing = UIFloat(6)
|
|
||||||
addSubview(stackView)
|
|
||||||
|
|
||||||
NSLayoutConstraint.activate([
|
|
||||||
stackView.topAnchor.constraint(equalTo: self.topAnchor),
|
|
||||||
stackView.bottomAnchor.constraint(equalTo: self.bottomAnchor),
|
|
||||||
stackView.leadingAnchor.constraint(equalTo: self.leadingAnchor),
|
|
||||||
stackView.trailingAnchor.constraint(equalTo: self.trailingAnchor)
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
convenience init(text: String) {
|
|
||||||
self.init(frame: .zero)
|
|
||||||
self.text = text
|
|
||||||
}
|
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
|
||||||
fatalError("init(coder:) has not been implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
private func updateState() {
|
|
||||||
let color = isCompliant ? Assets.green : Assets.red
|
|
||||||
|
|
||||||
tintColor = color
|
|
||||||
accessibilityLabel = "\(text): \(isCompliant ? "Compliant" : "Not compliant")"
|
|
||||||
imageView.image = isCompliant ? tickImage : crossImage
|
|
||||||
}
|
|
||||||
|
|
||||||
override func tintColorDidChange() {
|
|
||||||
super.tintColorDidChange()
|
|
||||||
label.textColor = tintColor
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@@ -1,91 +0,0 @@
|
|||||||
//
|
|
||||||
// AccessibilityContrastSelector.swift
|
|
||||||
// Alderis
|
|
||||||
//
|
|
||||||
// Created by Adam Demasi on 8/5/2022.
|
|
||||||
// Copyright © 2022 HASHBANG Productions. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import UIKit
|
|
||||||
|
|
||||||
internal class AccessibilityContrastSelector: UIView {
|
|
||||||
|
|
||||||
enum Mode: Int, CaseIterable {
|
|
||||||
case color, black, white
|
|
||||||
|
|
||||||
var label: String {
|
|
||||||
switch self {
|
|
||||||
case .color: return "Color"
|
|
||||||
case .black: return "Black"
|
|
||||||
case .white: return "White"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func color(withColor color: Color) -> Color {
|
|
||||||
switch self {
|
|
||||||
case .color: return color
|
|
||||||
case .black: return .black
|
|
||||||
case .white: return .white
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var text: String {
|
|
||||||
get { label.text! }
|
|
||||||
set { label.text = newValue }
|
|
||||||
}
|
|
||||||
|
|
||||||
var value: Mode = .white {
|
|
||||||
didSet {
|
|
||||||
if segmentedControl.selectedSegmentIndex != value.rawValue {
|
|
||||||
segmentedControl.selectedSegmentIndex = value.rawValue
|
|
||||||
handleChange?(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var handleChange: ((Mode) -> Void)?
|
|
||||||
|
|
||||||
private var label: UILabel!
|
|
||||||
private var segmentedControl: UISegmentedControl!
|
|
||||||
|
|
||||||
override init(frame: CGRect) {
|
|
||||||
super.init(frame: frame)
|
|
||||||
|
|
||||||
label = UILabel()
|
|
||||||
label.font = UIFont.systemFont(ofSize: UIFloat(16), weight: .medium)
|
|
||||||
|
|
||||||
segmentedControl = UISegmentedControl(items: Mode.allCases.map(\.label))
|
|
||||||
segmentedControl.addTarget(self, action: #selector(handleValueChanged), for: .valueChanged)
|
|
||||||
|
|
||||||
let stackView = UIStackView(arrangedSubviews: [label, UIView(), segmentedControl])
|
|
||||||
stackView.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
stackView.alignment = .center
|
|
||||||
stackView.distribution = .fill
|
|
||||||
stackView.spacing = UIFloat(5)
|
|
||||||
addSubview(stackView)
|
|
||||||
|
|
||||||
NSLayoutConstraint.activate([
|
|
||||||
stackView.topAnchor.constraint(equalTo: self.topAnchor),
|
|
||||||
stackView.bottomAnchor.constraint(equalTo: self.bottomAnchor),
|
|
||||||
stackView.leadingAnchor.constraint(equalTo: self.leadingAnchor),
|
|
||||||
stackView.trailingAnchor.constraint(equalTo: self.trailingAnchor)
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
|
||||||
fatalError("init(coder:) has not been implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
convenience init(text: String, value: Mode) {
|
|
||||||
self.init(frame: .zero)
|
|
||||||
self.text = text
|
|
||||||
self.value = value
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc private func handleValueChanged() {
|
|
||||||
value = Mode(rawValue: segmentedControl.selectedSegmentIndex)!
|
|
||||||
handleChange?(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@@ -1,11 +0,0 @@
|
|||||||
//
|
|
||||||
// Alderis.h
|
|
||||||
// Alderis
|
|
||||||
//
|
|
||||||
// Created by Adam Demasi on 16/3/20.
|
|
||||||
// Copyright © 2020 HASHBANG Productions. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
@import UIKit;
|
|
||||||
|
|
||||||
#import "AlderisSDKCompatibility.h"
|
|
@@ -1,21 +0,0 @@
|
|||||||
//
|
|
||||||
// AlderisSDKCompatibility.h
|
|
||||||
// Alderis
|
|
||||||
//
|
|
||||||
// Created by Adam Demasi on 3/10/20.
|
|
||||||
// Copyright © 2020 HASHBANG Productions. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
@import UIKit;
|
|
||||||
|
|
||||||
#ifndef __IPHONE_14_0
|
|
||||||
// Allows building with the iOS 13 SDK while retaining iOS 14 compatibility.
|
|
||||||
|
|
||||||
@interface UIControl ()
|
|
||||||
|
|
||||||
- (void)addAction:(UIAction *)action forControlEvents:(UIControlEvents)controlEvents NS_SWIFT_NAME(addAction(_:for:)) API_AVAILABLE(ios(14.0));
|
|
||||||
- (void)removeAction:(UIAction *)action forControlEvents:(UIControlEvents)controlEvents NS_SWIFT_NAME(removeAction(_:for:)) API_AVAILABLE(ios(14.0));
|
|
||||||
- (void)removeActionForIdentifier:(UIActionIdentifier)actionIdentifier forControlEvents:(UIControlEvents)controlEvents NS_SWIFT_NAME(removeAction(identifiedBy:for:)) API_AVAILABLE(ios(14.0));
|
|
||||||
|
|
||||||
@end
|
|
||||||
#endif
|
|
@@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"info" : {
|
|
||||||
"version" : 1,
|
|
||||||
"author" : "xcode"
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,26 +0,0 @@
|
|||||||
{
|
|
||||||
"images" : [
|
|
||||||
{
|
|
||||||
"idiom" : "universal",
|
|
||||||
"filename" : "sun.max.png",
|
|
||||||
"scale" : "1x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom" : "universal",
|
|
||||||
"filename" : "sun.max@2x.png",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom" : "universal",
|
|
||||||
"filename" : "sun.max@3x.png",
|
|
||||||
"scale" : "3x"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info" : {
|
|
||||||
"version" : 1,
|
|
||||||
"author" : "xcode"
|
|
||||||
},
|
|
||||||
"properties" : {
|
|
||||||
"template-rendering-intent" : "template"
|
|
||||||
}
|
|
||||||
}
|
|
Before Width: | Height: | Size: 310 B |
Before Width: | Height: | Size: 661 B |
Before Width: | Height: | Size: 942 B |
@@ -1,26 +0,0 @@
|
|||||||
{
|
|
||||||
"images" : [
|
|
||||||
{
|
|
||||||
"idiom" : "universal",
|
|
||||||
"filename" : "sun.min.png",
|
|
||||||
"scale" : "1x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom" : "universal",
|
|
||||||
"filename" : "sun.min@2x.png",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom" : "universal",
|
|
||||||
"filename" : "sun.min@3x.png",
|
|
||||||
"scale" : "3x"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info" : {
|
|
||||||
"version" : 1,
|
|
||||||
"author" : "xcode"
|
|
||||||
},
|
|
||||||
"properties" : {
|
|
||||||
"template-rendering-intent" : "template"
|
|
||||||
}
|
|
||||||
}
|
|
Before Width: | Height: | Size: 307 B |
Before Width: | Height: | Size: 606 B |
Before Width: | Height: | Size: 909 B |
@@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"info" : {
|
|
||||||
"author" : "xcode",
|
|
||||||
"version" : 1
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"info" : {
|
|
||||||
"author" : "xcode",
|
|
||||||
"version" : 1
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,26 +0,0 @@
|
|||||||
{
|
|
||||||
"images" : [
|
|
||||||
{
|
|
||||||
"filename" : "checkmark.circle.fill.png",
|
|
||||||
"idiom" : "universal",
|
|
||||||
"scale" : "1x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "checkmark.circle.fill@2x.png",
|
|
||||||
"idiom" : "universal",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "checkmark.circle.fill@3x.png",
|
|
||||||
"idiom" : "universal",
|
|
||||||
"scale" : "3x"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info" : {
|
|
||||||
"author" : "xcode",
|
|
||||||
"version" : 1
|
|
||||||
},
|
|
||||||
"properties" : {
|
|
||||||
"template-rendering-intent" : "template"
|
|
||||||
}
|
|
||||||
}
|
|
Before Width: | Height: | Size: 169 B |
Before Width: | Height: | Size: 287 B |
Before Width: | Height: | Size: 377 B |
@@ -1,26 +0,0 @@
|
|||||||
{
|
|
||||||
"images" : [
|
|
||||||
{
|
|
||||||
"filename" : "sparkles.png",
|
|
||||||
"idiom" : "universal",
|
|
||||||
"scale" : "1x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "sparkles@2x.png",
|
|
||||||
"idiom" : "universal",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "sparkles@3x.png",
|
|
||||||
"idiom" : "universal",
|
|
||||||
"scale" : "3x"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info" : {
|
|
||||||
"author" : "xcode",
|
|
||||||
"version" : 1
|
|
||||||
},
|
|
||||||
"properties" : {
|
|
||||||
"template-rendering-intent" : "template"
|
|
||||||
}
|
|
||||||
}
|
|
Before Width: | Height: | Size: 184 B |
Before Width: | Height: | Size: 324 B |
Before Width: | Height: | Size: 427 B |
@@ -1,26 +0,0 @@
|
|||||||
{
|
|
||||||
"images" : [
|
|
||||||
{
|
|
||||||
"filename" : "xmark.circle.fill.png",
|
|
||||||
"idiom" : "universal",
|
|
||||||
"scale" : "1x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "xmark.circle.fill@2x.png",
|
|
||||||
"idiom" : "universal",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "xmark.circle.fill@3x.png",
|
|
||||||
"idiom" : "universal",
|
|
||||||
"scale" : "3x"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info" : {
|
|
||||||
"author" : "xcode",
|
|
||||||
"version" : 1
|
|
||||||
},
|
|
||||||
"properties" : {
|
|
||||||
"template-rendering-intent" : "template"
|
|
||||||
}
|
|
||||||
}
|
|
Before Width: | Height: | Size: 164 B |
Before Width: | Height: | Size: 274 B |
Before Width: | Height: | Size: 383 B |
@@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"info" : {
|
|
||||||
"author" : "xcode",
|
|
||||||
"version" : 1
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,26 +0,0 @@
|
|||||||
{
|
|
||||||
"images" : [
|
|
||||||
{
|
|
||||||
"filename" : "circle.righthalf.fill.png",
|
|
||||||
"idiom" : "universal",
|
|
||||||
"scale" : "1x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "circle.righthalf.fill@2x.png",
|
|
||||||
"idiom" : "universal",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "circle.righthalf.fill@3x.png",
|
|
||||||
"idiom" : "universal",
|
|
||||||
"scale" : "3x"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info" : {
|
|
||||||
"author" : "xcode",
|
|
||||||
"version" : 1
|
|
||||||
},
|
|
||||||
"properties" : {
|
|
||||||
"template-rendering-intent" : "template"
|
|
||||||
}
|
|
||||||
}
|
|
Before Width: | Height: | Size: 229 B |
Before Width: | Height: | Size: 385 B |
Before Width: | Height: | Size: 574 B |
@@ -1,26 +0,0 @@
|
|||||||
{
|
|
||||||
"images" : [
|
|
||||||
{
|
|
||||||
"filename" : "slider.horizontal.3.png",
|
|
||||||
"idiom" : "universal",
|
|
||||||
"scale" : "1x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "slider.horizontal.3@2x.png",
|
|
||||||
"idiom" : "universal",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "slider.horizontal.3@3x.png",
|
|
||||||
"idiom" : "universal",
|
|
||||||
"scale" : "3x"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info" : {
|
|
||||||
"author" : "xcode",
|
|
||||||
"version" : 1
|
|
||||||
},
|
|
||||||
"properties" : {
|
|
||||||
"template-rendering-intent" : "template"
|
|
||||||
}
|
|
||||||
}
|
|
Before Width: | Height: | Size: 208 B |
Before Width: | Height: | Size: 361 B |
Before Width: | Height: | Size: 507 B |
@@ -1,26 +0,0 @@
|
|||||||
{
|
|
||||||
"images" : [
|
|
||||||
{
|
|
||||||
"filename" : "slider.horizontal.below.rectangle.png",
|
|
||||||
"idiom" : "universal",
|
|
||||||
"scale" : "1x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "slider.horizontal.below.rectangle@2x.png",
|
|
||||||
"idiom" : "universal",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "slider.horizontal.below.rectangle@3x.png",
|
|
||||||
"idiom" : "universal",
|
|
||||||
"scale" : "3x"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info" : {
|
|
||||||
"author" : "xcode",
|
|
||||||
"version" : 1
|
|
||||||
},
|
|
||||||
"properties" : {
|
|
||||||
"template-rendering-intent" : "template"
|
|
||||||
}
|
|
||||||
}
|
|
Before Width: | Height: | Size: 189 B |
Before Width: | Height: | Size: 309 B |
Before Width: | Height: | Size: 412 B |
@@ -1,26 +0,0 @@
|
|||||||
{
|
|
||||||
"images" : [
|
|
||||||
{
|
|
||||||
"filename" : "square.grid.4x3.fill.png",
|
|
||||||
"idiom" : "universal",
|
|
||||||
"scale" : "1x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "square.grid.4x3.fill@2x.png",
|
|
||||||
"idiom" : "universal",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "square.grid.4x3.fill@3x.png",
|
|
||||||
"idiom" : "universal",
|
|
||||||
"scale" : "3x"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info" : {
|
|
||||||
"author" : "xcode",
|
|
||||||
"version" : 1
|
|
||||||
},
|
|
||||||
"properties" : {
|
|
||||||
"template-rendering-intent" : "template"
|
|
||||||
}
|
|
||||||
}
|
|
Before Width: | Height: | Size: 211 B |
Before Width: | Height: | Size: 289 B |
Before Width: | Height: | Size: 419 B |
@@ -1,135 +0,0 @@
|
|||||||
//
|
|
||||||
// Assets.swift
|
|
||||||
// Alderis
|
|
||||||
//
|
|
||||||
// Created by Adam Demasi on 27/9/20.
|
|
||||||
// Copyright © 2020 HASHBANG Productions. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import UIKit
|
|
||||||
|
|
||||||
internal struct Assets {
|
|
||||||
|
|
||||||
internal enum SymbolScale: Int {
|
|
||||||
case `default` = -1
|
|
||||||
case unspecified, small, medium, large
|
|
||||||
|
|
||||||
@available(iOS 13, *)
|
|
||||||
var uiImageSymbolScale: UIImage.SymbolScale { UIImage.SymbolScale(rawValue: rawValue)! }
|
|
||||||
}
|
|
||||||
|
|
||||||
private static let bundle: Bundle = {
|
|
||||||
let myBundle = Bundle(for: ColorPickerViewController.self)
|
|
||||||
if let resourcesURL = myBundle.url(forResource: "Alderis", withExtension: "bundle"),
|
|
||||||
let resourcesBundle = Bundle(url: resourcesURL) {
|
|
||||||
return resourcesBundle
|
|
||||||
}
|
|
||||||
return myBundle
|
|
||||||
}()
|
|
||||||
private static let uikitBundle = Bundle(for: UIView.self)
|
|
||||||
|
|
||||||
// MARK: - Localization
|
|
||||||
|
|
||||||
static func uikitLocalize(_ key: String) -> String {
|
|
||||||
uikitBundle.localizedString(forKey: key, value: nil, table: nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Images
|
|
||||||
|
|
||||||
static func systemImage(named name: String, font: UIFont? = nil, scale: SymbolScale = .default) -> UIImage? {
|
|
||||||
if #available(iOS 13, *) {
|
|
||||||
var configuration: UIImage.SymbolConfiguration?
|
|
||||||
if let font = font {
|
|
||||||
configuration = UIImage.SymbolConfiguration(font: font, scale: scale.uiImageSymbolScale)
|
|
||||||
}
|
|
||||||
return UIImage(systemName: name, withConfiguration: configuration)
|
|
||||||
}
|
|
||||||
return UIImage(named: name, in: bundle, compatibleWith: nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Fonts
|
|
||||||
|
|
||||||
static func niceMonospaceDigitFont(ofSize size: CGFloat) -> UIFont {
|
|
||||||
// Take the monospace digit font and enable stylistic alternative 6, which provides a
|
|
||||||
// high-legibility, monospace-looking style of the system font.
|
|
||||||
let font = UIFont.monospacedDigitSystemFont(ofSize: size, weight: .regular)
|
|
||||||
let fontDescriptor = font.fontDescriptor.addingAttributes([
|
|
||||||
.featureSettings: [
|
|
||||||
[
|
|
||||||
.alderisFeature: kStylisticAlternativesType,
|
|
||||||
.alderisSelector: kStylisticAltSixOnSelector
|
|
||||||
]
|
|
||||||
] as [[UIFontDescriptor.FeatureKey: Int]]
|
|
||||||
])
|
|
||||||
return UIFont(descriptor: fontDescriptor, size: 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Colors
|
|
||||||
|
|
||||||
private static func color(userInterfaceStyles colors: [UIUserInterfaceStyle: UIColor], fallback: UIUserInterfaceStyle = .light) -> UIColor {
|
|
||||||
if #available(iOS 13, *) {
|
|
||||||
return UIColor { colors[$0.userInterfaceStyle] ?? colors[fallback] ?? colors.values.first! }
|
|
||||||
}
|
|
||||||
return colors[fallback] ?? colors.values.first!
|
|
||||||
}
|
|
||||||
|
|
||||||
static let backdropColor = UIColor(white: 0, alpha: 0.2)
|
|
||||||
static let separatorColor = UIColor(white: 1, alpha: 0.15)
|
|
||||||
|
|
||||||
static let labelColor: UIColor = {
|
|
||||||
if #available(iOS 13, *) {
|
|
||||||
return .label
|
|
||||||
}
|
|
||||||
return .black
|
|
||||||
}()
|
|
||||||
|
|
||||||
static let secondaryLabelColor: UIColor = {
|
|
||||||
if #available(iOS 13, *) {
|
|
||||||
return .secondaryLabel
|
|
||||||
}
|
|
||||||
return UIColor(white: 60 / 255, alpha: 0.6)
|
|
||||||
}()
|
|
||||||
|
|
||||||
static let borderColor: UIColor = {
|
|
||||||
if #available(iOS 13, *) {
|
|
||||||
return .separator
|
|
||||||
}
|
|
||||||
return UIColor(white: 1, alpha: 0.35)
|
|
||||||
}()
|
|
||||||
|
|
||||||
@available(iOS 13, *)
|
|
||||||
static let macTabBarSelectionColor = color(userInterfaceStyles: [
|
|
||||||
.light: .black,
|
|
||||||
.dark: .label
|
|
||||||
])
|
|
||||||
|
|
||||||
static let red = UIColor.systemRed
|
|
||||||
|
|
||||||
// .systemGreen adjusted to be more consistent / easier to read
|
|
||||||
static let green = color(userInterfaceStyles: [
|
|
||||||
.light: UIColor(red: 15 / 255, green: 189 / 255, blue: 59 / 255, alpha: 1),
|
|
||||||
// swiftlint:disable:next colon
|
|
||||||
.dark: UIColor(red: 41 / 255, green: 179 / 255, blue: 76 / 255, alpha: 1)
|
|
||||||
])
|
|
||||||
|
|
||||||
static let checkerboardPatternColor = color(userInterfaceStyles: [
|
|
||||||
.light: renderCheckerboardPattern(colors: (UIColor(white: 200 / 255, alpha: 1),
|
|
||||||
UIColor(white: 255 / 255, alpha: 1))),
|
|
||||||
// swiftlint:disable:next colon
|
|
||||||
.dark: renderCheckerboardPattern(colors: (UIColor(white: 140 / 255, alpha: 1),
|
|
||||||
UIColor(white: 186 / 255, alpha: 1)))
|
|
||||||
])
|
|
||||||
|
|
||||||
private static func renderCheckerboardPattern(colors: (dark: UIColor, light: UIColor)) -> UIColor {
|
|
||||||
let size = 11
|
|
||||||
let image = UIGraphicsImageRenderer(size: CGSize(width: size * 2, height: size * 2)).image { context in
|
|
||||||
colors.dark.setFill()
|
|
||||||
context.fill(CGRect(x: 0, y: 0, width: size * 2, height: size * 2))
|
|
||||||
colors.light.setFill()
|
|
||||||
context.fill(CGRect(x: size, y: 0, width: size, height: size))
|
|
||||||
context.fill(CGRect(x: 0, y: size, width: size, height: size))
|
|
||||||
}
|
|
||||||
return UIColor(patternImage: image)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@@ -1,48 +0,0 @@
|
|||||||
//
|
|
||||||
// BottomSheetTransition.swift
|
|
||||||
// Alderis
|
|
||||||
//
|
|
||||||
// Created by Adam Demasi on 20/9/20.
|
|
||||||
// Copyright © 2020 HASHBANG Productions. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import UIKit
|
|
||||||
|
|
||||||
internal class BottomSheetTransitioningDelegate: NSObject, UIViewControllerTransitioningDelegate {
|
|
||||||
|
|
||||||
func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
|
|
||||||
return BottomSheetTransition(direction: true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
|
|
||||||
return BottomSheetTransition(direction: false)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class BottomSheetTransition: NSObject, UIViewControllerAnimatedTransitioning {
|
|
||||||
|
|
||||||
// Opening: true
|
|
||||||
// Closing: false
|
|
||||||
let direction: Bool
|
|
||||||
|
|
||||||
init(direction: Bool) {
|
|
||||||
self.direction = direction
|
|
||||||
}
|
|
||||||
|
|
||||||
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
|
|
||||||
0.4
|
|
||||||
}
|
|
||||||
|
|
||||||
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
|
|
||||||
if direction {
|
|
||||||
let to = transitionContext.viewController(forKey: .to)!
|
|
||||||
transitionContext.containerView.addSubview(to.view)
|
|
||||||
}
|
|
||||||
|
|
||||||
Timer.scheduledTimer(withTimeInterval: transitionDuration(using: transitionContext), repeats: false) { _ in
|
|
||||||
transitionContext.completeTransition(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@@ -1,342 +0,0 @@
|
|||||||
//
|
|
||||||
// Color.swift
|
|
||||||
// Alderis
|
|
||||||
//
|
|
||||||
// Created by Adam Demasi on 15/3/20.
|
|
||||||
// Copyright © 2020 HASHBANG Productions. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import UIKit
|
|
||||||
|
|
||||||
internal struct Color: Equatable, Hashable {
|
|
||||||
static let black = Color(white: 0, alpha: 1)
|
|
||||||
static let white = Color(white: 1, alpha: 1)
|
|
||||||
|
|
||||||
var red: CGFloat = 0 {
|
|
||||||
didSet {
|
|
||||||
self = Color(red: red, green: green, blue: blue, alpha: alpha)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var green: CGFloat = 0 {
|
|
||||||
didSet {
|
|
||||||
self = Color(red: red, green: green, blue: blue, alpha: alpha)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var blue: CGFloat = 0 {
|
|
||||||
didSet {
|
|
||||||
self = Color(red: red, green: green, blue: blue, alpha: alpha)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var hue: CGFloat = 0 {
|
|
||||||
didSet {
|
|
||||||
self = Color(hue: hue, saturation: saturation, brightness: brightness, alpha: alpha)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var saturation: CGFloat = 0 {
|
|
||||||
didSet {
|
|
||||||
self = Color(hue: hue, saturation: saturation, brightness: brightness, alpha: alpha)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var brightness: CGFloat = 0 {
|
|
||||||
didSet {
|
|
||||||
self = Color(hue: hue, saturation: saturation, brightness: brightness, alpha: alpha)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var hslSaturation: CGFloat = 0 {
|
|
||||||
didSet {
|
|
||||||
self = Color(hue: hue, saturation: hslSaturation, lightness: lightness, alpha: alpha)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var lightness: CGFloat = 0 {
|
|
||||||
didSet {
|
|
||||||
self = Color(hue: hue, saturation: hslSaturation, lightness: lightness, alpha: alpha)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var white: CGFloat = 0 {
|
|
||||||
didSet {
|
|
||||||
self = Color(white: white, alpha: alpha)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var alpha: CGFloat = 0
|
|
||||||
|
|
||||||
static func == (lhs: Color, rhs: Color) -> Bool {
|
|
||||||
lhs.red == rhs.red &&
|
|
||||||
lhs.green == rhs.green &&
|
|
||||||
lhs.blue == rhs.blue &&
|
|
||||||
lhs.alpha == rhs.alpha
|
|
||||||
}
|
|
||||||
|
|
||||||
func hash(into hasher: inout Hasher) {
|
|
||||||
hasher.combine(red)
|
|
||||||
hasher.combine(green)
|
|
||||||
hasher.combine(blue)
|
|
||||||
hasher.combine(alpha)
|
|
||||||
}
|
|
||||||
|
|
||||||
var uiColor: UIColor { .init(red: red, green: green, blue: blue, alpha: alpha) }
|
|
||||||
|
|
||||||
init(uiColor: UIColor) {
|
|
||||||
uiColor.getRed(&red, green: &green, blue: &blue, alpha: &alpha)
|
|
||||||
uiColor.getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: nil)
|
|
||||||
self.white = brightness
|
|
||||||
(self.hslSaturation, self.lightness) = hslValue
|
|
||||||
}
|
|
||||||
|
|
||||||
init(red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) {
|
|
||||||
self.red = red
|
|
||||||
self.green = green
|
|
||||||
self.blue = blue
|
|
||||||
self.alpha = alpha
|
|
||||||
let uiColor = UIColor(red: red, green: green, blue: blue, alpha: alpha)
|
|
||||||
uiColor.getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: nil)
|
|
||||||
self.white = brightness
|
|
||||||
(self.hslSaturation, self.lightness) = hslValue
|
|
||||||
}
|
|
||||||
|
|
||||||
init(white: CGFloat, alpha: CGFloat) {
|
|
||||||
self.init(red: white, green: white, blue: white, alpha: alpha)
|
|
||||||
}
|
|
||||||
|
|
||||||
init(hue: CGFloat, saturation: CGFloat, brightness: CGFloat, alpha: CGFloat) {
|
|
||||||
self.hue = hue
|
|
||||||
self.saturation = saturation
|
|
||||||
self.brightness = brightness
|
|
||||||
self.white = brightness
|
|
||||||
self.alpha = alpha
|
|
||||||
let uiColor = UIColor(hue: hue, saturation: saturation, brightness: brightness, alpha: alpha)
|
|
||||||
uiColor.getRed(&red, green: &green, blue: &blue, alpha: nil)
|
|
||||||
(self.hslSaturation, self.lightness) = hslValue
|
|
||||||
}
|
|
||||||
|
|
||||||
init(hue: CGFloat, saturation: CGFloat, lightness: CGFloat, alpha: CGFloat) {
|
|
||||||
self.hue = hue
|
|
||||||
self.hslSaturation = saturation
|
|
||||||
self.lightness = lightness
|
|
||||||
self.alpha = alpha
|
|
||||||
(self.saturation, self.brightness) = hsbValue
|
|
||||||
let uiColor = UIColor(hue: hue, saturation: self.saturation, brightness: self.brightness, alpha: alpha)
|
|
||||||
uiColor.getRed(&red, green: &green, blue: &blue, alpha: nil)
|
|
||||||
self.white = brightness
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Color {
|
|
||||||
static var brightnessThreshold: CGFloat {
|
|
||||||
// Accessibility enabled: conforms to WCAG 2.1 AAA
|
|
||||||
// Accessibility disabled: conforms to WCAG 2.1 AA
|
|
||||||
UIAccessibility.isDarkerSystemColorsEnabled ? 7 : 4.5
|
|
||||||
}
|
|
||||||
|
|
||||||
var relativeLuminanceValues: (red: CGFloat, green: CGFloat, blue: CGFloat) {
|
|
||||||
// https://www.w3.org/TR/WCAG21/#dfn-relative-luminance
|
|
||||||
let values = [red, green, blue]
|
|
||||||
.map { $0 <= 0.03928 ? $0 / 12.92 : pow((($0 + 0.055) / 1.055), 2.4) }
|
|
||||||
return (values[0], values[1], values[2])
|
|
||||||
}
|
|
||||||
|
|
||||||
var relativeLuminance: CGFloat {
|
|
||||||
// https://www.w3.org/TR/WCAG21/#dfn-relative-luminance
|
|
||||||
let (r, g, b) = relativeLuminanceValues
|
|
||||||
return (r * 0.2126) + (g * 0.7152) + (b * 0.0722)
|
|
||||||
}
|
|
||||||
|
|
||||||
func perceivedBrightness(onBackgroundColor background: Color) -> CGFloat {
|
|
||||||
// https://www.w3.org/TR/WCAG21/#dfn-contrast-ratio - between 0-21
|
|
||||||
let a = relativeLuminance + 0.05
|
|
||||||
let b = background.relativeLuminance + 0.05
|
|
||||||
return a > b ? a / b : b / a
|
|
||||||
}
|
|
||||||
|
|
||||||
var isDark: Bool { perceivedBrightness(onBackgroundColor: .white) > Self.brightnessThreshold && alpha > 0.5 }
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Color {
|
|
||||||
struct HexOptions: OptionSet {
|
|
||||||
let rawValue: Int
|
|
||||||
static let allowShorthand = Self(rawValue: 1 << 0)
|
|
||||||
static let forceAlpha = Self(rawValue: 1 << 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// if the character in `value` is repeated, `repeatedValue` is a single copy of that character. If
|
|
||||||
// `value` consists of two unique characters, `repeatedValue` is nil
|
|
||||||
// e.g. valid return values are `("AA", "A")` and `("AB", nil)`
|
|
||||||
private func hex(_ val: CGFloat) -> (value: String, repeatedValue: Character?) {
|
|
||||||
let byte = Int(val * 255) & 0xFF
|
|
||||||
let isRepeated = (byte & 0xF) == (byte >> 4)
|
|
||||||
let value = String(format: "%02X", byte)
|
|
||||||
return (value, isRepeated ? value.first : nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func hexString(with options: HexOptions = []) -> String {
|
|
||||||
let (r, rRep) = hex(red)
|
|
||||||
let (g, gRep) = hex(green)
|
|
||||||
let (b, bRep) = hex(blue)
|
|
||||||
let (a, aRep) = hex(alpha)
|
|
||||||
let showAlpha = options.contains(.forceAlpha) || alpha != 1
|
|
||||||
if options.contains(.allowShorthand),
|
|
||||||
let rRep = rRep, let gRep = gRep, let bRep = bRep, let aRep = aRep {
|
|
||||||
return "#\(rRep)\(gRep)\(bRep)\(showAlpha ? "\(aRep)" : "")"
|
|
||||||
} else {
|
|
||||||
return "#\(r)\(g)\(b)\(showAlpha ? a : "")"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var hexString: String { hexString() }
|
|
||||||
|
|
||||||
var hslValue: (saturation: CGFloat, lightness: CGFloat) {
|
|
||||||
let lightness = brightness - (brightness * (saturation / 2))
|
|
||||||
var saturation = min(lightness, 1 - lightness)
|
|
||||||
saturation = saturation == 0 ? 0 : (brightness - lightness) / saturation
|
|
||||||
return (saturation, lightness)
|
|
||||||
}
|
|
||||||
|
|
||||||
var hsbValue: (saturation: CGFloat, brightness: CGFloat) {
|
|
||||||
let brightness = hslSaturation * min(lightness, 1 - lightness) + lightness
|
|
||||||
let saturation = brightness == 0 ? 0 : 2 - 2 * lightness / brightness
|
|
||||||
return (saturation, brightness)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func cssString(function: String, params: [String?]) -> String {
|
|
||||||
let filteredParams = params.compactMap { $0 }
|
|
||||||
return "\(function)\(filteredParams.count == 4 ? "a" : "")(\(filteredParams.joined(separator: ", ")))"
|
|
||||||
}
|
|
||||||
|
|
||||||
var rgbString: String {
|
|
||||||
cssString(function: "rgb", params: [
|
|
||||||
"\(Int(red * 255))",
|
|
||||||
"\(Int(green * 255))",
|
|
||||||
"\(Int(blue * 255))",
|
|
||||||
alpha == 1 ? nil : String(format: "%.2f", alpha)
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
var hslString: String {
|
|
||||||
cssString(function: "hsl", params: [
|
|
||||||
"\(Int(hue * 360))",
|
|
||||||
"\(Int(hslSaturation * 100))%",
|
|
||||||
"\(Int(lightness * 100))%",
|
|
||||||
alpha == 1 ? nil : String(format: "%.2f", alpha)
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
var objcString: String {
|
|
||||||
red == green && green == blue
|
|
||||||
? String(format: "[UIColor colorWithWhite:%.3f alpha:%.2f]", white, alpha)
|
|
||||||
: String(format: "[UIColor colorWithRed:%.3f green:%.3f blue:%.3f alpha:%.2f]", red, green, blue, alpha)
|
|
||||||
}
|
|
||||||
|
|
||||||
var swiftString: String {
|
|
||||||
red == green && green == blue
|
|
||||||
? String(format: "UIColor(white: %.3f, alpha: %.3f", white, alpha)
|
|
||||||
// swiftlint:disable:next color_init
|
|
||||||
: String(format: "UIColor(red: %.3f, green: %.3f, blue: %.3f, alpha: %.2f)", red, green, blue, alpha)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Color {
|
|
||||||
struct Component {
|
|
||||||
let keyPath: WritableKeyPath<Color, CGFloat>
|
|
||||||
let limit: CGFloat
|
|
||||||
let title: String
|
|
||||||
private let sliderTintColorForColor: (Color) -> [Color]
|
|
||||||
|
|
||||||
init(
|
|
||||||
keyPath: WritableKeyPath<Color, CGFloat>,
|
|
||||||
limit: CGFloat,
|
|
||||||
title: String,
|
|
||||||
sliderTintColorForColor: @escaping (Color) -> [Color]
|
|
||||||
) {
|
|
||||||
self.keyPath = keyPath
|
|
||||||
self.limit = limit
|
|
||||||
self.title = title
|
|
||||||
self.sliderTintColorForColor = sliderTintColorForColor
|
|
||||||
}
|
|
||||||
|
|
||||||
init(
|
|
||||||
keyPath: WritableKeyPath<Color, CGFloat>,
|
|
||||||
limit: CGFloat,
|
|
||||||
title: String,
|
|
||||||
sliderTint: [Color]
|
|
||||||
) {
|
|
||||||
self.keyPath = keyPath
|
|
||||||
self.limit = limit
|
|
||||||
self.title = title
|
|
||||||
self.sliderTintColorForColor = { _ in sliderTint }
|
|
||||||
}
|
|
||||||
|
|
||||||
func sliderTintColor(for color: Color) -> [Color] {
|
|
||||||
sliderTintColorForColor(color)
|
|
||||||
}
|
|
||||||
|
|
||||||
static let red: Component = .init(keyPath: \.red, limit: 255, title: "Red") { color in
|
|
||||||
[
|
|
||||||
Color(red: 0, green: color.green, blue: color.blue, alpha: 1),
|
|
||||||
Color(red: 1, green: color.green, blue: color.blue, alpha: 1)
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
static let green: Component = .init(keyPath: \.green, limit: 255, title: "Green") { color in
|
|
||||||
[
|
|
||||||
Color(red: color.red, green: 0, blue: color.blue, alpha: 1),
|
|
||||||
Color(red: color.red, green: 1, blue: color.blue, alpha: 1)
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
static let blue: Component = .init(keyPath: \.blue, limit: 255, title: "Blue") { color in
|
|
||||||
[
|
|
||||||
Color(red: color.red, green: color.green, blue: 0, alpha: 1),
|
|
||||||
Color(red: color.red, green: color.green, blue: 1, alpha: 1)
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
static let hue: Component = .init(keyPath: \.hue, limit: 360, title: "Hue") { color in
|
|
||||||
Array(0...8).map { Color(hue: CGFloat($0) * 45 / 360, saturation: color.saturation, brightness: color.brightness, alpha: 1) }
|
|
||||||
}
|
|
||||||
|
|
||||||
static let saturation: Component = .init(keyPath: \.saturation, limit: 100, title: "Satur.") { color in
|
|
||||||
[
|
|
||||||
.white,
|
|
||||||
Color(hue: color.hue, saturation: 1, brightness: color.brightness, alpha: 1)
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
static let brightness: Component = .init(keyPath: \.brightness, limit: 100, title: "Bright") { color in
|
|
||||||
[
|
|
||||||
.black,
|
|
||||||
Color(hue: color.hue, saturation: color.saturation, brightness: 1, alpha: 1)
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
static let hslSaturation: Component = .init(keyPath: \.hslSaturation, limit: 100, title: "Satur.") { color in
|
|
||||||
[
|
|
||||||
Color(hue: color.hue, saturation: 0, lightness: color.lightness, alpha: 1),
|
|
||||||
Color(hue: color.hue, saturation: 1, lightness: color.lightness, alpha: 1)
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
static let lightness: Component = .init(keyPath: \.lightness, limit: 100, title: "Light") { color in
|
|
||||||
[
|
|
||||||
.black,
|
|
||||||
Color(hue: color.hue, saturation: color.hslSaturation, lightness: 0.5, alpha: 1),
|
|
||||||
.white
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
static let white: Component = .init(keyPath: \.white, limit: 255, title: "White") { _ in
|
|
||||||
[
|
|
||||||
.black,
|
|
||||||
.white
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
static let alpha: Component = .init(keyPath: \.alpha, limit: 100, title: "Alpha") { color in
|
|
||||||
[
|
|
||||||
Color(red: color.red, green: color.green, blue: color.blue, alpha: 0),
|
|
||||||
Color(red: color.red, green: color.green, blue: color.blue, alpha: 1)
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,218 +0,0 @@
|
|||||||
//
|
|
||||||
// ColorPickerAccessibilityViewController.swift
|
|
||||||
// Alderis
|
|
||||||
//
|
|
||||||
// Created by Adam Demasi on 8/5/2022.
|
|
||||||
// Copyright © 2022 HASHBANG Productions. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import UIKit
|
|
||||||
|
|
||||||
internal class ColorPickerAccessibilityViewController: ColorPickerTabViewController {
|
|
||||||
|
|
||||||
static let title = "Contrast Checker"
|
|
||||||
static let imageName = "circle.righthalf.fill"
|
|
||||||
|
|
||||||
private static let percentFormatter: NumberFormatter = {
|
|
||||||
let formatter = NumberFormatter()
|
|
||||||
formatter.numberStyle = .percent
|
|
||||||
return formatter
|
|
||||||
}()
|
|
||||||
|
|
||||||
private var backgroundMode: AccessibilityContrastSelector.Mode = .white {
|
|
||||||
didSet { colorDidChange() }
|
|
||||||
}
|
|
||||||
private var foregroundMode: AccessibilityContrastSelector.Mode = .color {
|
|
||||||
didSet { colorDidChange() }
|
|
||||||
}
|
|
||||||
|
|
||||||
private var scrollView: UIScrollView!
|
|
||||||
|
|
||||||
private var demoContainerView: UIView!
|
|
||||||
private var demoLabels: [UIView]!
|
|
||||||
|
|
||||||
private var contrastStackView: UIStackView!
|
|
||||||
private var contrastRatioLabel: UILabel!
|
|
||||||
private var aaComplianceLabel: AccessibilityComplianceLabel!
|
|
||||||
private var aaaComplianceLabel: AccessibilityComplianceLabel!
|
|
||||||
|
|
||||||
private var backgroundSelector: AccessibilityContrastSelector!
|
|
||||||
private var foregroundSelector: AccessibilityContrastSelector!
|
|
||||||
|
|
||||||
override func viewDidLoad() {
|
|
||||||
super.viewDidLoad()
|
|
||||||
|
|
||||||
// Catalyst in iPad UI mode scales all UI down to 77%, so we cancel out the scaling (as well as
|
|
||||||
// we possibly can, given scaling down is throwing away quality) for the demo labels.
|
|
||||||
let scaleFactor: CGFloat = isCatalystPad ? 1 / 0.77 : 1
|
|
||||||
|
|
||||||
let demoTitleLabel = UILabel()
|
|
||||||
demoTitleLabel.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
demoTitleLabel.font = .systemFont(ofSize: 18 * scaleFactor, weight: .semibold)
|
|
||||||
demoTitleLabel.text = "Size 18 • Contrast Checker"
|
|
||||||
|
|
||||||
let demoImageView = UIImageView(image: Assets.systemImage(named: "sparkles", font: demoTitleLabel.font, scale: .small))
|
|
||||||
demoImageView.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
|
|
||||||
let titleStackView = UIStackView(arrangedSubviews: [demoImageView, demoTitleLabel])
|
|
||||||
titleStackView.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
titleStackView.spacing = UIFloat(6)
|
|
||||||
titleStackView.alignment = .center
|
|
||||||
|
|
||||||
let demoSubtitleLabel = UILabel()
|
|
||||||
demoSubtitleLabel.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
demoSubtitleLabel.font = .systemFont(ofSize: 14 * scaleFactor, weight: .medium)
|
|
||||||
demoSubtitleLabel.text = "Size 14 • Contrast ratios are a measure of how easily text and images can be read, especially by people with lower vision."
|
|
||||||
demoSubtitleLabel.numberOfLines = 0
|
|
||||||
|
|
||||||
let demoTextLabel = TextViewLabel()
|
|
||||||
demoTextLabel.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
demoTextLabel.linkTextAttributes = [
|
|
||||||
.underlineStyle: NSUnderlineStyle.single.rawValue
|
|
||||||
]
|
|
||||||
let explainerText = "Size 12 • Learn more about minimum (AA) and enhanced (AAA) contrast."
|
|
||||||
let attributedString = NSMutableAttributedString(string: explainerText,
|
|
||||||
attributes: [
|
|
||||||
.font: UIFont.systemFont(ofSize: 12 * scaleFactor, weight: .regular)
|
|
||||||
])
|
|
||||||
attributedString.addAttribute(.link,
|
|
||||||
value: URL(string: "https://www.w3.org/WAI/WCAG21/Understanding/contrast-minimum")!,
|
|
||||||
range: (attributedString.string as NSString).range(of: "minimum (AA)"))
|
|
||||||
attributedString.addAttribute(.link,
|
|
||||||
value: URL(string: "https://www.w3.org/WAI/WCAG21/Understanding/contrast-enhanced")!,
|
|
||||||
range: (attributedString.string as NSString).range(of: "enhanced (AAA)"))
|
|
||||||
demoTextLabel.attributedText = attributedString
|
|
||||||
|
|
||||||
demoLabels = [demoTitleLabel, demoSubtitleLabel, demoTextLabel]
|
|
||||||
|
|
||||||
let demoStackView = UIStackView(arrangedSubviews: [titleStackView, demoSubtitleLabel, demoTextLabel])
|
|
||||||
demoStackView.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
demoStackView.axis = .vertical
|
|
||||||
demoStackView.alignment = .leading
|
|
||||||
demoStackView.spacing = UIFloat(8)
|
|
||||||
|
|
||||||
demoContainerView = UIView()
|
|
||||||
demoContainerView.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
demoContainerView.layer.cornerRadius = 12
|
|
||||||
if #available(iOS 13, *) {
|
|
||||||
demoContainerView.layer.cornerCurve = .continuous
|
|
||||||
}
|
|
||||||
demoContainerView.addSubview(demoStackView)
|
|
||||||
|
|
||||||
contrastRatioLabel = UILabel()
|
|
||||||
contrastRatioLabel.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
contrastRatioLabel.font = .systemFont(ofSize: UIFloat(16), weight: .medium)
|
|
||||||
|
|
||||||
aaComplianceLabel = AccessibilityComplianceLabel(text: "AA")
|
|
||||||
aaaComplianceLabel = AccessibilityComplianceLabel(text: "AAA")
|
|
||||||
|
|
||||||
let complianceStackView = UIStackView(arrangedSubviews: [UIView(), aaComplianceLabel, aaaComplianceLabel])
|
|
||||||
complianceStackView.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
complianceStackView.spacing = UIFloat(12)
|
|
||||||
|
|
||||||
contrastStackView = UIStackView(arrangedSubviews: [contrastRatioLabel, complianceStackView])
|
|
||||||
contrastStackView.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
contrastStackView.spacing = UIFloat(8)
|
|
||||||
|
|
||||||
backgroundSelector = AccessibilityContrastSelector(text: "Background", value: backgroundMode)
|
|
||||||
backgroundSelector.handleChange = { self.backgroundMode = $0 }
|
|
||||||
|
|
||||||
foregroundSelector = AccessibilityContrastSelector(text: "Foreground", value: foregroundMode)
|
|
||||||
foregroundSelector.handleChange = { self.foregroundMode = $0 }
|
|
||||||
|
|
||||||
scrollView = UIScrollView()
|
|
||||||
scrollView.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
scrollView.alwaysBounceVertical = false
|
|
||||||
view.addSubview(scrollView)
|
|
||||||
|
|
||||||
let rootStackView = UIStackView(arrangedSubviews: [demoContainerView, UIView(), contrastStackView, backgroundSelector, foregroundSelector, UIView()])
|
|
||||||
rootStackView.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
rootStackView.axis = .vertical
|
|
||||||
rootStackView.alignment = .fill
|
|
||||||
rootStackView.distribution = .fill
|
|
||||||
rootStackView.spacing = UIFloat(10)
|
|
||||||
scrollView.addSubview(rootStackView)
|
|
||||||
|
|
||||||
NSLayoutConstraint.activate([
|
|
||||||
scrollView.topAnchor.constraint(equalTo: view.topAnchor),
|
|
||||||
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
|
|
||||||
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
|
|
||||||
scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
|
|
||||||
|
|
||||||
rootStackView.topAnchor.constraint(equalTo: scrollView.contentLayoutGuide.topAnchor, constant: UIFloat(15)),
|
|
||||||
rootStackView.bottomAnchor.constraint(equalTo: scrollView.contentLayoutGuide.bottomAnchor, constant: UIFloat(-15)),
|
|
||||||
rootStackView.leadingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.leadingAnchor, constant: UIFloat(15)),
|
|
||||||
rootStackView.trailingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.trailingAnchor, constant: UIFloat(-15)),
|
|
||||||
rootStackView.heightAnchor.constraint(equalTo: scrollView.contentLayoutGuide.heightAnchor, constant: UIFloat(-30)),
|
|
||||||
scrollView.contentLayoutGuide.widthAnchor.constraint(equalTo: scrollView.widthAnchor),
|
|
||||||
scrollView.contentLayoutGuide.heightAnchor.constraint(greaterThanOrEqualTo: scrollView.heightAnchor),
|
|
||||||
|
|
||||||
demoStackView.topAnchor.constraint(equalTo: demoContainerView.topAnchor, constant: UIFloat(16)),
|
|
||||||
demoStackView.bottomAnchor.constraint(equalTo: demoContainerView.bottomAnchor, constant: UIFloat(-17)),
|
|
||||||
demoStackView.leadingAnchor.constraint(equalTo: demoContainerView.leadingAnchor, constant: UIFloat(20)),
|
|
||||||
demoStackView.trailingAnchor.constraint(equalTo: demoContainerView.trailingAnchor, constant: UIFloat(-20)),
|
|
||||||
|
|
||||||
contrastStackView.heightAnchor.constraint(greaterThanOrEqualTo: backgroundSelector.heightAnchor),
|
|
||||||
contrastStackView.heightAnchor.constraint(greaterThanOrEqualTo: foregroundSelector.heightAnchor)
|
|
||||||
])
|
|
||||||
|
|
||||||
colorDidChange()
|
|
||||||
}
|
|
||||||
|
|
||||||
override func viewDidAppear(_ animated: Bool) {
|
|
||||||
super.viewDidAppear(animated)
|
|
||||||
|
|
||||||
scrollView.flashScrollIndicators()
|
|
||||||
}
|
|
||||||
|
|
||||||
override func viewWillLayoutSubviews() {
|
|
||||||
super.viewWillLayoutSubviews()
|
|
||||||
|
|
||||||
contrastStackView.axis = view.frame.size.width > UIFloat(300) ? .horizontal : .vertical
|
|
||||||
}
|
|
||||||
|
|
||||||
override func colorDidChange() {
|
|
||||||
let backgroundColor = backgroundMode.color(withColor: color)
|
|
||||||
let foregroundColor = foregroundMode.color(withColor: color)
|
|
||||||
|
|
||||||
if backgroundColor == foregroundColor {
|
|
||||||
// Change one or the other to not be identical
|
|
||||||
if backgroundMode == foregroundMode {
|
|
||||||
switch backgroundMode {
|
|
||||||
case .black, .white: foregroundMode = .color
|
|
||||||
default: foregroundMode = .white
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if foregroundMode == .color {
|
|
||||||
backgroundMode = backgroundColor == .white ? .black : .white
|
|
||||||
} else if backgroundMode == .color {
|
|
||||||
foregroundMode = foregroundColor == .white ? .black : .white
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
backgroundSelector.value = backgroundMode
|
|
||||||
foregroundSelector.value = foregroundMode
|
|
||||||
|
|
||||||
demoContainerView.backgroundColor = backgroundColor.uiColor
|
|
||||||
demoContainerView.tintColor = foregroundColor.uiColor
|
|
||||||
for label in demoLabels {
|
|
||||||
if let label = label as? UILabel {
|
|
||||||
label.textColor = foregroundColor.uiColor
|
|
||||||
} else if let label = label as? UITextView,
|
|
||||||
let attributedString = label.attributedText.mutableCopy() as? NSMutableAttributedString {
|
|
||||||
attributedString.addAttribute(.foregroundColor,
|
|
||||||
value: foregroundColor.uiColor,
|
|
||||||
range: NSRange(location: 0, length: attributedString.string.count))
|
|
||||||
label.attributedText = attributedString
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let contrastRatio = foregroundColor.perceivedBrightness(onBackgroundColor: backgroundColor)
|
|
||||||
contrastRatioLabel.text = "Contrast: \(String(format: "%.2f", contrastRatio)) (\(Self.percentFormatter.string(for: contrastRatio / 21)!))"
|
|
||||||
aaComplianceLabel.isCompliant = contrastRatio > 4.5
|
|
||||||
aaaComplianceLabel.isCompliant = contrastRatio > 7
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@@ -1,91 +0,0 @@
|
|||||||
//
|
|
||||||
// ColorPickerConfiguration.swift
|
|
||||||
// Alderis
|
|
||||||
//
|
|
||||||
// Created by Adam Demasi on 10/5/20.
|
|
||||||
// Copyright © 2020 HASHBANG Productions. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import UIKit
|
|
||||||
|
|
||||||
/// An enumeration of the tabs `ColorPickerViewController` features. Use these enumeration values to
|
|
||||||
/// set tab-related settings on `ColorPickerConfiguration`.
|
|
||||||
@objc(HBColorPickerTab)
|
|
||||||
public enum ColorPickerTab: Int, CaseIterable {
|
|
||||||
/// Tab 1: A grid of 9 variations of 11 colours, and a grayscale ramp. The first and default tab.
|
|
||||||
case swatch = 0
|
|
||||||
|
|
||||||
/// Tab 2: A color wheel displaying every possible hue and saturation combination. The user can
|
|
||||||
/// additionally adjust the brightness of the colour using a slider.
|
|
||||||
case map = 1
|
|
||||||
|
|
||||||
/// Tab 3: A set of sliders for red, green, and blue color values, which can be switched to hue,
|
|
||||||
/// saturation, and brightness. The user can additionally copy or enter a color value expressed
|
|
||||||
/// using a CSS-style hexadecimal string, and adjust alpha transparency.
|
|
||||||
case sliders = 2
|
|
||||||
|
|
||||||
/// Tab 4: A tab that allows the user to test various configurations of the color, and its
|
|
||||||
/// conformance to WCAG color contrast.
|
|
||||||
case accessibility = 3
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ColorPickerConfiguration is used to configure an instance of `ColorPickerViewController`.
|
|
||||||
@objc(HBColorPickerConfiguration)
|
|
||||||
open class ColorPickerConfiguration: NSObject {
|
|
||||||
|
|
||||||
/// Initialise a configuration object with the required color property configured.
|
|
||||||
@objc public init(color: UIColor) {
|
|
||||||
self.color = color
|
|
||||||
super.init()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The initial color to use when launching the color picker. Required. If you don’t have a value
|
|
||||||
/// set yet, provide a sensible default.
|
|
||||||
@objc open var color: UIColor
|
|
||||||
|
|
||||||
/// Whether to allow the user to set an alpha transparency value on the color. This controls the
|
|
||||||
/// visibility of an Alpha slider on the Sliders tab. When set to `false`, alpha values provided
|
|
||||||
/// via the `color` property, or by the user when entering a hexadecimal value on the Sliders tab,
|
|
||||||
/// will be discarded.
|
|
||||||
@objc open var supportsAlpha = true
|
|
||||||
|
|
||||||
/// The title to display at the top of the popup. If set to `nil`, no title will be displayed. The
|
|
||||||
/// default is `nil`.
|
|
||||||
@objc open var title: String?
|
|
||||||
|
|
||||||
/// The initial tab to select when the color picker is presented. The default is
|
|
||||||
/// `ColorPickerTab.swatch`.
|
|
||||||
///
|
|
||||||
/// This value must be found in `visibleTabs`.
|
|
||||||
///
|
|
||||||
/// - see: `visibleTabs`
|
|
||||||
@objc open var initialTab = ColorPickerTab.swatch
|
|
||||||
|
|
||||||
/// The tabs the user can select and switch between at the top of the window, if tabs are enabled
|
|
||||||
/// by `showTabs`.
|
|
||||||
///
|
|
||||||
/// - see: `initialTab`
|
|
||||||
@nonobjc open var visibleTabs: [ColorPickerTab] = [.swatch, .map, .sliders, .accessibility]
|
|
||||||
|
|
||||||
/// Maps `visibleTabs` to Objective-C due to Swift limitations. This is an implementation detail.
|
|
||||||
/// Ignore this and use `visibleTabs` per usual.
|
|
||||||
@objc(visibleTabs)
|
|
||||||
open var _visibleTabsObjC: [ColorPickerTab.RawValue] {
|
|
||||||
get { visibleTabs.map(\.rawValue) }
|
|
||||||
set { visibleTabs = newValue.map { ColorPickerTab(rawValue: $0)! } }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Whether to display the tab selection at the top of the popup. The default is `true`. When set
|
|
||||||
/// to `false`, the user will only be able to access the tab specified in initialTab.
|
|
||||||
@objc open var showTabs = true
|
|
||||||
|
|
||||||
/// When the Smart Invert accessibility feature is enabled, Alderis instructs the system to not
|
|
||||||
/// invert most of its user interface. This ensures the user can make a more accurate color
|
|
||||||
/// selection. If this behavior is not desired, you can disable it here.
|
|
||||||
@objc open var overrideSmartInvert = true
|
|
||||||
|
|
||||||
/// Whether the user can end a drag interaction by dropping on the color picker window, allowing
|
|
||||||
/// them to drag a color from a supporting app. The default is `true`.
|
|
||||||
@objc open var isDropInteractionEnabled = true
|
|
||||||
|
|
||||||
}
|
|
@@ -1,51 +0,0 @@
|
|||||||
//
|
|
||||||
// ColorPickerDelegate.swift
|
|
||||||
// Alderis
|
|
||||||
//
|
|
||||||
// Created by Adam Demasi on 16/3/20.
|
|
||||||
// Copyright © 2020 HASHBANG Productions. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import UIKit
|
|
||||||
|
|
||||||
/// Use `ColorPickerDelegate` to handle the user’s response to `ColorPickerViewController`.
|
|
||||||
@objc(HBColorPickerDelegate)
|
|
||||||
public protocol ColorPickerDelegate: NSObjectProtocol {
|
|
||||||
|
|
||||||
/// Informs the delegate that the user has selected a color in the color picker. Optional.
|
|
||||||
///
|
|
||||||
/// Use this to update your user interface with the new color value, if suitable to your use case.
|
|
||||||
///
|
|
||||||
/// You should, at minimum, implement either this method or `colorPicker(_:didAccept:)`. If you
|
|
||||||
/// don’t intend to implement this method, it is expected that you implement
|
|
||||||
/// `colorPicker(_:didAccept:)`. If you implement this method and the user selects Cancel, this
|
|
||||||
/// method will be called with the initial color passed in via `ColorPickerConfiguration.color` to
|
|
||||||
/// undo the selection.
|
|
||||||
///
|
|
||||||
/// - parameter colorPicker: The `ColorPickerViewController` instance that triggered the action.
|
|
||||||
/// - parameter color: The `UIColor` selection the user made.
|
|
||||||
/// - see: `colorPicker(_:didAccept:)`
|
|
||||||
@objc(colorPicker:didSelectColor:)
|
|
||||||
optional func colorPicker(_ colorPicker: ColorPickerViewController, didSelect color: UIColor)
|
|
||||||
|
|
||||||
/// Informs the delegate that the user has dismissed the color picker with a positive response,
|
|
||||||
/// having selected the selected color. Optional.
|
|
||||||
///
|
|
||||||
/// You should, at minimum, implement either this method or `colorPicker(_:didSelect:)`.
|
|
||||||
///
|
|
||||||
/// - parameter colorPicker: The `ColorPickerViewController` instance that triggered the action.
|
|
||||||
/// - parameter color: The `UIColor` selection the user made.
|
|
||||||
/// - see: `colorPicker(_:didSelect:)`
|
|
||||||
@objc(colorPicker:didAcceptColor:)
|
|
||||||
optional func colorPicker(_ colorPicker: ColorPickerViewController, didAccept color: UIColor)
|
|
||||||
|
|
||||||
/// Informs the delegate that the user has dismissed the color picker with a negative response.
|
|
||||||
/// Optional.
|
|
||||||
///
|
|
||||||
/// You usually do not need to handle this condition.
|
|
||||||
///
|
|
||||||
/// - parameter colorPicker: The `ColorPickerViewController` instance that triggered the action.
|
|
||||||
@objc(colorPickerDidCancel:)
|
|
||||||
optional func colorPickerDidCancel(_ colorPicker: ColorPickerViewController)
|
|
||||||
|
|
||||||
}
|
|
@@ -1,445 +0,0 @@
|
|||||||
//
|
|
||||||
// ColorPickerInnerViewController.swift
|
|
||||||
// Alderis
|
|
||||||
//
|
|
||||||
// Created by Adam Demasi on 12/3/20.
|
|
||||||
// Copyright © 2020 HASHBANG Productions. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import UIKit
|
|
||||||
|
|
||||||
internal extension ColorPickerTab {
|
|
||||||
var tabClass: ColorPickerTabViewController.Type {
|
|
||||||
switch self {
|
|
||||||
case .swatch: return ColorPickerSwatchViewController.self
|
|
||||||
case .map: return ColorPickerMapViewController.self
|
|
||||||
case .sliders: return ColorPickerSlidersViewController.self
|
|
||||||
case .accessibility: return ColorPickerAccessibilityViewController.self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var index: Int { Self.allCases.firstIndex(of: self)! }
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class ColorPickerInnerViewController: UIViewController {
|
|
||||||
|
|
||||||
weak var delegate: ColorPickerDelegate?
|
|
||||||
let configuration: ColorPickerConfiguration
|
|
||||||
var color: Color
|
|
||||||
|
|
||||||
var tab: ColorPickerTab {
|
|
||||||
get { configuration.visibleTabs[currentTab] }
|
|
||||||
set { currentTab = configuration.visibleTabs.firstIndex(of: newValue) ?? 0 }
|
|
||||||
}
|
|
||||||
|
|
||||||
var compatibilityMode = false
|
|
||||||
|
|
||||||
private var colorPicker: ColorPickerViewController {
|
|
||||||
// swiftlint:disable:next force_cast
|
|
||||||
parent as! ColorPickerViewController
|
|
||||||
}
|
|
||||||
|
|
||||||
init(delegate: ColorPickerDelegate?, configuration: ColorPickerConfiguration) {
|
|
||||||
self.delegate = delegate
|
|
||||||
self.configuration = configuration
|
|
||||||
color = Color(uiColor: configuration.color)
|
|
||||||
super.init(nibName: nil, bundle: nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
|
||||||
fatalError("init(coder:) has not been implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
private var currentTab = 0 {
|
|
||||||
didSet { tabDidChange(oldValue: oldValue) }
|
|
||||||
}
|
|
||||||
|
|
||||||
func setColor(_ color: Color, withSource source: ColorPickerTabViewControllerBase? = nil) {
|
|
||||||
self.color = color
|
|
||||||
colorDidChange(withSource: source)
|
|
||||||
}
|
|
||||||
|
|
||||||
private var pageViewController: UIPageViewController!
|
|
||||||
private var tabs = [ColorPickerTabViewController]()
|
|
||||||
private var tabsView: UISegmentedControl!
|
|
||||||
private var titleLabel: UILabel!
|
|
||||||
private var cancelButton: DialogButton?
|
|
||||||
private var saveButton: DialogButton?
|
|
||||||
private var tabsBackgroundView: UIView!
|
|
||||||
private var buttonsBackgroundView: UIView?
|
|
||||||
private var heightConstraint: NSLayoutConstraint!
|
|
||||||
private var backgroundView: UIView!
|
|
||||||
|
|
||||||
override func viewDidLoad() {
|
|
||||||
super.viewDidLoad()
|
|
||||||
|
|
||||||
for tabType in configuration.visibleTabs {
|
|
||||||
let tab = tabType.tabClass.init(tabDelegate: self, configuration: configuration, color: color)
|
|
||||||
// Force the view to be initialised
|
|
||||||
tab.loadViewIfNeeded()
|
|
||||||
tabs.append(tab)
|
|
||||||
}
|
|
||||||
|
|
||||||
if configuration.isDropInteractionEnabled {
|
|
||||||
view.addInteraction(UIDropInteraction(delegate: self))
|
|
||||||
}
|
|
||||||
|
|
||||||
backgroundView = UIView()
|
|
||||||
backgroundView.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
backgroundView.accessibilityIgnoresInvertColors = configuration.overrideSmartInvert
|
|
||||||
view.addSubview(backgroundView)
|
|
||||||
|
|
||||||
let tabsCheckerboardView = UIView()
|
|
||||||
tabsCheckerboardView.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
tabsCheckerboardView.accessibilityIgnoresInvertColors = configuration.overrideSmartInvert
|
|
||||||
tabsCheckerboardView.backgroundColor = Assets.checkerboardPatternColor
|
|
||||||
view.addSubview(tabsCheckerboardView)
|
|
||||||
|
|
||||||
tabsBackgroundView = UIView()
|
|
||||||
tabsBackgroundView.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
tabsBackgroundView.accessibilityIgnoresInvertColors = configuration.overrideSmartInvert
|
|
||||||
view.addSubview(tabsBackgroundView)
|
|
||||||
|
|
||||||
let topSeparatorView = SeparatorView(direction: .horizontal)
|
|
||||||
topSeparatorView.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
tabsBackgroundView.addSubview(topSeparatorView)
|
|
||||||
|
|
||||||
let titleView = UIView()
|
|
||||||
titleView.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
titleView.isHidden = configuration.title == nil || configuration.title!.isEmpty
|
|
||||||
|
|
||||||
titleLabel = UILabel()
|
|
||||||
titleLabel.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
titleLabel.textAlignment = .center
|
|
||||||
titleLabel.font = .systemFont(ofSize: UIFloat(17), weight: .semibold)
|
|
||||||
titleLabel.text = configuration.title
|
|
||||||
titleView.addSubview(titleLabel)
|
|
||||||
|
|
||||||
let tabsContainerView = UIView()
|
|
||||||
tabsContainerView.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
tabsContainerView.isHidden = !configuration.showTabs
|
|
||||||
|
|
||||||
tabsView = UISegmentedControl()
|
|
||||||
tabsView.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
tabsView.accessibilityIgnoresInvertColors = configuration.overrideSmartInvert
|
|
||||||
tabsView.addTarget(self, action: #selector(segmentControlChanged(_:)), for: .valueChanged)
|
|
||||||
tabsContainerView.addSubview(tabsView)
|
|
||||||
|
|
||||||
if #available(iOS 13, *) {
|
|
||||||
tabsView.selectedSegmentTintColor = UIColor.white.withAlphaComponent(0.35)
|
|
||||||
if isCatalystMac {
|
|
||||||
tabsView.setTitleTextAttributes([ .foregroundColor: Assets.macTabBarSelectionColor ], for: .highlighted)
|
|
||||||
tabsView.setTitleTextAttributes([ .foregroundColor: Assets.macTabBarSelectionColor ], for: .selected)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i, tab) in tabs.enumerated() {
|
|
||||||
let tabClass = type(of: tab)
|
|
||||||
#if swift(>=5.3)
|
|
||||||
if #available(iOS 14, *) {
|
|
||||||
tabsView.insertSegment(action: UIAction(title: tabClass.title,
|
|
||||||
image: tabClass.image,
|
|
||||||
handler: { _ in }),
|
|
||||||
at: i,
|
|
||||||
animated: false)
|
|
||||||
} else {
|
|
||||||
tabsView.insertSegment(with: tabClass.image, at: i, animated: false)
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
tabsView.insertSegment(with: tabClass.image, at: i, animated: false)
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
NSLayoutConstraint.activate([
|
|
||||||
tabsView.centerXAnchor.constraint(equalTo: tabsContainerView.centerXAnchor),
|
|
||||||
tabsView.centerYAnchor.constraint(equalTo: tabsContainerView.centerYAnchor),
|
|
||||||
tabsView.leadingAnchor.constraint(greaterThanOrEqualTo: tabsContainerView.leadingAnchor, constant: 4),
|
|
||||||
tabsView.trailingAnchor.constraint(lessThanOrEqualTo: tabsContainerView.trailingAnchor, constant: -4)
|
|
||||||
])
|
|
||||||
|
|
||||||
if #available(iOS 13, *) {
|
|
||||||
} else {
|
|
||||||
NSLayoutConstraint.activate([
|
|
||||||
tabsView.heightAnchor.constraint(equalToConstant: 32)
|
|
||||||
])
|
|
||||||
for i in 0..<tabsView.numberOfSegments {
|
|
||||||
tabsView.setWidth(40, forSegmentAt: i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let pageViewContainer = UIView()
|
|
||||||
pageViewContainer.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
|
|
||||||
pageViewController = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal, options: [:])
|
|
||||||
pageViewController.view.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
pageViewController.willMove(toParent: self)
|
|
||||||
addChild(pageViewController)
|
|
||||||
pageViewContainer.addSubview(pageViewController.view)
|
|
||||||
|
|
||||||
let mainStackView = UIStackView(arrangedSubviews: [titleView, tabsContainerView, pageViewContainer])
|
|
||||||
mainStackView.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
mainStackView.axis = .vertical
|
|
||||||
mainStackView.alignment = .fill
|
|
||||||
mainStackView.distribution = .fill
|
|
||||||
view.addSubview(mainStackView)
|
|
||||||
|
|
||||||
heightConstraint = pageViewContainer.heightAnchor.constraint(equalToConstant: 0)
|
|
||||||
|
|
||||||
let barHeight: CGFloat = UIFloat(48)
|
|
||||||
let topHeight = (titleView.isHidden ? 0 : barHeight) + (tabsContainerView.isHidden ? 0 : barHeight)
|
|
||||||
let titleLabelTopOffset: CGFloat = tabsContainerView.isHidden ? 0 : 3
|
|
||||||
NSLayoutConstraint.activate([
|
|
||||||
backgroundView.topAnchor.constraint(equalTo: view.topAnchor),
|
|
||||||
backgroundView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
|
|
||||||
backgroundView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
|
|
||||||
backgroundView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
|
|
||||||
|
|
||||||
mainStackView.topAnchor.constraint(equalTo: view.topAnchor),
|
|
||||||
mainStackView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
|
|
||||||
mainStackView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
|
|
||||||
mainStackView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
|
|
||||||
|
|
||||||
titleView.heightAnchor.constraint(equalToConstant: barHeight),
|
|
||||||
tabsContainerView.heightAnchor.constraint(equalToConstant: barHeight),
|
|
||||||
|
|
||||||
titleLabel.topAnchor.constraint(equalTo: titleView.topAnchor, constant: titleLabelTopOffset),
|
|
||||||
titleLabel.bottomAnchor.constraint(equalTo: titleView.bottomAnchor),
|
|
||||||
titleLabel.leadingAnchor.constraint(equalTo: titleView.leadingAnchor, constant: 4),
|
|
||||||
titleLabel.trailingAnchor.constraint(equalTo: titleView.trailingAnchor, constant: -4),
|
|
||||||
|
|
||||||
tabsBackgroundView.topAnchor.constraint(equalTo: view.topAnchor),
|
|
||||||
tabsBackgroundView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
|
|
||||||
tabsBackgroundView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
|
|
||||||
tabsBackgroundView.heightAnchor.constraint(equalToConstant: topHeight),
|
|
||||||
|
|
||||||
tabsCheckerboardView.topAnchor.constraint(equalTo: tabsBackgroundView.topAnchor),
|
|
||||||
tabsCheckerboardView.bottomAnchor.constraint(equalTo: tabsBackgroundView.bottomAnchor),
|
|
||||||
tabsCheckerboardView.leadingAnchor.constraint(equalTo: tabsBackgroundView.leadingAnchor),
|
|
||||||
tabsCheckerboardView.trailingAnchor.constraint(equalTo: tabsBackgroundView.trailingAnchor),
|
|
||||||
|
|
||||||
topSeparatorView.leadingAnchor.constraint(equalTo: tabsBackgroundView.leadingAnchor),
|
|
||||||
topSeparatorView.trailingAnchor.constraint(equalTo: tabsBackgroundView.trailingAnchor),
|
|
||||||
topSeparatorView.bottomAnchor.constraint(equalTo: tabsBackgroundView.bottomAnchor),
|
|
||||||
|
|
||||||
pageViewController.view.topAnchor.constraint(equalTo: pageViewContainer.topAnchor),
|
|
||||||
pageViewController.view.bottomAnchor.constraint(equalTo: pageViewContainer.bottomAnchor),
|
|
||||||
pageViewController.view.leadingAnchor.constraint(equalTo: pageViewContainer.leadingAnchor),
|
|
||||||
pageViewController.view.trailingAnchor.constraint(equalTo: pageViewContainer.trailingAnchor),
|
|
||||||
|
|
||||||
heightConstraint
|
|
||||||
])
|
|
||||||
|
|
||||||
if !isCatalystMac {
|
|
||||||
let buttonsCheckerboardView = UIView()
|
|
||||||
buttonsCheckerboardView.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
buttonsCheckerboardView.accessibilityIgnoresInvertColors = configuration.overrideSmartInvert
|
|
||||||
buttonsCheckerboardView.backgroundColor = Assets.checkerboardPatternColor
|
|
||||||
view.insertSubview(buttonsCheckerboardView, aboveSubview: tabsBackgroundView)
|
|
||||||
|
|
||||||
let buttonsBackgroundView = UIView()
|
|
||||||
buttonsBackgroundView.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
buttonsBackgroundView.accessibilityIgnoresInvertColors = configuration.overrideSmartInvert
|
|
||||||
view.insertSubview(buttonsBackgroundView, aboveSubview: buttonsCheckerboardView)
|
|
||||||
self.buttonsBackgroundView = buttonsBackgroundView
|
|
||||||
|
|
||||||
let bottomSeparatorView = SeparatorView(direction: .horizontal)
|
|
||||||
bottomSeparatorView.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
buttonsBackgroundView.addSubview(bottomSeparatorView)
|
|
||||||
|
|
||||||
let cancelButton = DialogButton()
|
|
||||||
cancelButton.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
cancelButton.accessibilityIgnoresInvertColors = configuration.overrideSmartInvert
|
|
||||||
cancelButton.titleLabel!.font = .systemFont(ofSize: 17, weight: .regular)
|
|
||||||
cancelButton.setTitle(Assets.uikitLocalize("Cancel"), for: .normal)
|
|
||||||
cancelButton.addTarget(self, action: #selector(cancelTapped), for: .touchUpInside)
|
|
||||||
self.cancelButton = cancelButton
|
|
||||||
|
|
||||||
let saveButton = DialogButton()
|
|
||||||
saveButton.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
saveButton.accessibilityIgnoresInvertColors = configuration.overrideSmartInvert
|
|
||||||
saveButton.titleLabel!.font = .systemFont(ofSize: 17, weight: .semibold)
|
|
||||||
saveButton.setTitle(Assets.uikitLocalize("Done"), for: .normal)
|
|
||||||
saveButton.addTarget(self, action: #selector(saveTapped), for: .touchUpInside)
|
|
||||||
self.saveButton = saveButton
|
|
||||||
|
|
||||||
let buttonSeparatorView = SeparatorView(direction: .vertical)
|
|
||||||
buttonSeparatorView.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
buttonsBackgroundView.addSubview(buttonSeparatorView)
|
|
||||||
|
|
||||||
let buttonsView = UIStackView(arrangedSubviews: [cancelButton, saveButton])
|
|
||||||
buttonsView.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
buttonsView.axis = .horizontal
|
|
||||||
buttonsView.alignment = .fill
|
|
||||||
mainStackView.addSubview(buttonsView)
|
|
||||||
mainStackView.addArrangedSubview(buttonsView)
|
|
||||||
|
|
||||||
NSLayoutConstraint.activate([
|
|
||||||
buttonsView.heightAnchor.constraint(equalToConstant: barHeight),
|
|
||||||
|
|
||||||
buttonsBackgroundView.topAnchor.constraint(equalTo: buttonsView.topAnchor),
|
|
||||||
buttonsBackgroundView.bottomAnchor.constraint(equalTo: buttonsView.bottomAnchor),
|
|
||||||
buttonsBackgroundView.leadingAnchor.constraint(equalTo: buttonsView.leadingAnchor),
|
|
||||||
buttonsBackgroundView.trailingAnchor.constraint(equalTo: buttonsView.trailingAnchor),
|
|
||||||
|
|
||||||
buttonSeparatorView.heightAnchor.constraint(equalToConstant: barHeight / 2),
|
|
||||||
buttonSeparatorView.centerXAnchor.constraint(equalTo: buttonsBackgroundView.centerXAnchor),
|
|
||||||
buttonSeparatorView.centerYAnchor.constraint(equalTo: buttonsBackgroundView.centerYAnchor),
|
|
||||||
|
|
||||||
buttonsCheckerboardView.topAnchor.constraint(equalTo: buttonsBackgroundView.topAnchor),
|
|
||||||
buttonsCheckerboardView.bottomAnchor.constraint(equalTo: buttonsBackgroundView.bottomAnchor),
|
|
||||||
buttonsCheckerboardView.leadingAnchor.constraint(equalTo: buttonsBackgroundView.leadingAnchor),
|
|
||||||
buttonsCheckerboardView.trailingAnchor.constraint(equalTo: buttonsBackgroundView.trailingAnchor),
|
|
||||||
|
|
||||||
bottomSeparatorView.leadingAnchor.constraint(equalTo: buttonsBackgroundView.leadingAnchor),
|
|
||||||
bottomSeparatorView.trailingAnchor.constraint(equalTo: buttonsBackgroundView.trailingAnchor),
|
|
||||||
bottomSeparatorView.topAnchor.constraint(equalTo: buttonsBackgroundView.topAnchor),
|
|
||||||
|
|
||||||
cancelButton.widthAnchor.constraint(equalTo: saveButton.widthAnchor)
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
colorDidChange()
|
|
||||||
tab = configuration.initialTab
|
|
||||||
tabsView?.selectedSegmentIndex = currentTab
|
|
||||||
}
|
|
||||||
|
|
||||||
override func viewWillLayoutSubviews() {
|
|
||||||
super.viewWillLayoutSubviews()
|
|
||||||
updateHeightConstraint()
|
|
||||||
}
|
|
||||||
|
|
||||||
override func viewDidLayoutSubviews() {
|
|
||||||
super.viewDidLayoutSubviews()
|
|
||||||
updateHeightConstraint()
|
|
||||||
}
|
|
||||||
|
|
||||||
override func preferredContentSizeDidChange(forChildContentContainer container: UIContentContainer) {
|
|
||||||
super.preferredContentSizeDidChange(forChildContentContainer: container)
|
|
||||||
updateHeightConstraint()
|
|
||||||
}
|
|
||||||
|
|
||||||
private func updateHeightConstraint() {
|
|
||||||
heightConstraint.constant = (view.frame.size.width / 12) * 10
|
|
||||||
preferredContentSize = view.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize)
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc private func segmentControlChanged(_ sender: UISegmentedControl) {
|
|
||||||
UIView.animate(withDuration: 0.2) {
|
|
||||||
self.currentTab = self.tabsView.selectedSegmentIndex
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc private func oldTabButtonTapped(_ sender: UIButton) {
|
|
||||||
UIView.animate(withDuration: 0.2) {
|
|
||||||
self.currentTab = sender.tag
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc private func cancelTapped() {
|
|
||||||
if !compatibilityMode {
|
|
||||||
delegate?.colorPicker?(colorPicker, didSelect: configuration.color)
|
|
||||||
}
|
|
||||||
delegate?.colorPickerDidCancel?(colorPicker)
|
|
||||||
dismiss(animated: true)
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc func saveTapped() {
|
|
||||||
if compatibilityMode {
|
|
||||||
delegate?.colorPicker?(colorPicker, didSelect: color.uiColor)
|
|
||||||
} else {
|
|
||||||
delegate?.colorPicker?(colorPicker, didAccept: color.uiColor)
|
|
||||||
}
|
|
||||||
dismiss(animated: true)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func colorDidChange(withSource source: ColorPickerTabViewControllerBase? = nil) {
|
|
||||||
let uiColor = color.uiColor
|
|
||||||
if !compatibilityMode {
|
|
||||||
delegate?.colorPicker?(colorPicker, didSelect: uiColor)
|
|
||||||
}
|
|
||||||
|
|
||||||
let foregroundColor: UIColor = color.isDark ? .white : .black
|
|
||||||
|
|
||||||
view.tintColor = uiColor
|
|
||||||
tabsBackgroundView.backgroundColor = uiColor
|
|
||||||
buttonsBackgroundView?.backgroundColor = uiColor
|
|
||||||
titleLabel.textColor = foregroundColor
|
|
||||||
cancelButton?.setTitleColor(foregroundColor, for: .normal)
|
|
||||||
saveButton?.setTitleColor(foregroundColor, for: .normal)
|
|
||||||
cancelButton?.highlightBackgroundColor = foregroundColor.withAlphaComponent(0.25)
|
|
||||||
saveButton?.highlightBackgroundColor = foregroundColor.withAlphaComponent(0.25)
|
|
||||||
tabsView.setTitleTextAttributes([ .foregroundColor: foregroundColor ], for: .normal)
|
|
||||||
|
|
||||||
if #available(iOS 13, *) {
|
|
||||||
} else {
|
|
||||||
tabsView.tintColor = foregroundColor
|
|
||||||
}
|
|
||||||
|
|
||||||
// Even though `shouldBroadcast: false` avoids recursion if we call setColor on the callee tab,
|
|
||||||
// doing so on ColorPickerSlidersViewController would reset `hexOptions`, leading to a buggy
|
|
||||||
// typing experience in `hexTextField`
|
|
||||||
for tab in tabs where tab != source {
|
|
||||||
tab.setColor(color, shouldBroadcast: false)
|
|
||||||
}
|
|
||||||
|
|
||||||
backgroundView.backgroundColor = uiColor.withAlphaComponent(color.alpha * 0.2)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func tabDidChange(oldValue: Int) {
|
|
||||||
let stuff = {
|
|
||||||
let direction: UIPageViewController.NavigationDirection = self.currentTab < oldValue ? .reverse : .forward
|
|
||||||
self.pageViewController.setViewControllers([self.tabs[self.currentTab]], direction: direction, animated: !isCatalystMac)
|
|
||||||
self.colorDidChange()
|
|
||||||
|
|
||||||
UIView.animate(withDuration: 0.2) {
|
|
||||||
self.view.layoutIfNeeded()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if isCatalystMac {
|
|
||||||
UIView.performWithoutAnimation(stuff)
|
|
||||||
} else {
|
|
||||||
stuff()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
extension ColorPickerInnerViewController: ColorPickerTabDelegate {
|
|
||||||
|
|
||||||
func colorPickerTab(_ tab: ColorPickerTabViewControllerBase, didSelect color: Color) {
|
|
||||||
setColor(color, withSource: tab)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
extension ColorPickerInnerViewController: UIDropInteractionDelegate {
|
|
||||||
|
|
||||||
/// :nodoc:
|
|
||||||
public func dropInteraction(_ interaction: UIDropInteraction, canHandle session: UIDropSession) -> Bool {
|
|
||||||
return session.items.count == 1 && session.canLoadObjects(ofClass: UIColor.self)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// :nodoc:
|
|
||||||
public func dropInteraction(_ interaction: UIDropInteraction, sessionDidUpdate session: UIDropSession) -> UIDropProposal {
|
|
||||||
return UIDropProposal(operation: .copy)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// :nodoc:
|
|
||||||
public func dropInteraction(_ interaction: UIDropInteraction, performDrop session: UIDropSession) {
|
|
||||||
session.loadObjects(ofClass: UIColor.self) { items in
|
|
||||||
if let color = items.first as? UIColor {
|
|
||||||
self.setColor(Color(uiColor: color), withSource: nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
extension ColorPickerInnerViewController: UIPopoverPresentationControllerDelegate {
|
|
||||||
|
|
||||||
/// :nodoc:
|
|
||||||
public func presentationControllerWillDismiss(_ presentationController: UIPresentationController) {
|
|
||||||
saveTapped()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@@ -1,49 +0,0 @@
|
|||||||
//
|
|
||||||
// ColorPickerMapSlider.swift
|
|
||||||
// Alderis
|
|
||||||
//
|
|
||||||
// Created by Kabir Oberai on 23/03/20.
|
|
||||||
// Copyright © 2020 HASHBANG Productions. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import UIKit
|
|
||||||
|
|
||||||
internal class ColorPickerMapSlider: ColorPickerComponentSlider {
|
|
||||||
|
|
||||||
init(minImageName: String, maxImageName: String, component: Color.Component, overrideSmartInvert: Bool) {
|
|
||||||
super.init(component: component, overrideSmartInvert: overrideSmartInvert)
|
|
||||||
|
|
||||||
stackView.alignment = .center
|
|
||||||
stackView.spacing = UIFloat(13)
|
|
||||||
|
|
||||||
let leftImageView = UIImageView(image: Assets.systemImage(named: minImageName))
|
|
||||||
leftImageView.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
leftImageView.contentMode = .center
|
|
||||||
leftImageView.tintColor = Assets.secondaryLabelColor
|
|
||||||
stackView.insertArrangedSubview(leftImageView, at: 0)
|
|
||||||
|
|
||||||
let rightImageView = UIImageView(image: Assets.systemImage(named: maxImageName))
|
|
||||||
rightImageView.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
rightImageView.contentMode = .center
|
|
||||||
rightImageView.tintColor = Assets.secondaryLabelColor
|
|
||||||
stackView.addArrangedSubview(rightImageView)
|
|
||||||
|
|
||||||
if #available(iOS 13, *) {
|
|
||||||
let symbolConfig = UIImage.SymbolConfiguration(font: .systemFont(ofSize: UIFloat(18), weight: .medium), scale: .medium)
|
|
||||||
leftImageView.preferredSymbolConfiguration = symbolConfig
|
|
||||||
rightImageView.preferredSymbolConfiguration = symbolConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
NSLayoutConstraint.activate([
|
|
||||||
leftImageView.widthAnchor.constraint(equalToConstant: UIFloat(22)),
|
|
||||||
leftImageView.widthAnchor.constraint(equalTo: rightImageView.widthAnchor),
|
|
||||||
leftImageView.heightAnchor.constraint(equalTo: leftImageView.widthAnchor),
|
|
||||||
rightImageView.heightAnchor.constraint(equalTo: rightImageView.widthAnchor)
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
|
||||||
fatalError("init(coder:) has not been implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@@ -1,79 +0,0 @@
|
|||||||
//
|
|
||||||
// ColorPickerMapViewController.swift
|
|
||||||
// Alderis
|
|
||||||
//
|
|
||||||
// Created by Adam Demasi on 14/3/20.
|
|
||||||
// Copyright © 2020 HASHBANG Productions. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import UIKit
|
|
||||||
|
|
||||||
internal class ColorPickerMapViewController: ColorPickerTabViewController {
|
|
||||||
|
|
||||||
static let title = "Color Wheel"
|
|
||||||
static let imageName = "slider.horizontal.below.rectangle"
|
|
||||||
|
|
||||||
private var wheelView: ColorPickerWheelView!
|
|
||||||
private var sliders = [ColorPickerMapSlider]()
|
|
||||||
|
|
||||||
override func viewDidLoad() {
|
|
||||||
super.viewDidLoad()
|
|
||||||
|
|
||||||
wheelView = ColorPickerWheelView(color: color)
|
|
||||||
wheelView.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
wheelView.accessibilityIgnoresInvertColors = configuration.overrideSmartInvert
|
|
||||||
wheelView.delegate = self
|
|
||||||
view.addSubview(wheelView)
|
|
||||||
|
|
||||||
sliders = [
|
|
||||||
ColorPickerMapSlider(
|
|
||||||
minImageName: "sun.min", maxImageName: "sun.max", component: .brightness,
|
|
||||||
overrideSmartInvert: configuration.overrideSmartInvert
|
|
||||||
)
|
|
||||||
]
|
|
||||||
|
|
||||||
sliders.forEach {
|
|
||||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
$0.addTarget(self, action: #selector(sliderChanged(_:)), for: .valueChanged)
|
|
||||||
}
|
|
||||||
|
|
||||||
let mainStackView = UIStackView(arrangedSubviews: [wheelView] + sliders)
|
|
||||||
mainStackView.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
mainStackView.axis = .vertical
|
|
||||||
mainStackView.alignment = .fill
|
|
||||||
mainStackView.distribution = .fill
|
|
||||||
view.addSubview(mainStackView)
|
|
||||||
|
|
||||||
NSLayoutConstraint.activate([
|
|
||||||
mainStackView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: UIFloat(15)),
|
|
||||||
mainStackView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: UIFloat(-15)),
|
|
||||||
mainStackView.topAnchor.constraint(equalTo: view.topAnchor, constant: 0),
|
|
||||||
mainStackView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: UIFloat(-10))
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
override func viewDidLayoutSubviews() {
|
|
||||||
super.viewDidLayoutSubviews()
|
|
||||||
colorDidChange()
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc private func sliderChanged(_ slider: ColorPickerMapSlider) {
|
|
||||||
var color = self.color
|
|
||||||
slider.apply(to: &color)
|
|
||||||
self.setColor(color)
|
|
||||||
}
|
|
||||||
|
|
||||||
override func colorDidChange() {
|
|
||||||
wheelView.color = color
|
|
||||||
sliders.forEach { $0.setColor(color) }
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
extension ColorPickerMapViewController: ColorPickerWheelViewDelegate {
|
|
||||||
|
|
||||||
func colorPickerWheelView(didSelectColor color: Color) {
|
|
||||||
self.setColor(color)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@@ -1,83 +0,0 @@
|
|||||||
//
|
|
||||||
// ColorPickerNumericSlider.swift
|
|
||||||
// Alderis
|
|
||||||
//
|
|
||||||
// Created by Kabir Oberai on 28/03/20.
|
|
||||||
// Copyright © 2020 HASHBANG Productions. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import UIKit
|
|
||||||
|
|
||||||
internal class ColorPickerNumericSlider: ColorPickerComponentSlider {
|
|
||||||
|
|
||||||
private var textField: UITextField!
|
|
||||||
|
|
||||||
override init(component: Color.Component, overrideSmartInvert: Bool) {
|
|
||||||
super.init(component: component, overrideSmartInvert: overrideSmartInvert)
|
|
||||||
|
|
||||||
stackView.alignment = .fill
|
|
||||||
stackView.spacing = UIFloat(8)
|
|
||||||
|
|
||||||
let label = UILabel()
|
|
||||||
label.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
label.font = UIFont.systemFont(ofSize: UIFloat(16), weight: .medium)
|
|
||||||
label.text = component.title
|
|
||||||
stackView.insertArrangedSubview(label, at: 0)
|
|
||||||
|
|
||||||
textField = UITextField()
|
|
||||||
textField.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
textField.delegate = self
|
|
||||||
textField.returnKeyType = .next
|
|
||||||
textField.keyboardType = .numberPad
|
|
||||||
textField.autocapitalizationType = .none
|
|
||||||
textField.autocorrectionType = .no
|
|
||||||
textField.spellCheckingType = .no
|
|
||||||
textField.textAlignment = .right
|
|
||||||
textField.font = Assets.niceMonospaceDigitFont(ofSize: UIFloat(16))
|
|
||||||
stackView.addArrangedSubview(textField)
|
|
||||||
|
|
||||||
NSLayoutConstraint.activate([
|
|
||||||
label.widthAnchor.constraint(equalToConstant: UIFloat(50)),
|
|
||||||
textField.widthAnchor.constraint(equalToConstant: UIFloat(35))
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
|
||||||
fatalError("init(coder:) has not been implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override func setColor(_ color: Color) {
|
|
||||||
super.setColor(color)
|
|
||||||
textField.text = "\(Int((color[keyPath: component.keyPath] * component.limit).rounded()))"
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
extension ColorPickerNumericSlider: UITextFieldDelegate {
|
|
||||||
|
|
||||||
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
|
|
||||||
let newString = textField.text!.replacingCharacters(in: Range(range, in: textField.text!)!, with: string)
|
|
||||||
guard !newString.isEmpty else { return true }
|
|
||||||
|
|
||||||
// Numeric only, 0-limit
|
|
||||||
let badCharacterSet = CharacterSet(charactersIn: "0123456789").inverted
|
|
||||||
guard newString.rangeOfCharacter(from: badCharacterSet) == nil else {
|
|
||||||
beep()
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
let limit = component.limit
|
|
||||||
guard let value = Int(newString), 0...limit ~= CGFloat(value) else {
|
|
||||||
beep()
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run this after the input is fully processed by enqueuing it onto the run loop
|
|
||||||
OperationQueue.main.addOperation {
|
|
||||||
self.value = CGFloat(value) / limit
|
|
||||||
self.sliderChanged()
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@@ -1,206 +0,0 @@
|
|||||||
//
|
|
||||||
// ColorPickerSlider.swift
|
|
||||||
// Alderis
|
|
||||||
//
|
|
||||||
// Created by Kabir Oberai on 28/03/20.
|
|
||||||
// Copyright © 2020 HASHBANG Productions. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import UIKit
|
|
||||||
|
|
||||||
internal class ColorPickerSliderBase: UIControl {
|
|
||||||
|
|
||||||
var overrideSmartInvert: Bool {
|
|
||||||
didSet {
|
|
||||||
slider.accessibilityIgnoresInvertColors = overrideSmartInvert
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let stackView: UIStackView
|
|
||||||
let slider: ColorSlider
|
|
||||||
|
|
||||||
var value: CGFloat {
|
|
||||||
get { CGFloat(slider.value) }
|
|
||||||
set { slider.value = Float(newValue) }
|
|
||||||
}
|
|
||||||
|
|
||||||
init(overrideSmartInvert: Bool) {
|
|
||||||
self.overrideSmartInvert = overrideSmartInvert
|
|
||||||
|
|
||||||
slider = ColorSlider()
|
|
||||||
slider.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
slider.accessibilityIgnoresInvertColors = overrideSmartInvert
|
|
||||||
|
|
||||||
stackView = UIStackView(arrangedSubviews: [slider])
|
|
||||||
stackView.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
stackView.axis = .horizontal
|
|
||||||
stackView.distribution = .fill
|
|
||||||
|
|
||||||
super.init(frame: .zero)
|
|
||||||
|
|
||||||
slider.addTarget(self, action: #selector(sliderChanged), for: .valueChanged)
|
|
||||||
addSubview(stackView)
|
|
||||||
|
|
||||||
NSLayoutConstraint.activate([
|
|
||||||
stackView.leadingAnchor.constraint(equalTo: self.leadingAnchor),
|
|
||||||
stackView.trailingAnchor.constraint(equalTo: self.trailingAnchor),
|
|
||||||
stackView.topAnchor.constraint(equalTo: self.topAnchor),
|
|
||||||
stackView.bottomAnchor.constraint(equalTo: self.bottomAnchor)
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
|
||||||
fatalError("init(coder:) has not been implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc internal func sliderChanged() {
|
|
||||||
sendActions(for: .valueChanged)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
internal protocol ColorPickerSliderProtocol: ColorPickerSliderBase {
|
|
||||||
func setColor(_ color: Color)
|
|
||||||
func apply(to color: inout Color)
|
|
||||||
}
|
|
||||||
|
|
||||||
internal typealias ColorPickerSlider = ColorPickerSliderBase & ColorPickerSliderProtocol
|
|
||||||
|
|
||||||
internal class ColorPickerComponentSlider: ColorPickerSlider {
|
|
||||||
|
|
||||||
let component: Color.Component
|
|
||||||
|
|
||||||
init(component: Color.Component, overrideSmartInvert: Bool) {
|
|
||||||
self.component = component
|
|
||||||
super.init(overrideSmartInvert: overrideSmartInvert)
|
|
||||||
}
|
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
|
||||||
fatalError("init(coder:) has not been implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
func setColor(_ color: Color) {
|
|
||||||
value = color[keyPath: component.keyPath]
|
|
||||||
slider.color = color.uiColor
|
|
||||||
slider.gradientColors = component.sliderTintColor(for: color).map(\.uiColor)
|
|
||||||
}
|
|
||||||
|
|
||||||
func apply(to color: inout Color) {
|
|
||||||
color[keyPath: component.keyPath] = value
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class ColorSlider: UISlider {
|
|
||||||
private let thumbImage = UIGraphicsImageRenderer(size: CGSize(width: 26, height: 26)).image { _ in }
|
|
||||||
|
|
||||||
var gradientColors = [UIColor]() {
|
|
||||||
didSet { gradientView.gradientLayer.colors = gradientColors.map(\.cgColor) }
|
|
||||||
}
|
|
||||||
|
|
||||||
var color: UIColor? {
|
|
||||||
get { selectionView?.color }
|
|
||||||
set { selectionView?.color = newValue }
|
|
||||||
}
|
|
||||||
|
|
||||||
private var checkerboardView: UIView!
|
|
||||||
private var gradientView: GradientView!
|
|
||||||
|
|
||||||
private var selectionView: ColorWell?
|
|
||||||
private var selectionViewXConstraint: NSLayoutConstraint?
|
|
||||||
private var valueObserver: NSKeyValueObservation?
|
|
||||||
|
|
||||||
override init(frame: CGRect) {
|
|
||||||
super.init(frame: frame)
|
|
||||||
|
|
||||||
#if swift(>=5.5)
|
|
||||||
var useSliderTrack = !isCatalystMac
|
|
||||||
if #available(iOS 15, *) {
|
|
||||||
preferredBehavioralStyle = .pad
|
|
||||||
useSliderTrack = true
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
let useSliderTrack = true
|
|
||||||
#endif
|
|
||||||
if useSliderTrack {
|
|
||||||
setMinimumTrackImage(UIImage(), for: .normal)
|
|
||||||
setMaximumTrackImage(UIImage(), for: .normal)
|
|
||||||
setThumbImage(thumbImage, for: .normal)
|
|
||||||
}
|
|
||||||
|
|
||||||
checkerboardView = UIView()
|
|
||||||
checkerboardView.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
checkerboardView.backgroundColor = Assets.checkerboardPatternColor
|
|
||||||
checkerboardView.clipsToBounds = true
|
|
||||||
if #available(iOS 13, *) {
|
|
||||||
checkerboardView.layer.cornerCurve = .continuous
|
|
||||||
}
|
|
||||||
insertSubview(checkerboardView, at: 0)
|
|
||||||
|
|
||||||
gradientView = GradientView()
|
|
||||||
gradientView.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
gradientView.gradientLayer.startPoint = CGPoint(x: 0, y: 0)
|
|
||||||
gradientView.gradientLayer.endPoint = CGPoint(x: 1, y: 0)
|
|
||||||
gradientView.gradientLayer.allowsGroupOpacity = false
|
|
||||||
checkerboardView.addSubview(gradientView)
|
|
||||||
|
|
||||||
NSLayoutConstraint.activate([
|
|
||||||
checkerboardView.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: UIFloat(-3)),
|
|
||||||
checkerboardView.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: UIFloat(3)),
|
|
||||||
checkerboardView.topAnchor.constraint(equalTo: self.topAnchor, constant: -1),
|
|
||||||
checkerboardView.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: 1),
|
|
||||||
|
|
||||||
gradientView.leadingAnchor.constraint(equalTo: checkerboardView.leadingAnchor),
|
|
||||||
gradientView.trailingAnchor.constraint(equalTo: checkerboardView.trailingAnchor),
|
|
||||||
gradientView.topAnchor.constraint(equalTo: checkerboardView.topAnchor),
|
|
||||||
gradientView.bottomAnchor.constraint(equalTo: checkerboardView.bottomAnchor),
|
|
||||||
])
|
|
||||||
|
|
||||||
if useSliderTrack {
|
|
||||||
let selectionView = ColorWell()
|
|
||||||
selectionView.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
selectionView.isDragInteractionEnabled = false
|
|
||||||
selectionView.isDropInteractionEnabled = false
|
|
||||||
#if swift(>=5.3)
|
|
||||||
if #available(iOS 14, *) {
|
|
||||||
selectionView.isContextMenuInteractionEnabled = false
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
insertSubview(selectionView, aboveSubview: checkerboardView)
|
|
||||||
self.selectionView = selectionView
|
|
||||||
|
|
||||||
selectionViewXConstraint = selectionView.leadingAnchor.constraint(equalTo: checkerboardView.leadingAnchor)
|
|
||||||
|
|
||||||
// Remove minimum width constraint configured by ColorWell internally
|
|
||||||
let selectionWidthConstraint = selectionView.constraints.first { $0.firstAnchor == selectionView.widthAnchor }
|
|
||||||
selectionWidthConstraint?.isActive = false
|
|
||||||
|
|
||||||
NSLayoutConstraint.activate([
|
|
||||||
selectionViewXConstraint!,
|
|
||||||
selectionView.centerYAnchor.constraint(equalTo: self.centerYAnchor),
|
|
||||||
selectionView.widthAnchor.constraint(equalToConstant: UIFloat(24))
|
|
||||||
])
|
|
||||||
|
|
||||||
valueObserver = observe(\.value) { _, _ in self.valueChanged() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
|
||||||
fatalError("init(coder:) has not been implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override func layoutSubviews() {
|
|
||||||
super.layoutSubviews()
|
|
||||||
checkerboardView.layer.cornerRadius = checkerboardView.frame.size.height / 2
|
|
||||||
valueChanged()
|
|
||||||
}
|
|
||||||
|
|
||||||
private func valueChanged() {
|
|
||||||
guard let selectionView = selectionView,
|
|
||||||
let selectionViewXConstraint = selectionViewXConstraint else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
let spacing = frame.size.height - selectionView.frame.size.height
|
|
||||||
selectionViewXConstraint.constant = (spacing / 2) + ((frame.size.width - selectionView.frame.size.width - spacing) * CGFloat(value))
|
|
||||||
}
|
|
||||||
}
|
|