Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 0 additions & 17 deletions Code.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
9A017D692EAC1DE200216925 /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = 9A017D682EAC1DE200216925 /* Kingfisher */; };
9A444EE72E8C414D002B1E39 /* BigDecimal in Frameworks */ = {isa = PBXBuildFile; productRef = 9A444EE62E8C414D002B1E39 /* BigDecimal */; };
9A780F972EDF817D009BC4D9 /* CodeScanner in Frameworks */ = {isa = PBXBuildFile; productRef = 9A780F962EDF817D009BC4D9 /* CodeScanner */; };
9AE5C0122FA10003004C0DE0 /* SharedCoreKit in Frameworks */ = {isa = PBXBuildFile; productRef = 9AE5C0112FA10002004C0DE0 /* SharedCoreKit */; };
9ABDD1952D9D7B61006B6CDA /* FlipcashCore in Frameworks */ = {isa = PBXBuildFile; productRef = 9ABDD1942D9D7B61006B6CDA /* FlipcashCore */; };
9AC011182DA4320F0030298E /* FlipcashUI in Frameworks */ = {isa = PBXBuildFile; productRef = 9AC011172DA4320F0030298E /* FlipcashUI */; };
9AC0156C2DA576FA0030298E /* opencv2.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9AD5E64B25F2BF3E007388AE /* opencv2.framework */; };
Expand Down Expand Up @@ -181,7 +180,6 @@
9ABDD1952D9D7B61006B6CDA /* FlipcashCore in Frameworks */,
4CA1B0032FD00003000AA003 /* FlipcashStore in Frameworks */,
9ADEF1D92DD627C6001B260A /* Mixpanel in Frameworks */,
9AE5C0122FA10003004C0DE0 /* SharedCoreKit in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -387,7 +385,6 @@
9A780F962EDF817D009BC4D9 /* CodeScanner */,
4CB225752F77260D0075874E /* FirebaseInstallations */,
4CB225772F7726500075874E /* FirebaseMessaging */,
9AE5C0112FA10002004C0DE0 /* SharedCoreKit */,
);
productName = Flipcash;
productReference = 9A516F7A2D9B12E900AF478B /* Flipcash.app */;
Expand Down Expand Up @@ -516,7 +513,6 @@
10A6C0E8F8974C1887219D41 /* XCRemoteSwiftPackageReference "tweetnacl-swiftwrap" */,
9A444EE52E8C414D002B1E39 /* XCRemoteSwiftPackageReference "BigDecimal" */,
9A780F952EDF817D009BC4D9 /* XCLocalSwiftPackageReference "CodeScanner" */,
9AE5C0102FA10001004C0DE0 /* XCRemoteSwiftPackageReference "flipcash-shared-core-spm" */,
);
productRefGroup = 9AED1101258BE1310088D902 /* Products */;
projectDirPath = "";
Expand Down Expand Up @@ -1770,14 +1766,6 @@
kind = branch;
};
};
9AE5C0102FA10001004C0DE0 /* XCRemoteSwiftPackageReference "flipcash-shared-core-spm" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/code-payments/flipcash-shared-core-spm";
requirement = {
kind = upToNextMinorVersion;
minimumVersion = 0.7.0;
};
};
9ACE172927E6287C00ACA047 /* XCRemoteSwiftPackageReference "mixpanel-swift" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/mixpanel/mixpanel-swift";
Expand Down Expand Up @@ -1839,11 +1827,6 @@
package = 9A9499D62CFB829300DC219B /* XCRemoteSwiftPackageReference "SQLite" */;
productName = SQLite;
};
9AE5C0112FA10002004C0DE0 /* SharedCoreKit */ = {
isa = XCSwiftPackageProductDependency;
package = 9AE5C0102FA10001004C0DE0 /* XCRemoteSwiftPackageReference "flipcash-shared-core-spm" */;
productName = SharedCoreKit;
};
9ADEF1D62DD627C0001B260A /* Bugsnag */ = {
isa = XCSwiftPackageProductDependency;
package = 9A476D482978884700C5B5CE /* XCRemoteSwiftPackageReference "bugsnag-cocoa" */;
Expand Down
24 changes: 22 additions & 2 deletions CrossPlatformVectors/Package.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
// swift-tools-version: 5.9
import PackageDescription
import Foundation

// `FLIPCASH_SHARED_CORE_LOCAL` swaps the pinned package for a path dependency into a
// `code-android-app` checkout. `FlipcashCore/Package.swift` carries the full rationale and the
// loop; the one thing to know here is that all three manifests consuming `SharedCoreKit` have to
// move together, because SPM resolves one version for the whole graph.
let sharedCoreLocalRoot = ProcessInfo.processInfo.environment["FLIPCASH_SHARED_CORE_LOCAL"]
.map { ($0 as NSString).expandingTildeInPath }
.flatMap { $0.isEmpty ? nil : $0 }

// A path dependency takes its identity from the directory's basename rather than the `Package(name:)`
// inside it, so under the override the package is `spm`. Product references have to follow.
let sharedCorePackage = sharedCoreLocalRoot == nil ? "flipcash-shared-core-spm" : "spm"

let sharedCore: Package.Dependency = {
if let sharedCoreLocalRoot {
return .package(path: "\(sharedCoreLocalRoot)/kmp/shared-core/spm")
}
return .package(url: "https://github.com/code-payments/flipcash-shared-core-spm", .upToNextMinor(from: "0.7.0"))
}()

// Cross-platform test-vector GATE (Track-B/C safety net). Asserts the ed25519 this app signs
// with reproduces the canonical fixtures in `code/test-vectors/` — the SAME fixtures the Android
Expand All @@ -21,12 +41,12 @@ let package = Package(
.iOS(.v15),
],
dependencies: [
.package(url: "https://github.com/code-payments/flipcash-shared-core-spm", .upToNextMinor(from: "0.7.0")),
sharedCore,
],
targets: [
.testTarget(
name: "CrossPlatformVectorsTests",
dependencies: [.product(name: "SharedCoreKit", package: "flipcash-shared-core-spm")],
dependencies: [.product(name: "SharedCoreKit", package: sharedCorePackage)],
resources: [.copy("Fixtures")]
),
]
Expand Down
8 changes: 5 additions & 3 deletions Flipcash/Core/Controllers/ConversationController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1149,9 +1149,11 @@ final class ConversationController {
case .conflict: "Message Changed"
case .failure:
switch action {
case .edit: "Couldn't Edit Message"
case .delete: "Couldn't Delete Message"
case .copy, .reply: "Something Went Wrong"
case .edit: "Couldn't Edit Message"
case .delete: "Couldn't Delete Message"
// Neither of these mutates the transcript, so neither can raise a mutation alert.
// Report files straight from its sheet and reports its own outcome there.
case .copy, .reply, .report: "Something Went Wrong"
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -300,8 +300,11 @@ extension ChatItem {

/// Menu order is fixed here, not at the call site — a `Set` has no order, and the context menu
/// must not shuffle its rows between renders of the same message.
///
/// Report goes last: it is the rarest row and the only one that never appears on your own
/// message, so the menu reads "yours ends with delete, theirs ends with report".
nonisolated private static func orderedActions(_ capabilities: Set<MessageCapability>) -> [MessageCapability] {
[.copy, .reply, .edit, .delete].filter(capabilities.contains)
[.copy, .reply, .edit, .delete, .report].filter(capabilities.contains)
}

/// "Read 3:42 PM" / "Read Yesterday" / "Read Monday" / "Read Tue, Jun 17" once the counterpart's
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,8 +189,9 @@ struct ChatScreenRepresentable: UIViewControllerRepresentable {
screen?.focusComposer()
case .reply:
screen?.focusComposer()
case .delete: screen?.dismissKeyboard()
case .copy: break
// Both raise a sheet over the transcript, so the keyboard goes down first.
case .delete, .report: screen?.dismissKeyboard()
case .copy: break
}
}
}
Expand Down
23 changes: 23 additions & 0 deletions Flipcash/Core/Screens/Conversation/ConversationScreen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ struct ConversationScreen: View {
/// Whether the invite sheet is up. A link is the only way into a group, so the empty group's
/// card hands one out (node 10127:118280).
@State private var isInviting = false
@State private var messageReport: MessageReportRequest?

/// Horizontal space the back button (leading) reserves on each side of the
/// centered title item, so the avatar + name can left-align inside a
Expand Down Expand Up @@ -647,6 +648,13 @@ struct ConversationScreen: View {
GroupInviteSheet(conversationID: conversationID, isPresented: $isInviting)
}
}
.fullScreenCover(item: $messageReport) { report in
NavigationStack {
ReportFlowScreen(
target: .message(chatID: report.chatID, messageID: report.messageID)
)
}
}
.background {
// Measure the bar width so the centered title item can be sized to
// (almost) fill it — the system toolbar won't honor maxWidth on a
Expand Down Expand Up @@ -835,9 +843,24 @@ struct ConversationScreen: View {
composer.beginEditing(messageID: message.id, stableID: stableID, currentText: text)
case .delete:
confirmDelete(message.id)
case .report:
// A report names the message, not the chat and not the writer: a chat-level report from
// here would name a DM id this client derived, and the server has never been told about
// that one.
guard let conversationID else { return }
messageReport = MessageReportRequest(id: stableID, chatID: conversationID, messageID: message.id)
}
}

/// The message a report is being filed against, so the sheet can be presented by item rather
/// than from a loose boolean and a second piece of state that could disagree with it.
private struct MessageReportRequest: Identifiable {
/// The transcript row's stable id — already unique per row, and already a `String`.
let id: String
let chatID: ConversationID
let messageID: MessageID
}

/// The composer strip's preview of the message being answered — the same three-way split the
/// transcript's quote panel uses, so the strip and the sent bubble read alike.
///
Expand Down
Loading
Loading