mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-03-30 18:35:49 +00:00
ios: disable chats in share-sheet based on preferences (#4549)
* claenup * cleanup * remove groupFeatureEnabled from Chat --------- Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
This commit is contained in:
@@ -871,24 +871,6 @@ final class Chat: ObservableObject, Identifiable, ChatLike {
|
||||
|
||||
var viewId: String { get { "\(chatInfo.id) \(created.timeIntervalSince1970)" } }
|
||||
|
||||
func groupFeatureEnabled(_ feature: GroupFeature) -> Bool {
|
||||
if case let .group(groupInfo) = self.chatInfo {
|
||||
let p = groupInfo.fullGroupPreferences
|
||||
return switch feature {
|
||||
case .timedMessages: p.timedMessages.on
|
||||
case .directMessages: p.directMessages.on(for: groupInfo.membership)
|
||||
case .fullDelete: p.fullDelete.on
|
||||
case .reactions: p.reactions.on
|
||||
case .voice: p.voice.on(for: groupInfo.membership)
|
||||
case .files: p.files.on(for: groupInfo.membership)
|
||||
case .simplexLinks: p.simplexLinks.on(for: groupInfo.membership)
|
||||
case .history: p.history.on
|
||||
}
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
public static var sampleData: Chat = Chat(chatInfo: ChatInfo.sampleData.direct, chatItems: [])
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@ struct ChatItemForwardingView: View {
|
||||
@State private var searchText: String = ""
|
||||
@FocusState private var searchFocused
|
||||
@State private var alert: SomeAlert?
|
||||
@State private var hasSimplexLink_: Bool?
|
||||
private let chatsToForwardTo = filterChatsToForwardTo(chats: ChatModel.shared.chats)
|
||||
|
||||
var body: some View {
|
||||
@@ -67,34 +66,6 @@ struct ChatItemForwardingView: View {
|
||||
}
|
||||
}
|
||||
|
||||
private func prohibitedByPref(_ chat: Chat) -> Bool {
|
||||
// preference checks should match checks in compose view
|
||||
let simplexLinkProhibited = hasSimplexLink && !chat.groupFeatureEnabled(.simplexLinks)
|
||||
let fileProhibited = (ci.content.msgContent?.isMediaOrFileAttachment ?? false) && !chat.groupFeatureEnabled(.files)
|
||||
let voiceProhibited = (ci.content.msgContent?.isVoice ?? false) && !chat.chatInfo.featureEnabled(.voice)
|
||||
return switch chat.chatInfo {
|
||||
case .direct: voiceProhibited
|
||||
case .group: simplexLinkProhibited || fileProhibited || voiceProhibited
|
||||
case .local: false
|
||||
case .contactRequest: false
|
||||
case .contactConnection: false
|
||||
case .invalidJSON: false
|
||||
}
|
||||
}
|
||||
|
||||
private var hasSimplexLink: Bool {
|
||||
if let hasSimplexLink_ { return hasSimplexLink_ }
|
||||
let r =
|
||||
if let mcText = ci.content.msgContent?.text,
|
||||
let parsedMsg = parseSimpleXMarkdown(mcText) {
|
||||
parsedMsgHasSimplexLink(parsedMsg)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
hasSimplexLink_ = r
|
||||
return r
|
||||
}
|
||||
|
||||
private func emptyList() -> some View {
|
||||
Text("No filtered chats")
|
||||
.foregroundColor(theme.colors.secondary)
|
||||
@@ -102,7 +73,11 @@ struct ChatItemForwardingView: View {
|
||||
}
|
||||
|
||||
@ViewBuilder private func forwardListChatView(_ chat: Chat) -> some View {
|
||||
let prohibited = prohibitedByPref(chat)
|
||||
let prohibited = chat.prohibitedByPref(
|
||||
hasSimplexLink: hasSimplexLink(ci.content.msgContent?.text),
|
||||
isMediaOrFileAttachment: ci.content.msgContent?.isMediaOrFileAttachment ?? false,
|
||||
isVoice: ci.content.msgContent?.isVoice ?? false
|
||||
)
|
||||
Button {
|
||||
if prohibited {
|
||||
alert = SomeAlert(
|
||||
|
||||
@@ -1120,10 +1120,6 @@ struct ComposeView: View {
|
||||
}
|
||||
}
|
||||
|
||||
func parsedMsgHasSimplexLink(_ parsedMsg: [FormattedText]) -> Bool {
|
||||
parsedMsg.contains(where: { ft in ft.format?.isSimplexLink ?? false })
|
||||
}
|
||||
|
||||
struct ComposeView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
let chat = Chat(chatInfo: ChatInfo.sampleData.direct, chatItems: [])
|
||||
|
||||
@@ -27,6 +27,7 @@ class ShareModel: ObservableObject {
|
||||
@Published var isLoaded = false
|
||||
@Published var bottomBar: BottomBar = .loadingSpinner
|
||||
@Published var errorAlert: ErrorAlert?
|
||||
@Published var hasSimplexLink = false
|
||||
@Published var alertRequiresPassword = false
|
||||
|
||||
enum BottomBar {
|
||||
@@ -49,7 +50,13 @@ class ShareModel: ObservableObject {
|
||||
|
||||
private var itemProvider: NSItemProvider?
|
||||
|
||||
var isSendDisbled: Bool { sharedContent == nil || selected == nil }
|
||||
var isSendDisbled: Bool { sharedContent == nil || selected == nil || isProhibited(selected) }
|
||||
|
||||
func isProhibited(_ chat: ChatData?) -> Bool {
|
||||
if let chat, let sharedContent {
|
||||
sharedContent.prohibited(in: chat, hasSimplexLink: hasSimplexLink)
|
||||
} else { false }
|
||||
}
|
||||
|
||||
var filteredChats: Array<ChatData> {
|
||||
search.isEmpty
|
||||
@@ -379,6 +386,14 @@ enum SharedContent {
|
||||
case .data: .file(comment)
|
||||
}
|
||||
}
|
||||
|
||||
func prohibited(in chatData: ChatData, hasSimplexLink: Bool) -> Bool {
|
||||
chatData.prohibitedByPref(
|
||||
hasSimplexLink: hasSimplexLink,
|
||||
isMediaOrFileAttachment: cryptoFile != nil,
|
||||
isVoice: false
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
extension NSItemProvider {
|
||||
|
||||
@@ -20,18 +20,31 @@ struct ShareView: View {
|
||||
ZStack(alignment: .bottom) {
|
||||
if model.isLoaded {
|
||||
List(model.filteredChats) { chat in
|
||||
let isProhibited = model.isProhibited(chat)
|
||||
let isSelected = model.selected == chat
|
||||
HStack {
|
||||
profileImage(
|
||||
chatInfoId: chat.chatInfo.id,
|
||||
iconName: chatIconName(chat.chatInfo),
|
||||
size: 30
|
||||
)
|
||||
Text(chat.chatInfo.displayName)
|
||||
Text(chat.chatInfo.displayName).foregroundStyle(
|
||||
isProhibited ? .secondary : .primary
|
||||
)
|
||||
Spacer()
|
||||
radioButton(selected: chat == model.selected)
|
||||
radioButton(selected: isSelected && !isProhibited)
|
||||
}
|
||||
.contentShape(Rectangle())
|
||||
.onTapGesture { model.selected = model.selected == chat ? nil : chat }
|
||||
.onTapGesture {
|
||||
if isProhibited {
|
||||
model.errorAlert = ErrorAlert(
|
||||
title: "Cannot forward message",
|
||||
message: "Selected chat preferences prohibit this message."
|
||||
) { Button("Ok", role: .cancel) { } }
|
||||
} else {
|
||||
model.selected = isSelected ? nil : chat
|
||||
}
|
||||
}
|
||||
.tag(chat)
|
||||
}
|
||||
} else {
|
||||
@@ -66,6 +79,9 @@ struct ShareView: View {
|
||||
Button("Ok") { model.completion() }
|
||||
}
|
||||
}
|
||||
.onChange(of: model.comment) {
|
||||
model.hasSimplexLink = hasSimplexLink($0)
|
||||
}
|
||||
}
|
||||
|
||||
private func compose(isLoading: Bool) -> some View {
|
||||
@@ -77,7 +93,7 @@ struct ShareView: View {
|
||||
HStack {
|
||||
Group {
|
||||
if #available(iOSApplicationExtension 16.0, *) {
|
||||
TextField("Comment", text: $model.comment, axis: .vertical)
|
||||
TextField("Comment", text: $model.comment, axis: .vertical).lineLimit(6)
|
||||
} else {
|
||||
TextField("Comment", text: $model.comment)
|
||||
}
|
||||
|
||||
@@ -14,6 +14,45 @@ public protocol ChatLike {
|
||||
var chatStats: ChatStats { get }
|
||||
}
|
||||
|
||||
extension ChatLike {
|
||||
public func groupFeatureEnabled(_ feature: GroupFeature) -> Bool {
|
||||
if case let .group(groupInfo) = self.chatInfo {
|
||||
let p = groupInfo.fullGroupPreferences
|
||||
return switch feature {
|
||||
case .timedMessages: p.timedMessages.on
|
||||
case .directMessages: p.directMessages.on(for: groupInfo.membership)
|
||||
case .fullDelete: p.fullDelete.on
|
||||
case .reactions: p.reactions.on
|
||||
case .voice: p.voice.on(for: groupInfo.membership)
|
||||
case .files: p.files.on(for: groupInfo.membership)
|
||||
case .simplexLinks: p.simplexLinks.on(for: groupInfo.membership)
|
||||
case .history: p.history.on
|
||||
}
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
public func prohibitedByPref(
|
||||
hasSimplexLink: Bool,
|
||||
isMediaOrFileAttachment: Bool,
|
||||
isVoice: Bool
|
||||
) -> Bool {
|
||||
// preference checks should match checks in compose view
|
||||
let simplexLinkProhibited = hasSimplexLink && !groupFeatureEnabled(.simplexLinks)
|
||||
let fileProhibited = isMediaOrFileAttachment && !groupFeatureEnabled(.files)
|
||||
let voiceProhibited = isVoice && !chatInfo.featureEnabled(.voice)
|
||||
return switch chatInfo {
|
||||
case .direct: voiceProhibited
|
||||
case .group: simplexLinkProhibited || fileProhibited || voiceProhibited
|
||||
case .local: false
|
||||
case .contactRequest: false
|
||||
case .contactConnection: false
|
||||
case .invalidJSON: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func filterChatsToForwardTo<C: ChatLike>(chats: [C]) -> [C] {
|
||||
var filteredChats = chats.filter { c in
|
||||
c.chatInfo.chatType != .local && canForwardToChat(c.chatInfo)
|
||||
@@ -60,3 +99,15 @@ public func chatIconName(_ cInfo: ChatInfo) -> String {
|
||||
default: "circle.fill"
|
||||
}
|
||||
}
|
||||
|
||||
public func hasSimplexLink(_ text: String?) -> Bool {
|
||||
if let text, let parsedMsg = parseSimpleXMarkdown(text) {
|
||||
parsedMsgHasSimplexLink(parsedMsg)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
public func parsedMsgHasSimplexLink(_ parsedMsg: [FormattedText]) -> Bool {
|
||||
parsedMsg.contains(where: { ft in ft.format?.isSimplexLink ?? false })
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user