mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-03-30 18:35:49 +00:00
ios: mute notifications per chat (#950)
* mute notifications per chat * toggle notifications * update settings api * move model changes to main thread * add mute indication, remove swipe buttons * icon Co-authored-by: JRoberts <8711996+jr-simplex@users.noreply.github.com> Co-authored-by: JRoberts <8711996+jr-simplex@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
e6233722db
commit
307db450d8
@@ -200,7 +200,9 @@ class NtfManager: NSObject, UNUserNotificationCenterDelegate, ObservableObject {
|
||||
|
||||
func notifyMessageReceived(_ cInfo: ChatInfo, _ cItem: ChatItem) {
|
||||
logger.debug("NtfManager.notifyMessageReceived")
|
||||
addNotification(createMessageReceivedNtf(cInfo, cItem))
|
||||
if cInfo.ntfsEnabled {
|
||||
addNotification(createMessageReceivedNtf(cInfo, cItem))
|
||||
}
|
||||
}
|
||||
|
||||
func notifyCallInvitation(_ invitation: RcvCallInvitation) {
|
||||
|
||||
@@ -308,6 +308,10 @@ func setNetworkConfig(_ cfg: NetCfg) throws {
|
||||
throw r
|
||||
}
|
||||
|
||||
func apiSetChatSettings(type: ChatType, id: Int64, chatSettings: ChatSettings) async throws {
|
||||
try await sendCommandOkResp(.apiSetChatSettings(type: type, id: id, chatSettings: chatSettings))
|
||||
}
|
||||
|
||||
func apiContactInfo(contactId: Int64) async throws -> ConnectionStats? {
|
||||
let r = await chatSendCmd(.apiContactInfo(contactId: contactId))
|
||||
if case let .contactInfo(_, connStats) = r { return connStats }
|
||||
|
||||
@@ -118,6 +118,7 @@ struct ChatView: View {
|
||||
Label("Video call", systemImage: "video")
|
||||
}
|
||||
searchButton()
|
||||
toggleNtfsButton(chat)
|
||||
} label: {
|
||||
Image(systemName: "ellipsis")
|
||||
}
|
||||
@@ -132,6 +133,7 @@ struct ChatView: View {
|
||||
}
|
||||
Menu {
|
||||
searchButton()
|
||||
toggleNtfsButton(chat)
|
||||
} label: {
|
||||
Image(systemName: "ellipsis")
|
||||
}
|
||||
@@ -502,6 +504,40 @@ struct ChatView: View {
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder func toggleNtfsButton(_ chat: Chat) -> some View {
|
||||
Button {
|
||||
toggleNotifications(chat, enableNtfs: !chat.chatInfo.ntfsEnabled)
|
||||
} label: {
|
||||
if chat.chatInfo.ntfsEnabled {
|
||||
Label("Mute", systemImage: "speaker.slash")
|
||||
} else {
|
||||
Label("Unmute", systemImage: "speaker.wave.2")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func toggleNotifications(_ chat: Chat, enableNtfs: Bool) {
|
||||
Task {
|
||||
do {
|
||||
let chatSettings = ChatSettings(enableNtfs: enableNtfs)
|
||||
try await apiSetChatSettings(type: chat.chatInfo.chatType, id: chat.chatInfo.apiId, chatSettings: chatSettings)
|
||||
await MainActor.run {
|
||||
switch chat.chatInfo {
|
||||
case var .direct(contact):
|
||||
contact.chatSettings = chatSettings
|
||||
ChatModel.shared.updateContact(contact)
|
||||
case var .group(groupInfo):
|
||||
groupInfo.chatSettings = chatSettings
|
||||
ChatModel.shared.updateGroup(groupInfo)
|
||||
default: ()
|
||||
}
|
||||
}
|
||||
} catch let error {
|
||||
logger.error("apiSetChatSettings error \(responseError(error))")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ChatView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
let chatModel = ChatModel()
|
||||
|
||||
@@ -41,15 +41,13 @@ struct ChatListNavLink: View {
|
||||
label: { ChatPreviewView(chat: chat) },
|
||||
disabled: !contact.ready
|
||||
)
|
||||
.swipeActions(edge: .leading) {
|
||||
.swipeActions(edge: .leading, allowsFullSwipe: true) {
|
||||
if chat.chatStats.unreadCount > 0 {
|
||||
markReadButton()
|
||||
}
|
||||
}
|
||||
.swipeActions(edge: .trailing, allowsFullSwipe: true) {
|
||||
clearChatButton()
|
||||
}
|
||||
.swipeActions(edge: .trailing) {
|
||||
Button(role: .destructive) {
|
||||
AlertManager.shared.showAlert(
|
||||
contact.ready
|
||||
@@ -78,8 +76,6 @@ struct ChatListNavLink: View {
|
||||
.frame(height: 80)
|
||||
.swipeActions(edge: .trailing, allowsFullSwipe: true) {
|
||||
joinGroupButton()
|
||||
}
|
||||
.swipeActions(edge: .trailing) {
|
||||
if groupInfo.canDelete {
|
||||
deleteGroupChatButton(groupInfo)
|
||||
}
|
||||
@@ -104,15 +100,13 @@ struct ChatListNavLink: View {
|
||||
disabled: !groupInfo.ready
|
||||
)
|
||||
.frame(height: 80)
|
||||
.swipeActions(edge: .leading) {
|
||||
.swipeActions(edge: .leading, allowsFullSwipe: true) {
|
||||
if chat.chatStats.unreadCount > 0 {
|
||||
markReadButton()
|
||||
}
|
||||
}
|
||||
.swipeActions(edge: .trailing, allowsFullSwipe: true) {
|
||||
clearChatButton()
|
||||
}
|
||||
.swipeActions(edge: .trailing) {
|
||||
if (groupInfo.membership.memberCurrent) {
|
||||
Button {
|
||||
AlertManager.shared.showAlert(leaveGroupAlert(groupInfo))
|
||||
|
||||
@@ -36,7 +36,6 @@ struct ChatPreviewView: View {
|
||||
.frame(minWidth: 60, alignment: .trailing)
|
||||
.foregroundColor(.secondary)
|
||||
.padding(.top, 4)
|
||||
|
||||
}
|
||||
.padding(.top, 4)
|
||||
.padding(.horizontal, 8)
|
||||
@@ -113,8 +112,11 @@ struct ChatPreviewView: View {
|
||||
.foregroundColor(.white)
|
||||
.padding(.horizontal, 4)
|
||||
.frame(minWidth: 18, minHeight: 18)
|
||||
.background(Color.accentColor)
|
||||
.background(chat.chatInfo.ntfsEnabled ? Color.accentColor : Color.secondary)
|
||||
.cornerRadius(10)
|
||||
} else if !chat.chatInfo.ntfsEnabled {
|
||||
Image(systemName: "speaker.slash.fill")
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -13,11 +13,11 @@
|
||||
3CDBCF4227FAE51000354CDD /* ComposeLinkView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CDBCF4127FAE51000354CDD /* ComposeLinkView.swift */; };
|
||||
3CDBCF4827FF621E00354CDD /* CILinkView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CDBCF4727FF621E00354CDD /* CILinkView.swift */; };
|
||||
5C00164428A26FBC0094D739 /* ContextMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C00164328A26FBC0094D739 /* ContextMenu.swift */; };
|
||||
5C00164C28ACEA380094D739 /* libHSsimplex-chat-3.1.0-iRSBBAuo4W6e6BG2FodFz-ghc8.10.7.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C00164728ACEA380094D739 /* libHSsimplex-chat-3.1.0-iRSBBAuo4W6e6BG2FodFz-ghc8.10.7.a */; };
|
||||
5C00164D28ACEA380094D739 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C00164828ACEA380094D739 /* libgmp.a */; };
|
||||
5C00164E28ACEA380094D739 /* libHSsimplex-chat-3.1.0-iRSBBAuo4W6e6BG2FodFz.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C00164928ACEA380094D739 /* libHSsimplex-chat-3.1.0-iRSBBAuo4W6e6BG2FodFz.a */; };
|
||||
5C00164F28ACEA380094D739 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C00164A28ACEA380094D739 /* libffi.a */; };
|
||||
5C00165028ACEA380094D739 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C00164B28ACEA380094D739 /* libgmpxx.a */; };
|
||||
5C00165628B02AF40094D739 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C00165128B02AF30094D739 /* libffi.a */; };
|
||||
5C00165728B02AF40094D739 /* libHSsimplex-chat-3.1.0-KA4pfwpgEHbFrTKfOobU7J-ghc8.10.7.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C00165228B02AF30094D739 /* libHSsimplex-chat-3.1.0-KA4pfwpgEHbFrTKfOobU7J-ghc8.10.7.a */; };
|
||||
5C00165828B02AF40094D739 /* libHSsimplex-chat-3.1.0-KA4pfwpgEHbFrTKfOobU7J.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C00165328B02AF30094D739 /* libHSsimplex-chat-3.1.0-KA4pfwpgEHbFrTKfOobU7J.a */; };
|
||||
5C00165928B02AF40094D739 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C00165428B02AF30094D739 /* libgmp.a */; };
|
||||
5C00165A28B02AF40094D739 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C00165528B02AF30094D739 /* libgmpxx.a */; };
|
||||
5C029EA82837DBB3004A9677 /* CICallItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C029EA72837DBB3004A9677 /* CICallItemView.swift */; };
|
||||
5C029EAA283942EA004A9677 /* CallController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C029EA9283942EA004A9677 /* CallController.swift */; };
|
||||
5C05DF532840AA1D00C683F9 /* CallSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C05DF522840AA1D00C683F9 /* CallSettings.swift */; };
|
||||
@@ -196,11 +196,11 @@
|
||||
3CDBCF4127FAE51000354CDD /* ComposeLinkView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeLinkView.swift; sourceTree = "<group>"; };
|
||||
3CDBCF4727FF621E00354CDD /* CILinkView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CILinkView.swift; sourceTree = "<group>"; };
|
||||
5C00164328A26FBC0094D739 /* ContextMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContextMenu.swift; sourceTree = "<group>"; };
|
||||
5C00164728ACEA380094D739 /* libHSsimplex-chat-3.1.0-iRSBBAuo4W6e6BG2FodFz-ghc8.10.7.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-3.1.0-iRSBBAuo4W6e6BG2FodFz-ghc8.10.7.a"; sourceTree = "<group>"; };
|
||||
5C00164828ACEA380094D739 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
|
||||
5C00164928ACEA380094D739 /* libHSsimplex-chat-3.1.0-iRSBBAuo4W6e6BG2FodFz.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-3.1.0-iRSBBAuo4W6e6BG2FodFz.a"; sourceTree = "<group>"; };
|
||||
5C00164A28ACEA380094D739 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
|
||||
5C00164B28ACEA380094D739 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
|
||||
5C00165128B02AF30094D739 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
|
||||
5C00165228B02AF30094D739 /* libHSsimplex-chat-3.1.0-KA4pfwpgEHbFrTKfOobU7J-ghc8.10.7.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-3.1.0-KA4pfwpgEHbFrTKfOobU7J-ghc8.10.7.a"; sourceTree = "<group>"; };
|
||||
5C00165328B02AF30094D739 /* libHSsimplex-chat-3.1.0-KA4pfwpgEHbFrTKfOobU7J.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-3.1.0-KA4pfwpgEHbFrTKfOobU7J.a"; sourceTree = "<group>"; };
|
||||
5C00165428B02AF30094D739 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
|
||||
5C00165528B02AF30094D739 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
|
||||
5C029EA72837DBB3004A9677 /* CICallItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CICallItemView.swift; sourceTree = "<group>"; };
|
||||
5C029EA9283942EA004A9677 /* CallController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallController.swift; sourceTree = "<group>"; };
|
||||
5C05DF522840AA1D00C683F9 /* CallSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallSettings.swift; sourceTree = "<group>"; };
|
||||
@@ -350,12 +350,12 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5CE2BA93284534B000EC33A6 /* libiconv.tbd in Frameworks */,
|
||||
5C00164F28ACEA380094D739 /* libffi.a in Frameworks */,
|
||||
5C00165728B02AF40094D739 /* libHSsimplex-chat-3.1.0-KA4pfwpgEHbFrTKfOobU7J-ghc8.10.7.a in Frameworks */,
|
||||
5C00165828B02AF40094D739 /* libHSsimplex-chat-3.1.0-KA4pfwpgEHbFrTKfOobU7J.a in Frameworks */,
|
||||
5C00165628B02AF40094D739 /* libffi.a in Frameworks */,
|
||||
5C00165928B02AF40094D739 /* libgmp.a in Frameworks */,
|
||||
5CE2BA94284534BB00EC33A6 /* libz.tbd in Frameworks */,
|
||||
5C00164E28ACEA380094D739 /* libHSsimplex-chat-3.1.0-iRSBBAuo4W6e6BG2FodFz.a in Frameworks */,
|
||||
5C00164D28ACEA380094D739 /* libgmp.a in Frameworks */,
|
||||
5C00164C28ACEA380094D739 /* libHSsimplex-chat-3.1.0-iRSBBAuo4W6e6BG2FodFz-ghc8.10.7.a in Frameworks */,
|
||||
5C00165028ACEA380094D739 /* libgmpxx.a in Frameworks */,
|
||||
5C00165A28B02AF40094D739 /* libgmpxx.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -410,11 +410,11 @@
|
||||
5C764E5C279C70B7000C6508 /* Libraries */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5C00164A28ACEA380094D739 /* libffi.a */,
|
||||
5C00164828ACEA380094D739 /* libgmp.a */,
|
||||
5C00164B28ACEA380094D739 /* libgmpxx.a */,
|
||||
5C00164728ACEA380094D739 /* libHSsimplex-chat-3.1.0-iRSBBAuo4W6e6BG2FodFz-ghc8.10.7.a */,
|
||||
5C00164928ACEA380094D739 /* libHSsimplex-chat-3.1.0-iRSBBAuo4W6e6BG2FodFz.a */,
|
||||
5C00165128B02AF30094D739 /* libffi.a */,
|
||||
5C00165428B02AF30094D739 /* libgmp.a */,
|
||||
5C00165528B02AF30094D739 /* libgmpxx.a */,
|
||||
5C00165228B02AF30094D739 /* libHSsimplex-chat-3.1.0-KA4pfwpgEHbFrTKfOobU7J-ghc8.10.7.a */,
|
||||
5C00165328B02AF30094D739 /* libHSsimplex-chat-3.1.0-KA4pfwpgEHbFrTKfOobU7J.a */,
|
||||
);
|
||||
path = Libraries;
|
||||
sourceTree = "<group>";
|
||||
|
||||
@@ -597,6 +597,10 @@ public struct KeepAliveOpts: Codable, Equatable {
|
||||
public struct ChatSettings: Codable {
|
||||
public var enableNtfs: Bool
|
||||
|
||||
public init(enableNtfs: Bool) {
|
||||
self.enableNtfs = enableNtfs
|
||||
}
|
||||
|
||||
public static let defaults: ChatSettings = ChatSettings(enableNtfs: true)
|
||||
}
|
||||
|
||||
|
||||
@@ -189,6 +189,14 @@ public enum ChatInfo: Identifiable, Decodable, NamedChat {
|
||||
}
|
||||
}
|
||||
|
||||
public var ntfsEnabled: Bool {
|
||||
switch self {
|
||||
case let .direct(contact): return contact.chatSettings.enableNtfs
|
||||
case let .group(groupInfo): return groupInfo.chatSettings.enableNtfs
|
||||
default: return false
|
||||
}
|
||||
}
|
||||
|
||||
var createdAt: Date {
|
||||
switch self {
|
||||
case let .direct(contact): return contact.createdAt
|
||||
@@ -244,7 +252,7 @@ public struct Contact: Identifiable, Decodable, NamedChat {
|
||||
public var profile: Profile
|
||||
public var activeConn: Connection
|
||||
public var viaGroup: Int64?
|
||||
// public var chatSettings: ChatSettings
|
||||
public var chatSettings: ChatSettings
|
||||
var createdAt: Date
|
||||
var updatedAt: Date
|
||||
|
||||
@@ -265,6 +273,7 @@ public struct Contact: Identifiable, Decodable, NamedChat {
|
||||
localDisplayName: "alice",
|
||||
profile: Profile.sampleData,
|
||||
activeConn: Connection.sampleData,
|
||||
chatSettings: ChatSettings.defaults,
|
||||
createdAt: .now,
|
||||
updatedAt: .now
|
||||
)
|
||||
@@ -434,7 +443,7 @@ public struct GroupInfo: Identifiable, Decodable, NamedChat {
|
||||
var localDisplayName: GroupName
|
||||
public var groupProfile: GroupProfile
|
||||
public var membership: GroupMember
|
||||
// public var chatSettings: ChatSettings
|
||||
public var chatSettings: ChatSettings
|
||||
var createdAt: Date
|
||||
var updatedAt: Date
|
||||
|
||||
@@ -463,6 +472,7 @@ public struct GroupInfo: Identifiable, Decodable, NamedChat {
|
||||
localDisplayName: "team",
|
||||
groupProfile: GroupProfile.sampleData,
|
||||
membership: GroupMember.sampleData,
|
||||
chatSettings: ChatSettings.defaults,
|
||||
createdAt: .now,
|
||||
updatedAt: .now
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user