diff --git a/App/App/Localizable.xcstrings b/App/App/Localizable.xcstrings index 8982e7e..55932e6 100644 --- a/App/App/Localizable.xcstrings +++ b/App/App/Localizable.xcstrings @@ -18,7 +18,6 @@ } }, "%@ savedGames.section.unfinished.entry %@" : { - "extractionState" : "stale", "localizations" : { "en" : { "stringUnit" : { @@ -68,6 +67,22 @@ } } }, + "generic.datetime %@ %@" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@" + } + } + } + }, "generic.player.type.aiFinnishHim" : { "extractionState" : "manual", "localizations" : { @@ -587,7 +602,6 @@ } }, "savedGames.section.unfinished" : { - "extractionState" : "stale", "localizations" : { "en" : { "stringUnit" : { diff --git a/App/App/View/SavedGamesView.swift b/App/App/View/SavedGamesView.swift index 405c295..d2a8dec 100644 --- a/App/App/View/SavedGamesView.swift +++ b/App/App/View/SavedGamesView.swift @@ -5,21 +5,60 @@ struct SavedGamesView: View { private var vm = SavedGamesVM() var body: some View { - VStack { - // TODO: use the same collection view with headers instead? Or use collapsible sections? - //Section("savedGames.section.unfinished") { - // ScoreboardView("scoreboard.table.column.players") { result in - // "\(result.player1) savedGames.section.unfinished.entry \(result.player2)" - // } - //} - Section("savedGames.section.finished") { - ScoreboardView(results: self.$vm.results, "scoreboard.table.column.players") { result in - "\(result.player1) savedGames.section.finished.entry \(result.player2)" + TabView { + /* VStack { + Section("savedGames.section.unfinished") { + ScoreboardView(results: self.$vm.results, "scoreboard.table.column.players") { + result in + let n1 = if result.player1 != nil { + Text(result.player1!) + } else { + Text(LocalizedStringKey(result.player1Type.baseTranslationKey)) + } + let n2 = if result.player2 != nil { + Text(result.player2!) + } else { + Text(LocalizedStringKey(result.player2Type.baseTranslationKey)) + } + + return LocalizedStringKey("\(n1) savedGames.section.unfinished.entry \(n2)") + } + } + } */ + + VStack { + Section("savedGames.section.finished") { + ScoreboardView(results: self.$vm.results, "scoreboard.table.column.players") { + result in + let n1 = if result.player1 != nil { + Text(result.player1!) + } else { + Text(LocalizedStringKey(result.player1Type.baseTranslationKey)) + } + let n2 = if result.player2 != nil { + Text(result.player2!) + } else { + Text(LocalizedStringKey(result.player2Type.baseTranslationKey)) + } + + return LocalizedStringKey("\(n1) savedGames.section.finished.entry \(n2)") + } } } - }.onAppear { - vm.loadData() } +#if os(macOS) + .tabViewStyle(.automatic) +#else + .tabViewStyle(.page) +#endif + // VStack { + // // TODO: use the same collection view with headers instead? Or use collapsible sections? + // //Section("savedGames.section.") { + // // ScoreboardView("scoreboard.table.column.players") { result in + // // "\(result.player1) savedGames.section.unfinished.entry \(result.player2)" + // // } + // //} + // } } init() { diff --git a/App/App/View/ScoreboardView.swift b/App/App/View/ScoreboardView.swift index fdd6cfe..e487a2f 100644 --- a/App/App/View/ScoreboardView.swift +++ b/App/App/View/ScoreboardView.swift @@ -24,7 +24,7 @@ struct ScoreboardView: View { VStack(alignment: .center) { Text(localizedKeyProvider(result)) HStack { - Text(result.date, style: .date) + Text("generic.datetime \(Text(result.date, style: .date)) \(Text(result.date, style: .time))") Spacer() Text(result.rules.baseTranslationKey) }.foregroundStyle(.secondary) diff --git a/App/App/ViewModel/InGameVM.swift b/App/App/ViewModel/InGameVM.swift index 753cd82..e0be21f 100644 --- a/App/App/ViewModel/InGameVM.swift +++ b/App/App/ViewModel/InGameVM.swift @@ -97,10 +97,10 @@ class IngameVM: ObservableObject { } if result == .notFinished { - _ = try await Persistance.saveGame(withName: "\(self.gameName).co4", andGame: self.game, withFolderName: "connect4.games") + _ = try await Persistance.saveGame(withName: "lastUnfinished.co4", andGame: self.game, withFolderName: "connect4.games") return } - + _ = try await Persistance.saveGameResult(withName: "savedGames.json", andGame: game, andResult: result, withFolderName: "connect4.games") } game.addGameStartedListener { board in diff --git a/App/App/ViewModel/SavedGamesVM.swift b/App/App/ViewModel/SavedGamesVM.swift index 087d782..b843a3b 100644 --- a/App/App/ViewModel/SavedGamesVM.swift +++ b/App/App/ViewModel/SavedGamesVM.swift @@ -2,26 +2,16 @@ import Foundation import Connect4Persistance class SavedGamesVM: ObservableObject { - private var loaded: Bool = false - @Published var results: [ResultVM] = [] init() { - - } - - func loadData() { - if (!loaded) { - loaded = true + Task(priority: .userInitiated) { + let results = (try await Persistance.loadGameResults(withName: "savedGames.json", withFolderName: "connect4.games")) ?? [] + let vms = results.sorted(by: { $0.date > $1.date }).map(ResultVM.init) - Task(priority: .userInitiated) { - let results = (try await Persistance.loadGameResults(withName: "savedGames.json", withFolderName: "connect4.games")) ?? [] - let vms = results.map(ResultVM.init) - - DispatchQueue.main.async { - self.results = vms - } + DispatchQueue.main.async { + self.results = vms } } } @@ -31,28 +21,33 @@ class ResultVM: Identifiable { var id: Date { self.date } let date: Date - let player1: String + let player1: String? let player1Type: PlayerType - let player2: String + let player2: String? let player2Type: PlayerType let rules: RulesType init(from: GameResult) { self.date = from.date - let p = from.players[0] - - if p.id == .player1 { - self.player1 = p.name - self.player1Type = Self.i(data: p) - self.player2 = p.name - self.player2Type = Self.i(data: from.players[1]) + let (p1, p2) = if from.players[0].id == .player1 { + (from.players[0], from.players[1]) } else { - self.player2 = p.name - self.player2Type = Self.i(data: p) - self.player1 = p.name - self.player1Type = Self.i(data: from.players[1]) + (from.players[1], from.players[0]) } + self.player1Type = Self.i(data: p1) + self.player1 = if p1.name.isEmpty { + nil + } else { + p1.name + } + self.player2Type = Self.i(data: p2) + self.player2 = if p2.name.isEmpty { + nil + } else { + p2.name + } + self.rules = switch (from.rules.type) { case "Connect4Rules": .Classic case "TicTacToeRules": .TicTacToe