You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
PadelClub/PadelClub/Views/Club/ClubDetailView.swift

215 lines
8.6 KiB

//
// ClubDetailView.swift
// PadelClub
//
// Created by Razmig Sarkissian on 20/03/2024.
//
import SwiftUI
import LeStorage
struct ClubDetailView: View {
@Bindable var club: Club
var displayContext: DisplayContext
@EnvironmentObject var dataStore: DataStore
@FocusState var focusedField: Club.CodingKeys?
@State private var acronymMode: Club.AcronymMode = .automatic
@State private var city: String
@State private var zipCode: String
init(club: Club, displayContext: DisplayContext) {
_club = Bindable(club)
self.displayContext = displayContext
_acronymMode = State(wrappedValue: club.shortNameMode())
_city = State(wrappedValue: club.city ?? "")
_zipCode = State(wrappedValue: club.zipCode ?? "")
}
var body: some View {
Form {
Section {
VStack(alignment: .leading, spacing: 0) {
Text("Nom du club").foregroundStyle(.secondary).font(.caption)
TextField("Nom du club", text: $club.name)
.fixedSize()
.focused($focusedField, equals: ._name)
.submitLabel( displayContext == .addition ? .next : .done)
.onSubmit {
if club.acronym.isEmpty {
club.acronym = club.name.canonicalVersion.replaceCharactersFromSet(characterSet: .whitespacesAndNewlines)
}
if displayContext == .addition {
focusedField = ._acronym
}
}
}
.onTapGesture {
focusedField = ._name
}
LabeledContent {
if acronymMode == .automatic {
Text(club.acronym)
} else {
TextField("Nom court", text: $club.acronym)
.textInputAutocapitalization(.never)
.fixedSize()
.focused($focusedField, equals: ._acronym)
.submitLabel(.done)
.multilineTextAlignment(.trailing)
.onSubmit(of: .text) {
if club.acronym.count > 10 {
club.acronym = String(club.acronym.prefix(10))
}
}
}
} label: {
VStack(alignment: .leading, spacing: 0) {
Text("Nom court (10 caractères max.)").foregroundStyle(.secondary).font(.caption)
Menu {
Section {
ForEach(Club.AcronymMode.allCases, id: \.self) { option in
Toggle(isOn: .init(get: {
acronymMode == option
}, set: { value in
acronymMode = option
})) {
Text(option.rawValue)
}
}
} header: {
Text("Nom court")
}
} label: {
Text(acronymMode.rawValue)
}
}
}
.onChange(of: acronymMode) {
focusedField = ._acronym
if acronymMode == .custom {
club.acronym = ""
}
}
if club.code == nil {
VStack(alignment: .leading, spacing: 0) {
Text("Ville").foregroundStyle(.secondary).font(.caption)
TextField("Ville", text: $city)
.fixedSize()
.focused($focusedField, equals: ._city)
.submitLabel( displayContext == .addition ? .next : .done)
.onSubmit {
if displayContext == .addition {
focusedField = ._zipCode
}
club.city = city
}
}
.onTapGesture {
focusedField = ._city
}
VStack(alignment: .leading, spacing: 0) {
Text("Code Postal").foregroundStyle(.secondary).font(.caption)
TextField("Code Postal", text: $zipCode)
.fixedSize()
.focused($focusedField, equals: ._zipCode)
.submitLabel( displayContext == .addition ? .next : .done)
.onSubmit {
club.zipCode = zipCode
}
}
.onTapGesture {
focusedField = ._zipCode
}
}
} footer: {
if displayContext == .lockedForEditing {
Text("Édition impossible, vous n'êtes pas le créateur de ce club.").foregroundStyle(.logoRed)
} else {
Text("Vous pouvez personaliser le nom court ou laisser celui généré par défaut.")
}
}
.disabled(displayContext == .lockedForEditing)
if let federalLink = club.federalLink() {
Section {
LabeledContent("Code Club") {
Text(club.code ?? "")
}
LabeledContent("Ville") {
Text(club.city ?? "")
}
LabeledContent("Code Postal") {
Text(club.zipCode ?? "")
}
Link(destination: federalLink) {
Text("Fiche du club sur tenup")
}
}
}
if displayContext == .edition {
Section {
RowButtonView("Supprimer ce club", role: .destructive) {
do {
try dataStore.clubs.deleteById(club.id)
dataStore.user?.clubs?.removeAll(where: { $0 == club.id })
try dataStore.userStorage.update()
} catch {
Logger.error(error)
}
}
}
}
}
.keyboardType(.alphabet)
.autocorrectionDisabled()
.defaultFocus($focusedField, ._name, priority: .automatic)
.navigationTitle(displayContext == .addition ? "Nouveau club" : club.name)
.navigationBarTitleDisplayMode(.inline)
.toolbar(.visible, for: .navigationBar)
.toolbarBackground(.visible, for: .navigationBar)
.toolbar {
if displayContext == .edition || displayContext == .lockedForEditing {
let isFavorite = club.isFavorite()
ToolbarItem(placement: .topBarTrailing) {
BarButtonView("Favori", icon: isFavorite ? "start" : "star.fill") {
do {
if isFavorite {
dataStore.user?.clubs?.removeAll(where: { $0 == club.id })
} else {
dataStore.user?.clubs?.append(club.id)
}
try dataStore.userStorage.update()
} catch {
Logger.error(error)
}
}
}
}
}
.onDisappear {
if displayContext == .edition {
do {
try dataStore.clubs.addOrUpdate(instance: club)
} catch {
Logger.error(error)
}
}
}
.onAppear {
if displayContext == .addition {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
focusedField = ._name
}
}
}
}
}
#Preview {
ClubDetailView(club: Club.mock(), displayContext: .edition)
}