Adds “Contributors” section to Credits
Lists everyone who has contributed to Delta in some way besides the core team, as well as what they contributed. Moves Grant Gliner and Chris Rittenhouse to Contributors from main Credits.
This commit is contained in:
parent
d1c45c9ad0
commit
45665138b2
@ -170,11 +170,14 @@
|
||||
D524F4A3273DE9C000D500B2 /* ProcessInfo+JIT.swift in Sources */ = {isa = PBXBuildFile; fileRef = D524F4A2273DE9C000D500B2 /* ProcessInfo+JIT.swift */; };
|
||||
D524F4A5273DEBB400D500B2 /* ServerManager+Delta.swift in Sources */ = {isa = PBXBuildFile; fileRef = D524F4A4273DEBB400D500B2 /* ServerManager+Delta.swift */; };
|
||||
D5011C48281B6E8B00A0760B /* CharacterSet+Filename.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5011C47281B6E8B00A0760B /* CharacterSet+Filename.swift */; };
|
||||
D53415A5298C782A00FD67B1 /* ContributorsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D53415A4298C782A00FD67B1 /* ContributorsView.swift */; };
|
||||
D53415A7298C78BC00FD67B1 /* Contributors.plist in Resources */ = {isa = PBXBuildFile; fileRef = D53415A6298C78BC00FD67B1 /* Contributors.plist */; };
|
||||
D5864970297734280081477E /* CheatMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = D586496F297734280081477E /* CheatMetadata.swift */; };
|
||||
D586497229774ABD0081477E /* CheatBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = D586497129774ABD0081477E /* CheatBase.swift */; };
|
||||
D5864978297756CE0081477E /* CheatBaseView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5864977297756CE0081477E /* CheatBaseView.swift */; };
|
||||
D5A98CE2284EF14B00E023E5 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A98CE1284EF14B00E023E5 /* SceneDelegate.swift */; };
|
||||
D5AAF27729884F8600F21ACF /* CheatDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5AAF27629884F8600F21ACF /* CheatDevice.swift */; };
|
||||
D5D797E6298D946200738869 /* Contributor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5D797E5298D946200738869 /* Contributor.swift */; };
|
||||
D5F82FB82981D3AC00B229AF /* LegacySearchBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5F82FB72981D3AC00B229AF /* LegacySearchBar.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
@ -373,11 +376,14 @@
|
||||
D524F4A2273DE9C000D500B2 /* ProcessInfo+JIT.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ProcessInfo+JIT.swift"; sourceTree = "<group>"; };
|
||||
D524F4A4273DEBB400D500B2 /* ServerManager+Delta.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ServerManager+Delta.swift"; sourceTree = "<group>"; };
|
||||
D5011C47281B6E8B00A0760B /* CharacterSet+Filename.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CharacterSet+Filename.swift"; sourceTree = "<group>"; };
|
||||
D53415A4298C782A00FD67B1 /* ContributorsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContributorsView.swift; sourceTree = "<group>"; };
|
||||
D53415A6298C78BC00FD67B1 /* Contributors.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Contributors.plist; sourceTree = "<group>"; };
|
||||
D586496F297734280081477E /* CheatMetadata.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheatMetadata.swift; sourceTree = "<group>"; };
|
||||
D586497129774ABD0081477E /* CheatBase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheatBase.swift; sourceTree = "<group>"; };
|
||||
D5864977297756CE0081477E /* CheatBaseView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheatBaseView.swift; sourceTree = "<group>"; };
|
||||
D5A98CE1284EF14B00E023E5 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
|
||||
D5AAF27629884F8600F21ACF /* CheatDevice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheatDevice.swift; sourceTree = "<group>"; };
|
||||
D5D797E5298D946200738869 /* Contributor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Contributor.swift; sourceTree = "<group>"; };
|
||||
D5F82FB72981D3AC00B229AF /* LegacySearchBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacySearchBar.swift; sourceTree = "<group>"; };
|
||||
DC866E433B3BA9AE18ABA1EC /* libPods-Delta.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Delta.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
/* End PBXFileReference section */
|
||||
@ -744,6 +750,7 @@
|
||||
BF11734E1DA32CEC00047DF8 /* Controllers */,
|
||||
BF1DAD5B1D9F574900E752A7 /* Controller Skins */,
|
||||
BF48F74C219A16C100BC2FC1 /* Syncing */,
|
||||
D5D797E4298D944C00738869 /* Contributors */,
|
||||
);
|
||||
path = Settings;
|
||||
sourceTree = "<group>";
|
||||
@ -795,6 +802,7 @@
|
||||
BF6BB2451BB73FE800CCF94A /* Assets.xcassets */,
|
||||
BF02D5D91DDEBB3000A5E131 /* openvgdb.sqlite */,
|
||||
D5050A1B2989A84200ABE08D /* cheatbase.sqlite */,
|
||||
D53415A6298C78BC00FD67B1 /* Contributors.plist */,
|
||||
);
|
||||
path = Resources;
|
||||
sourceTree = "<group>";
|
||||
@ -917,6 +925,15 @@
|
||||
path = Cheats;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D5D797E4298D944C00738869 /* Contributors */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D5D797E5298D946200738869 /* Contributor.swift */,
|
||||
D53415A4298C782A00FD67B1 /* ContributorsView.swift */,
|
||||
);
|
||||
path = Contributors;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
FD1E8AE87FA2DB8793F7B937 /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -1023,6 +1040,7 @@
|
||||
BF3540001C5DA3C500C1184C /* PausePresentationControllerContentView.xib in Resources */,
|
||||
BF5E7F461B9A652600AE44F8 /* Settings.storyboard in Resources */,
|
||||
BF02D5DA1DDEBB3000A5E131 /* openvgdb.sqlite in Resources */,
|
||||
D53415A7298C78BC00FD67B1 /* Contributors.plist in Resources */,
|
||||
BF71CF8A1FE904B1001F1613 /* GameTableViewCell.xib in Resources */,
|
||||
BFFC46461D59861000AF2CC6 /* LaunchScreen.storyboard in Resources */,
|
||||
D5050A1C2989A84200ABE08D /* cheatbase.sqlite in Resources */,
|
||||
@ -1183,6 +1201,7 @@
|
||||
BF5942951E09BD1A0051894B /* NSManagedObjectContext+Conveniences.swift in Sources */,
|
||||
BFC3628021ADE2BA00EF2BE6 /* UIAlertController+Error.swift in Sources */,
|
||||
BF353FF91C5D870B00C1184C /* MenuItem.swift in Sources */,
|
||||
D5D797E6298D946200738869 /* Contributor.swift in Sources */,
|
||||
BFDB3418219E4B1700595A62 /* SyncStatusViewController.swift in Sources */,
|
||||
BF18B61F1E2985F900F70067 /* UIAlertController+Importing.swift in Sources */,
|
||||
D586497229774ABD0081477E /* CheatBase.swift in Sources */,
|
||||
@ -1193,6 +1212,7 @@
|
||||
BF59426B1E09BBD00051894B /* GridCollectionViewLayout.swift in Sources */,
|
||||
BF6424851F5CBDC900D6AB44 /* UIView+ParentViewController.swift in Sources */,
|
||||
BF04E6FF1DB8625C000F35D3 /* ControllerSkinsViewController.swift in Sources */,
|
||||
D53415A5298C782A00FD67B1 /* ContributorsView.swift in Sources */,
|
||||
BF5942891E09BC8B0051894B /* _GameCollection.swift in Sources */,
|
||||
BF34FA111CF1899D006624C7 /* CheatTextView.swift in Sources */,
|
||||
D524F4A5273DEBB400D500B2 /* ServerManager+Delta.swift in Sources */,
|
||||
|
||||
@ -643,6 +643,22 @@
|
||||
</subviews>
|
||||
</tableViewCellContentView>
|
||||
</tableViewCell>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="DetailCell" textLabel="g59-8E-zW7" style="IBUITableViewCellStyleDefault" id="hkv-lx-68h">
|
||||
<rect key="frame" x="0.0" y="1766.5" width="375" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="hkv-lx-68h" id="bNT-kB-3cI">
|
||||
<rect key="frame" x="0.0" y="0.0" width="348.5" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" ambiguous="YES" text="Contributors" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="g59-8E-zW7">
|
||||
<rect key="frame" x="16" y="0.0" width="324.5" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
</tableViewCellContentView>
|
||||
</tableViewCell>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="DetailCell" textLabel="2K3-IL-94S" style="IBUITableViewCellStyleDefault" id="j7p-ZK-mHq">
|
||||
<rect key="frame" x="0.0" y="1567.5" width="375" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
|
||||
45
Delta/Settings/Contributors/Contributor.swift
Normal file
45
Delta/Settings/Contributors/Contributor.swift
Normal file
@ -0,0 +1,45 @@
|
||||
//
|
||||
// Contributor.swift
|
||||
// Delta
|
||||
//
|
||||
// Created by Riley Testut on 2/3/23.
|
||||
// Copyright © 2023 Riley Testut. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct Contributor: Identifiable, Decodable
|
||||
{
|
||||
var name: String
|
||||
|
||||
var id: String {
|
||||
// Use names as identifiers for now.
|
||||
return self.name
|
||||
}
|
||||
|
||||
var url: URL? {
|
||||
guard let link = self.link, let url = URL(string: link) else { return nil }
|
||||
return url
|
||||
}
|
||||
private var link: String?
|
||||
|
||||
var linkName: String?
|
||||
|
||||
var contributions: [Contribution]
|
||||
}
|
||||
|
||||
struct Contribution: Identifiable, Decodable
|
||||
{
|
||||
var name: String
|
||||
|
||||
var id: String {
|
||||
// Use names as identifiers for now.
|
||||
return self.name
|
||||
}
|
||||
|
||||
var url: URL? {
|
||||
guard let link = self.link, let url = URL(string: link) else { return nil }
|
||||
return url
|
||||
}
|
||||
private var link: String?
|
||||
}
|
||||
200
Delta/Settings/Contributors/ContributorsView.swift
Normal file
200
Delta/Settings/Contributors/ContributorsView.swift
Normal file
@ -0,0 +1,200 @@
|
||||
//
|
||||
// ContributionsView.swift
|
||||
// Delta
|
||||
//
|
||||
// Created by Riley Testut on 2/2/23.
|
||||
// Copyright © 2023 Riley Testut. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import SafariServices
|
||||
|
||||
@available(iOS 14, *)
|
||||
private extension NavigationLink where Label == EmptyView, Destination == EmptyView
|
||||
{
|
||||
// Copied from https://stackoverflow.com/a/66891173
|
||||
static var empty: NavigationLink {
|
||||
self.init(destination: EmptyView(), label: { EmptyView() })
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 14, *)
|
||||
extension ContributorsView
|
||||
{
|
||||
fileprivate class ViewModel: ObservableObject
|
||||
{
|
||||
@Published
|
||||
var contributors: [Contributor]?
|
||||
|
||||
@Published
|
||||
var error: Error?
|
||||
|
||||
@Published
|
||||
var webViewURL: URL?
|
||||
|
||||
weak var hostingController: UIViewController?
|
||||
|
||||
func loadContributors()
|
||||
{
|
||||
guard self.contributors == nil else { return }
|
||||
|
||||
do
|
||||
{
|
||||
let fileURL = Bundle.main.url(forResource: "Contributors", withExtension: "plist")!
|
||||
let data = try Data(contentsOf: fileURL)
|
||||
|
||||
let contributors = try PropertyListDecoder().decode([Contributor].self, from: data)
|
||||
self.contributors = contributors
|
||||
}
|
||||
catch
|
||||
{
|
||||
self.error = error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static func makeViewController() -> UIHostingController<some View>
|
||||
{
|
||||
let viewModel = ViewModel()
|
||||
let contributorsView = ContributorsView(viewModel: viewModel)
|
||||
|
||||
let hostingController = UIHostingController(rootView: contributorsView)
|
||||
hostingController.title = NSLocalizedString("Contributors", comment: "")
|
||||
|
||||
viewModel.hostingController = hostingController
|
||||
|
||||
return hostingController
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 14, *)
|
||||
struct ContributorsView: View
|
||||
{
|
||||
@StateObject
|
||||
private var viewModel: ViewModel
|
||||
|
||||
@State
|
||||
private var showErrorAlert: Bool = false
|
||||
|
||||
var body: some View {
|
||||
List {
|
||||
Section(content: {}, footer: {
|
||||
Text("These individuals have contributed to the open-source Delta project on GitHub.\n\nThank you to all our contributors, your help is much appreciated 💜")
|
||||
.font(.subheadline)
|
||||
})
|
||||
|
||||
ForEach(viewModel.contributors ?? []) { contributor in
|
||||
Section {
|
||||
// First row = contributor
|
||||
ContributionCell(name: Text(contributor.name).bold(), url: contributor.url, linkName: contributor.linkName) { webViewURL in
|
||||
viewModel.webViewURL = webViewURL
|
||||
}
|
||||
|
||||
// Remaining rows = contributions
|
||||
ForEach(contributor.contributions) { contribution in
|
||||
ContributionCell(name: Text(contribution.name), url: contribution.url) { webViewURL in
|
||||
viewModel.webViewURL = webViewURL
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.listStyle(.grouped) // TODO: Change to .insetGrouped once we drop iOS 13 support.
|
||||
.environmentObject(viewModel)
|
||||
.alert(isPresented: $showErrorAlert) {
|
||||
Alert(title: Text("Unable to Load Contributors"), message: Text(viewModel.error?.localizedDescription ?? ""), dismissButton: .default(Text("OK")) {
|
||||
guard let hostingController = viewModel.hostingController else { return }
|
||||
hostingController.navigationController?.popViewController(animated: true)
|
||||
})
|
||||
}
|
||||
.onReceive(viewModel.$error) { error in
|
||||
guard error != nil else { return }
|
||||
showErrorAlert = true
|
||||
}
|
||||
.onReceive(viewModel.$webViewURL) { webViewURL in
|
||||
guard let webViewURL else { return }
|
||||
openURL(webViewURL)
|
||||
}
|
||||
.onAppear {
|
||||
viewModel.loadContributors()
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate init(contributors: [Contributor]? = nil, viewModel: ViewModel = ViewModel())
|
||||
{
|
||||
if let contributors
|
||||
{
|
||||
// Don't overwrite passed-in viewModel.contributors if contributors is nil.
|
||||
viewModel.contributors = contributors
|
||||
}
|
||||
|
||||
self._viewModel = StateObject(wrappedValue: viewModel)
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 14, *)
|
||||
struct ContributionCell: View
|
||||
{
|
||||
var name: Text
|
||||
var url: URL?
|
||||
var linkName: String?
|
||||
|
||||
var action: (URL) -> Void
|
||||
|
||||
var body: some View {
|
||||
|
||||
let body = Button {
|
||||
guard let url else { return }
|
||||
|
||||
Task { @MainActor in
|
||||
// Dispatch Task to avoid "Publishing changes from within view updates is not allowed, this will cause undefined behavior." runtime error on iOS 16.
|
||||
self.action(url)
|
||||
}
|
||||
|
||||
} label: {
|
||||
HStack {
|
||||
self.name
|
||||
.font(.system(size: 17)) // Match Settings screen
|
||||
|
||||
Spacer()
|
||||
|
||||
if let linkName
|
||||
{
|
||||
Text(linkName)
|
||||
.font(.system(size: 17)) // Match Settings screen
|
||||
.foregroundColor(.gray)
|
||||
}
|
||||
|
||||
if url != nil
|
||||
{
|
||||
NavigationLink.empty
|
||||
.fixedSize()
|
||||
}
|
||||
}
|
||||
}
|
||||
.accentColor(.primary)
|
||||
|
||||
if url != nil
|
||||
{
|
||||
body
|
||||
}
|
||||
else
|
||||
{
|
||||
// No URL to open, so disable cell highlighting.
|
||||
body.buttonStyle(.plain)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 14, *)
|
||||
private extension ContributorsView
|
||||
{
|
||||
func openURL(_ url: URL)
|
||||
{
|
||||
guard let hostingController = viewModel.hostingController else { return }
|
||||
|
||||
let safariViewController = SFSafariViewController(url: url)
|
||||
safariViewController.preferredControlTintColor = .deltaPurple
|
||||
hostingController.present(safariViewController, animated: true)
|
||||
}
|
||||
}
|
||||
@ -49,6 +49,7 @@ private extension SettingsViewController
|
||||
case caroline
|
||||
case grant
|
||||
case litRitt
|
||||
case contributors
|
||||
case softwareLicenses
|
||||
}
|
||||
}
|
||||
@ -279,6 +280,13 @@ private extension SettingsViewController
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 14, *)
|
||||
func showContributors()
|
||||
{
|
||||
let hostingController = ContributorsView.makeViewController()
|
||||
self.navigationController?.pushViewController(hostingController, animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
private extension SettingsViewController
|
||||
@ -418,6 +426,10 @@ extension SettingsViewController
|
||||
case .caroline: self.openTwitter(username: "1carolinemoore")
|
||||
case .grant: self.openTwitter(username: "grantgliner")
|
||||
case .litRitt: self.openTwitter(username: "litritt_z")
|
||||
case .contributors:
|
||||
guard #available(iOS 14, *) else { return }
|
||||
self.showContributors()
|
||||
|
||||
case .softwareLicenses: break
|
||||
}
|
||||
}
|
||||
@ -425,13 +437,35 @@ extension SettingsViewController
|
||||
|
||||
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
|
||||
{
|
||||
primary:
|
||||
switch Section(rawValue: indexPath.section)!
|
||||
{
|
||||
#if !BETA
|
||||
case .credits where indexPath.row == CreditsRow.litRitt.rawValue: return 0.0
|
||||
#endif
|
||||
default: return super.tableView(tableView, heightForRowAt: indexPath)
|
||||
case .credits:
|
||||
let row = CreditsRow(rawValue: indexPath.row)!
|
||||
switch row
|
||||
{
|
||||
case .grant:
|
||||
// Hide row on iOS 14 and above
|
||||
guard #available(iOS 14, *) else { break primary }
|
||||
return 0.0
|
||||
|
||||
case .litRitt:
|
||||
// Hide row on iOS 14 and above
|
||||
guard #available(iOS 14, *) else { break primary }
|
||||
return 0.0
|
||||
|
||||
case .contributors:
|
||||
// Hide row on iOS 13 and below
|
||||
guard #unavailable(iOS 14) else { break primary }
|
||||
return 0.0
|
||||
|
||||
default: break
|
||||
}
|
||||
|
||||
default: break
|
||||
}
|
||||
|
||||
return super.tableView(tableView, heightForRowAt: indexPath)
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String?
|
||||
|
||||
70
Resources/Contributors.plist
Normal file
70
Resources/Contributors.plist
Normal file
@ -0,0 +1,70 @@
|
||||
<?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">
|
||||
<array>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Grant Gliner</string>
|
||||
<key>link</key>
|
||||
<string>https://twitter.com/GrantGliner</string>
|
||||
<key>linkName</key>
|
||||
<string>@GrantGliner</string>
|
||||
<key>contributions</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Pause Menu Icons</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Eric Lewis</string>
|
||||
<key>link</key>
|
||||
<string>https://github.com/ericlewis</string>
|
||||
<key>linkName</key>
|
||||
<string>github.com/ericlewis</string>
|
||||
<key>contributions</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Dark Mode</string>
|
||||
<key>link</key>
|
||||
<string>https://github.com/rileytestut/Delta/pull/82</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Chris Rittenhouse</string>
|
||||
<key>link</key>
|
||||
<string>https://github.com/LitRitt</string>
|
||||
<key>linkName</key>
|
||||
<string>github.com/LitRitt</string>
|
||||
<key>contributions</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Genesis Skin</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Noah Keck</string>
|
||||
<key>link</key>
|
||||
<string>https://github.com/noah978</string>
|
||||
<key>linkName</key>
|
||||
<string>github.com/noah978</string>
|
||||
<key>contributions</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>CheatBase</string>
|
||||
<key>link</key>
|
||||
<string>https://github.com/CheatBase/CheatBase</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
</plist>
|
||||
Loading…
Reference in New Issue
Block a user