diff options
| author | Fuwn <[email protected]> | 2025-02-12 23:25:10 -0800 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2025-02-12 23:25:10 -0800 |
| commit | ee6cc230c73a4bad1df711a0cd0352af7e4baced (patch) | |
| tree | ceb5f14e3d30292af7cc501039738874c5374b39 /HoloBar/ContentView.swift | |
| parent | feat(HoloBarApp): Add more avatar fallback levels (diff) | |
| download | holobar-ui.tar.xz holobar-ui.zip | |
feat: Add a UI windowui
Diffstat (limited to 'HoloBar/ContentView.swift')
| -rw-r--r-- | HoloBar/ContentView.swift | 70 |
1 files changed, 70 insertions, 0 deletions
diff --git a/HoloBar/ContentView.swift b/HoloBar/ContentView.swift new file mode 100644 index 0000000..784f45e --- /dev/null +++ b/HoloBar/ContentView.swift @@ -0,0 +1,70 @@ +import SwiftUI + +struct ContentView: View { + @EnvironmentObject var fetcher: CharacterFetcher + @State private var searchText: String = "" + + private var filteredCharacters: [Character] { + if searchText.isEmpty { return fetcher.characters } + + return fetcher.characters.filter { + $0.name.localizedCaseInsensitiveContains(searchText) + } + } + + var body: some View { + NavigationView { + List(filteredCharacters) { character in + Button { + NSWorkspace.shared.open(character.profileURL) + } label: { + HStack(spacing: 16) { + AsyncImage(url: character.avatarURL) { phase in + if let image = phase.image { + image + .resizable() + .aspectRatio(contentMode: .fill) + } else if phase.error != nil { + Image(systemName: "person.crop.circle.badge.exclamationmark") + .resizable() + .aspectRatio(contentMode: .fill) + .foregroundStyle(.gray) + } else { + Image(systemName: "person.crop.circle") + .resizable() + .aspectRatio(contentMode: .fill) + .foregroundStyle(.gray) + .opacity(0.25) + } + } + .frame(width: 40, height: 40) + .clipShape(Circle()) + .overlay( + Circle().stroke(Color.secondary.opacity(0.3), lineWidth: 1) + ) + + VStack(alignment: .leading, spacing: 4) { + Text(character.rawName).font(.headline) + + Text(character.affiliation) + .font(.subheadline) + .foregroundColor(.secondary) + } + } + .padding(.vertical, 8) + } + .buttonStyle(PlainButtonStyle()) + } + .navigationTitle("Characters") + .searchable(text: $searchText, placement: .automatic, prompt: "Search Characters") + .toolbar { + ToolbarItem { + Button(action: fetcher.refreshCharactersForToday) { + Image(systemName: "arrow.clockwise") + } + .help("Refresh Characters") + } + } + } + } +} |