commit 5c9571d6bcd460844133c536f07218558685b15d
parent 9e364976cc2580514a47c3b3bce474db46def332
Author: Michael Camilleri <[email protected]>
Date: Fri, 15 May 2026 18:12:25 +0900
Show seven completed puzzles on launch
This commit changes Game List to only show seven completed puzzles on
cold launch.
Co-Authored-By: Claude Opus 4.7 <[email protected]>
Diffstat:
1 file changed, 55 insertions(+), 24 deletions(-)
diff --git a/Crossmate/Views/GameListView.swift b/Crossmate/Views/GameListView.swift
@@ -24,6 +24,9 @@ struct GameListView: View {
@State private var leaveTarget: GameSummary?
@State private var leaveError: Error?
@State private var summaryCache = GameSummaryCache()
+ @State private var completedVisibleCount = completedPageSize
+
+ private static let completedPageSize = 7
var body: some View {
GeometryReader { geometry in
@@ -119,40 +122,68 @@ struct GameListView: View {
let completed = summaries
.filter { $0.completedAt != nil }
.sorted { ($0.completedAt ?? .distantPast) > ($1.completedAt ?? .distantPast) }
+ let visibleCount = min(completedVisibleCount, completed.count)
+ let visibleCompleted = Array(completed.prefix(visibleCount))
+ let hasMore = visibleCount < completed.count
- Group {
- List {
- if !inProgress.isEmpty {
- Section {
- ForEach(inProgress) { game in
- rowView(for: game, usesRoomierType: usesRoomierType)
- }
- } header: {
- Text("In Progress")
+ List {
+ if !inProgress.isEmpty {
+ Section {
+ ForEach(inProgress) { game in
+ rowView(for: game, usesRoomierType: usesRoomierType)
}
+ } header: {
+ Text("In Progress")
}
+ }
- if !completed.isEmpty {
- Section {
- ForEach(completed) { game in
- rowView(for: game, usesRoomierType: usesRoomierType)
+ if !completed.isEmpty {
+ Section {
+ ForEach(visibleCompleted) { game in
+ rowView(for: game, usesRoomierType: usesRoomierType)
+ }
+ } header: {
+ Text("Completed")
+ } footer: {
+ if hasMore {
+ HStack {
+ Spacer()
+ Button {
+ withAnimation(.easeInOut(duration: 0.25)) {
+ completedVisibleCount += Self.completedPageSize
+ }
+ } label: {
+ Text("Load More")
+ .font(.subheadline.weight(.semibold))
+ .foregroundColor(.secondary)
+ .padding(.horizontal, 18)
+ .padding(.vertical, 8)
+ .background(Color(.tertiarySystemFill), in: Capsule())
+ }
+ .buttonStyle(.plain)
+ .textCase(nil)
+ Spacer()
}
- } header: {
- Text("Completed")
+ .padding(.top, 8)
}
}
}
- .overlay {
- if games.isEmpty {
- ContentUnavailableView {
- Label("No Puzzles", systemImage: "square.grid.3x3")
- } description: {
- Text("Tap the + button to start a new puzzle, or pull down to refresh.")
- }
+ }
+ .overlay {
+ if games.isEmpty {
+ ContentUnavailableView {
+ Label("No Puzzles", systemImage: "square.grid.3x3")
+ } description: {
+ Text("Tap the + button to start a new puzzle, or pull down to refresh.")
}
}
- .refreshable {
- await onRefresh()
+ }
+ .refreshable {
+ await onRefresh()
+ }
+ .onChange(of: completed.count) { oldCount, newCount in
+ if newCount > oldCount {
+ completedVisibleCount += (newCount - oldCount)
}
}
}