proofmode 0.9.0

Capture, share, and preserve verifiable photos and videos
Documentation
import SwiftUI

struct ProofListView: View {
    @EnvironmentObject var proofViewModel: ProofViewModel
    @Binding var selectedProof: Proof?
    @State private var searchText = ""
    
    var filteredProofs: [Proof] {
        if searchText.isEmpty {
            return proofViewModel.proofs
        } else {
            return proofViewModel.proofs.filter { proof in
                proof.fileName.localizedCaseInsensitiveContains(searchText) ||
                proof.hash.localizedCaseInsensitiveContains(searchText)
            }
        }
    }
    
    var body: some View {
        VStack {
            if proofViewModel.proofs.isEmpty {
                VStack(spacing: 20) {
                    Image(systemName: "shield.slash")
                        .font(.system(size: 60))
                        .foregroundColor(.gray)
                    Text("No Proofs Yet")
                        .font(.title2)
                        .fontWeight(.semibold)
                    Text("Generate proofs by taking photos or selecting from your library")
                        .font(.subheadline)
                        .foregroundColor(.secondary)
                        .multilineTextAlignment(.center)
                        .padding(.horizontal)
                }
                .frame(maxWidth: .infinity, maxHeight: .infinity)
            } else {
                List {
                    ForEach(filteredProofs) { proof in
                        ProofRow(proof: proof) {
                            print("DEBUG: Setting selectedProof to \(proof.fileName)")
                            selectedProof = proof
                        }
                    }
                    .onDelete(perform: deleteProofs)
                }
                .searchable(text: $searchText, prompt: "Search proofs")
                .refreshable {
                    await proofViewModel.refreshProofs()
                }
            }
        }
    }
    
    private func deleteProofs(at offsets: IndexSet) {
        for index in offsets {
            let proof = filteredProofs[index]
            proofViewModel.deleteProof(proof)
        }
    }
}

struct ProofRow: View {
    let proof: Proof
    let onTap: () -> Void
    
    var body: some View {
        Button(action: onTap) {
            HStack {
                // Thumbnail
                if let thumbnail = proof.thumbnail {
                    Image(uiImage: thumbnail)
                        .resizable()
                        .aspectRatio(contentMode: .fill)
                        .frame(width: 60, height: 60)
                        .clipShape(RoundedRectangle(cornerRadius: 8))
                } else {
                    RoundedRectangle(cornerRadius: 8)
                        .fill(Color.gray.opacity(0.3))
                        .frame(width: 60, height: 60)
                        .overlay(
                            Image(systemName: "photo")
                                .foregroundColor(.gray)
                        )
                }
                
                VStack(alignment: .leading, spacing: 4) {
                    Text(proof.fileName)
                        .font(.headline)
                        .lineLimit(1)
                    
                    Text(proof.formattedDate)
                        .font(.caption)
                        .foregroundColor(.secondary)
                    
                    HStack {
                        Image(systemName: proof.isVerified ? "checkmark.circle.fill" : "xmark.circle.fill")
                            .foregroundColor(proof.isVerified ? .green : .red)
                            .font(.caption)
                        
                        Text(proof.isVerified ? "Verified" : "Not Verified")
                            .font(.caption)
                            .foregroundColor(proof.isVerified ? .green : .red)
                    }
                }
                
                Spacer()
                
                Image(systemName: "chevron.right")
                    .font(.caption)
                    .foregroundColor(.secondary)
            }
            .padding(.vertical, 4)
        }
        .buttonStyle(PlainButtonStyle())
    }
}