fix fortune wheel stuff

multistore
Razmig Sarkissian 1 year ago
parent cd2fd1f254
commit 645beb7171
  1. 4
      PadelClub.xcodeproj/project.pbxproj
  2. 8
      PadelClub/Data/Match.swift
  3. 14
      PadelClub/Data/TeamRegistration.swift
  4. 97
      PadelClub/Views/Components/FortuneWheelView.swift
  5. 32
      PadelClub/Views/GroupStage/Components/GroupStageTeamView.swift
  6. 13
      PadelClub/Views/GroupStage/GroupStagesView.swift
  7. 104
      PadelClub/Views/Round/RoundView.swift
  8. 5
      PadelClub/Views/Round/RoundsView.swift
  9. 8
      PadelClub/Views/Subscription/Guard.swift
  10. 2
      PadelClub/Views/Tournament/TournamentBuildView.swift
  11. 4
      PadelClub/Views/Tournament/TournamentRunningView.swift

@ -1923,7 +1923,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 23;
CURRENT_PROJECT_VERSION = 24;
DEFINES_MODULE = YES;
DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\"";
DEVELOPMENT_TEAM = BQ3Y44M3Q6;
@ -1961,7 +1961,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 23;
CURRENT_PROJECT_VERSION = 24;
DEFINES_MODULE = YES;
DEVELOPMENT_ASSET_PATHS = "\"PadelClub/Preview Content\"";
DEVELOPMENT_TEAM = BQ3Y44M3Q6;

