added downloadtheme funciton to download and import a theme from an iterm2colorschemes.com link

added import theme to import a theme
updated loadthemes
updated themesview to add import buttons and updated the view
fix themesview making a new instance of hostsmanager
added suiColor to get a swiftui color from a swiftterm color
fix uicolor returning black all the time
This commit is contained in:
neon443
2025-06-27 18:01:27 +01:00
parent 56289f0f6d
commit d33b7d4eaf
5 changed files with 115 additions and 233 deletions

View File

@@ -17,6 +17,7 @@ class HostsManager: ObservableObject, @unchecked Sendable {
init() { init() {
loadSavedHosts() loadSavedHosts()
loadThemes()
} }
@@ -28,12 +29,31 @@ class HostsManager: ObservableObject, @unchecked Sendable {
guard let decodedThemeNames = try? JSONDecoder().decode([String].self, from: dataThemeNames) else { return } guard let decodedThemeNames = try? JSONDecoder().decode([String].self, from: dataThemeNames) else { return }
for index in 0..<decodedThemes.count { for index in 0..<decodedThemes.count {
if let encoded = try? JSONEncoder().encode(decodedThemes) { guard let encoded = try? JSONEncoder().encode(decodedThemes) else { return }
if let synthedTheme = Theme.fromiTermColors(name: decodedThemeNames[index], data: encoded) { guard let synthedTheme = Theme.decodeTheme(name: decodedThemeNames[index], data: encoded) else { return }
self.themes.append(synthedTheme) self.themes.append(synthedTheme)
} }
}
func downloadTheme(fromUrl: URL?) {
guard let fromUrl else { return }
let task = URLSession.shared.dataTask(with: fromUrl) { data, response, error in
guard let data else { return }
let name = fromUrl.lastPathComponent.replacingOccurrences(of: ".itermcolors", with: "")
DispatchQueue.main.async {
self.importTheme(name: name, data: data)
} }
} }
task.resume()
}
@MainActor
func importTheme(name: String, data: Data?) {
guard let data else { return }
guard let theme = Theme.decodeTheme(name: name, data: data) else { return }
self.themes.append(theme)
saveThemes()
} }
func saveThemes() { func saveThemes() {

View File

@@ -21,224 +21,6 @@ struct ShhShellApp: App {
keyManager: keyManager keyManager: keyManager
) )
.colorScheme(.dark) .colorScheme(.dark)
.onAppear {
let data = """
<?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>Ansi 0 Color</key>
<dict>
<key>Blue Component</key>
<real>0.0</real>
<key>Green Component</key>
<real>0.0</real>
<key>Red Component</key>
<real>0.0</real>
</dict>
<key>Ansi 1 Color</key>
<dict>
<key>Blue Component</key>
<real>0.40000000000000002</real>
<key>Green Component</key>
<real>0.40000000000000002</real>
<key>Red Component</key>
<real>0.80000000000000004</real>
</dict>
<key>Ansi 10 Color</key>
<dict>
<key>Blue Component</key>
<real>0.40784313729999999</real>
<key>Green Component</key>
<real>0.74117647060000003</real>
<key>Red Component</key>
<real>0.70980392160000005</real>
</dict>
<key>Ansi 11 Color</key>
<dict>
<key>Blue Component</key>
<real>0.4549019608</real>
<key>Green Component</key>
<real>0.77647058820000003</real>
<key>Red Component</key>
<real>0.94117647059999998</real>
</dict>
<key>Ansi 12 Color</key>
<dict>
<key>Blue Component</key>
<real>0.74509803919999995</real>
<key>Green Component</key>
<real>0.63529411759999999</real>
<key>Red Component</key>
<real>0.50588235290000005</real>
</dict>
<key>Ansi 13 Color</key>
<dict>
<key>Blue Component</key>
<real>0.73333333329999995</real>
<key>Green Component</key>
<real>0.58039215690000001</real>
<key>Red Component</key>
<real>0.69803921570000005</real>
</dict>
<key>Ansi 14 Color</key>
<dict>
<key>Blue Component</key>
<real>0.71764705880000002</real>
<key>Green Component</key>
<real>0.74509803919999995</real>
<key>Red Component</key>
<real>0.54117647059999996</real>
</dict>
<key>Ansi 15 Color</key>
<dict>
<key>Blue Component</key>
<real>0.99999129772186279</real>
<key>Green Component</key>
<real>0.99997437000274658</real>
<key>Red Component</key>
<real>1</real>
</dict>
<key>Ansi 2 Color</key>
<dict>
<key>Blue Component</key>
<real>0.40784313725490196</real>
<key>Green Component</key>
<real>0.74117647058823533</real>
<key>Red Component</key>
<real>0.70980392156862748</real>
</dict>
<key>Ansi 3 Color</key>
<dict>
<key>Blue Component</key>
<real>0.45490196078431372</real>
<key>Green Component</key>
<real>0.77647058823529413</real>
<key>Red Component</key>
<real>0.94117647058823528</real>
</dict>
<key>Ansi 4 Color</key>
<dict>
<key>Blue Component</key>
<real>0.74509803921568629</real>
<key>Green Component</key>
<real>0.63529411764705879</real>
<key>Red Component</key>
<real>0.50588235294117645</real>
</dict>
<key>Ansi 5 Color</key>
<dict>
<key>Blue Component</key>
<real>0.73333333333333328</real>
<key>Green Component</key>
<real>0.58039215686274503</real>
<key>Red Component</key>
<real>0.69803921568627447</real>
</dict>
<key>Ansi 6 Color</key>
<dict>
<key>Blue Component</key>
<real>0.71764705882352942</real>
<key>Green Component</key>
<real>0.74509803921568629</real>
<key>Red Component</key>
<real>0.54117647058823526</real>
</dict>
<key>Ansi 7 Color</key>
<dict>
<key>Blue Component</key>
<real>0.99999129772186279</real>
<key>Green Component</key>
<real>0.99997437000274658</real>
<key>Red Component</key>
<real>1</real>
</dict>
<key>Ansi 8 Color</key>
<dict>
<key>Blue Component</key>
<real>0.0</real>
<key>Green Component</key>
<real>0.0</real>
<key>Red Component</key>
<real>0.0</real>
</dict>
<key>Ansi 9 Color</key>
<dict>
<key>Blue Component</key>
<real>0.40000000000000002</real>
<key>Green Component</key>
<real>0.40000000000000002</real>
<key>Red Component</key>
<real>0.80000000000000004</real>
</dict>
<key>Background Color</key>
<dict>
<key>Blue Component</key>
<real>0.12941177189350128</real>
<key>Green Component</key>
<real>0.12156862765550613</real>
<key>Red Component</key>
<real>0.11372549086809158</real>
</dict>
<key>Bold Color</key>
<dict>
<key>Blue Component</key>
<real>0.77647058820000003</real>
<key>Green Component</key>
<real>0.7843137255</real>
<key>Red Component</key>
<real>0.7725490196</real>
</dict>
<key>Cursor Color</key>
<dict>
<key>Blue Component</key>
<real>0.77647058820000003</real>
<key>Green Component</key>
<real>0.7843137255</real>
<key>Red Component</key>
<real>0.7725490196</real>
</dict>
<key>Cursor Text Color</key>
<dict>
<key>Blue Component</key>
<real>0.12941177189350128</real>
<key>Green Component</key>
<real>0.12156862765550613</real>
<key>Red Component</key>
<real>0.11372549086809158</real>
</dict>
<key>Foreground Color</key>
<dict>
<key>Blue Component</key>
<real>0.77647058823529413</real>
<key>Green Component</key>
<real>0.78431372549019607</real>
<key>Red Component</key>
<real>0.77254901960784317</real>
</dict>
<key>Selected Text Color</key>
<dict>
<key>Blue Component</key>
<real>0.77647058820000003</real>
<key>Green Component</key>
<real>0.7843137255</real>
<key>Red Component</key>
<real>0.7725490196</real>
</dict>
<key>Selection Color</key>
<dict>
<key>Blue Component</key>
<real>0.25490196078431371</real>
<key>Green Component</key>
<real>0.23137254901960785</real>
<key>Red Component</key>
<real>0.21568627450980393</real>
</dict>
</dict>
</plist>
""".data(using: .utf8)
print("theme \(Theme.fromiTermColors(name: "tomorrow night", data: data))")
}
} }
} }
} }

