chadtmiller.com/knotless
git that lives in your Atmosphere account
1
10
The iOS app's diffs load after being scrolled past
ios/Knotless/Views/FilesView.swift+24−6
| @@ -68,6 +68,7 @@ struct FileSection: View { | ||
@State private var open = true | ||
@State private var lines: [Line]? | ||
@State private var note: String? | ||
@State private var failed = false | ||
| ||
var body: some View { | ||
Section { | ||
| @@ -78,7 +79,16 @@ struct FileSection: View { | ||
} else { | ||
DiffLines(lines: lines) | ||
} | ||
} else if failed { | ||
VStack(alignment: .leading, spacing: Space.s2) { | ||
Text("This file's diff didn't load.").foregroundStyle(.secondary) | ||
Button("Try again") { failed = false } | ||
} | ||
.font(.footnote) | ||
.padding() | ||
} else { | ||
// A row that leaves the screen cancels this, and asks again | ||
// when it comes back. | ||
ProgressView().frame(maxWidth: .infinity).padding().task { await load() } | ||
} | ||
} | ||
| @@ -109,14 +119,22 @@ struct FileSection: View { | ||
private func load() async { | ||
var source = file | ||
if source.rows.isEmpty, source.note == nil, let uri { | ||
let answer: DiffAnswer? = try? await Client.shared.query( | ||
"getPullDiff", ["repo": repo.uri, "uri": uri, "paths": file.path]) | ||
guard let found = answer?.files.first else { | ||
note = "This file's diff didn't load." | ||
lines = [] | ||
do { | ||
let answer: DiffAnswer = try await Client.shared.query( | ||
"getPullDiff", ["repo": repo.uri, "uri": uri, "paths": file.path]) | ||
guard let found = answer.files.first else { | ||
failed = true | ||
return | ||
} | ||
source = found | ||
} catch is CancellationError { | ||
return | ||
} catch let error as URLError where error.code == .cancelled { | ||
return | ||
} catch { | ||
failed = true | ||
return | ||
} | ||
source = found | ||
} | ||
note = source.note | ||
let rows = source.rows | ||
ios/KnotlessUITests/FlowTests.swift+21−0
| @@ -67,6 +67,27 @@ final class FlowTests: XCTestCase { | ||
notFailed() | ||
} | ||
| ||
/// A row scrolled past before its diff comes has its read cancelled, which | ||
/// isn't a read that failed: coming back to it reads it again. | ||
func testFlickingPastAPullsFilesLeavesThemToLoad() { | ||
app.terminate() | ||
let did = "did:plc:bcgltzqazw5tb6k2g3ttenbj" | ||
app.launchEnvironment["KNOTLESS_ROUTE"] = "files|\(did)|chadtmiller.com|knotless|at://\(did)/dev.knotless.pull/3myzh6t32uark" | ||
app.launch() | ||
see("Files changed") | ||
let failed = app.staticTexts.containing(NSPredicate(format: "label CONTAINS %@", "diff didn't load")).firstMatch | ||
for _ in 0..<8 { app.swipeUp(velocity: .fast) } | ||
for _ in 0..<8 { app.swipeDown(velocity: .fast) } | ||
sleep(4) | ||
shot("flow-files-flicked") | ||
XCTAssertFalse(failed.exists, "A file scrolled past stayed unread") | ||
for _ in 0..<6 { | ||
app.swipeUp() | ||
XCTAssertTrue(app.activityIndicators.firstMatch.waitForNonExistence(timeout: 20), "A file scrolled past never loaded") | ||
XCTAssertFalse(failed.exists, "A file scrolled past stayed unread") | ||
} | ||
} | ||
| ||
func testRepoToCodeAndAFile() { | ||
tab("Explore") | ||
let row = app.cells.firstMatch | ||