@ -588,15 +588,17 @@ class Match: ModelObject, Storable {
}
func hasSpaceLeft() -> Bool {
teams().count == 1
teamScores.count < 2
}
func isReady() -> Bool {
teams().count == 2
teamScores.count == 2
// teams().count == 2
}
func isEmpty() -> Bool {
teams().isEmpty
teamScores.isEmpty
// teams().isEmpty
}
func hasEnded() -> Bool {

@ -117,7 +117,19 @@ class TeamRegistration: ModelObject, Storable {
func teamScores() -> [TeamScore] {
Store.main.filter(isIncluded: { $0.teamRegistration == id })
}
func wins() -> [Match] {
Store.main.filter(isIncluded: { $0.winningTeamId == id })
}
func loses() -> [Match] {
Store.main.filter(isIncluded: { $0.losingTeamId == id })
}
func matches() -> [Match] {
Store.main.filter(isIncluded: { $0.losingTeamId == id || $0.winningTeamId == id })
}
var tournamentCategory: TournamentCategory {
tournamentObject()?.tournamentCategory ?? .men
}
@ -171,7 +183,7 @@ class TeamRegistration: ModelObject, Storable {
}
func canPlay() -> Bool {
teamScores().isEmpty == false || players().allSatisfy({ $0.hasPaid() || $0.hasArrived })
matches().isEmpty == false || players().allSatisfy({ $0.hasPaid() || $0.hasArrived })
}
func availableForSeedPick() -> Bool {

@ -61,16 +61,14 @@ struct SpinDrawView: View {
let drawees: [any SpinDrawable]
@State var segments: [any SpinDrawable]
let completion: ([DrawResult]) -> Void // Completion closure
var autoMode: Bool = false
let completion: ([DrawResult]) async -> Void // Completion closure
@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 {
HStack(spacing: 0.0) {
VStack(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
// Calculate rotation based on the velocity of the drag
let initialVelocity = value.predictedEndTranslation.width / 10 // Adjust sensitivity
rotation += Double(initialVelocity)
}
.onEnded { value in
// Roll the wheel when drag ends
rollWheel()
DragGesture().onChanged({ (value) in
if value.translation.width < 0 {
rotation = Double(-value.translation.width)
}
}).onEnded({ (value) in
rollWheel()
})
)
}
func rollWheel() {
rotation = 0
//rotation = 0
// Generate a random angle for the wheel to rotate
let randomAngle = Double.random(in: 1440...2880) // Adjust range for more or less rotations

@ -23,22 +23,22 @@ struct GroupStageTeamView: View {
}
if groupStage.tournamentObject()?.hasEnded() == false {
if team.qualified && team.bracketPosition == nil, let tournament = team.tournamentObject() {
Section {
NavigationLink {
SpinDrawView(drawees: [team], segments: tournament.matchesWithSpace()) { results in
}
} label: {
Text("Tirage au sort visuel")
}
}
Section {
RowButtonView("Tirage au sort automatique", role: .destructive) {
}
}
}
// if team.qualified && team.bracketPosition == nil, let tournament = team.tournamentObject() {
// Section {
// NavigationLink {
// SpinDrawView(drawees: [team], segments: tournament.matchesWithSpace()) { results in
//
// }
// } label: {
// Text("Tirage au sort visuel")
// }
// }
//
// Section {
// RowButtonView("Tirage au sort automatique", role: .destructive) {
// }
// }
// }
if team.qualified == false {
Section {

@ -51,8 +51,12 @@ struct GroupStagesView: View {
}
}
let allMatches: [Match]
init(tournament: Tournament) {
self.tournament = tournament
self.allMatches = tournament.groupStages().flatMap({ $0.playedMatches() })
if tournament.shouldVerifyGroupStage {
_selectedDestination = State(wrappedValue: nil)
} else if tournament.unsortedTeams().filter({ $0.groupStagePosition != nil }).isEmpty {
@ -77,11 +81,10 @@ struct GroupStagesView: View {
GenericDestinationPickerView(selectedDestination: $selectedDestination, destinations: allDestinations(), nilDestinationIsValid: true)
switch selectedDestination {
case .all:
let allGroupStages = tournament.groupStages()
let availableToStart = allGroupStages.flatMap({ $0.availableToStart() })
let runningMatches = allGroupStages.flatMap({ $0.runningMatches() })
let readyMatches = allGroupStages.flatMap({ $0.readyMatches() })
let finishedMatches = allGroupStages.flatMap({ $0.finishedMatches() })
let availableToStart = tournament.availableToStart(allMatches)
let runningMatches = tournament.runningMatches(allMatches)
let readyMatches = tournament.readyMatches(allMatches)
let finishedMatches = tournament.finishedMatches(allMatches)
List {
MatchListView(section: "disponible", matches: availableToStart, matchViewStyle: .standardStyle, isExpanded: false)

@ -31,6 +31,7 @@ struct RoundView: View {
let availableQualifiedTeams = tournament.availableQualifiedTeams()
let displayableMatches = round.displayableMatches().sorted(by: \.index)
let spaceLeft = displayableMatches.filter({ $0.hasSpaceLeft() })
let seedSpaceLeft = displayableMatches.filter({ $0.isEmpty() })
if isEditingTournamentSeed.wrappedValue == false {
//(where: { $0.isDisabled() == false || isEditingTournamentSeed.wrappedValue })
if loserRounds.isEmpty == false {
@ -45,41 +46,82 @@ struct RoundView: View {
}
}
}
} else if availableQualifiedTeams.isEmpty == false && spaceLeft.isEmpty == false {
NavigationLink("Tirer au sort la position d'un qualifié") {
SpinDrawView(drawees: availableQualifiedTeams, segments: spaceLeft) { results in
results.forEach { drawResult in
print(availableQualifiedTeams[drawResult.drawee].teamLabel())
print(spaceLeft[drawResult.drawIndex].matchTitle())
availableQualifiedTeams[drawResult.drawee].setSeedPosition(inSpot: spaceLeft[drawResult.drawIndex], slot: nil, opposingSeeding: true)
} else {
if let availableSeedGroup = tournament.seedGroupAvailable(atRoundIndex: round.index) {
Section {
RowButtonView("Placer \(availableSeedGroup.localizedLabel())" + ((availableSeedGroup.isFixed() == false) ? " au hasard" : "")) {
tournament.setSeeds(inRoundIndex: round.index, inSeedGroup: availableSeedGroup)
_save()
if tournament.availableSeeds().isEmpty && tournament.availableQualifiedTeams().isEmpty {
self.isEditingTournamentSeed.wrappedValue = false
}
}
_save()
if tournament.availableSeeds().isEmpty && tournament.availableQualifiedTeams().isEmpty {
self.isEditingTournamentSeed.wrappedValue = false
} footer: {
if availableSeedGroup.isFixed() == false {
Text("Le tirage au sort ne sera pas visuel. Toutes les équipes de ce chapeau seront tirées.")
}
}
if (availableSeedGroup.isFixed() == false) {
Section {
RowButtonView("Tirage au sort \(availableSeedGroup.localizedLabel()) visuel") {
self.selectedSeedGroup = availableSeedGroup
}
} footer: {
Text("Le tirage au sort sera visuel et automatique, n'hésitez pas à enregistrer une vidéo de votre écran. Toutes les équipes de ce chapeau seront tirées les unes après les autres.")
}
}
}
} else if let availableSeedGroup = tournament.seedGroupAvailable(atRoundIndex: round.index) {
Section {
RowButtonView("Placer \(availableSeedGroup.localizedLabel())" + ((availableSeedGroup.isFixed() == false) ? " au hasard" : "")) {
tournament.setSeeds(inRoundIndex: round.index, inSeedGroup: availableSeedGroup)
_save()
if tournament.availableSeeds().isEmpty && tournament.availableQualifiedTeams().isEmpty {
self.isEditingTournamentSeed.wrappedValue = false
if availableQualifiedTeams.isEmpty == false && spaceLeft.isEmpty == false {
Section {
ForEach(availableQualifiedTeams) { team in
NavigationLink {
SpinDrawView(drawees: [team], segments: spaceLeft) { results in
Task {
results.forEach { drawResult in
team.setSeedPosition(inSpot: spaceLeft[drawResult.drawIndex], slot: nil, opposingSeeding: true)
}
_save()
if tournament.availableSeeds().isEmpty && tournament.availableQualifiedTeams().isEmpty {
self.isEditingTournamentSeed.wrappedValue = false
}
}
}
} label: {
TeamRowView(team: team, displayCallDate: false)
}
}
} header: {
Text("Tirage au sort visuel d'un qualifié").font(.subheadline)
}
}
if (availableSeedGroup.isFixed() == false) {
if tournament.availableSeeds().isEmpty == false && seedSpaceLeft.isEmpty == false {
Section {
RowButtonView("Tirage au sort \(availableSeedGroup.localizedLabel()) visuel") {
self.selectedSeedGroup = availableSeedGroup
ForEach(tournament.availableSeeds()) { team in
NavigationLink {
SpinDrawView(drawees: [team], segments: seedSpaceLeft) { results in
Task {
results.forEach { drawResult in
team.setSeedPosition(inSpot: seedSpaceLeft[drawResult.drawIndex], slot: nil, opposingSeeding: false)
}
_save()
if tournament.availableSeeds().isEmpty && tournament.availableQualifiedTeams().isEmpty {
self.isEditingTournamentSeed.wrappedValue = false
}
}
}
} label: {
TeamRowView(team: team, displayCallDate: false)
}
}
} header: {
Text("Tirage au sort visuel d'une tête de série").font(.subheadline)
}
}
}
ForEach(displayableMatches) { match in
Section {
MatchRowView(match: match, matchViewStyle: .sectionedStandardStyle)
@ -100,20 +142,20 @@ struct RoundView: View {
}
}
}
.sheet(isPresented: showVisualDrawView) {
.fullScreenCover(isPresented: showVisualDrawView) {
if let availableSeedGroup = selectedSeedGroup {
let seeds = tournament.seeds(inSeedGroup: availableSeedGroup)
let availableSeedSpot = tournament.availableSeedSpot(inRoundIndex: round.index)
NavigationStack {
SpinDrawView(drawees: seeds, segments: availableSeedSpot) { draws in
draws.forEach { drawResult in
print(seeds[drawResult.drawee].teamLabel())
print(availableSeedSpot[drawResult.drawIndex].matchTitle())
seeds[drawResult.drawee].setSeedPosition(inSpot: availableSeedSpot[drawResult.drawIndex], slot: nil, opposingSeeding: false)
}
_save()
if tournament.availableSeeds().isEmpty && tournament.availableQualifiedTeams().isEmpty {
self.isEditingTournamentSeed.wrappedValue = false
SpinDrawView(drawees: seeds, segments: availableSeedSpot, autoMode: true) { draws in
Task {
draws.forEach { drawResult in
seeds[drawResult.drawee].setSeedPosition(inSpot: availableSeedSpot[drawResult.drawIndex], slot: nil, opposingSeeding: false)
}
_save()
if tournament.availableSeeds().isEmpty && tournament.availableQualifiedTeams().isEmpty {
self.isEditingTournamentSeed.wrappedValue = false
}
}
}
}

@ -14,12 +14,13 @@ struct RoundsView: View {
init(tournament: Tournament) {
self.tournament = tournament
if tournament.shouldVerifyBracket {
let availableSeeds = tournament.availableSeeds()
if tournament.shouldVerifyBracket && availableSeeds.isEmpty {
_selectedRound = State(wrappedValue: nil)
} else {
_selectedRound = State(wrappedValue: tournament.getActiveRound())
}
if tournament.availableSeeds().isEmpty == false || tournament.availableQualifiedTeams().isEmpty == false {
if availableSeeds.isEmpty == false || tournament.availableQualifiedTeams().isEmpty == false {
_isEditingTournamentSeed = State(wrappedValue: true)
}
}

@ -145,14 +145,14 @@ import LeStorage
}
var currentPlan: StoreItem? {
// #if DEBUG
// return .monthlyUnlimited
// #else
#if DEBUG
return .monthlyUnlimited
#else
if let currentBestPlan = self.currentBestPlan, let plan = StoreItem(rawValue: currentBestPlan.productID) {
return plan
}
return nil
// #endif
#endif
}
func userFilteredPurchases() -> [StoreKit.Transaction] {

@ -25,6 +25,7 @@ struct TournamentBuildView: View {
NavigationLink(value: Screen.groupStage) {
LabeledContent {
Text(tournament.groupStageStatus())
.multilineTextAlignment(.trailing)
} label: {
Text("Poules")
if tournament.shouldVerifyGroupStage {
@ -38,6 +39,7 @@ struct TournamentBuildView: View {
NavigationLink(value: Screen.round) {
LabeledContent {
Text(tournament.bracketStatus())
.multilineTextAlignment(.trailing)
} label: {
Text("Tableau")
if tournament.shouldVerifyBracket {

@ -19,8 +19,8 @@ struct TournamentRunningView: View {
@ViewBuilder
var body: some View {
MatchListView(section: "en cours", matches: tournament.runningMatches(allMatches))
MatchListView(section: "à lancer", matches: tournament.readyMatches(allMatches), isExpanded: false)
MatchListView(section: "disponible", matches: tournament.availableToStart(allMatches), isExpanded: false)
// MatchListView(section: "à lancer", matches: tournament.readyMatches(allMatches), isExpanded: false)
// MatchListView(section: "disponible", matches: tournament.availableToStart(allMatches), isExpanded: false)
MatchListView(section: "terminés", matches: tournament.finishedMatches(allMatches), isExpanded: false)
}
}

Loading…
Cancel
Save