!!!!!!!!!!

fixed selecting themes - it now actually remembers!!
fix all themes having no names
fix remembering selected themes
added toTheme to return a theme from a themecodable
removed themeNames - its not needed as the names are saved in the ThemeCodable itself
extracted colorcodable and themecodable into their own files
removed all the debug prints
This commit is contained in:
neon443
2025-06-29 10:43:47 +01:00
parent 834fb266e9
commit a4d245caec
20 changed files with 231 additions and 138 deletions

View File

@@ -19,25 +19,22 @@ class HostsManager: ObservableObject, @unchecked Sendable {
init() {
loadHosts()
loadThemes()
print(selectedTheme == Theme.defaultTheme)
}
func loadThemes() {
guard let dataTheme = userDefaults.data(forKey: "themes") else { return }
guard let dataThemeNames = userDefaults.data(forKey: "themeNames") else { return }
guard let decodedThemes = try? JSONDecoder().decode([ThemeCodable].self, from: dataTheme) else { return }
guard let decodedThemeNames = try? JSONDecoder().decode([String].self, from: dataThemeNames) else { return }
for index in 0..<decodedThemes.count {
guard let encoded = try? JSONEncoder().encode(decodedThemes[index]) else { return }
guard let synthedTheme = Theme.decodeTheme(name: decodedThemeNames[index], data: encoded) else { return }
guard let synthedTheme = Theme.decodeTheme(data: encoded) else { return }
self.themes.append(synthedTheme)
}
guard let dataSelTheme = userDefaults.data(forKey: "selectedTheme") else { return }
guard let decodedSelTheme = Theme.decodeTheme(name: "", data: dataSelTheme) else { return }
guard let decodedSelTheme = Theme.decodeTheme(data: dataSelTheme) else { return }
//name doesnt matter
self.selectedTheme = decodedSelTheme
}
@@ -46,9 +43,8 @@ class HostsManager: ObservableObject, @unchecked Sendable {
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)
self.importTheme(data: data, fromUrl: fromUrl)
}
}
@@ -57,7 +53,6 @@ class HostsManager: ObservableObject, @unchecked Sendable {
func selectTheme(_ selectedTheme: Theme) {
withAnimation { self.selectedTheme = selectedTheme }
print("selected: \(selectedTheme.name) \(selectedTheme.id)")
saveThemes()
}
@@ -65,7 +60,7 @@ class HostsManager: ObservableObject, @unchecked Sendable {
var themeInQWithSameID = themeInQuestion
themeInQWithSameID.id = selectedTheme.id
return themeInQuestion.id == self.selectedTheme.id
return themeInQWithSameID == self.selectedTheme
}
func renameTheme(_ theme: Theme?, to newName: String) {
@@ -86,9 +81,10 @@ class HostsManager: ObservableObject, @unchecked Sendable {
}
@MainActor
func importTheme(name: String, data: Data?) {
func importTheme(data: Data?, fromUrl: URL? = nil) {
guard let data else { return }
guard let theme = Theme.decodeTheme(name: name, data: data) else { return }
guard var theme = Theme.decodeTheme(data: data) else { return }
theme.name = fromUrl?.lastPathComponent.replacingOccurrences(of: ".itermcolors", with: "") ?? ""
self.themes.append(theme)
saveThemes()
}
@@ -97,17 +93,11 @@ class HostsManager: ObservableObject, @unchecked Sendable {
let encoder = JSONEncoder()
// map the theme to themecodable
guard let encodedThemes = try? encoder.encode(themes.map({$0.themeCodable})) else { return }
//map the themes to get their names
guard let encodedThemeNames = try? encoder.encode(themes.map{$0.name}) else { return }
userDefaults.set(encodedThemes, forKey: "themes")
userDefaults.set(encodedThemeNames, forKey: "themeNames")
guard let encodedSelectedTheme = try? encoder.encode(selectedTheme.themeCodable) else { return }
userDefaults.set(encodedSelectedTheme, forKey: "selectedTheme")
userDefaults.synchronize()
print(Theme.decodeTheme(name: "", data: userDefaults.data(forKey: "selectedTheme")))
print("saved themes")
}
func getHostIndexMatching(_ hostSearchingFor: Host) -> Int? {

View File

@@ -0,0 +1,57 @@
//
// ColorCodable.swift
// ShhShell
//
// Created by neon443 on 29/06/2025.
//
import Foundation
import SwiftTerm
import SwiftUI
struct ColorCodable: Codable {
var red: Double
var green: Double
var blue: Double
enum CodingKeys: String, CodingKey {
case red = "Red Component"
case green = "Green Component"
case blue = "Blue Component"
}
}
extension ColorCodable {
var stColor: SwiftTerm.Color {
return SwiftTerm.Color(self)
}
}
extension SwiftTerm.Color {
convenience init(_ colorCodable: ColorCodable) {
let red = UInt16(colorCodable.red * 65535)
let green = UInt16(colorCodable.green * 65535)
let blue = UInt16(colorCodable.blue * 65535)
self.init(red: red, green: green, blue: blue)
}
var colorCodable: ColorCodable {
let red = Double(self.red)/65535
let green = Double(self.green)/65535
let blue = Double(self.blue)/65535
return ColorCodable(red: red, green: green, blue: blue)
}
}
extension SwiftTerm.Color {
var suiColor: SwiftUI.Color {
return Color(uiColor: self.uiColor)
}
var uiColor: UIColor {
let red = CGFloat(self.red)/65535
let green = CGFloat(self.green)/65535
let blue = CGFloat(self.blue)/65535
return UIColor(red: red, green: green, blue: blue, alpha: 1)
}
}

View File

@@ -10,7 +10,7 @@ import SwiftTerm
import SwiftUI
struct Theme: Hashable, Equatable, Identifiable {
var id: String = UUID().uuidString
var id: String
var name: String
var ansi: [SwiftTerm.Color]
var foreground: SwiftTerm.Color
@@ -23,6 +23,7 @@ struct Theme: Hashable, Equatable, Identifiable {
var themeCodable: ThemeCodable {
return ThemeCodable(
id: id,
name: name,
ansi0: ansi[0].colorCodable,
ansi1: ansi[1].colorCodable,
@@ -50,7 +51,7 @@ struct Theme: Hashable, Equatable, Identifiable {
)
}
static func decodeTheme(name: String, data: Data?) -> Theme? {
static func decodeTheme( data: Data?) -> Theme? {
guard let data else { fatalError() }
let plistDecoder = PropertyListDecoder()
@@ -60,18 +61,7 @@ struct Theme: Hashable, Equatable, Identifiable {
(try? plistDecoder.decode(ThemeCodable.self, from: data)) ??
(try? jsonDecoder.decode(ThemeCodable.self, from: data))
else { fatalError() }
var theme = Theme(
name: decoded.name ?? name,
ansi: decoded.ansi,
foreground: Color(decoded.foreground),
background: Color(decoded.background),
cursor: Color(decoded.cursor),
cursorText: Color(decoded.cursorText),
bold: Color(decoded.bold),
selectedText: Color(decoded.selectedText),
selection: Color(decoded.selection)
)
return theme
return decoded.toTheme()
}
static func decodeLocalTheme(fileName: String) -> Theme? {
@@ -80,10 +70,7 @@ struct Theme: Hashable, Equatable, Identifiable {
guard let fileContents = try? Data(contentsOf: path) else { return nil }
guard var theme = Theme.decodeTheme(name: themeName, data: fileContents) else { return nil }
theme.name = themeName
theme.id = themeName
return theme
return Theme.decodeTheme(data: fileContents)
}
static var defaultTheme: Theme {
@@ -93,6 +80,17 @@ struct Theme: Hashable, Equatable, Identifiable {
static var builtinThemes: [Theme] {
return ThemesBuiltin.allCases.map({ decodeLocalTheme(fileName: $0.rawValue)! })
}
// static func ==(lhs: Theme, rhs: Theme) -> Bool {
// return lhs.ansi == rhs.ansi &&
// lhs.foreground == rhs.foreground &&
// lhs.background == rhs.background &&
// lhs.cursor == rhs.cursor &&
// lhs.cursorText == rhs.cursorText &&
// lhs.bold == rhs.bold &&
// lhs.selectedText == rhs.selectedText &&
// lhs.selection == rhs.selection
// }
}
enum ThemesBuiltin: String, CaseIterable, Hashable, Equatable {
@@ -110,105 +108,3 @@ enum ThemesBuiltin: String, CaseIterable, Hashable, Equatable {
case gruvboxDark = "gruvboxDark"
case ubuntu = "ubuntu"
}
struct ThemeCodable: Codable {
var name: String?
var ansi0: ColorCodable
var ansi1: ColorCodable
var ansi2: ColorCodable
var ansi3: ColorCodable
var ansi4: ColorCodable
var ansi5: ColorCodable
var ansi6: ColorCodable
var ansi7: ColorCodable
var ansi8: ColorCodable
var ansi9: ColorCodable
var ansi10: ColorCodable
var ansi11: ColorCodable
var ansi12: ColorCodable
var ansi13: ColorCodable
var ansi14: ColorCodable
var ansi15: ColorCodable
var foreground: ColorCodable
var background: ColorCodable
var cursor: ColorCodable
var cursorText: ColorCodable
var bold: ColorCodable
var selectedText: ColorCodable
var selection: ColorCodable
enum CodingKeys: String, CodingKey {
case ansi0 = "Ansi 0 Color"
case ansi1 = "Ansi 1 Color"
case ansi2 = "Ansi 2 Color"
case ansi3 = "Ansi 3 Color"
case ansi4 = "Ansi 4 Color"
case ansi5 = "Ansi 5 Color"
case ansi6 = "Ansi 6 Color"
case ansi7 = "Ansi 7 Color"
case ansi8 = "Ansi 8 Color"
case ansi9 = "Ansi 9 Color"
case ansi10 = "Ansi 10 Color"
case ansi11 = "Ansi 11 Color"
case ansi12 = "Ansi 12 Color"
case ansi13 = "Ansi 13 Color"
case ansi14 = "Ansi 14 Color"
case ansi15 = "Ansi 15 Color"
case foreground = "Foreground Color"
case background = "Background Color"
case cursor = "Cursor Color"
case cursorText = "Cursor Text Color"
case bold = "Bold Color"
case selectedText = "Selected Text Color"
case selection = "Selection Color"
}
}
extension ThemeCodable {
var ansi: [SwiftTerm.Color] {
let arr = [ansi0, ansi1, ansi2, ansi3, ansi4, ansi5, ansi6, ansi7, ansi8, ansi9, ansi10, ansi11, ansi12, ansi13, ansi14, ansi15]
return arr.map(SwiftTerm.Color.init)
}
}
struct ColorCodable: Codable {
var red: Double
var green: Double
var blue: Double
enum CodingKeys: String, CodingKey {
case red = "Red Component"
case green = "Green Component"
case blue = "Blue Component"
}
}
extension SwiftTerm.Color {
convenience init(_ colorCodable: ColorCodable) {
let red = UInt16(colorCodable.red * 65535)
let green = UInt16(colorCodable.green * 65535)
let blue = UInt16(colorCodable.blue * 65535)
self.init(red: red, green: green, blue: blue)
}
var colorCodable: ColorCodable {
let red = Double(self.red)/65535
let green = Double(self.green)/65535
let blue = Double(self.blue)/65535
return ColorCodable(red: red, green: green, blue: blue)
}
}
extension SwiftTerm.Color {
var suiColor: SwiftUI.Color {
return Color(uiColor: self.uiColor)
}
var uiColor: UIColor {
let red = CGFloat(self.red)/65535
let green = CGFloat(self.green)/65535
let blue = CGFloat(self.blue)/65535
return UIColor(red: red, green: green, blue: blue, alpha: 1)
}
}

View File

@@ -0,0 +1,89 @@
//
// ThemeCodable.swift
// ShhShell
//
// Created by neon443 on 29/06/2025.
//
import Foundation
import SwiftTerm
struct ThemeCodable: Codable {
var id: String?
var name: String?
var ansi0: ColorCodable
var ansi1: ColorCodable
var ansi2: ColorCodable
var ansi3: ColorCodable
var ansi4: ColorCodable
var ansi5: ColorCodable
var ansi6: ColorCodable
var ansi7: ColorCodable
var ansi8: ColorCodable
var ansi9: ColorCodable
var ansi10: ColorCodable
var ansi11: ColorCodable
var ansi12: ColorCodable
var ansi13: ColorCodable
var ansi14: ColorCodable
var ansi15: ColorCodable
var foreground: ColorCodable
var background: ColorCodable
var cursor: ColorCodable
var cursorText: ColorCodable
var bold: ColorCodable
var selectedText: ColorCodable
var selection: ColorCodable
enum CodingKeys: String, CodingKey {
case id = "id"
case name = "name"
case ansi0 = "Ansi 0 Color"
case ansi1 = "Ansi 1 Color"
case ansi2 = "Ansi 2 Color"
case ansi3 = "Ansi 3 Color"
case ansi4 = "Ansi 4 Color"
case ansi5 = "Ansi 5 Color"
case ansi6 = "Ansi 6 Color"
case ansi7 = "Ansi 7 Color"
case ansi8 = "Ansi 8 Color"
case ansi9 = "Ansi 9 Color"
case ansi10 = "Ansi 10 Color"
case ansi11 = "Ansi 11 Color"
case ansi12 = "Ansi 12 Color"
case ansi13 = "Ansi 13 Color"
case ansi14 = "Ansi 14 Color"
case ansi15 = "Ansi 15 Color"
case foreground = "Foreground Color"
case background = "Background Color"
case cursor = "Cursor Color"
case cursorText = "Cursor Text Color"
case bold = "Bold Color"
case selectedText = "Selected Text Color"
case selection = "Selection Color"
}
}
extension ThemeCodable {
var ansi: [SwiftTerm.Color] {
let arr = [ansi0, ansi1, ansi2, ansi3, ansi4, ansi5, ansi6, ansi7, ansi8, ansi9, ansi10, ansi11, ansi12, ansi13, ansi14, ansi15]
return arr.map(SwiftTerm.Color.init)
}
}
extension ThemeCodable {
func toTheme() -> Theme {
return Theme(
id: id ?? UUID().uuidString,
name: self.name ?? "",
ansi: self.ansi,
foreground: self.foreground.stColor,
background: self.background.stColor,
cursor: self.cursor.stColor,
cursorText: self.cursorText.stColor,
bold: self.bold.stColor,
selectedText: self.selectedText.stColor,
selection: self.selection.stColor
)
}
}

View File

@@ -83,6 +83,7 @@ struct ThemeManagerView: View {
ThemePreview(hostsManager: hostsManager, theme: theme)
}
}
.animation(.default, value: hostsManager.themes)
}
.scrollIndicators(.hidden)
.fixedSize(horizontal: false, vertical: true)

View File

@@ -63,6 +63,6 @@ struct ThemePreview: View {
ThemePreview(
hostsManager: HostsManager(),
theme: Theme.decodeTheme(name: "theme", data: data)!
theme: Theme.decodeTheme(data: data)!
)
}