View File

@@ -49,13 +49,16 @@ struct Theme: Hashable, Equatable, Identifiable {
) )
} }
static func fromiTermColors(name: String, data: Data?) -> Theme? { static func decodeTheme(name: String, data: Data?) -> Theme? {
guard let data else { return nil } guard let data else { return nil }
let decoder = PropertyListDecoder() let plistDecoder = PropertyListDecoder()
let jsonDecoder = JSONDecoder()
guard let decoded = try? decoder.decode(ThemeCodable.self, from: data) else { return nil }
guard let decoded =
(try? plistDecoder.decode(ThemeCodable.self, from: data)) ??
(try? jsonDecoder.decode(ThemeCodable.self, from: data))
else { return nil }
let theme = Theme( let theme = Theme(
name: name, name: name,
ansi: decoded.ansi, ansi: decoded.ansi,
@@ -161,10 +164,14 @@ extension SwiftTerm.Color {
} }
extension SwiftTerm.Color { extension SwiftTerm.Color {
var suiColor: SwiftUI.Color {
return Color(uiColor: self.uiColor)
}
var uiColor: UIColor { var uiColor: UIColor {
let red = CGFloat(self.red/65535) let red = CGFloat(self.red)/65535
let green = CGFloat(self.green/65535) let green = CGFloat(self.green)/65535
let blue = CGFloat(self.blue/65535) let blue = CGFloat(self.blue)/65535
return UIColor(red: red, green: green, blue: blue, alpha: 1) return UIColor(red: red, green: green, blue: blue, alpha: 1)
} }
} }

View File

@@ -68,7 +68,7 @@ struct HostsView: View {
Section() { Section() {
NavigationLink { NavigationLink {
ThemesView(hostsManager: HostsManager()) ThemesView(hostsManager: hostsManager)
} label: { } label: {
Label("Themes", systemImage: "swatchpalette") Label("Themes", systemImage: "swatchpalette")
} }

View File

@@ -10,10 +10,83 @@ import SwiftUI
struct ThemesView: View { struct ThemesView: View {
@ObservedObject var hostsManager: HostsManager @ObservedObject var hostsManager: HostsManager
@State var showAlert: Bool = false
@State var importURL: String = ""
@State var toImportName: String = ""
var body: some View { var body: some View {
ForEach(hostsManager.themes) { theme in NavigationStack {
ZStack { List {
RoundedRectangle(cornerRadius: 10) ScrollView(.horizontal) {
HStack {
ForEach(hostsManager.themes) { theme in
ZStack(alignment: .center) {
RoundedRectangle(cornerRadius: 10)
.fill(theme.background.suiColor)
VStack(alignment: .leading) {
Text(theme.name)
.foregroundStyle(theme.foreground.suiColor)
HStack {
ForEach(0..<8, id: \.self) { index in
Rectangle()
.frame(width: 12)
.foregroundStyle(theme.ansi[index].suiColor)
.onAppear {
print(index)
}
}
}
HStack {
ForEach(8..<16, id: \.self) { index in
Rectangle()
.frame(width: 12)
.foregroundStyle(theme.ansi[index].suiColor)
.onAppear {
print(index)
}
}
}
}
}
.frame(width: 100, height: 100)
}
}
}
.scrollIndicators(.hidden)
}
.alert("Enter URL of your theme", isPresented: $showAlert) {
TextField("", text: $importURL, prompt: Text("from iterm2colorschemes.com"))
Button() {
hostsManager.downloadTheme(fromUrl: URL(string: importURL))
importURL = ""
} label: {
Label("Import", systemImage: "square.and.arrow.down")
}
}
.toolbar {
ToolbarItem(placement: .confirmationAction) {
Button() {
if let pasteboard = UIPasteboard().string {
hostsManager.importTheme(name: toImportName, data: pasteboard.data(using: .utf8))
}
} label: {
Label("Import", systemImage: "plus")
}
}
ToolbarItem() {
Button() {
UIApplication.shared.open(URL(string: "https://iterm2colorschemes.com")!)
} label: {
Label("Open themes site", systemImage: "safari")
}
}
ToolbarItem() {
Button() {
showAlert.toggle()
} label: {
Label("From URL", systemImage: "link")
}
}
} }
} }
} }