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
24 changes: 0 additions & 24 deletions .claude/settings.local.json

This file was deleted.

1 change: 0 additions & 1 deletion Convos.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,6 @@
"Conversation Detail/Messages/Messages Collection Layout/Models/SectionModel.swift",
"Conversation Detail/Messages/Messages View Controller/Constants.swift",
"Conversation Detail/Messages/Messages View Controller/Helpers/ManualAnimator.swift",
"Conversation Detail/Messages/Messages View Controller/Helpers/MessagesDateFormatter.swift",
"Conversation Detail/Messages/Messages View Controller/Helpers/SetActor.swift",
"Conversation Detail/Messages/Messages View Controller/Helpers/UICollectionView+DifferenceKit.swift",
"Conversation Detail/Messages/Messages View Controller/Helpers/UIView+Extension.swift",
Expand Down
112 changes: 59 additions & 53 deletions Convos/App Settings/AppSettingsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ struct AppSettingsView: View {
@Bindable var viewModel: AppSettingsViewModel
@Bindable var quicknameViewModel: QuicknameSettingsViewModel
let session: any SessionManagerProtocol
var databaseManager: (any DatabaseManagerProtocol)?
let onDeleteAllData: () -> Void
@State private var showingDeleteAllDataConfirmation: Bool = false
@Environment(\.openURL) private var openURL: OpenURLAction
Expand Down Expand Up @@ -147,59 +148,7 @@ struct AppSettingsView: View {
}
.listRowSeparatorTint(.colorBorderSubtle)

Section {
Button {
openExternalURL("https://xmtp.org")
} label: {
NavigationLink {
EmptyView()
} label: {
HStack(alignment: .firstTextBaseline, spacing: 0.0) {
Text("Secured by ")
Image("xmtpIcon")
.renderingMode(.template)
.foregroundStyle(.colorTextPrimary)
.padding(.trailing, 1.0)
Text("XMTP")
}
.foregroundStyle(.colorTextPrimary)
}
}
.foregroundStyle(.colorTextPrimary)

Button {
openExternalURL("https://hq.convos.org/privacy-and-terms")
} label: {
NavigationLink("Privacy & Terms", destination: EmptyView())
}
.foregroundStyle(.colorTextPrimary)

Button {
sendFeedback()
} label: {
Text("Send feedback")
}
.foregroundStyle(.colorTextPrimary)

if !ConfigManager.shared.currentEnvironment.isProduction {
NavigationLink {
DebugExportView(environment: ConfigManager.shared.currentEnvironment, session: session)
} label: {
Text("Debug")
}
.accessibilityIdentifier("debug-row")
.foregroundStyle(.colorTextPrimary)
}
} footer: {
HStack {
Text("Made in the open by XMTP Labs")
Spacer()
Text("V\(Bundle.appVersion)")
.foregroundStyle(.colorTextTertiary)
}
.foregroundStyle(.colorTextSecondary)
}
.listRowSeparatorTint(.colorBorderSubtle)
aboutSection

Section {
Button(role: .destructive) {
Expand Down Expand Up @@ -243,6 +192,63 @@ struct AppSettingsView: View {
}
}

@ViewBuilder
private var aboutSection: some View {
Section {
Button {
openExternalURL("https://xmtp.org")
} label: {
NavigationLink {
EmptyView()
} label: {
HStack(alignment: .firstTextBaseline, spacing: 0.0) {
Text("Secured by ")
Image("xmtpIcon")
.renderingMode(.template)
.foregroundStyle(.colorTextPrimary)
.padding(.trailing, 1.0)
Text("XMTP")
}
.foregroundStyle(.colorTextPrimary)
}
}
.foregroundStyle(.colorTextPrimary)

Button {
openExternalURL("https://hq.convos.org/privacy-and-terms")
} label: {
NavigationLink("Privacy & Terms", destination: EmptyView())
}
.foregroundStyle(.colorTextPrimary)

Button {
sendFeedback()
} label: {
Text("Send feedback")
}
.foregroundStyle(.colorTextPrimary)

if !ConfigManager.shared.currentEnvironment.isProduction {
NavigationLink {
DebugExportView(environment: ConfigManager.shared.currentEnvironment, session: session, databaseManager: databaseManager)
} label: {
Text("Debug")
}
.accessibilityIdentifier("debug-row")
.foregroundStyle(.colorTextPrimary)
}
} footer: {
HStack {
Text("Made in the open by XMTP Labs")
Spacer()
Text("V\(Bundle.appVersion)")
.foregroundStyle(.colorTextTertiary)
}
.foregroundStyle(.colorTextSecondary)
}
.listRowSeparatorTint(.colorBorderSubtle)
}

private func sendFeedback() {
let email = "convos@xmtp.com"
let subject = "Convos Feedback"
Expand Down
1 change: 1 addition & 0 deletions Convos/Config/Dev.xcconfig
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ NOTIFICATION_SERVICE_BUNDLE_ID = $(MAIN_BUNDLE_ID).ConvosNSE

// Environment-specific entitlements
APP_GROUP_IDENTIFIER = group.$(MAIN_BUNDLE_ID)
ICLOUD_CONTAINER_IDENTIFIER = iCloud.$(MAIN_BUNDLE_ID)
ASSOCIATED_DOMAIN = dev.convos.org
WEB_CREDENTIALS_DOMAIN = dev.convos.org
SECONDARY_ASSOCIATED_DOMAIN = app-dev.convos.org
Expand Down
1 change: 1 addition & 0 deletions Convos/Config/Local.xcconfig
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ NOTIFICATION_SERVICE_BUNDLE_ID = $(MAIN_BUNDLE_ID).ConvosNSE

// Environment-specific entitlements
APP_GROUP_IDENTIFIER = group.$(MAIN_BUNDLE_ID)
ICLOUD_CONTAINER_IDENTIFIER = iCloud.$(MAIN_BUNDLE_ID)
ASSOCIATED_DOMAIN = local.convos.org
WEB_CREDENTIALS_DOMAIN = local.convos.org
SECONDARY_ASSOCIATED_DOMAIN = app-local.convos.org
Expand Down
1 change: 1 addition & 0 deletions Convos/Config/Prod.xcconfig
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ NOTIFICATION_SERVICE_BUNDLE_ID = $(MAIN_BUNDLE_ID).ConvosNSE

// Environment-specific entitlements
APP_GROUP_IDENTIFIER = group.$(MAIN_BUNDLE_ID)
ICLOUD_CONTAINER_IDENTIFIER = iCloud.$(MAIN_BUNDLE_ID)
ASSOCIATED_DOMAIN = popup.convos.org
WEB_CREDENTIALS_DOMAIN = convos.org
SECONDARY_ASSOCIATED_DOMAIN = app.convos.org
Expand Down
63 changes: 34 additions & 29 deletions Convos/Conversation Detail/ConversationInfoView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,39 @@ struct ConversationInfoView: View {
}
}

@ViewBuilder
private var comingSoonSections: some View {
Section {
HStack {
Text("Vanish")
.foregroundStyle(.colorTextPrimary)
Spacer()
SoonLabel()
}
} footer: {
Text("Choose when this convo disappears from your device")
.foregroundStyle(.colorTextSecondary)
}
.disabled(true)

Section {
NavigationLink {
EmptyView()
} label: {
HStack {
Text("Permissions")
.foregroundStyle(.colorTextPrimary)
Spacer()
SoonLabel()
}
}
.disabled(true)
} footer: {
Text("Choose who can manage the group")
.foregroundStyle(.colorTextSecondary)
}
}

var body: some View {
NavigationStack {
List {
Expand Down Expand Up @@ -356,35 +389,7 @@ struct ConversationInfoView: View {

convoRulesSection

Section {
HStack {
Text("Vanish")
.foregroundStyle(.colorTextPrimary)
Spacer()
SoonLabel()
}
} footer: {
Text("Choose when this convo disappears from your device")
.foregroundStyle(.colorTextSecondary)
}
.disabled(true)

Section {
NavigationLink {
EmptyView()
} label: {
HStack {
Text("Permissions")
.foregroundStyle(.colorTextPrimary)
Spacer()
SoonLabel()
}
}
.disabled(true)
} footer: {
Text("Choose who can manage the group")
.foregroundStyle(.colorTextSecondary)
}
comingSoonSections

if !ConfigManager.shared.currentEnvironment.isProduction {
Section {
Expand Down
48 changes: 43 additions & 5 deletions Convos/Conversation Detail/ConversationView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@ struct ConversationView<MessagesBottomBar: View>: View {
@State private var showingProcessingPowerInfo: Bool = false
@State private var showingFullInfo: Bool = false
@State private var showingAssistantsInfo: Bool = false
@State private var showingReconnectionAlert: Bool = false
@State private var scrollOverscrollAmount: CGFloat = 0.0
@State private var didReleasePastThreshold: Bool = false
@Environment(\.dismiss) private var dismiss: DismissAction
@Environment(\.openURL) private var openURL: OpenURLAction

private var showPullToAddAssistant: Bool {
!viewModel.conversation.hasAgent
Expand Down Expand Up @@ -64,18 +66,38 @@ struct ConversationView<MessagesBottomBar: View>: View {
viewModel.onProfilePhotoTap(focusCoordinator: focusCoordinator)
},
onSendMessage: {
viewModel.onSendMessage(focusCoordinator: focusCoordinator)
if viewModel.isInactive {
showingReconnectionAlert = true
} else {
viewModel.onSendMessage(focusCoordinator: focusCoordinator)
}
},
onClearInvite: viewModel.clearPendingInvite,
onClearLinkPreview: { viewModel.pastedLinkPreview = nil },
onTapAvatar: viewModel.onTapAvatar(_:),
onTapInvite: viewModel.onTapInvite(_:),
onReaction: viewModel.onReaction(emoji:messageId:),
onToggleReaction: viewModel.onReaction(emoji:messageId:),
onReaction: { emoji, messageId in
if viewModel.isInactive {
showingReconnectionAlert = true
} else {
viewModel.onReaction(emoji: emoji, messageId: messageId)
}
},
onToggleReaction: { emoji, messageId in
if viewModel.isInactive {
showingReconnectionAlert = true
} else {
viewModel.onReaction(emoji: emoji, messageId: messageId)
}
},
onTapReactions: viewModel.onTapReactions(_:),
onReply: { message in
viewModel.onReply(message)
focusCoordinator.moveFocus(to: .message)
if viewModel.isInactive {
showingReconnectionAlert = true
} else {
viewModel.onReply(message)
focusCoordinator.moveFocus(to: .message)
}
},
replyingToMessage: viewModel.replyingToMessage,
onCancelReply: viewModel.cancelReply,
Expand Down Expand Up @@ -143,6 +165,14 @@ struct ConversationView<MessagesBottomBar: View>: View {

bottomBarContent()

if viewModel.isInactive {
InactiveConversationBanner {
if let url = URL(string: "https://learn.convos.org/") {
openURL(url)
}
}
}

ConversationOnboardingView(
coordinator: onboardingCoordinator,
focusCoordinator: focusCoordinator,
Expand Down Expand Up @@ -197,6 +227,14 @@ struct ConversationView<MessagesBottomBar: View>: View {
viewModel.onProfileSettingsDismissed(focusCoordinator: focusCoordinator)
}
}
.alert(
"Awaiting reconnection",
isPresented: $showingReconnectionAlert
) {
Button("Got it", role: .cancel) {}
} message: {
Text("You can see and send new messages, reactions and more after another member sends a message.")
}
.toolbar {
ToolbarItem(placement: .topBarTrailing) {
if viewModel.isLocked {
Expand Down
8 changes: 7 additions & 1 deletion Convos/Conversation Detail/ConversationViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,10 @@ class ConversationViewModel {
conversation.isLocked
}

var isInactive: Bool {
!conversation.isActive
}

var isFull: Bool {
conversation.isFull
}
Expand Down Expand Up @@ -514,7 +518,9 @@ class ConversationViewModel {
if conversation.isPendingInvite {
onboardingCoordinator.isWaitingForInviteAcceptance = true
}
startOnboarding()
if !isInactive {
startOnboarding()
}
registerInlineAttachmentRecovery()
scheduleVoiceMemoTranscriptionsIfNeeded(in: messages)
}
Expand Down
Loading
Loading