fix(ipad): ship iPad P0 layout/globe fixes, edit-last-input, drop clipboard commands

Adapt typing/voice surfaces for iPad width and height, add the system globe
key and last-input editing flow, harden host-only Rime deployment, and remove
clipboard voice commands. Bump build to 61.
This commit is contained in:
Rocky
2026-08-10 13:50:50 +08:00
parent 53abad2050
commit 2bc8c1b87d
85 changed files with 5703 additions and 3997 deletions
@@ -0,0 +1,69 @@
import XCTest
@testable import OSGKeyboardShared
@MainActor
final class SpeechHistoryRevisionTests: XCTestCase {
func testMergePrefersHigherRevisionForSameID() {
let id = UUID()
let createdAt = Date(timeIntervalSince1970: 100)
let old = SpeechHistoryEntry(
id: id,
text: "old",
createdAt: createdAt,
modifiedAt: createdAt,
revision: 0
)
let edited = SpeechHistoryEntry(
id: id,
text: "edited",
createdAt: createdAt,
modifiedAt: Date(timeIntervalSince1970: 200),
revision: 1
)
let merged = SyncedSpeechHistory.merge(
local: SyncedSpeechHistory(entries: [old]),
remote: SyncedSpeechHistory(entries: [edited])
)
XCTAssertEqual(merged.entries, [edited])
}
func testMutationUpdatesExistingEntryAndBumpsRevision() throws {
let suite = "SpeechHistoryRevisionTests.\(UUID().uuidString)"
let defaults = try XCTUnwrap(UserDefaults(suiteName: suite))
defer { defaults.removePersistentDomain(forName: suite) }
let store = SpeechHistoryStore(defaults: defaults)
let entry = try XCTUnwrap(store.append(text: "old"))
let updated = store.applyHistoryMutation(
HistoryMutation(
action: .update,
entryID: entry.id,
expectedRevision: entry.revision,
text: "new"
)
)
XCTAssertEqual(updated?.id, entry.id)
XCTAssertEqual(updated?.text, "new")
XCTAssertEqual(updated?.revision, 1)
}
func testReplayingMutationDoesNotBumpRevisionOrDuplicate() throws {
let suite = "SpeechHistoryMutationReplayTests.\(UUID().uuidString)"
let defaults = try XCTUnwrap(UserDefaults(suiteName: suite))
defer { defaults.removePersistentDomain(forName: suite) }
let store = SpeechHistoryStore(defaults: defaults)
let entry = try XCTUnwrap(store.append(text: "old"))
let mutation = HistoryMutation(
action: .update,
entryID: entry.id,
expectedRevision: 0,
text: "new"
)
let first = store.applyHistoryMutation(mutation)
let replay = store.applyHistoryMutation(mutation)
XCTAssertEqual(first, replay)
XCTAssertEqual(store.entries.count, 1)
XCTAssertEqual(store.entries.first?.revision, 1)
}
}