mirror of
https://github.com/neon443/ShhShell.git
synced 2026-03-11 13:26:16 +00:00
added themes to hostsmanager
added loadthemes added savethemes theme is now identifieable theme has a computed property themecodable to make it easier to convert extended swiftterm.color to have a colorCodabel property adding themes amanger ui
This commit is contained in:
@@ -40,6 +40,7 @@
|
|||||||
A9C4140C2E096DB7005E3047 /* SSHError.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9C4140B2E096DB7005E3047 /* SSHError.swift */; };
|
A9C4140C2E096DB7005E3047 /* SSHError.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9C4140B2E096DB7005E3047 /* SSHError.swift */; };
|
||||||
A9C897EF2DF1A9A400EF9A5F /* SSHHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9C897EE2DF1A9A400EF9A5F /* SSHHandler.swift */; };
|
A9C897EF2DF1A9A400EF9A5F /* SSHHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9C897EE2DF1A9A400EF9A5F /* SSHHandler.swift */; };
|
||||||
A9D819292E0E904200442D38 /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9D819282E0E904200442D38 /* Theme.swift */; };
|
A9D819292E0E904200442D38 /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9D819282E0E904200442D38 /* Theme.swift */; };
|
||||||
|
A9D8192D2E0E9EB500442D38 /* ThemesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9D8192C2E0E9EB500442D38 /* ThemesView.swift */; };
|
||||||
A9DA97712E0D30ED00142DDC /* HostSymbol.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9DA97702E0D30ED00142DDC /* HostSymbol.swift */; };
|
A9DA97712E0D30ED00142DDC /* HostSymbol.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9DA97702E0D30ED00142DDC /* HostSymbol.swift */; };
|
||||||
A9DA97732E0D40C100142DDC /* SymbolPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9DA97722E0D40C100142DDC /* SymbolPreview.swift */; };
|
A9DA97732E0D40C100142DDC /* SymbolPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9DA97722E0D40C100142DDC /* SymbolPreview.swift */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
@@ -114,6 +115,7 @@
|
|||||||
A9C4140B2E096DB7005E3047 /* SSHError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SSHError.swift; sourceTree = "<group>"; };
|
A9C4140B2E096DB7005E3047 /* SSHError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SSHError.swift; sourceTree = "<group>"; };
|
||||||
A9C897EE2DF1A9A400EF9A5F /* SSHHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SSHHandler.swift; sourceTree = "<group>"; };
|
A9C897EE2DF1A9A400EF9A5F /* SSHHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SSHHandler.swift; sourceTree = "<group>"; };
|
||||||
A9D819282E0E904200442D38 /* Theme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Theme.swift; sourceTree = "<group>"; };
|
A9D819282E0E904200442D38 /* Theme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Theme.swift; sourceTree = "<group>"; };
|
||||||
|
A9D8192C2E0E9EB500442D38 /* ThemesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemesView.swift; sourceTree = "<group>"; };
|
||||||
A9DA97702E0D30ED00142DDC /* HostSymbol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HostSymbol.swift; sourceTree = "<group>"; };
|
A9DA97702E0D30ED00142DDC /* HostSymbol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HostSymbol.swift; sourceTree = "<group>"; };
|
||||||
A9DA97722E0D40C100142DDC /* SymbolPreview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SymbolPreview.swift; sourceTree = "<group>"; };
|
A9DA97722E0D40C100142DDC /* SymbolPreview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SymbolPreview.swift; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
@@ -217,6 +219,7 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
A92538C52DEE0742007E0A18 /* ContentView.swift */,
|
A92538C52DEE0742007E0A18 /* ContentView.swift */,
|
||||||
|
A9D8192B2E0E9EA400442D38 /* Themes */,
|
||||||
A98554532E05534F009051BD /* Keys */,
|
A98554532E05534F009051BD /* Keys */,
|
||||||
A96C6B042E0C523E00F377FE /* Hosts */,
|
A96C6B042E0C523E00F377FE /* Hosts */,
|
||||||
A923172B2E0712F200ECE1E6 /* Terminal */,
|
A923172B2E0712F200ECE1E6 /* Terminal */,
|
||||||
@@ -321,6 +324,14 @@
|
|||||||
path = Themes;
|
path = Themes;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
A9D8192B2E0E9EA400442D38 /* Themes */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
A9D8192C2E0E9EB500442D38 /* ThemesView.swift */,
|
||||||
|
);
|
||||||
|
path = Themes;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
/* End PBXGroup section */
|
/* End PBXGroup section */
|
||||||
|
|
||||||
/* Begin PBXNativeTarget section */
|
/* Begin PBXNativeTarget section */
|
||||||
@@ -467,6 +478,7 @@
|
|||||||
A923172F2E08851200ECE1E6 /* ShellView.swift in Sources */,
|
A923172F2E08851200ECE1E6 /* ShellView.swift in Sources */,
|
||||||
A985545F2E056EDD009051BD /* KeychainLayer.swift in Sources */,
|
A985545F2E056EDD009051BD /* KeychainLayer.swift in Sources */,
|
||||||
A9D819292E0E904200442D38 /* Theme.swift in Sources */,
|
A9D819292E0E904200442D38 /* Theme.swift in Sources */,
|
||||||
|
A9D8192D2E0E9EB500442D38 /* ThemesView.swift in Sources */,
|
||||||
A93143C62DF61FE300FCD5DB /* ViewModifiers.swift in Sources */,
|
A93143C62DF61FE300FCD5DB /* ViewModifiers.swift in Sources */,
|
||||||
A98554632E0587DF009051BD /* HostsView.swift in Sources */,
|
A98554632E0587DF009051BD /* HostsView.swift in Sources */,
|
||||||
A96C6A8A2E0C0B1100F377FE /* SSHState.swift in Sources */,
|
A96C6A8A2E0C0B1100F377FE /* SSHState.swift in Sources */,
|
||||||
|
|||||||
@@ -13,15 +13,39 @@ class HostsManager: ObservableObject, @unchecked Sendable {
|
|||||||
private let userDefaults = NSUbiquitousKeyValueStore.default
|
private let userDefaults = NSUbiquitousKeyValueStore.default
|
||||||
|
|
||||||
@Published var savedHosts: [Host] = []
|
@Published var savedHosts: [Host] = []
|
||||||
|
@Published var themes: [Theme] = []
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
loadSavedHosts()
|
loadSavedHosts()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get the index of a matching host in saved hosts
|
|
||||||
/// - Parameter host: input a host
|
func loadThemes() {
|
||||||
/// - Returns: if an item in savedHosts has a matching uuid to the parameter, it returns the index
|
guard let dataTheme = userDefaults.data(forKey: "themes") else { return }
|
||||||
/// else returns nil
|
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 {
|
||||||
|
if let encoded = try? JSONEncoder().encode(decodedThemes) {
|
||||||
|
if let synthedTheme = Theme.fromiTermColors(name: decodedThemeNames[index], data: encoded) {
|
||||||
|
self.themes.append(synthedTheme)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func saveThemes() {
|
||||||
|
let encoder = JSONEncoder()
|
||||||
|
guard let encodedThemes = try? encoder.encode(themes.map({$0.themeCodable})) else { return }
|
||||||
|
guard let encodedThemeNames = try? encoder.encode(themes.map{$0.name}) else { return }
|
||||||
|
|
||||||
|
userDefaults.set(encodedThemes, forKey: "themes")
|
||||||
|
userDefaults.set(encodedThemeNames, forKey: "themeNames")
|
||||||
|
userDefaults.synchronize()
|
||||||
|
}
|
||||||
|
|
||||||
func getHostIndexMatching(_ hostSearchingFor: Host) -> Int? {
|
func getHostIndexMatching(_ hostSearchingFor: Host) -> Int? {
|
||||||
if let index = savedHosts.firstIndex(where: { $0.id == hostSearchingFor.id }) {
|
if let index = savedHosts.firstIndex(where: { $0.id == hostSearchingFor.id }) {
|
||||||
return index
|
return index
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ import Foundation
|
|||||||
import SwiftTerm
|
import SwiftTerm
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct Theme: Hashable, Equatable {
|
struct Theme: Hashable, Equatable, Identifiable {
|
||||||
|
var id = UUID()
|
||||||
var name: String
|
var name: String
|
||||||
var ansi: [SwiftTerm.Color]
|
var ansi: [SwiftTerm.Color]
|
||||||
var foreground: SwiftTerm.Color
|
var foreground: SwiftTerm.Color
|
||||||
@@ -20,6 +21,34 @@ struct Theme: Hashable, Equatable {
|
|||||||
var selectedText: SwiftTerm.Color
|
var selectedText: SwiftTerm.Color
|
||||||
var selection: SwiftTerm.Color
|
var selection: SwiftTerm.Color
|
||||||
|
|
||||||
|
var themeCodable: ThemeCodable {
|
||||||
|
return ThemeCodable(
|
||||||
|
ansi0: ansi[0].colorCodable,
|
||||||
|
ansi1: ansi[1].colorCodable,
|
||||||
|
ansi2: ansi[2].colorCodable,
|
||||||
|
ansi3: ansi[3].colorCodable,
|
||||||
|
ansi4: ansi[4].colorCodable,
|
||||||
|
ansi5: ansi[5].colorCodable,
|
||||||
|
ansi6: ansi[6].colorCodable,
|
||||||
|
ansi7: ansi[7].colorCodable,
|
||||||
|
ansi8: ansi[8].colorCodable,
|
||||||
|
ansi9: ansi[9].colorCodable,
|
||||||
|
ansi10: ansi[10].colorCodable,
|
||||||
|
ansi11: ansi[11].colorCodable,
|
||||||
|
ansi12: ansi[12].colorCodable,
|
||||||
|
ansi13: ansi[13].colorCodable,
|
||||||
|
ansi14: ansi[14].colorCodable,
|
||||||
|
ansi15: ansi[15].colorCodable,
|
||||||
|
foreground: foreground.colorCodable,
|
||||||
|
background: background.colorCodable,
|
||||||
|
cursor: cursor.colorCodable,
|
||||||
|
cursorText: cursorText.colorCodable,
|
||||||
|
bold: bold.colorCodable,
|
||||||
|
selectedText: selectedText.colorCodable,
|
||||||
|
selection: selection.colorCodable
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
static func fromiTermColors(name: String, data: Data?) -> Theme? {
|
static func fromiTermColors(name: String, data: Data?) -> Theme? {
|
||||||
guard let data else { return nil }
|
guard let data else { return nil }
|
||||||
|
|
||||||
@@ -122,6 +151,13 @@ extension SwiftTerm.Color {
|
|||||||
let blue = UInt16(colorCodable.blue * 65535)
|
let blue = UInt16(colorCodable.blue * 65535)
|
||||||
self.init(red: red, green: green, blue: blue)
|
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 {
|
extension SwiftTerm.Color {
|
||||||
|
|||||||
@@ -65,6 +65,14 @@ struct HostsView: View {
|
|||||||
.onMove(perform: {
|
.onMove(perform: {
|
||||||
hostsManager.moveHost(from: $0, to: $1)
|
hostsManager.moveHost(from: $0, to: $1)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Section() {
|
||||||
|
NavigationLink {
|
||||||
|
ThemesView(hostsManager: HostsManager())
|
||||||
|
} label: {
|
||||||
|
Label("Themes", systemImage: "swatchpalette")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.transition(.opacity)
|
.transition(.opacity)
|
||||||
.toolbar {
|
.toolbar {
|
||||||
|
|||||||
24
ShhShell/Views/Themes/ThemesView.swift
Normal file
24
ShhShell/Views/Themes/ThemesView.swift
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
//
|
||||||
|
// ThemesView.swift
|
||||||
|
// ShhShell
|
||||||
|
//
|
||||||
|
// Created by neon443 on 27/06/2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct ThemesView: View {
|
||||||
|
@ObservedObject var hostsManager: HostsManager
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
ForEach(hostsManager.themes) { theme in
|
||||||
|
ZStack {
|
||||||
|
RoundedRectangle(cornerRadius: 10)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#Preview {
|
||||||
|
ThemesView(hostsManager: HostsManager())
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user