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
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ struct ChatScreenRepresentable: UIViewControllerRepresentable {
/// Fired when the user taps an `@handle` in a message. The owner looks the handle up and opens
/// that person's profile.
let onMentionTap: (Username) -> Void
/// Fired when the Share button on a shared-profile widget is tapped.
let onShareProfile: (LinkCard.User) -> Void
/// Fired when the Share button on a shared-profile widget is tapped, with the name it shows once resolved.
let onShareProfile: (LinkCard.User, String?) -> Void
let ownProfile: OwnProfileCard?
/// Fired when the user taps the card drawn in place of a link, with the whole card and the
/// stable id of the message it came on. The owner decides where it lands, which differs by kind.
Expand Down
4 changes: 2 additions & 2 deletions Flipcash/Core/Screens/Conversation/ConversationScreen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1285,8 +1285,8 @@ struct ConversationScreen: View {
}

/// Opens the share sheet on the widget's person, with the public link their own You tab shares.
private func shareProfile(_ card: LinkCard.User) {
let item = TipCodeShareItem(url: card.url, title: card.linkedHandle ?? card.url.absoluteString, preview: nil)
private func shareProfile(_ card: LinkCard.User, displayName: String?) {
let item = TipCodeShareItem.profile(url: card.url, displayName: displayName)
ShareSheet.present(activityItem: item) { _ in }
}

Expand Down
13 changes: 2 additions & 11 deletions Flipcash/Core/Screens/Main/Tips/TipcardScreen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -127,19 +127,10 @@ struct TipcardScreen: View {

// MARK: - Sharing -

/// The label iOS shows beside the preview; the sharer's name, not the URL.
private var shareTitle: String {
if let name = profile?.displayName, !name.isEmpty {
"Tip \(name)"
} else {
"My Tip Card"
}
}

private func shareTipCard() {
let item = TipCodeShareItem(
let item = TipCodeShareItem.profile(
url: url,
title: shareTitle,
displayName: profile?.displayName,
preview: previewCache.preview(for: sessionContainer.session.userID)
)

Expand Down
8 changes: 2 additions & 6 deletions Flipcash/Core/Screens/Main/You/YouScreen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -636,14 +636,10 @@ struct YouScreen: View {
}
}

private var shareTitle: String {
if let displayName { "Tip \(displayName)" } else { "My Tip Card" }
}

private func shareTipCard() {
let item = TipCodeShareItem(
let item = TipCodeShareItem.profile(
url: url,
title: shareTitle,
displayName: displayName,
preview: previewCache.preview(for: sessionContainer.session.userID)
)
ShareSheet.present(activityItem: item) { _ in }
Expand Down
6 changes: 1 addition & 5 deletions Flipcash/Core/Screens/Profile/UserProfileScreen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -349,11 +349,7 @@ final class UserProfileViewModel {

/// Opens the share sheet on this person's public link, the one their own You tab shares.
func share() {
let item = TipCodeShareItem(
url: .tipcard(for: userID, username: username),
title: displayName,
preview: nil
)
let item = TipCodeShareItem.profile(url: .tipcard(for: userID, username: username), displayName: name)
ShareSheet.present(activityItem: item) { _ in }
}

Expand Down
17 changes: 14 additions & 3 deletions Flipcash/Share/TipCodeShareItem.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,27 @@ import LinkPresentation
final class TipCodeShareItem: NSObject, UIActivityItemSource {

private let url: URL
private let title: String
private let title: String?
private let preview: TipCodePreview?

init(url: URL, title: String, preview: TipCodePreview?) {
init(url: URL, title: String?, preview: TipCodePreview?) {
self.url = url
self.title = title
self.preview = preview
super.init()
}

/// Shares a person's profile link, titled for them — the one way every profile share is built.
static func profile(url: URL, displayName: String?, preview: TipCodePreview? = nil) -> TipCodeShareItem {
TipCodeShareItem(url: url, title: profileTitle(for: displayName), preview: preview)
}

/// "Chat with <name> on Flipcash", or nil when there is no name, so the link goes untitled.
static func profileTitle(for displayName: String?) -> String? {
guard let displayName, !displayName.isEmpty else { return nil }
return String(localized: "Chat with \(displayName) on Flipcash", comment: "Share sheet title for a person's profile link")
}

// MARK: - UIActivityItemSource -

func activityViewControllerPlaceholderItem(_ activityViewController: UIActivityViewController) -> Any {
Expand All @@ -35,7 +46,7 @@ final class TipCodeShareItem: NSObject, UIActivityItemSource {
}

func activityViewController(_ activityViewController: UIActivityViewController, subjectForActivityType activityType: UIActivity.ActivityType?) -> String {
title
title ?? ""
}

func activityViewControllerLinkMetadata(_ activityViewController: UIActivityViewController) -> LPLinkMetadata? {
Expand Down
23 changes: 23 additions & 0 deletions FlipcashTests/ProfileShareTitleTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//
// ProfileShareTitleTests.swift
// FlipcashTests
//

import Foundation
import Testing
@testable import Flipcash

@MainActor
@Suite("Profile share title")
struct ProfileShareTitleTests {

@Test("A named profile is titled as an invitation to chat")
func named() {
#expect(TipCodeShareItem.profileTitle(for: "Ada") == "Chat with Ada on Flipcash")
}

@Test("A profile without a name shares untitled", arguments: [nil, ""] as [String?])
func unnamed(displayName: String?) {
#expect(TipCodeShareItem.profileTitle(for: displayName) == nil)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ public final class ChatScreenViewController: UIViewController {
set { transcript.ownProfile = newValue }
}

public var onShareProfile: ((LinkCard.User) -> Void)? {
public var onShareProfile: ((LinkCard.User, String?) -> Void)? {
get { transcript.onShareProfile }
set { transcript.onShareProfile = newValue }
}
Expand Down
14 changes: 11 additions & 3 deletions FlipcashUI/Sources/FlipcashUI/Chat/ChatShareProfileCell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,9 @@ public final class ChatShareProfileCell: ChatColumnCell {
/// which is where the card subscribes.
weak var linkCardSource: (any LinkCardSource)?

/// Called when the Share button is tapped, with the card whose handle is being shared.
var onShare: ((LinkCard.User) -> Void)?
/// Called when the Share button is tapped, with the card being shared and the person's display
/// name, nil until the lookup resolves one.
var onShare: ((LinkCard.User, String?) -> Void)?

private let card = BubbleBackgroundView()
private let reactionRow = ReactionPillRowView()
Expand Down Expand Up @@ -167,10 +168,17 @@ public final class ChatShareProfileCell: ChatColumnCell {
}
}

private static func displayName(_ state: LinkCard.User.State?) -> String? {
switch state {
case .resolved(let resolved): resolved.displayName.isEmpty ? nil : resolved.displayName
case .notFound, nil: nil
}
}

private func draw(_ profile: LinkCard.User, state: LinkCard.User.State?) {
content.configuration = UIHostingConfiguration {
ShareProfileWidgetView(username: profile.linkedHandle, state: state) { [weak self] in
self?.onShare?(profile)
self?.onShare?(profile, Self.displayName(state))
}
}
.margins(.all, 0)
Expand Down
7 changes: 4 additions & 3 deletions FlipcashUI/Sources/FlipcashUI/Chat/ChatViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,9 @@ public final class ChatViewController: UICollectionViewController {

/// Called when the user taps a URL in a text bubble; the owner opens it.
public var onOpenURL: ((URL) -> Void)?
/// Fired when a shared-profile widget's Share button is tapped.
public var onShareProfile: ((LinkCard.User) -> Void)?
/// Fired when a shared-profile widget's Share button is tapped, with the person's display name
/// once the lookup has resolved it.
public var onShareProfile: ((LinkCard.User, String?) -> Void)?

/// The viewer's own profile, which a shared-profile widget naming them draws from directly. Rows
/// on screen pick a change up without a diff.
Expand Down Expand Up @@ -666,7 +667,7 @@ public final class ChatViewController: UICollectionViewController {
case let cell as ChatShareProfileCell:
cell.linkCardSource = linkCardSource
cell.ownProfile = ownProfile
cell.onShare = { [weak self] card in self?.onShareProfile?(card) }
cell.onShare = { [weak self] card, name in self?.onShareProfile?(card, name) }
let cardWidth = available - ChatColumnCell.rowInset * 2
cell.configure(with: message, maxWidth: cardWidth, authorImageData: authorImageData)
cell.onReactionTap = { [weak self] emoji in self?.onReactionTap?(message.messageID, emoji) }
Expand Down
Loading