@ -5,20 +5,20 @@
// C r e a t e d b y R a z m i g S a r k i s s i a n o n 0 7 / 0 4 / 2 0 2 4 .
//
import SwiftUI
import LeStorage
import TipKit
import PadelClubData
import SwiftUI
import TipKit
struct PlanningView : View {
@ EnvironmentObject var dataStore : DataStore
@ Environment ( Tournament . self ) var tournament : Tournament
@ State private var selectedDay : Date ?
@ Binding var selectedScheduleDestination : ScheduleDestination ?
@ State private var filterOption : PlanningFilterOption = . byDefault
@ State private var showFinishedMatches : Bool = false
@ State private var enableMove : Bool = false
@ Environment ( \ . editMode ) private var editMode
let allMatches : [ Match ]
let timeSlotMoveOptionTip = TimeSlotMoveOptionTip ( )
@ -32,15 +32,15 @@ struct PlanningView: View {
allMatches . filter ( { showFinishedMatches || $0 . endDate = = nil } )
}
var timeSlots : [ Date : [ Match ] ] {
Dictionary ( grouping : matches ) { $0 . startDate ? ? . distantFuture }
var timeSlots : [ Date : [ Match ] ] {
Dictionary ( grouping : matches ) { $0 . plannedStartDate ? ? $0 . startDate ? ? . distantFuture }
}
func days ( timeSlots : [ Date : [ Match ] ] ) -> [ Date ] {
func days ( timeSlots : [ Date : [ Match ] ] ) -> [ Date ] {
Set ( timeSlots . keys . map { $0 . startOfDay } ) . sorted ( )
}
func keys ( timeSlots : [ Date : [ Match ] ] ) -> [ Date ] {
func keys ( timeSlots : [ Date : [ Match ] ] ) -> [ Date ] {
timeSlots . keys . sorted ( )
}
@ -56,18 +56,37 @@ struct PlanningView: View {
}
}
private func _confirmationMode ( ) -> Bool {
enableMove || editMode ? . wrappedValue = = . active
}
private var enableEditionBinding : Binding < Bool > {
Binding {
editMode ? . wrappedValue = = . active
} set : { value in
if value {
editMode ? . wrappedValue = . active
} else {
editMode ? . wrappedValue = . inactive
}
}
}
var body : some View {
let timeSlots = self . timeSlots
let keys = self . keys ( timeSlots : timeSlots )
let days = self . days ( timeSlots : timeSlots )
let matches = matches
let notSlots = matches . allSatisfy ( { $0 . startDate = = nil } )
BySlotView ( days : days , keys : keys , timeSlots : timeSlots , matches : matches , selectedDay : selectedDay )
BySlotView (
days : days , keys : keys , timeSlots : timeSlots , matches : matches , selectedDay : selectedDay
)
. environment ( \ . filterOption , filterOption )
. environment ( \ . showFinishedMatches , showFinishedMatches )
. environment ( \ . enableMove , enableMove )
. navigationTitle ( Text ( _computedTitle ( days : days ) ) )
. navigationBarBackButtonHidden ( enableMove )
. navigationBarBackButtonHidden ( _confirmationMode ( ) )
. toolbar ( content : {
if days . count > 1 {
ToolbarTitleMenu {
@ -77,46 +96,63 @@ struct PlanningView: View {
if day . monthYearFormatted = = Date . distantFuture . monthYearFormatted {
Text ( " Sans horaire " ) . tag ( day as Date ? )
} else {
Text ( day . formatted ( . dateTime . day ( ) . weekday ( ) . month ( ) ) ) . tag ( day as Date ? )
Text ( day . formatted ( . dateTime . day ( ) . weekday ( ) . month ( ) ) ) . tag (
day as Date ? )
}
}
} label : {
Text ( " Jour " )
}
. pickerStyle ( . automatic )
. disabled ( enableMove )
. disabled ( _confirmationMode ( ) )
}
}
if enableMove {
if _confirmationMode ( ) {
ToolbarItem ( placement : . topBarLeading ) {
Button ( " Annuler " ) {
enableMove = false
enableEditionBinding . wrappedValue = false
}
}
ToolbarItem ( placement : . topBarTrailing ) {
if enableMove {
ToolbarItemGroup ( placement : . topBarTrailing ) {
Button ( " Sauver " ) {
do {
try self . tournament . tournamentStore ? . matches . addOrUpdate ( contentOfs : allMatches )
} catch {
Logger . error ( error )
let groupByTournaments = allMatches . grouped { match in
match . currentTournament ( )
}
groupByTournaments . forEach { tournament , matches in
tournament ? . tournamentStore ? . matches . addOrUpdate ( contentOfs : matches )
}
enableMove = false
}
}
}
} else {
ToolbarItemGroup ( placement : . topBarTrailing ) {
if notSlots = = false {
ToolbarItemGroup ( placement : . bottomBar ) {
HStack {
CourtOptionsView ( timeSlots : timeSlots , underlined : false )
Spacer ( )
Toggle ( isOn : $ enableMove ) {
Label ( " Déplacer " , systemImage : " rectangle.2.swap " )
Label {
Text ( " Déplacer " )
} icon : {
Image ( systemName : " rectangle.2.swap " )
}
}
. popoverTip ( timeSlotMoveOptionTip )
. disabled ( _confirmationMode ( ) )
Spacer ( )
Toggle ( isOn : enableEditionBinding ) {
Text ( " Modifier " )
}
. disabled ( _confirmationMode ( ) )
}
}
}
ToolbarItemGroup ( placement : . topBarTrailing ) {
Menu {
Section {
Picker ( selection : $ showFinishedMatches ) {
@ -149,7 +185,8 @@ struct PlanningView: View {
}
} label : {
Label ( " Trier " , systemImage : " line.3.horizontal.decrease.circle " )
. symbolVariant ( filterOption = = . byCourt || showFinishedMatches ? . fill : . none )
. symbolVariant (
filterOption = = . byCourt || showFinishedMatches ? . fill : . none )
}
}
@ -160,8 +197,11 @@ struct PlanningView: View {
ContentUnavailableView {
Label ( " Aucun horaire défini " , systemImage : " clock.badge.questionmark " )
} description : {
Text ( " Vous n'avez pas encore défini d'horaire pour les différentes phases du tournoi " )
Text (
" Vous n'avez pas encore défini d'horaire pour les différentes phases du tournoi "
)
} actions : {
if selectedScheduleDestination != nil {
RowButtonView ( " Horaire intelligent " ) {
selectedScheduleDestination = nil
}
@ -169,12 +209,16 @@ struct PlanningView: View {
}
}
}
}
struct BySlotView : View {
@ Environment ( Tournament . self ) var tournament : Tournament
@ Environment ( \ . filterOption ) private var filterOption
@ Environment ( \ . showFinishedMatches ) private var showFinishedMatches
@ Environment ( \ . enableMove ) private var enableMove
@ Environment ( \ . editMode ) private var editMode
@ State private var selectedIds = Set < String > ( )
@ State private var showDateUpdateView : Bool = false
@ State private var dateToUpdate : Date = Date ( )
let days : [ Date ]
let keys : [ Date ]
@ -184,15 +228,15 @@ struct PlanningView: View {
let timeSlotMoveTip = TimeSlotMoveTip ( )
var body : some View {
List {
List ( selection : $ selectedIds ) {
if enableMove {
TipView ( timeSlotMoveTip )
. tipStyle ( tint : . logoYellow , asSection : true )
}
if ! matches . allSatisfy ( { $0 . startDate = = nil } ) {
ForEach ( days . filter ( { selectedDay = = nil || selectedDay = = $0 } ) , id : \ . self ) { day in
ForEach ( days . filter ( { selectedDay = = nil || selectedDay = = $0 } ) , id : \ . self ) {
day in
DaySectionView (
day : day ,
keys : keys . filter ( { $0 . dayInt = = day . dayInt } ) ,
@ -202,15 +246,116 @@ struct PlanningView: View {
}
}
}
. toolbar ( content : {
if editMode ? . wrappedValue = = . active {
ToolbarItem ( placement : . bottomBar ) {
Button {
showDateUpdateView = true
} label : {
Text ( " Modifier la date des matchs sélectionnés " )
}
. disabled ( selectedIds . isEmpty )
}
}
} )
. sheet ( isPresented : $ showDateUpdateView , onDismiss : {
selectedIds . removeAll ( )
} ) {
let selectedMatches = matches . filter ( { selectedIds . contains ( $0 . stringId ) } )
DateUpdateView ( selectedMatches : selectedMatches )
}
}
}
struct DateUpdateView : View {
@ Environment ( \ . dismiss ) var dismiss
let selectedMatches : [ Match ]
let selectedFormats : [ MatchFormat ]
@ State private var dateToUpdate : Date
init ( selectedMatches : [ Match ] ) {
self . selectedMatches = selectedMatches
self . selectedFormats = Array ( Set ( selectedMatches . map ( { match in
match . matchFormat
} ) ) )
_dateToUpdate = . init ( wrappedValue : selectedMatches . first ? . plannedStartDate ? ? selectedMatches . first ? . startDate ? ? Date ( ) )
}
var body : some View {
NavigationStack {
List {
Section {
DatePicker ( selection : $ dateToUpdate ) {
Text ( dateToUpdate . formatted ( . dateTime . weekday ( . wide ) ) ) . font ( . headline )
}
}
Section {
DateAdjusterView ( date : $ dateToUpdate )
DateAdjusterView ( date : $ dateToUpdate , time : 10 )
ForEach ( selectedFormats , id : \ . self ) { matchFormat in
DateAdjusterView ( date : $ dateToUpdate , matchFormat : matchFormat )
}
}
Section {
ForEach ( selectedMatches ) { match in
MatchRowView ( match : match )
}
} header : {
Text ( " Matchs à modifier " )
}
}
. navigationTitle ( " Modification de la date " )
. navigationBarTitleDisplayMode ( . inline )
. toolbarBackground ( . visible , for : . navigationBar )
. toolbar ( content : {
ToolbarItem ( placement : . topBarLeading ) {
Button ( " Annuler " , role : . cancel ) {
dismiss ( )
}
}
ToolbarItem ( placement : . topBarTrailing ) {
Button ( " Valider " ) {
_updateDate ( )
}
}
} )
}
}
private func _updateDate ( ) {
selectedMatches . forEach { match in
if match . hasStarted ( ) || match . hasEnded ( ) {
match . plannedStartDate = dateToUpdate
} else {
let hasStarted = match . currentTournament ( ) ? . hasStarted ( ) = = true
match . startDate = dateToUpdate
if hasStarted {
match . plannedStartDate = dateToUpdate
}
}
}
let groupByTournaments = selectedMatches . grouped { match in
match . currentTournament ( )
}
groupByTournaments . forEach { tournament , matches in
tournament ? . tournamentStore ? . matches . addOrUpdate ( contentOfs : matches )
}
dismiss ( )
}
}
struct DaySectionView : View {
@ Environment ( Tournament . self ) var tournament : Tournament
@ Environment ( \ . filterOption ) private var filterOption
@ Environment ( \ . showFinishedMatches ) private var showFinishedMatches
@ Environment ( \ . enableMove ) private var enableMove
@ Environment ( \ . editMode ) private var editMode
let day : Date
let keys : [ Date ]
@ -222,15 +367,23 @@ struct PlanningView: View {
ForEach ( keys , id : \ . self ) { key in
TimeSlotSectionView (
key : key ,
matches : timeSlots [ key ] ? . sorted ( by : filterOption = = . byDefault ? \ . computedOrder : \ . courtIndexForSorting ) ? ? [ ]
matches : timeSlots [ key ] ? . sorted (
by : filterOption = = . byDefault
? \ . computedOrder : \ . courtIndexForSorting ) ? ? [ ]
)
}
. onMove ( perform : enableMove ? moveSection : nil )
} header : {
HeaderView ( day : day , timeSlots : timeSlots )
} footer : {
VStack ( alignment : . leading ) {
if day . monthYearFormatted = = Date . distantFuture . monthYearFormatted {
Text ( " Il s'agit des matchs qui n'ont pas réussi à être placé par Padel Club. Peut-être à cause de créneaux indisponibles, d'autres tournois ou des réglages. " )
Text (
" Il s'agit des matchs qui n'ont pas réussi à être placé par Padel Club. Peut-être à cause de créneaux indisponibles, d'autres tournois ou des réglages. "
)
}
CourtOptionsView ( timeSlots : timeSlots , underlined : true )
}
}
}
@ -240,7 +393,8 @@ struct PlanningView: View {
guard let sourceIdx = source . first ,
sourceIdx < daySlots . count ,
destination <= daySlots . count else {
destination <= daySlots . count
else {
return
}
@ -272,22 +426,47 @@ struct PlanningView: View {
}
}
struct TimeSlotSectionView : View {
@ Environment ( \ . enableMove ) private var enableMove
@ Environment ( \ . editMode ) private var editMode
let key : Date
let matches : [ Match ]
@ State private var isExpanded : Bool = false
@ State private var showDateUpdateView : Bool = false
var body : some View {
if ! matches . isEmpty {
if enableMove {
TimeSlotHeaderView ( key : key , matches : matches )
} else {
DisclosureGroup {
DisclosureGroup ( isExpanded : $ isExpanded ) {
MatchListView ( matches : matches )
} label : {
TimeSlotHeaderView ( key : key , matches : matches )
}
. contextMenu {
PlanningView . CourtOptionsView ( timeSlots : [ key : matches ] , underlined : false )
Button {
showDateUpdateView = true
} label : {
Text ( " Modifier la date " )
}
}
. sheet ( isPresented : $ showDateUpdateView , onDismiss : {
} ) {
PlanningView . DateUpdateView ( selectedMatches : matches )
}
// . o n C h a n g e ( o f : e d i t M o d e ? . w r a p p e d V a l u e ) {
// i f e d i t M o d e ? . w r a p p e d V a l u e = = . a c t i v e , i s E x p a n d e d = = f a l s e {
// i s E x p a n d e d = t r u e
// } e l s e i f e d i t M o d e ? . w r a p p e d V a l u e = = . i n a c t i v e , i s E x p a n d e d = = t r u e {
// i s E x p a n d e d = f a l s e
// }
// }
}
}
}
@ -297,7 +476,7 @@ struct PlanningView: View {
let matches : [ Match ]
var body : some View {
ForEach ( matches ) { match in
ForEach ( matches , id : \ . stringId ) { match in
NavigationLink {
MatchDetailView ( match : match )
. matchViewStyle ( . sectionedStandardStyle )
@ -309,24 +488,35 @@ struct PlanningView: View {
}
struct MatchRowView : View {
@ Environment ( \ . matchViewStyle ) private var matchViewStyle
let match : Match
var body : some View {
LabeledContent {
VStack ( alignment : . center ) {
if let courtName = match . courtName ( ) {
Text ( courtName )
Text ( courtName ) . foregroundStyle ( . primary )
}
Text ( match . matchFormat . shortFormat + " (~ " + match . getDuration ( ) . formatted ( ) + " m) " ) . font ( . footnote ) . foregroundStyle ( . tertiary )
}
} label : {
if let groupStage = match . groupStageObject {
Text ( groupStage . groupStageTitle ( . title ) )
Text ( match . matchTitle ( ) )
} else if let round = match . roundObject {
Text ( round . roundTitle ( ) )
}
if round . index > 0 {
Text ( match . matchTitle ( ) )
}
}
if matchViewStyle = = . feedStyle , let tournament = match . currentTournament ( ) {
Text ( tournament . tournamentTitle ( ) )
}
Text ( match . startDate ? . formattedAsHourMinute ( ) ? ? " -- " )
}
}
}
struct HeaderView : View {
@ Environment ( \ . filterOption ) private var filterOption
@ -365,7 +555,6 @@ struct PlanningView: View {
struct TimeSlotHeaderView : View {
let key : Date
let matches : [ Match ]
@ Environment ( Tournament . self ) var tournament : Tournament
var body : some View {
LabeledContent {
@ -379,7 +568,6 @@ struct PlanningView: View {
. fontWeight ( . semibold )
}
if matches . count <= tournament . courtCount {
let names = matches . sorted ( by : \ . computedOrder )
. compactMap ( { $0 . roundTitle ( ) } )
. reduce ( into : [ String ] ( ) ) { uniqueNames , name in
@ -388,158 +576,234 @@ struct PlanningView: View {
}
}
Text ( names . joined ( separator : " , " ) ) . lineLimit ( 1 ) . truncationMode ( . tail )
} else {
Text ( matches . count . formatted ( ) . appending ( " matchs " ) )
// i f m a t c h e s . c o u n t < = m a t c h e s . f i r s t ? . c o u r t C o u n t ( ) ? ? {
// } e l s e {
// T e x t ( m a t c h e s . c o u n t . f o r m a t t e d ( ) . a p p e n d i n g ( " m a t c h s " ) )
// }
}
}
}
struct CourtOptionsView : View {
let timeSlots : [ Date : [ Match ] ]
let underlined : Bool
var allMatches : [ Match ] {
timeSlots . flatMap { $0 . value }
}
private func _removeCourts ( ) {
allMatches . forEach { match in
match . courtIndex = nil
}
}
private func _eventCourtCount ( ) -> Int { timeSlots . first ? . value . first ? . currentTournament ( ) ? . eventObject ( ) ? . eventCourtCount ( ) ? ? 2
}
// s t r u c t B y S l o t V i e w : V i e w {
// @ E n v i r o n m e n t ( T o u r n a m e n t . s e l f ) v a r t o u r n a m e n t : T o u r n a m e n t
// l e t d a y s : [ D a t e ]
// l e t k e y s : [ D a t e ]
// l e t t i m e S l o t s : [ D a t e : [ M a t c h ] ]
// l e t m a t c h e s : [ M a t c h ]
// l e t s e l e c t e d D a y : D a t e ?
// l e t f i l t e r O p t i o n : P l a n n i n g F i l t e r O p t i o n
// l e t s h o w F i n i s h e d M a t c h e s : B o o l
//
// v a r b o d y : s o m e V i e w {
// L i s t {
// i f m a t c h e s . a l l S a t i s f y ( { $ 0 . s t a r t D a t e = = n i l } ) = = f a l s e {
// F o r E a c h ( d a y s . f i l t e r ( { s e l e c t e d D a y = = n i l | | s e l e c t e d D a y = = $ 0 } ) , i d : \ . s e l f ) { d a y i n
// S e c t i o n {
// F o r E a c h ( k e y s . f i l t e r ( { $ 0 . d a y I n t = = d a y . d a y I n t } ) , i d : \ . s e l f ) { k e y i n
// i f l e t _ m a t c h e s = t i m e S l o t s [ k e y ] ? . s o r t e d ( b y : f i l t e r O p t i o n = = . b y D e f a u l t ? \ . c o m p u t e d O r d e r : \ . c o u r t I n d e x F o r S o r t i n g ) {
// D i s c l o s u r e G r o u p {
// F o r E a c h ( _ m a t c h e s ) { m a t c h i n
// N a v i g a t i o n L i n k {
// M a t c h D e t a i l V i e w ( m a t c h : m a t c h )
// . m a t c h V i e w S t y l e ( . s e c t i o n e d S t a n d a r d S t y l e )
//
// } l a b e l : {
// L a b e l e d C o n t e n t {
// i f l e t c o u r t N a m e = m a t c h . c o u r t N a m e ( ) {
// T e x t ( c o u r t N a m e )
// }
// } l a b e l : {
// i f l e t g r o u p S t a g e = m a t c h . g r o u p S t a g e O b j e c t {
// T e x t ( g r o u p S t a g e . g r o u p S t a g e T i t l e ( . t i t l e ) )
// } e l s e i f l e t r o u n d = m a t c h . r o u n d O b j e c t {
// T e x t ( r o u n d . r o u n d T i t l e ( ) )
// }
// T e x t ( m a t c h . m a t c h T i t l e ( ) )
// }
// }
// }
// } l a b e l : {
// _ t i m e S l o t V i e w ( k e y : k e y , m a t c h e s : _ m a t c h e s )
// }
// }
// }
// . o n M o v e ( p e r f o r m : m o v e S e c t i o n )
// } h e a d e r : {
// H S t a c k {
// i f d a y . m o n t h Y e a r F o r m a t t e d = = D a t e . d i s t a n t F u t u r e . m o n t h Y e a r F o r m a t t e d {
// T e x t ( " S a n s h o r a i r e " )
// } e l s e {
// T e x t ( d a y . f o r m a t t e d ( . d a t e T i m e . d a y ( ) . w e e k d a y ( ) . m o n t h ( ) ) )
// }
// S p a c e r ( )
// l e t c o u n t = _ m a t c h e s C o u n t ( i n D a y I n t : d a y . d a y I n t , t i m e S l o t s : t i m e S l o t s )
// i f s h o w F i n i s h e d M a t c h e s {
// T e x t ( s e l f . _ f o r m a t t e d M a t c h C o u n t ( c o u n t ) )
// } e l s e {
// T e x t ( s e l f . _ f o r m a t t e d M a t c h C o u n t ( c o u n t ) + " r e s t a n t \ ( c o u n t . p l u r a l S u f f i x ) " )
// }
// }
// } f o o t e r : {
// i f d a y . m o n t h Y e a r F o r m a t t e d = = D a t e . d i s t a n t F u t u r e . m o n t h Y e a r F o r m a t t e d {
// T e x t ( " I l s ' a g i t d e s m a t c h s q u i n ' o n t p a s r é u s s i à ê t r e p l a c é p a r P a d e l C l u b . P e u t - ê t r e à c a u s e d e c r é n e a u x i n d i s p o n i b l e s , d ' a u t r e s t o u r n o i s o u d e s r é g l a g e s . " )
// }
// }
// . h e a d e r P r o m i n e n c e ( . i n c r e a s e d )
// }
// }
// }
// }
//
// f u n c m o v e S e c t i o n ( f r o m s o u r c e : I n d e x S e t , t o d e s t i n a t i o n : I n t ) {
// l e t d a y S l o t s = k e y s . f i l t e r { s e l e c t e d D a y = = n i l | | $ 0 . d a y I n t = = s e l e c t e d D a y ? . d a y I n t } . s o r t e d ( )
//
// g u a r d l e t s o u r c e I d x = s o u r c e . f i r s t ,
// s o u r c e I d x < d a y S l o t s . c o u n t ,
// d e s t i n a t i o n < = d a y S l o t s . c o u n t e l s e {
// r e t u r n
// }
//
// / / C r e a t e a m u t a b l e c o p y o f t h e t i m e s l o t s f o r t h i s d a y
// v a r s l o t s T o U p d a t e = d a y S l o t s
//
// l e t u p d a t e R a n g e = m i n ( s o u r c e I d x , d e s t i n a t i o n ) . . . m a x ( s o u r c e I d x , d e s t i n a t i o n ) - 1
// p r i n t ( u p d a t e R a n g e )
//
// / / P e r f o r m t h e m o v e i n t h e a r r a y
// l e t s o u r c e T i m e = s l o t s T o U p d a t e . r e m o v e ( a t : s o u r c e I d x )
// i f s o u r c e I d x < d e s t i n a t i o n {
// s l o t s T o U p d a t e . i n s e r t ( s o u r c e T i m e , a t : d e s t i n a t i o n - 1 )
// } e l s e {
// s l o t s T o U p d a t e . i n s e r t ( s o u r c e T i m e , a t : d e s t i n a t i o n )
// }
//
// / / U p d a t e m a t c h e s b y s w a p p i n g t h e i r s t a r t D a t e s
// f o r i n d e x i n u p d a t e R a n g e {
// / / F i n d t h e n e w t i m e s l o t f o r t h e s e m a t c h e s
// l e t o l d S t a r t T i m e = s l o t s T o U p d a t e [ i n d e x ]
// l e t n e w S t a r t T i m e = d a y S l o t s [ i n d e x ]
// g u a r d l e t m a t c h e s T o U p d a t e = t i m e S l o t s [ o l d S t a r t T i m e ] e l s e { c o n t i n u e }
// p r i n t ( " m o v i n g " , o l d S t a r t T i m e , " t o " , n e w S t a r t T i m e )
//
// / / U p d a t e e a c h m a t c h w i t h t h e n e w s t a r t t i m e
// f o r m a t c h i n m a t c h e s T o U p d a t e {
// m a t c h . s t a r t D a t e = n e w S t a r t T i m e
// }
// }
//
// t r y ? s e l f . t o u r n a m e n t . t o u r n a m e n t S t o r e ? . m a t c h e s . a d d O r U p d a t e ( c o n t e n t O f s : m a t c h e s )
// }
//
//
// p r i v a t e f u n c _ m a t c h e s C o u n t ( i n D a y I n t d a y I n t : I n t , t i m e S l o t s : [ D a t e : [ M a t c h ] ] ) - > I n t {
// t i m e S l o t s . f i l t e r { $ 0 . k e y . d a y I n t = = d a y I n t } . f l a t M a p ( { $ 0 . v a l u e } ) . c o u n t
// }
//
// p r i v a t e f u n c _ t i m e S l o t V i e w ( k e y : D a t e , m a t c h e s : [ M a t c h ] ) - > s o m e V i e w {
// L a b e l e d C o n t e n t {
// T e x t ( s e l f . _ f o r m a t t e d M a t c h C o u n t ( m a t c h e s . c o u n t ) )
// } l a b e l : {
// i f k e y . m o n t h Y e a r F o r m a t t e d = = D a t e . d i s t a n t F u t u r e . m o n t h Y e a r F o r m a t t e d {
// T e x t ( " A u c u n h o r a i r e " )
// } e l s e {
// T e x t ( k e y . f o r m a t t e d ( d a t e : . o m i t t e d , t i m e : . s h o r t e n e d ) ) . f o n t ( . t i t l e ) . f o n t W e i g h t ( . s e m i b o l d )
// }
// i f m a t c h e s . c o u n t < = t o u r n a m e n t . c o u r t C o u n t {
// l e t n a m e s = m a t c h e s . s o r t e d ( b y : \ . c o m p u t e d O r d e r )
// . c o m p a c t M a p ( { $ 0 . r o u n d T i t l e ( ) } )
// . r e d u c e ( i n t o : [ S t r i n g ] ( ) ) { u n i q u e N a m e s , n a m e i n
// i f ! u n i q u e N a m e s . c o n t a i n s ( n a m e ) {
// u n i q u e N a m e s . a p p e n d ( n a m e )
// }
// }
// T e x t ( n a m e s . j o i n e d ( s e p a r a t o r : " , " ) ) . l i n e L i m i t ( 1 ) . t r u n c a t i o n M o d e ( . t a i l )
// } e l s e {
// T e x t ( m a t c h e s . c o u n t . f o r m a t t e d ( ) . a p p e n d i n g ( " m a t c h s " ) )
// }
// }
// }
//
// f i l e p r i v a t e f u n c _ f o r m a t t e d M a t c h C o u n t ( _ c o u n t : I n t ) - > S t r i n g {
// r e t u r n " \ ( c o u n t . f o r m a t t e d ( ) ) m a t c h \ ( c o u n t . p l u r a l S u f f i x ) "
// }
// }
private func _save ( ) {
let groupByTournaments = allMatches . grouped { match in
match . currentTournament ( )
}
groupByTournaments . forEach { tournament , matches in
tournament ? . tournamentStore ? . matches . addOrUpdate ( contentOfs : matches )
}
}
var body : some View {
Menu {
Button ( " Supprimer " ) {
_removeCourts ( )
_save ( )
}
Button ( " Tirer au sort " ) {
_removeCourts ( )
let eventCourtCount = _eventCourtCount ( )
for slot in timeSlots {
var courtsAvailable = Array ( 0. . . eventCourtCount )
let matches = slot . value
matches . forEach { match in
if let rand = courtsAvailable . randomElement ( ) {
match . courtIndex = rand
courtsAvailable . remove ( elements : [ rand ] )
}
}
}
_save ( )
}
Button ( " Fixer par ordre croissant " ) {
_removeCourts ( )
let eventCourtCount = _eventCourtCount ( )
for slot in timeSlots {
var courtsAvailable = Array ( 0. . < eventCourtCount )
let matches = slot . value . sorted ( by : \ . computedOrder )
for i in 0. . < matches . count {
if ! courtsAvailable . isEmpty {
let court = courtsAvailable . removeFirst ( )
matches [ i ] . courtIndex = court
}
}
}
_save ( )
}
} label : {
Text ( " Pistes " )
. underline ( underlined )
}
}
}
// s t r u c t B y S l o t V i e w : V i e w {
// @ E n v i r o n m e n t ( T o u r n a m e n t . s e l f ) v a r t o u r n a m e n t : T o u r n a m e n t
// l e t d a y s : [ D a t e ]
// l e t k e y s : [ D a t e ]
// l e t t i m e S l o t s : [ D a t e : [ M a t c h ] ]
// l e t m a t c h e s : [ M a t c h ]
// l e t s e l e c t e d D a y : D a t e ?
// l e t f i l t e r O p t i o n : P l a n n i n g F i l t e r O p t i o n
// l e t s h o w F i n i s h e d M a t c h e s : B o o l
//
// v a r b o d y : s o m e V i e w {
// L i s t {
// i f m a t c h e s . a l l S a t i s f y ( { $ 0 . s t a r t D a t e = = n i l } ) = = f a l s e {
// F o r E a c h ( d a y s . f i l t e r ( { s e l e c t e d D a y = = n i l | | s e l e c t e d D a y = = $ 0 } ) , i d : \ . s e l f ) { d a y i n
// S e c t i o n {
// F o r E a c h ( k e y s . f i l t e r ( { $ 0 . d a y I n t = = d a y . d a y I n t } ) , i d : \ . s e l f ) { k e y i n
// i f l e t _ m a t c h e s = t i m e S l o t s [ k e y ] ? . s o r t e d ( b y : f i l t e r O p t i o n = = . b y D e f a u l t ? \ . c o m p u t e d O r d e r : \ . c o u r t I n d e x F o r S o r t i n g ) {
// D i s c l o s u r e G r o u p {
// F o r E a c h ( _ m a t c h e s ) { m a t c h i n
// N a v i g a t i o n L i n k {
// M a t c h D e t a i l V i e w ( m a t c h : m a t c h )
// . m a t c h V i e w S t y l e ( . s e c t i o n e d S t a n d a r d S t y l e )
//
// } l a b e l : {
// L a b e l e d C o n t e n t {
// i f l e t c o u r t N a m e = m a t c h . c o u r t N a m e ( ) {
// T e x t ( c o u r t N a m e )
// }
// } l a b e l : {
// i f l e t g r o u p S t a g e = m a t c h . g r o u p S t a g e O b j e c t {
// T e x t ( g r o u p S t a g e . g r o u p S t a g e T i t l e ( . t i t l e ) )
// } e l s e i f l e t r o u n d = m a t c h . r o u n d O b j e c t {
// T e x t ( r o u n d . r o u n d T i t l e ( ) )
// }
// T e x t ( m a t c h . m a t c h T i t l e ( ) )
// }
// }
// }
// } l a b e l : {
// _ t i m e S l o t V i e w ( k e y : k e y , m a t c h e s : _ m a t c h e s )
// }
// }
// }
// . o n M o v e ( p e r f o r m : m o v e S e c t i o n )
// } h e a d e r : {
// H S t a c k {
// i f d a y . m o n t h Y e a r F o r m a t t e d = = D a t e . d i s t a n t F u t u r e . m o n t h Y e a r F o r m a t t e d {
// T e x t ( " S a n s h o r a i r e " )
// } e l s e {
// T e x t ( d a y . f o r m a t t e d ( . d a t e T i m e . d a y ( ) . w e e k d a y ( ) . m o n t h ( ) ) )
// }
// S p a c e r ( )
// l e t c o u n t = _ m a t c h e s C o u n t ( i n D a y I n t : d a y . d a y I n t , t i m e S l o t s : t i m e S l o t s )
// i f s h o w F i n i s h e d M a t c h e s {
// T e x t ( s e l f . _ f o r m a t t e d M a t c h C o u n t ( c o u n t ) )
// } e l s e {
// T e x t ( s e l f . _ f o r m a t t e d M a t c h C o u n t ( c o u n t ) + " r e s t a n t \ ( c o u n t . p l u r a l S u f f i x ) " )
// }
// }
// } f o o t e r : {
// i f d a y . m o n t h Y e a r F o r m a t t e d = = D a t e . d i s t a n t F u t u r e . m o n t h Y e a r F o r m a t t e d {
// T e x t ( " I l s ' a g i t d e s m a t c h s q u i n ' o n t p a s r é u s s i à ê t r e p l a c é p a r P a d e l C l u b . P e u t - ê t r e à c a u s e d e c r é n e a u x i n d i s p o n i b l e s , d ' a u t r e s t o u r n o i s o u d e s r é g l a g e s . " )
// }
// }
// . h e a d e r P r o m i n e n c e ( . i n c r e a s e d )
// }
// }
// }
// }
//
// f u n c m o v e S e c t i o n ( f r o m s o u r c e : I n d e x S e t , t o d e s t i n a t i o n : I n t ) {
// l e t d a y S l o t s = k e y s . f i l t e r { s e l e c t e d D a y = = n i l | | $ 0 . d a y I n t = = s e l e c t e d D a y ? . d a y I n t } . s o r t e d ( )
//
// g u a r d l e t s o u r c e I d x = s o u r c e . f i r s t ,
// s o u r c e I d x < d a y S l o t s . c o u n t ,
// d e s t i n a t i o n < = d a y S l o t s . c o u n t e l s e {
// r e t u r n
// }
//
// / / C r e a t e a m u t a b l e c o p y o f t h e t i m e s l o t s f o r t h i s d a y
// v a r s l o t s T o U p d a t e = d a y S l o t s
//
// l e t u p d a t e R a n g e = m i n ( s o u r c e I d x , d e s t i n a t i o n ) . . . m a x ( s o u r c e I d x , d e s t i n a t i o n ) - 1
// p r i n t ( u p d a t e R a n g e )
//
// / / P e r f o r m t h e m o v e i n t h e a r r a y
// l e t s o u r c e T i m e = s l o t s T o U p d a t e . r e m o v e ( a t : s o u r c e I d x )
// i f s o u r c e I d x < d e s t i n a t i o n {
// s l o t s T o U p d a t e . i n s e r t ( s o u r c e T i m e , a t : d e s t i n a t i o n - 1 )
// } e l s e {
// s l o t s T o U p d a t e . i n s e r t ( s o u r c e T i m e , a t : d e s t i n a t i o n )
// }
//
// / / U p d a t e m a t c h e s b y s w a p p i n g t h e i r s t a r t D a t e s
// f o r i n d e x i n u p d a t e R a n g e {
// / / F i n d t h e n e w t i m e s l o t f o r t h e s e m a t c h e s
// l e t o l d S t a r t T i m e = s l o t s T o U p d a t e [ i n d e x ]
// l e t n e w S t a r t T i m e = d a y S l o t s [ i n d e x ]
// g u a r d l e t m a t c h e s T o U p d a t e = t i m e S l o t s [ o l d S t a r t T i m e ] e l s e { c o n t i n u e }
// p r i n t ( " m o v i n g " , o l d S t a r t T i m e , " t o " , n e w S t a r t T i m e )
//
// / / U p d a t e e a c h m a t c h w i t h t h e n e w s t a r t t i m e
// f o r m a t c h i n m a t c h e s T o U p d a t e {
// m a t c h . s t a r t D a t e = n e w S t a r t T i m e
// }
// }
//
// t r y ? s e l f . t o u r n a m e n t . t o u r n a m e n t S t o r e ? . m a t c h e s . a d d O r U p d a t e ( c o n t e n t O f s : m a t c h e s )
// }
//
//
// p r i v a t e f u n c _ m a t c h e s C o u n t ( i n D a y I n t d a y I n t : I n t , t i m e S l o t s : [ D a t e : [ M a t c h ] ] ) - > I n t {
// t i m e S l o t s . f i l t e r { $ 0 . k e y . d a y I n t = = d a y I n t } . f l a t M a p ( { $ 0 . v a l u e } ) . c o u n t
// }
//
// p r i v a t e f u n c _ t i m e S l o t V i e w ( k e y : D a t e , m a t c h e s : [ M a t c h ] ) - > s o m e V i e w {
// L a b e l e d C o n t e n t {
// T e x t ( s e l f . _ f o r m a t t e d M a t c h C o u n t ( m a t c h e s . c o u n t ) )
// } l a b e l : {
// i f k e y . m o n t h Y e a r F o r m a t t e d = = D a t e . d i s t a n t F u t u r e . m o n t h Y e a r F o r m a t t e d {
// T e x t ( " A u c u n h o r a i r e " )
// } e l s e {
// T e x t ( k e y . f o r m a t t e d ( d a t e : . o m i t t e d , t i m e : . s h o r t e n e d ) ) . f o n t ( . t i t l e ) . f o n t W e i g h t ( . s e m i b o l d )
// }
// i f m a t c h e s . c o u n t < = t o u r n a m e n t . c o u r t C o u n t {
// l e t n a m e s = m a t c h e s . s o r t e d ( b y : \ . c o m p u t e d O r d e r )
// . c o m p a c t M a p ( { $ 0 . r o u n d T i t l e ( ) } )
// . r e d u c e ( i n t o : [ S t r i n g ] ( ) ) { u n i q u e N a m e s , n a m e i n
// i f ! u n i q u e N a m e s . c o n t a i n s ( n a m e ) {
// u n i q u e N a m e s . a p p e n d ( n a m e )
// }
// }
// T e x t ( n a m e s . j o i n e d ( s e p a r a t o r : " , " ) ) . l i n e L i m i t ( 1 ) . t r u n c a t i o n M o d e ( . t a i l )
// } e l s e {
// T e x t ( m a t c h e s . c o u n t . f o r m a t t e d ( ) . a p p e n d i n g ( " m a t c h s " ) )
// }
// }
// }
//
// f i l e p r i v a t e f u n c _ f o r m a t t e d M a t c h C o u n t ( _ c o u n t : I n t ) - > S t r i n g {
// r e t u r n " \ ( c o u n t . f o r m a t t e d ( ) ) m a t c h \ ( c o u n t . p l u r a l S u f f i x ) "
// }
// }
}
enum PlanningFilterOption : Int , CaseIterable , Identifiable {
@ -551,14 +815,13 @@ enum PlanningFilterOption: Int, CaseIterable, Identifiable {
func localizedPlanningLabel ( ) -> String {
switch self {
case . byCourt :
return " Par terrain "
return " Par pis te "
case . byDefault :
return " Par ordre des matchs "
}
}
}
struct FilterOptionKey : EnvironmentKey {
static let defaultValue : PlanningFilterOption = . byDefault
}