diff --git a/ShhShell/Host/HostsManager.swift b/ShhShell/Host/HostsManager.swift index 1edff23..91b9320 100644 --- a/ShhShell/Host/HostsManager.swift +++ b/ShhShell/Host/HostsManager.swift @@ -15,6 +15,7 @@ class HostsManager: ObservableObject, @unchecked Sendable { @Published var hosts: [Host] = [] @Published var themes: [Theme] = [] @Published var selectedTheme: Theme = Theme.defaultTheme + @Published var selectedAnsi: Int = 1 init() { loadHosts() @@ -33,11 +34,25 @@ class HostsManager: ObservableObject, @unchecked Sendable { self.themes.append(synthedTheme) } - guard let dataSelTheme = userDefaults.data(forKey: "selectedTheme") else { return } guard let decodedSelTheme = Theme.decodeTheme(data: dataSelTheme) else { return } //name doesnt matter self.selectedTheme = decodedSelTheme + + selectedAnsi = Int(userDefaults.longLong(forKey: "selectedAnsi")) + } + + func saveThemes() { + let encoder = JSONEncoder() + // map the theme to themecodable + guard let encodedThemes = try? encoder.encode(themes.map({$0.themeCodable})) else { return } + userDefaults.set(encodedThemes, forKey: "themes") + + guard let encodedSelectedTheme = try? encoder.encode(selectedTheme.themeCodable) else { return } + userDefaults.set(encodedSelectedTheme, forKey: "selectedTheme") + + userDefaults.set(Int64(selectedAnsi), forKey: "selectedAnsi") + userDefaults.synchronize() } func downloadTheme(fromUrl: URL?) { @@ -87,17 +102,6 @@ class HostsManager: ObservableObject, @unchecked Sendable { saveThemes() } - func saveThemes() { - let encoder = JSONEncoder() - // map the theme to themecodable - guard let encodedThemes = try? encoder.encode(themes.map({$0.themeCodable})) else { return } - userDefaults.set(encodedThemes, forKey: "themes") - - guard let encodedSelectedTheme = try? encoder.encode(selectedTheme.themeCodable) else { return } - userDefaults.set(encodedSelectedTheme, forKey: "selectedTheme") - userDefaults.synchronize() - } - func getHostIndexMatching(_ hostSearchingFor: Host) -> Int? { if let index = hosts.firstIndex(where: { $0.id == hostSearchingFor.id }) { return index diff --git a/ShhShell/ShhShellApp.swift b/ShhShell/ShhShellApp.swift index cb050db..58b279d 100644 --- a/ShhShell/ShhShellApp.swift +++ b/ShhShell/ShhShellApp.swift @@ -28,6 +28,7 @@ struct ShhShellApp: App { keyManager: keyManager ) .colorScheme(.dark) + .tint(hostsManager.selectedTheme.ansi[hostsManager.selectedAnsi].suiColor) } } } diff --git a/ShhShell/Views/Sessions/SessionView.swift b/ShhShell/Views/Sessions/SessionView.swift index 7cb0f15..68fab5a 100644 --- a/ShhShell/Views/Sessions/SessionView.swift +++ b/ShhShell/Views/Sessions/SessionView.swift @@ -34,10 +34,7 @@ struct SessionView: View { } } .fullScreenCover(isPresented: $shellPresented) { - ShellView( - handler: container.sessions[key]?.handler ?? SSHHandler(host: Host.blank, keyManager: keyManager), - hostsManager: hostsManager - ) + ShellTabView(handler: nil, hostsManager: hostsManager, selectedID: key) } } } diff --git a/ShhShell/Views/Terminal/ShellTabView.swift b/ShhShell/Views/Terminal/ShellTabView.swift index c84a6f8..2ab5535 100644 --- a/ShhShell/Views/Terminal/ShellTabView.swift +++ b/ShhShell/Views/Terminal/ShellTabView.swift @@ -8,7 +8,7 @@ import SwiftUI struct ShellTabView: View { - @ObservedObject var handler: SSHHandler + @State var handler: SSHHandler? @ObservedObject var hostsManager: HostsManager @ObservedObject var container = TerminalViewContainer.shared @@ -23,13 +23,38 @@ struct ShellTabView: View { ScrollView(.horizontal, showsIndicators: false) { HStack(spacing: 0) { ForEach(container.sessionIDs, id: \.self) { id in + let selected = selectedID == id + let foreground = hostsManager.selectedTheme.foreground.suiColor + let ansi7 = hostsManager.selectedTheme.ansi[6].suiColor.opacity(0.7) + let background = hostsManager.selectedTheme.background.suiColor ZStack { Rectangle() - .fill(selectedID == id ? .orange : .gray) - .opacity(0.5) - Text(container.sessions[id]!.handler.host.description) - .frame(width: oneTabWidth) + .fill(selected ? ansi7 : background) + HStack { + if selected { + Button() { + container.sessions[id]?.handler.disconnect() + } label: { + Image(systemName: "xmark.app.fill") + .resizable().scaledToFit() + } + .padding() + } + Spacer() + VStack { + Text(container.sessions[id]!.handler.title) + .monospaced() + .foregroundStyle(foreground) + .bold(selected) + Text(container.sessions[id]!.handler.host.description) + .foregroundStyle(foreground.opacity(0.7)) + .monospaced() + .font(.caption) + } + Spacer() + } } + .frame(width: oneTabWidth) .ignoresSafeArea(.all) .onTapGesture { withAnimation { selectedID = id } @@ -40,7 +65,11 @@ struct ShellTabView: View { .frame(height: 30) .onAppear { if selectedID == nil { - selectedID = handler.sessionID + if let handler { + selectedID = handler.sessionID + } else { + dismiss() + } } } @@ -62,7 +91,11 @@ struct ShellTabView: View { .id(selectedID) .transition(.opacity) } else { - ShellView(handler: handler, hostsManager: hostsManager) + if let handler { + ShellView(handler: handler, hostsManager: hostsManager) + } else { + Text("No SSH Handler") + } } } } diff --git a/ShhShell/Views/Terminal/ShellView.swift b/ShhShell/Views/Terminal/ShellView.swift index b97fbae..a5ac5db 100644 --- a/ShhShell/Views/Terminal/ShellView.swift +++ b/ShhShell/Views/Terminal/ShellView.swift @@ -37,24 +37,6 @@ struct ShellView: View { .onAppear { handler.applySelectedTheme() } - .navigationTitle(handler.title) - .navigationBarTitleDisplayMode(.inline) - .toolbar { - ToolbarItem(placement: .cancellationAction) { - Button() { - handler.disconnect() - } label: { - Label("Disconnect", systemImage: "xmark.app.fill") - } - } - ToolbarItem(placement: .cancellationAction) { - Button() { - dismiss() - } label: { - Label("Close", systemImage: "arrow.down.right.and.arrow.up.left") - } - } - } } } } diff --git a/ShhShell/Views/Themes/ThemeManagerView.swift b/ShhShell/Views/Themes/ThemeManagerView.swift index de741e2..1528dc3 100644 --- a/ShhShell/Views/Themes/ThemeManagerView.swift +++ b/ShhShell/Views/Themes/ThemeManagerView.swift @@ -33,74 +33,101 @@ struct ThemeManagerView: View { hostsManager.selectedTheme.background.suiColor.opacity(0.7) .ignoresSafeArea(.all) GeometryReader { geo in - let columns: Int = max(1, Int((geo.size.width - 2*spacing) / (minColWidth + spacing))) - let layout = Array(repeating: grid, count: columns) - ScrollView { - if hostsManager.themes.isEmpty { - VStack(alignment: .leading) { - Image(systemName: "paintpalette") - .resizable().scaledToFit() - .symbolRenderingMode(.multicolor) - .frame(width: 50) - Text("No themes (yet)") - .font(.title) - .padding(.vertical, 10) - .bold() - Text("Tap the Safari icon at the top right to find themes!") - Text("Once you find one that you like, copy it's link and enter it here using the link button.") + VStack { + VStack(spacing: 0) { + HStack(spacing: 0) { + ForEach(0..<8, id: \.self) { index in + Rectangle() + .fill(hostsManager.selectedTheme.ansi[index].suiColor) + .onTapGesture { + hostsManager.selectedAnsi = index + hostsManager.saveThemes() + } + } + } + HStack(spacing: 0) { + ForEach(8..<16, id: \.self) { index in + Rectangle() + .fill(hostsManager.selectedTheme.ansi[index].suiColor) + .onTapGesture { + hostsManager.selectedAnsi = index + hostsManager.saveThemes() + } + } + } + } + .clipShape(RoundedRectangle(cornerRadius: 15)) + .frame(maxWidth: geo.size.width, maxHeight: geo.size.height/2) + + let columns: Int = max(1, Int((geo.size.width - 2*spacing) / (minColWidth + spacing))) + let layout = Array(repeating: grid, count: columns) + ScrollView { + if hostsManager.themes.isEmpty { + VStack(alignment: .leading) { + Image(systemName: "paintpalette") + .resizable().scaledToFit() + .symbolRenderingMode(.multicolor) + .frame(width: 50) + Text("No themes (yet)") + .font(.title) + .padding(.vertical, 10) + .bold() + Text("Tap the Safari icon at the top right to find themes!") + Text("Once you find one that you like, copy it's link and enter it here using the link button.") + } + } else { + LazyVGrid(columns: layout, alignment: .center, spacing: 8) { + ForEach(hostsManager.themes) { theme in + ThemePreview(hostsManager: hostsManager, theme: theme, canModify: true) + } + } + .padding(.horizontal) + .animation(.default, value: hostsManager.themes) + } + + HStack { + Text("Built-in Themes") + .padding(.top) + .padding(.horizontal) + .font(.headline) + Spacer() } - } else { LazyVGrid(columns: layout, alignment: .center, spacing: 8) { - ForEach(hostsManager.themes) { theme in - ThemePreview(hostsManager: hostsManager, theme: theme, canModify: true) + ForEach(Theme.builtinThemes) { theme in + ThemePreview(hostsManager: hostsManager, theme: theme, canModify: false) } } .padding(.horizontal) .animation(.default, value: hostsManager.themes) } - - HStack { - Text("Built-in Themes") - .padding(.top) - .padding(.horizontal) - .font(.headline) - Spacer() - } - LazyVGrid(columns: layout, alignment: .center, spacing: 8) { - ForEach(Theme.builtinThemes) { theme in - ThemePreview(hostsManager: hostsManager, theme: theme, canModify: false) - } - } - .padding(.horizontal) - .animation(.default, value: hostsManager.themes) - } - .navigationTitle("Themes") - .alert("Enter URL", isPresented: $showAlert) { - TextField("", text: $importURL, prompt: Text("URL")) - Button("Cancel") {} - Button() { - hostsManager.downloadTheme(fromUrl: URL(string: importURL)) - importURL = "" - } label: { - Label("Import", systemImage: "square.and.arrow.down") - .bold() - } - } - .toolbar { - ToolbarItem() { + .navigationTitle("Themes") + .alert("Enter URL", isPresented: $showAlert) { + TextField("", text: $importURL, prompt: Text("URL")) + Button("Cancel") {} Button() { - UIApplication.shared.open(URL(string: "https://iterm2colorschemes.com")!) + hostsManager.downloadTheme(fromUrl: URL(string: importURL)) + importURL = "" } label: { - Label("Open themes site", systemImage: "safari") + Label("Import", systemImage: "square.and.arrow.down") + .bold() } } - ToolbarItem() { - Button() { - showAlert.toggle() - } label: { - Label("From URL", systemImage: "link") + .toolbar { + 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") + } + } - } } }