Last active
November 14, 2022 01:50
-
-
Save simonbs/6387d695d73a4118e668ce240fec55d1 to your computer and use it in GitHub Desktop.
Sample app that lets you browse Xcode releases. Depends on ScriptUI, my yet-to-be-releases project for building native SwiftUI interfaces in JavaScript.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
UI.view = RootView() | |
function RootView() { | |
const [isLoading, setLoading] = createSignal(true) | |
const [xcodeGroups, setXcodeGroups] = createSignal([]) | |
fetchXcodes().then((xcodes) => { | |
setLoading(false) | |
setXcodeGroups(groupXcodes(xcodes)) | |
}) | |
return () => { | |
NavigationStack(() => { | |
Group(() => { | |
if (isLoading()) { | |
LoadingView() | |
} else { | |
XcodeListView(xcodeGroups()) | |
} | |
}) | |
.background(Color("#f2f2f7")) | |
.navigationTitle("Xcode Releases") | |
}) | |
} | |
} | |
function XcodeListView(xcodeGroups) { | |
return List(() => { | |
for (const xcodeGroup of xcodeGroups) { | |
Section(() => { | |
for (xcode of xcodeGroup.xcodes) { | |
NavigationLink(() => { | |
XcodeDetailView(xcode) | |
}, () => { | |
XcodeRowView(xcode) | |
}) | |
} | |
}, () => { | |
Text(xcodeGroup.year) | |
}) | |
} | |
}) | |
} | |
function LoadingView() { | |
ZStack(() => { | |
Color("#f2f2f7") | |
VStack({spacing: 25}, () => { | |
ProgressView() | |
.scaleEffect(2) | |
Text("Loading releases...") | |
}) | |
}) | |
} | |
function XcodeRowView(xcode) { | |
VStack({alignment: HorizontalAlignment.leading}, () => { | |
Text(xcodeTitle(xcode)) | |
Text(releaseDate(xcode)).foregroundColor(Color.secondary) | |
}) | |
} | |
function XcodeDetailView(xcode) { | |
List(() => { | |
Section(() => { | |
TitleDetailRowView("Release Date", releaseDate(xcode)) | |
TitleDetailRowView("Build", xcode.version.build) | |
TitleDetailRowView("Required OS", "macOS " + xcode.requires) | |
}) | |
if (xcode.hasOwnProperty("links")) { | |
Section(() => { | |
if (xcode.links.hasOwnProperty("notes")) { | |
Button(() => { | |
Safari.open(xcode.links.notes.url) | |
}, () => { | |
HStack(() => { | |
Text("Release Notes") | |
Spacer() | |
Image.system("arrow.up.forward.app") | |
}) | |
}) | |
} | |
if (xcode.links.hasOwnProperty("download")) { | |
Button(() => { | |
Safari.open(xcode.links.download.url) | |
}, () => { | |
HStack(() => { | |
Text("Download") | |
Spacer() | |
Image.system("arrow.up.forward.app") | |
}) | |
}) | |
} | |
}) | |
} | |
if (xcode.hasOwnProperty("sdks")) { | |
Section(() => { | |
if (xcode.sdks.hasOwnProperty("macOS")) { | |
for (version of xcode.sdks["macOS"]) { | |
TitleDetailRowView("macOS", versionTitle(version, true)) | |
} | |
} | |
if (xcode.sdks.hasOwnProperty("iOS")) { | |
TitleDetailRowView("iOS", versionTitle(version, true)) | |
} | |
if (xcode.sdks.hasOwnProperty("watchOS")) { | |
TitleDetailRowView("watchOS", versionTitle(version, true)) | |
} | |
if (xcode.sdks.hasOwnProperty("tvOS")) { | |
TitleDetailRowView("tvOS", versionTitle(version, true)) | |
} | |
}, () => { | |
Text("SDKs") | |
}) | |
} | |
if (xcode.hasOwnProperty("compilers")) { | |
Section(() => { | |
if (xcode.compilers.hasOwnProperty("swift")) { | |
for (version of xcode.compilers["swift"]) { | |
TitleDetailRowView("Swift", versionTitle(version, true)) | |
} | |
} | |
if (xcode.compilers.hasOwnProperty("clang")) { | |
for (version of xcode.compilers["clang"]) { | |
TitleDetailRowView("Clang", versionTitle(version, true)) | |
} | |
} | |
}, () => { | |
Text("Compilers") | |
}) | |
} | |
if (xcode.hasOwnProperty("checksums") && xcode.checksums.hasOwnProperty("sha1")) { | |
Section(() => { | |
Text(xcode.checksums.sha1) | |
}, () => { | |
Text("Checksum") | |
}) | |
} | |
}) | |
.navigationTitle(xcodeTitle(xcode)) | |
.navigationBarTitleDisplayMode(NavigationBarTitleDisplayMode.inline) | |
} | |
function TitleDetailRowView(title, detail) { | |
HStack(() => { | |
if (title != null && title.length > 0) { | |
Text(title) | |
} | |
if (detail != null && detail.length > 0) { | |
Spacer() | |
Text(detail).foregroundColor(Color.secondary) | |
} | |
}) | |
} | |
/** | |
* Formatters | |
*/ | |
function xcodeTitle(xcode) { | |
return xcode.name + " " + versionTitle(xcode.version) | |
} | |
function versionTitle(version, includeBuild) { | |
let release = version.release | |
let str = version.number | |
if (includeBuild && version.hasOwnProperty("build")) { | |
str += " (" + version.build + ")" | |
} | |
if (release.hasOwnProperty("gm") && release.gm) { | |
str += " GM" | |
} else if (release.hasOwnProperty("gmseed")) { | |
str += " GM Seed " + release.gmseed | |
} else if (release.hasOwnProperty("beta")) { | |
str += " beta " + release.beta | |
} else if (release.hasOwnProperty("dp")) { | |
str += " Developer Preview " + release.dp | |
} | |
return str | |
} | |
function releaseDate(xcode) { | |
let date = new Date(xcode.date.year, xcode.date.month - 1, xcode.date.day) | |
let dateFormatter = new DateFormatter() | |
dateFormatter.locale = "en_US" | |
dateFormatter.useLongDateStyle() | |
dateFormatter.useNoTimeStyle() | |
return dateFormatter.string(date) | |
} | |
/** | |
* Data | |
*/ | |
async function fetchXcodes() { | |
let url = "https://xcodereleases.com/api/all.json" | |
let request = new Request(url) | |
return await request.loadJSON() | |
} | |
function groupXcodes(xcodes) { | |
var groups = {} | |
for (xcode of xcodes) { | |
let key = xcode.date.year | |
let groupValues = groups[key] | |
if (groupValues != null) { | |
groupValues.push(xcode) | |
groups[key] = groupValues | |
} else { | |
groups[key] = [xcode] | |
} | |
} | |
var result = [] | |
let keys = Object.keys(groups).sort((a, b) => b - a) | |
for (key of keys) { | |
result.push({year: key, xcodes: groups[key]}) | |
} | |
return result | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment