Add view of all images for a cap
This commit is contained in:
@ -54,6 +54,12 @@ struct ContentView: View {
|
||||
|
||||
@State
|
||||
private var selectedCapId: Int?
|
||||
|
||||
@State
|
||||
var showImageOverviewForCap = false
|
||||
|
||||
@State
|
||||
private var selectedCapToShowImages: Cap?
|
||||
|
||||
var filteredCaps: [Cap] {
|
||||
let text = searchString
|
||||
@ -125,7 +131,7 @@ struct ContentView: View {
|
||||
.onTapGesture {
|
||||
didTap(cap: cap)
|
||||
}
|
||||
.swipeActions() {
|
||||
.swipeActions(edge: .trailing) {
|
||||
Button {
|
||||
showRenameWindow(for: cap)
|
||||
} label: {
|
||||
@ -133,6 +139,14 @@ struct ContentView: View {
|
||||
}
|
||||
.tint(.purple)
|
||||
}
|
||||
.swipeActions(edge: .leading) {
|
||||
Button {
|
||||
showAllImages(for: cap)
|
||||
} label: {
|
||||
Label("Images", systemSymbol: .photoStack)
|
||||
}
|
||||
.tint(.purple)
|
||||
}
|
||||
}
|
||||
.refreshable {
|
||||
refresh()
|
||||
@ -260,7 +274,11 @@ struct ContentView: View {
|
||||
}
|
||||
.sheet(isPresented: $showGridView) {
|
||||
GridView(isPresented: $showGridView, database: database)
|
||||
}.alert(isPresented: $showNewClassifierAlert) {
|
||||
}
|
||||
.bottomSheet(isPresented: $showImageOverviewForCap, height: 400) {
|
||||
CapImagesView(cap: $selectedCapToShowImages, database: database, isPresented: $showImageOverviewForCap)
|
||||
}
|
||||
.alert(isPresented: $showNewClassifierAlert) {
|
||||
Alert(title: Text("New classifier available"),
|
||||
message: Text("Classifier \(database.serverClassifierVersion) is available. You have version \(database.classifierVersion). Do you want to download it now?"),
|
||||
primaryButton: .default(Text("Download"), action: downloadClassifier),
|
||||
@ -377,6 +395,11 @@ struct ContentView: View {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
private func showAllImages(for cap: Cap) {
|
||||
selectedCapToShowImages = cap
|
||||
showImageOverviewForCap = true
|
||||
}
|
||||
}
|
||||
|
||||
struct ContentView_Previews: PreviewProvider {
|
||||
|
@ -24,12 +24,20 @@ struct Cap {
|
||||
|
||||
/// The subpath to the main image on the server
|
||||
var mainImagePath: String {
|
||||
String(format: "images/%04d/%04d-%02d.jpg", id, id, mainImage)
|
||||
imagePath(version: mainImage)
|
||||
}
|
||||
|
||||
func imagePath(version: Int) -> String {
|
||||
String(format: "images/%04d/%04d-%02d.jpg", id, id, version)
|
||||
}
|
||||
|
||||
var image: CapImage {
|
||||
.init(cap: id, version: mainImage)
|
||||
}
|
||||
|
||||
func image(version: Int) -> CapImage {
|
||||
.init(cap: id, version: version)
|
||||
}
|
||||
|
||||
/**
|
||||
Create a new cap.
|
||||
|
@ -6,3 +6,8 @@ struct CapImage: Codable, Equatable, Hashable {
|
||||
|
||||
let version: Int
|
||||
}
|
||||
|
||||
extension CapImage: Identifiable {
|
||||
|
||||
var id: Int { version }
|
||||
}
|
||||
|
@ -241,7 +241,7 @@ final class Database: ObservableObject {
|
||||
|
||||
@discardableResult
|
||||
func downloadCaps() async -> Bool {
|
||||
print("Downloading cap data")
|
||||
print("Downloading cap data from \(serverDbUrl)")
|
||||
let data: Data
|
||||
let response: URLResponse
|
||||
do {
|
||||
@ -250,7 +250,11 @@ final class Database: ObservableObject {
|
||||
print("Failed to download classifier version: \(error)")
|
||||
return false
|
||||
}
|
||||
guard (response as? HTTPURLResponse)?.statusCode == 200 else {
|
||||
guard let httpResponse = response as? HTTPURLResponse else {
|
||||
return false
|
||||
}
|
||||
guard httpResponse.statusCode == 200 else {
|
||||
print("Failed to download caps: \(httpResponse.statusCode)")
|
||||
return false
|
||||
}
|
||||
|
||||
@ -261,6 +265,7 @@ final class Database: ObservableObject {
|
||||
print("Failed to decode server database: \(error)")
|
||||
return false
|
||||
}
|
||||
print("Downloaded \(capData) caps")
|
||||
var inserts = 0
|
||||
var updates = 0
|
||||
for cap in capData {
|
||||
@ -358,6 +363,10 @@ final class Database: ObservableObject {
|
||||
func hasPendingOperations(for cap: Int) -> Bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func cap(for id: Int) -> Cap? {
|
||||
caps[id]
|
||||
}
|
||||
|
||||
// MARK: Adding new data
|
||||
|
||||
|
75
Caps/Views/CapImagesView.swift
Normal file
75
Caps/Views/CapImagesView.swift
Normal file
@ -0,0 +1,75 @@
|
||||
import SwiftUI
|
||||
|
||||
struct CapImagesView: View {
|
||||
|
||||
private let imageSize: CGFloat = 70
|
||||
|
||||
@Binding
|
||||
var cap: Cap?
|
||||
|
||||
@Binding
|
||||
var isPresented: Bool
|
||||
|
||||
init(cap: Binding<Cap?>, database: Database, isPresented: Binding<Bool>) {
|
||||
self.database = database
|
||||
self._cap = cap
|
||||
self._isPresented = isPresented
|
||||
}
|
||||
|
||||
let database: Database
|
||||
|
||||
var images: [CapImage] {
|
||||
guard let cap else {
|
||||
return []
|
||||
}
|
||||
return (0..<cap.imageCount).map {
|
||||
cap.image(version: $0)
|
||||
}
|
||||
}
|
||||
|
||||
var title: String {
|
||||
guard let cap else {
|
||||
return "Images"
|
||||
}
|
||||
return "Cap \(cap.id)"
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
GeometryReader { geo in
|
||||
VStack {
|
||||
HStack {
|
||||
Text(title).font(.title2).bold()
|
||||
Spacer()
|
||||
Button(action: { isPresented = false }) {
|
||||
Image(systemSymbol: .xmarkCircleFill)
|
||||
.foregroundColor(.gray)
|
||||
.font(.system(size: 26))
|
||||
}
|
||||
}
|
||||
let gridItem = GridItem(.flexible(), spacing: 10, alignment: .leading)
|
||||
ScrollView(.vertical) {
|
||||
LazyVGrid(columns: [gridItem, gridItem, gridItem, gridItem]) {
|
||||
ForEach(images) { item in
|
||||
CachedCapImage(
|
||||
item,
|
||||
check: { database.images.cachedImage(item) },
|
||||
fetch: { await database.images.image(item) },
|
||||
content: { $0.resizable() },
|
||||
placeholder: { ProgressView() })
|
||||
.frame(width: imageSize,
|
||||
height: imageSize)
|
||||
.clipShape(Circle())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding(.horizontal)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct CapImagesView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
CapImagesView(cap: .constant(.init(id: 123, name: "Some")), database: .mock, isPresented: .constant(true))
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user