@ -61,16 +61,14 @@ struct SpinDrawView: View {
let drawees : [ any SpinDrawable ]
@ State var segments : [ any SpinDrawable ]
let completion : ( [ DrawResult ] ) -> Void // C o m p l e t i o n c l o s u r e
var autoMode : Bool = false
let completion : ( [ DrawResult ] ) async -> Void // C o m p l e t i o n c l o s u r e
@ State private var drawCount : Int = 0
@ State private var draws : [ DrawResult ] = [ DrawResult ] ( )
@ State private var drawOptions : [ DrawOption ] = [ DrawOption ] ( )
@ State private var selectedIndex : Int ?
var autoMode : Bool {
drawees . count > 1
}
@ State private var disabled : Bool = false
var body : some View {
List {
@ -79,7 +77,7 @@ struct SpinDrawView: View {
_validationLabelView ( drawee : drawCount , result : segments [ draws . last ! . drawIndex ] )
if autoMode = = false || drawCount = = drawees . count {
RowButtonView ( " Valider le tirage " ) {
completion ( draws )
await completion ( draws )
dismiss ( )
}
} else {
@ -92,27 +90,49 @@ struct SpinDrawView: View {
}
Section {
FortuneWheelContainerView ( segments : drawOptions , autoMode : autoMode ) { index in
self . selectedIndex = index
self . draws . append ( DrawResult ( drawee : drawCount , drawIndex : drawOptions [ index ] . initialIndex ) )
self . drawOptions . remove ( at : index )
if autoMode && drawCount < drawees . count {
DispatchQueue . main . asyncAfter ( deadline : . now ( ) + 1 ) {
self . drawCount += 1
if drawOptions . count = = 1 {
self . draws . append ( DrawResult ( drawee : self . drawCount , drawIndex : self . drawOptions [ 0 ] . initialIndex ) )
self . drawOptions . remove ( at : 0 )
ZStack {
FortuneWheelContainerView ( segments : drawOptions , autoMode : autoMode ) { index in
self . selectedIndex = index
self . draws . append ( DrawResult ( drawee : drawCount , drawIndex : drawOptions [ index ] . initialIndex ) )
self . drawOptions . remove ( at : index )
if autoMode && drawCount < drawees . count {
DispatchQueue . main . asyncAfter ( deadline : . now ( ) + 1 ) {
self . drawCount += 1
self . selectedIndex = nil
} else {
self . selectedIndex = nil
if drawOptions . count = = 1 {
self . draws . append ( DrawResult ( drawee : self . drawCount , drawIndex : self . drawOptions [ 0 ] . initialIndex ) )
self . drawOptions . remove ( at : 0 )
self . drawCount += 1
self . selectedIndex = nil
} else {
self . selectedIndex = nil
}
}
}
}
. simultaneousGesture (
DragGesture ( ) . onChanged ( { ( value ) in
disabled = true
} ) . onEnded ( { ( value ) in
} )
)
Rectangle ( )
. fill ( . white . opacity ( 0.01 ) )
. clipShape ( Circle ( ) )
. allowsHitTesting ( disabled )
}
. listRowBackground ( Color . clear )
. listRowSeparator ( . hidden )
} footer : {
HStack {
Spacer ( )
if autoMode {
Text ( " Mode automatique " )
} else {
Text ( " Lancer la roue en glissant avec le doigt " ) . multilineTextAlignment ( . center )
}
Spacer ( )
}
}
} else {
Section {
@ -123,7 +143,7 @@ struct SpinDrawView: View {
}
RowButtonView ( " Valider les tirages " ) {
completion ( draws )
await completion ( draws )
dismiss ( )
}
}
@ -142,6 +162,7 @@ struct SpinDrawView: View {
Button ( " Annuler " , role : . cancel ) {
dismiss ( )
}
. disabled ( disabled || autoMode )
}
}
. navigationBarBackButtonHidden ( )
@ -151,6 +172,7 @@ struct SpinDrawView: View {
. toolbar ( . hidden , for : . tabBar )
. listStyle ( . insetGrouped )
. scrollDisabled ( true )
. interactiveDismissDisabled ( )
. onAppear {
for ( index , segment ) in segments . enumerated ( ) {
drawOptions . append ( DrawOption ( initialIndex : index , option : segment ) )
@ -162,19 +184,24 @@ struct SpinDrawView: View {
private func _segmentLabelView ( segment : [ String ] , horizontalAlignment : HorizontalAlignment = . leading ) -> some View {
VStack ( alignment : horizontalAlignment , spacing : 0.0 ) {
ForEach ( segment , id : \ . self ) { string in
Text ( string )
Text ( string ) . font ( . title3 )
. frame ( maxWidth : . infinity )
. lineLimit ( 1 )
}
}
}
@ ViewBuilder
private func _validationLabelView ( drawee : Int , result : SpinDrawable ) -> some View {
H Stack( spacing : 0.0 ) {
V Stack( spacing : 0.0 ) {
let draw = drawees [ drawee ]
_segmentLabelView ( segment : draw . segmentLabel ( . wide ) , horizontalAlignment : . leading )
Image ( systemName : " arrowshape.forward.fill " )
_segmentLabelView ( segment : result . segmentLabel ( . wide ) , horizontalAlignment : . trailing )
_segmentLabelView ( segment : draw . segmentLabel ( . wide ) , horizontalAlignment : . center )
if result as ? TeamRegistration != nil {
Image ( systemName : " flag.2.crossed.fill " ) . font ( . largeTitle ) . foregroundColor ( . logoRed )
} else {
Image ( systemName : " arrowshape.down.fill " ) . font ( . largeTitle ) . foregroundColor ( . logoRed )
}
_segmentLabelView ( segment : result . segmentLabel ( . wide ) , horizontalAlignment : . center )
}
}
}
@ -200,26 +227,24 @@ struct FortuneWheelContainerView: View {
. onAppear {
if autoMode {
DispatchQueue . main . asyncAfter ( deadline : . now ( ) + 1 ) {
rotation = 0
rollWheel ( )
}
}
}
. gesture (
DragGesture ( )
. onChanged { value in
// C a l c u l a t e r o t a t i o n b a s e d o n t h e v e l o c i t y o f t h e d r a g
let initialVelocity = value . predictedEndTranslation . width / 10 // A d j u s t s e n s i t i v i t y
rotation += Double ( initialVelocity )
}
. onEnded { value in
// R o l l t h e w h e e l w h e n d r a g e n d s
rollWheel ( )
DragGesture ( ) . onChanged ( { ( value ) in
if value . translation . width < 0 {
rotation = Double ( - value . translation . width )
}
} ) . onEnded ( { ( value ) in
rollWheel ( )
} )
)
}
func rollWheel ( ) {
rotation = 0
// r o t a t i o n = 0
// G e n e r a t e a r a n d o m a n g l e f o r t h e w h e e l t o r o t a t e
let randomAngle = Double . random ( in : 1440. . . 2880 ) // A d j u s t r a n g e f o r m o r e o r l e s s r o t a t i o n s