fix(@desktop/notifications): revamp notifications settings & behaviour

- signal for adding notification to the Activity Center introduced
and emitted, but that part is not handled within this commit since
there are some details needed to be discussed in the PR#5334
- signal for displaying ephemeral app notification is introduced
and emitted, but that part is not handled within this commit since
we don't have yet ephemeral notificaiton in place.

Fixes #4902
This commit is contained in:
Sale Djenic 2022-04-04 13:09:23 +02:00 committed by Iuri Matias
parent ddf816a649
commit 03d7632f32
30 changed files with 1601 additions and 701 deletions

View File

@ -6,25 +6,38 @@ include ../../../app_service/common/json_utils
type
NotificationType* {.pure.} = enum
NewContactRequest = 1,
TestNotification,
NewContactRequest,
AcceptedContactRequest,
JoinCommunityRequest,
MyRequestToJoinCommunityAccepted,
MyRequestToJoinCommunityRejected,
NewMessage,
NewMention
NewMessageWithPersonalMention,
NewMessageWithGlobalMention,
IdentityVerificationRequest
NotificationDetails* = object
notificationType*: NotificationType
sectionId*: string
isCommunitySection*: bool
sectionActive*: bool
chatId*: string
chatActive*: bool
isOneToOne*: bool
isGroupChat*: bool
messageId*: string
proc toNotificationDetails*(jsonObj: JsonNode): NotificationDetails =
var notificationType: int
if (not (jsonObj.getProp("notificationType", notificationType) and
jsonObj.getProp("sectionId", result.sectionId) and
jsonObj.getProp("isCommunitySection", result.isCommunitySection) and
jsonObj.getProp("sectionActive", result.sectionActive) and
jsonObj.getProp("chatId", result.chatId) and
jsonObj.getProp("chatActive", result.chatActive) and
jsonObj.getProp("isOneToOne", result.isOneToOne) and
jsonObj.getProp("isGroupChat", result.isGroupChat) and
jsonObj.getProp("messageId", result.messageId))):
return NotificationDetails()
@ -34,6 +47,11 @@ proc toJsonNode*(self: NotificationDetails): JsonNode =
result = %* {
"notificationType": self.notificationType.int,
"sectionId": self.sectionId,
"isCommunitySection": self.isCommunitySection,
"sectionActive": self.sectionActive,
"chatId": self.chatId,
"chatActive": self.chatActive,
"isOneToOne": self.isOneToOne,
"isGroupChat": self.isGroupChat,
"messageId": self.messageId
}

View File

@ -13,6 +13,7 @@ logScope:
const NOTIFICATION_SOUND = "qrc:/imports/assets/audio/notification.wav"
# Signals which may be emitted by this class:
const SIGNAL_ADD_NOTIFICATION_TO_ACTIVITY_CENTER* = "addNotificationToActivityCenter"
const SIGNAL_DISPLAY_APP_NOTIFICATION* = "displayAppNotification"
const SIGNAL_OS_NOTIFICATION_CLICKED* = "osNotificationClicked"
@ -63,18 +64,18 @@ QtObject:
self.soundManager = newStatusSoundManager()
signalConnect(self.osNotification, "notificationClicked(QString)", self, "onOSNotificationClicked(QString)", 2)
signalConnect(singletonInstance.globalEvents, "showNormalMessageNotification(QString, QString, QString, QString, QString)",
self, "onShowNormalMessageNotification(QString, QString, QString, QString, QString)", 2)
signalConnect(singletonInstance.globalEvents, "showMentionMessageNotification(QString, QString, QString, QString, QString)",
self, "onShowMentionMessageNotification(QString, QString, QString, QString, QString)", 2)
signalConnect(singletonInstance.globalEvents, "showTestNotification(QString, QString)",
self, "onShowTestNotification(QString, QString)", 2)
signalConnect(singletonInstance.globalEvents, "showMessageNotification(QString, QString, QString, bool, bool, QString, bool, QString, int, bool, bool)",
self, "onShowMessageNotification(QString, QString, QString, bool, bool, QString, bool, QString, int, bool, bool)", 2)
signalConnect(singletonInstance.globalEvents, "showNewContactRequestNotification(QString, QString, QString)",
self, "onShowNewContactRequestNotification(QString, QString, QString)", 2)
signalConnect(singletonInstance.globalEvents, "newCommunityMembershipRequestNotification(QString, QString, QString)",
self, "onNewCommunityMembershipRequestNotification(QString, QString, QString)", 2)
signalConnect(singletonInstance.globalEvents, "myRequestToJoinCommunityHasBeenAcccepted(QString, QString, QString)",
self, "onMyRequestToJoinCommunityHasBeenAcccepted(QString, QString, QString)", 2)
signalConnect(singletonInstance.globalEvents, "myRequestToJoinCommunityAcccepted(QString, QString, QString)",
self, "onMyRequestToJoinCommunityAcccepted(QString, QString, QString)", 2)
signalConnect(singletonInstance.globalEvents, "myRequestToJoinCommunityHasBeenRejected(QString, QString, QString)",
self, "onMyRequestToJoinCommunityHasBeenRejected(QString, QString, QString)", 2)
self, "onMyRequestToJoinCommunityRejected(QString, QString, QString)", 2)
self.notificationSetUp = true
proc showOSNotification(self: NotificationsManager, title: string, message: string, identifier: string) =
@ -91,23 +92,35 @@ QtObject:
app_makeItActive(singletonInstance.engine)
let details = toNotificationDetails(parseJson(identifier))
if(details.notificationType == NotificationType.TestNotification):
info "Test notification was clicked"
return
if(details.notificationType == NotificationType.NewMessage or
details.notificationType == NotificationType.NewMention):
details.notificationType == NotificationType.NewMessageWithPersonalMention or
details.notificationType == NotificationType.NewMessageWithGlobalMention):
let data = ActiveSectionChatArgs(sectionId: details.sectionId, chatId: details.chatId, messageId: details.messageId)
self.events.emit(SIGNAL_MAKE_SECTION_CHAT_ACTIVE, data)
else:
self.events.emit(SIGNAL_OS_NOTIFICATION_CLICKED, ClickedNotificationArgs(details: details))
proc onShowNormalMessageNotification(self: NotificationsManager, title: string, message: string, sectionId: string,
chatId: string, messageId: string) {.slot.} =
let details = NotificationDetails(notificationType: NotificationType.NewMessage, sectionId: sectionId,
chatId: chatId, messageId: messageId)
proc onShowTestNotification(self: NotificationsManager, title: string, message: string) {.slot.} =
let details = NotificationDetails(notificationType: NotificationType.TestNotification)
self.processNotification(title, message, details)
proc onShowMentionMessageNotification(self: NotificationsManager, title: string, message: string, sectionId: string,
chatId: string, messageId: string) {.slot.} =
let details = NotificationDetails(notificationType: NotificationType.NewMention, sectionId: sectionId,
chatId: chatId, messageId: messageId)
proc onShowMessageNotification(self: NotificationsManager, title: string, message: string, sectionId: string,
isCommunitySection: bool, isSectionActive: bool, chatId: string, isChatActive: bool, messageId: string,
notificationType: int, isOneToOne: bool, isGroupChat: bool) {.slot.} =
let details = NotificationDetails(
notificationType: notificationType.NotificationType,
sectionId: sectionId,
isCommunitySection: isCommunitySection,
sectionActive: isSectionActive,
chatId: chatId,
chatActive: isChatActive,
isOneToOne: isOneToOne,
isGroupChat: isGroupChat,
messageId: messageId)
self.processNotification(title, message, details)
proc onShowNewContactRequestNotification*(self: NotificationsManager, title: string, message: string,
@ -120,70 +133,171 @@ QtObject:
let details = NotificationDetails(notificationType: NotificationType.JoinCommunityRequest, sectionId: sectionId)
self.processNotification(title, message, details)
proc onMyRequestToJoinCommunityHasBeenAcccepted*(self: NotificationsManager, title: string, message: string,
proc onMyRequestToJoinCommunityAcccepted*(self: NotificationsManager, title: string, message: string,
sectionId: string) {.slot.} =
let details = NotificationDetails(notificationType: NotificationType.MyRequestToJoinCommunityAccepted,
sectionId: sectionId)
self.processNotification(title, message, details)
proc onMyRequestToJoinCommunityHasBeenRejected*(self: NotificationsManager, title: string, message: string,
proc onMyRequestToJoinCommunityRejected*(self: NotificationsManager, title: string, message: string,
sectionId: string) {.slot.} =
let details = NotificationDetails(notificationType: NotificationType.MyRequestToJoinCommunityRejected,
sectionId: sectionId)
self.processNotification(title, message, details)
proc getExemptions(self: NotificationsManager, id: string): JsonNode =
# This proc returns exemptions as json object for the passed `id` if there are no set exemptions,
# json object with the default values will be returned.
let allExemptions = singletonInstance.localAccountSensitiveSettings.getNotifSettingExemptionsAsJson()
result = %* {
EXEMPTION_KEY_MUTE_ALL_MESSAGES: false,
EXEMPTION_KEY_PERSONAL_MENTIONS: LSS_VALUE_NOTIF_SEND_ALERTS,
EXEMPTION_KEY_GLOBAL_MENTIONS: LSS_VALUE_NOTIF_SEND_ALERTS,
EXEMPTION_KEY_OTHER_MESSAGES: LSS_VALUE_NOTIF_SEND_TURN_OFF
}
if(allExemptions.contains(id)):
let obj = allExemptions[id]
if(obj.contains(EXEMPTION_KEY_MUTE_ALL_MESSAGES)):
result[EXEMPTION_KEY_MUTE_ALL_MESSAGES] = obj[EXEMPTION_KEY_MUTE_ALL_MESSAGES]
if(obj.contains(EXEMPTION_KEY_PERSONAL_MENTIONS)):
result[EXEMPTION_KEY_PERSONAL_MENTIONS] = obj[EXEMPTION_KEY_PERSONAL_MENTIONS]
if(obj.contains(EXEMPTION_KEY_GLOBAL_MENTIONS)):
result[EXEMPTION_KEY_GLOBAL_MENTIONS] = obj[EXEMPTION_KEY_GLOBAL_MENTIONS]
if(obj.contains(EXEMPTION_KEY_OTHER_MESSAGES)):
result[EXEMPTION_KEY_OTHER_MESSAGES] = obj[EXEMPTION_KEY_OTHER_MESSAGES]
proc notificationCheck(self: NotificationsManager, title: string, message: string, details: NotificationDetails,
notificationWay: string) =
var data = NotificationArgs(title: title, message: message, details: details)
# All but the NewMessage notifications go to Activity Center
if(details.notificationType != NotificationType.NewMessage):
debug "Add AC notification", title=title, message=message
self.events.emit(SIGNAL_ADD_NOTIFICATION_TO_ACTIVITY_CENTER, data)
# An exemption from the diagrams, at least for now, is that we don't need to implement the "Badge Check" block here,
# cause that's already handled in appropriate modules.
if(details.notificationType == NotificationType.NewMessage or
details.notificationType == NotificationType.NewMessageWithPersonalMention or
details.notificationType == NotificationType.NewMessageWithGlobalMention or
details.notificationType == NotificationType.NewContactRequest or
details.notificationType == NotificationType.IdentityVerificationRequest):
if(notificationWay == LSS_VALUE_NOTIF_SEND_DELIVER_QUIETLY):
return
if((details.notificationType == NotificationType.NewMessage or
details.notificationType == NotificationType.NewMessageWithPersonalMention or
details.notificationType == NotificationType.NewMessageWithGlobalMention) and
details.sectionActive and
details.chatActive):
return
let appIsActive = app_isActive(singletonInstance.engine)
if(appIsActive):
debug "Add APP notification", title=title, message=message
self.events.emit(SIGNAL_DISPLAY_APP_NOTIFICATION, data)
if(not appIsActive or details.notificationType == NotificationType.TestNotification):
# Check anonymity level
if(singletonInstance.localAccountSensitiveSettings.getNotificationMessagePreviewSetting() == PREVIEW_ANONYMOUS):
data.title = "Status"
data.message = "You have a new message"
elif(singletonInstance.localAccountSensitiveSettings.getNotificationMessagePreviewSetting() == PREVIEW_NAME_ONLY):
data.message = "You have a new message"
let identifier = $(details.toJsonNode())
debug "Add OS notification", title=data.title, message=data.message, identifier=identifier
self.showOSNotification(data.title, data.message, identifier)
if(singletonInstance.localAccountSensitiveSettings.getNotificationSoundsEnabled()):
self.soundManager.setPlayerVolume(singletonInstance.localAccountSensitiveSettings.getVolume())
self.soundManager.playSound(NOTIFICATION_SOUND)
proc processNotification(self: NotificationsManager, title: string, message: string, details: NotificationDetails) =
## This is the main method which need to be called to process an event according to the preferences set in the
## notifications panel of the settings section.
## "Notifications & Sounds" panel of the "Settings" section.
##
## This method determines whether a notification need to be displayed or not, what notification to display, whether
## to display App or OS notification, what level of anonymous to apply, whether to play sound or not and so...
## to display App or OS notification and/or add notification to Activity Center, what level of anonymous to apply,
## whether to play sound or not and so...
# I am not 100% sure about this.
# According to this:
# https://github.com/status-im/status-desktop/pull/4789#discussion_r805028513
# The app should use OS notification only in case it is not the active app or it's minimized at the moment
# we're processing an event.
if(singletonInstance.localAccountSensitiveSettings.getUseOSNotifications() and
app_isActive(singletonInstance.engine)):
# The flow used here follows these diagrams:
# - https://drive.google.com/file/d/1L_9c2CMObcDcSuhVUu97s9-_26gtutES/view
# - https://drive.google.com/file/d/1KmG7lJDJIx6R_HJWeFvMYT2wk32RoTJQ/view
if(not singletonInstance.localAccountSensitiveSettings.getNotifSettingAllowNotifications()):
return
var finalTitle = title
var finalMessage = message
# In case of contact request
if(details.notificationType == NotificationType.NewContactRequest):
if(singletonInstance.localAccountSensitiveSettings.getNotifSettingContactRequests() != LSS_VALUE_NOTIF_SEND_TURN_OFF):
self.notificationCheck(title, message, details, singletonInstance.localAccountSensitiveSettings.getNotifSettingContactRequests())
return
# Check if notification need to be displayed
if(singletonInstance.localAccountSensitiveSettings.getNotificationSetting() == NOTIFY_NOTHING_ABOUT and
(details.notificationType == NotificationType.NewMessage or
details.notificationType == NotificationType.NewMention)):
return
# In case of identity verification request
elif(details.notificationType == NotificationType.IdentityVerificationRequest):
if(singletonInstance.localAccountSensitiveSettings.getNotifSettingIdentityVerificationRequests() != LSS_VALUE_NOTIF_SEND_TURN_OFF):
self.notificationCheck(title, message, details, singletonInstance.localAccountSensitiveSettings.getNotifSettingIdentityVerificationRequests())
return
if(singletonInstance.localAccountSensitiveSettings.getNotificationSetting() == NOTIFY_JUST_ABOUT_MENTIONS and
details.notificationType == NotificationType.NewMessage):
return
# In case of new message (regardless it's message with mention or not)
elif(details.notificationType == NotificationType.NewMessage or
details.notificationType == NotificationType.NewMessageWithPersonalMention or
details.notificationType == NotificationType.NewMessageWithGlobalMention):
if(singletonInstance.localAccountSensitiveSettings.getNotifSettingAllMessages() != LSS_VALUE_NOTIF_SEND_TURN_OFF):
self.notificationCheck(title, message, details, singletonInstance.localAccountSensitiveSettings.getNotifSettingAllMessages())
return
if(not singletonInstance.localAccountSensitiveSettings.getNotifyOnNewRequests() and
details.notificationType == NotificationType.NewContactRequest):
return
let messageBelongsToCommunity = details.isCommunitySection
if(messageBelongsToCommunity):
let exemptionObj = self.getExemptions(details.sectionId)
if(exemptionObj[EXEMPTION_KEY_MUTE_ALL_MESSAGES].getBool):
return
# Check anonymous level
if(singletonInstance.localAccountSensitiveSettings.getNotificationMessagePreviewSetting() == PREVIEW_ANONYMOUS):
finalTitle = "Status"
finalMessage = "You have a new message"
elif(singletonInstance.localAccountSensitiveSettings.getNotificationMessagePreviewSetting() == PREVIEW_NAME_ONLY):
finalMessage = "You have a new message"
# Check whether to display APP or OS notification
if(singletonInstance.localAccountSensitiveSettings.getUseOSNotifications()):
let identifier = $(details.toJsonNode())
debug "Add OS notification", title=finalTitle, message=finalMessage, identifier=identifier
self.showOSNotification(finalTitle, finalMessage, identifier)
if(details.notificationType == NotificationType.NewMessageWithPersonalMention and
exemptionObj[EXEMPTION_KEY_PERSONAL_MENTIONS].getStr != LSS_VALUE_NOTIF_SEND_TURN_OFF):
self.notificationCheck(title, message, details, exemptionObj[EXEMPTION_KEY_PERSONAL_MENTIONS].getStr)
return
if(details.notificationType == NotificationType.NewMessageWithGlobalMention and
exemptionObj[EXEMPTION_KEY_GLOBAL_MENTIONS].getStr != LSS_VALUE_NOTIF_SEND_TURN_OFF):
self.notificationCheck(title, message, details, exemptionObj[EXEMPTION_KEY_GLOBAL_MENTIONS].getStr)
return
if(details.notificationType == NotificationType.NewMessage and
exemptionObj[EXEMPTION_KEY_OTHER_MESSAGES].getStr != LSS_VALUE_NOTIF_SEND_TURN_OFF):
self.notificationCheck(title, message, details, exemptionObj[EXEMPTION_KEY_OTHER_MESSAGES].getStr)
return
return
else:
if(details.isOneToOne or details.isGroupChat):
let exemptionObj = self.getExemptions(details.chatId)
if(exemptionObj[EXEMPTION_KEY_MUTE_ALL_MESSAGES].getBool):
return
if(details.notificationType == NotificationType.NewMessageWithPersonalMention and
singletonInstance.localAccountSensitiveSettings.getNotifSettingPersonalMentions() != LSS_VALUE_NOTIF_SEND_TURN_OFF):
self.notificationCheck(title, message, details, singletonInstance.localAccountSensitiveSettings.getNotifSettingPersonalMentions())
return
if(details.notificationType == NotificationType.NewMessageWithGlobalMention and
singletonInstance.localAccountSensitiveSettings.getNotifSettingGlobalMentions() != LSS_VALUE_NOTIF_SEND_TURN_OFF):
self.notificationCheck(title, message, details, singletonInstance.localAccountSensitiveSettings.getNotifSettingGlobalMentions())
return
if(details.notificationType == NotificationType.NewMessage):
if(details.isOneToOne and
singletonInstance.localAccountSensitiveSettings.getNotifSettingOneToOneChats() != LSS_VALUE_NOTIF_SEND_TURN_OFF):
self.notificationCheck(title, message, details, singletonInstance.localAccountSensitiveSettings.getNotifSettingOneToOneChats())
return
if(details.isGroupChat and
singletonInstance.localAccountSensitiveSettings.getNotifSettingGroupChats() != LSS_VALUE_NOTIF_SEND_TURN_OFF):
self.notificationCheck(title, message, details, singletonInstance.localAccountSensitiveSettings.getNotifSettingGroupChats())
return
# In all other cases (TestNotification, AcceptedContactRequest, JoinCommunityRequest, MyRequestToJoinCommunityAccepted,
# MyRequestToJoinCommunityRejected)
else:
let data = NotificationArgs(title: finalTitle, message: finalMessage, details: details)
debug "Add APP notification", title=finalTitle, message=finalMessage
self.events.emit(SIGNAL_DISPLAY_APP_NOTIFICATION, data)
# Check whether to play a sound
if(singletonInstance.localAccountSensitiveSettings.getNotificationSoundsEnabled()):
let currentVolume = singletonInstance.localAccountSensitiveSettings.getVolume() * 10
self.soundManager.setPlayerVolume(currentVolume)
self.soundManager.playSound(NOTIFICATION_SOUND)
self.notificationCheck(title, message, details, "")

View File

@ -13,16 +13,20 @@ QtObject:
new(result, delete)
result.setup
proc showNormalMessageNotification*(self: GlobalEvents, title: string, message: string, sectionId: string,
chatId: string, messageId: string) {.signal.}
proc showMentionMessageNotification*(self: GlobalEvents, title: string, message: string, sectionId: string,
chatId: string, messageId: string) {.signal.}
proc showTestNotification*(self: GlobalEvents, title: string, message: string) {.signal.}
proc showMessageNotification*(self: GlobalEvents, title: string, message: string, sectionId: string,
isCommunitySection: bool, isSectionActive: bool, chatId: string, isChatActive: bool, messageId: string,
notificationType: int, isOneToOne: bool, isGroupChat: bool) {.signal.}
proc showNewContactRequestNotification*(self: GlobalEvents, title: string, message: string, sectionId: string)
{.signal.}
proc newCommunityMembershipRequestNotification*(self: GlobalEvents, title: string, message: string,
sectionId: string) {.signal.}
proc myRequestToJoinCommunityHasBeenAcccepted*(self: GlobalEvents, title: string, message: string,
proc myRequestToJoinCommunityAcccepted*(self: GlobalEvents, title: string, message: string,
sectionId: string) {.signal.}
proc myRequestToJoinCommunityHasBeenRejected*(self: GlobalEvents, title: string, message: string,
sectionId: string) {.signal.}
proc myRequestToJoinCommunityRejected*(self: GlobalEvents, title: string, message: string,
sectionId: string) {.signal.}

View File

@ -1,4 +1,4 @@
import NimQml, os
import NimQml, os, json, chronicles
import ../../constants
@ -37,17 +37,11 @@ const DEFAULT_HIDDEN_COMMUNITY_CHANNELS_AND_CATEGORIES_BANNERS = ""
const LSS_KEY_HIDDEN_COMMUNITY_BACKUP_BANNERS* = "hiddenCommunityBackUpBanners"
const DEFAULT_HIDDEN_COMMUNITY_BACKUP_BANNERS = ""
const LSS_KEY_VOLUME* = "volume"
const DEFAULT_VOLUME = 2
const LSS_KEY_NOTIFICATION_SETTING* = "notificationSetting"
const DEFAULT_NOTIFICATION_SETTING = 1 #notifyJustMentions from qml
const DEFAULT_VOLUME = 50
const LSS_KEY_NOTIFICATION_SOUNDS_ENABLED* = "notificationSoundsEnabled"
const DEFAULT_NOTIFICATION_SOUNDS_ENABLED = true
const LSS_KEY_USE_OS_NOTIFICATIONS* = "useOSNotifications"
const DEFAULT_USE_OS_NOTIFICATIONS = true
const LSS_KEY_NOTIFICATION_MESSAGE_PREVIEW_SETTING* = "notificationMessagePreviewSetting"
const DEFAULT_NOTIFICATION_MESSAGE_PREVIEW_SETTING = 2 #notificationPreviewNameAndMessage from qml
const LSS_KEY_NOTIFY_ON_NEW_REQUESTS* = "notifyOnNewRequests"
const DEFAULT_NOTIFY_ON_NEW_REQUESTS = true
const LSS_KEY_WITHLISTED_UNFURLING_SITES* = "whitelistedUnfurlingSites"
const DEFAULT_WITHLISTED_UNFURLING_SITES = ""
const LSS_KEY_NEVER_ASK_ABOUT_UNFURLING_AGAIN* = "neverAskAboutUnfurlingAgain"
@ -107,6 +101,40 @@ const DEFAULT_IS_DDMMYY_DATE_FORMAT = false
const LSS_KEY_IS_24H_TIME_FORMAT* = "is_24h_time_format"
const DEFAULT_IS_24H_TIME_FORMAT = false
# Exemption Keys
const EXEMPTION_KEY_MUTE_ALL_MESSAGES* = "muteAllMessages"
const EXEMPTION_KEY_PERSONAL_MENTIONS* = "personalMentions"
const EXEMPTION_KEY_GLOBAL_MENTIONS* = "globalMentions"
const EXEMPTION_KEY_OTHER_MESSAGES* = "otherMessages"
# Exemption Values
const LSS_VALUE_NOTIF_SEND_ALERTS* = "sendAlerts"
const LSS_VALUE_NOTIF_SEND_DELIVER_QUIETLY* = "deliverQuietly"
const LSS_VALUE_NOTIF_SEND_TURN_OFF* = "turnOff"
# Notifications
const LSS_KEY_NOTIF_SETTING_ALLOW_NOTIFICATIONS* = "allowNotifications"
const DEFAULT_NOTIF_SETTING_ALLOW_NOTIFICATIONS = true
const LSS_KEY_NOTIF_SETTING_ONE_TO_ONE_CHATS* = "notifSettingOneToOneChats"
const DEFAULT_NOTIF_SETTING_ONE_TO_ONE_CHATS = LSS_VALUE_NOTIF_SEND_ALERTS
const LSS_KEY_NOTIF_SETTING_GROUP_CHATS* = "notifSettingGroupChats"
const DEFAULT_NOTIF_SETTING_GROUP_CHATS = LSS_VALUE_NOTIF_SEND_ALERTS
const LSS_KEY_NOTIF_SETTING_PERSONAL_MENTIONS* = "notifSettingPersonalMentions"
const DEFAULT_NOTIF_SETTING_PERSONAL_MENTIONS = LSS_VALUE_NOTIF_SEND_ALERTS
const LSS_KEY_NOTIF_SETTING_GLOBAL_MENTIONS* = "notifSettingGlobalMentions"
const DEFAULT_NOTIF_SETTING_GLOBAL_MENTIONS = LSS_VALUE_NOTIF_SEND_ALERTS
const LSS_KEY_NOTIF_SETTING_ALL_MESSAGES* = "notifSettingAllMessages"
const DEFAULT_NOTIF_SETTING_ALL_MESSAGES = LSS_VALUE_NOTIF_SEND_TURN_OFF
const LSS_KEY_NOTIF_SETTING_CONTACT_REQUESTS* = "notifSettingContactRequests"
const DEFAULT_NOTIF_SETTING_CONTACT_REQUESTS = LSS_VALUE_NOTIF_SEND_ALERTS
const LSS_KEY_NOTIF_SETTING_IDENTITY_VERIF_REQUESTS* = "notifSettingIdentityVerificationRequests"
const DEFAULT_NOTIF_SETTING_IDENTITY_VERIF_REQUESTS = LSS_VALUE_NOTIF_SEND_ALERTS
const LSS_KEY_NOTIF_SETTING_EXEMPTIONS* = "notificationsExemptions"
const DEFAULT_NOTIF_SETTING_EXEMPTIONS = ""
logScope:
topics = "la-sensitive-settings"
QtObject:
type LocalAccountSensitiveSettings* = ref object of QObject
settingsFileDir: string
@ -400,26 +428,12 @@ QtObject:
proc setVolume*(self: LocalAccountSensitiveSettings, value: int) {.slot.} =
setSettingsProp(self, LSS_KEY_VOLUME, newQVariant(value)):
self.volumeChanged()
QtProperty[int] volume:
read = getVolume
write = setVolume
notify = volumeChanged
proc notificationSettingChanged*(self: LocalAccountSensitiveSettings) {.signal.}
proc getNotificationSetting*(self: LocalAccountSensitiveSettings): int {.slot.} =
getSettingsProp[int](self, LSS_KEY_NOTIFICATION_SETTING, newQVariant(DEFAULT_NOTIFICATION_SETTING))
proc setNotificationSetting*(self: LocalAccountSensitiveSettings, value: int) {.slot.} =
setSettingsProp(self, LSS_KEY_NOTIFICATION_SETTING, newQVariant(value)):
self.notificationSettingChanged()
QtProperty[int] notificationSetting:
read = getNotificationSetting
write = setNotificationSetting
notify = notificationSettingChanged
proc notificationSoundsEnabledChanged*(self: LocalAccountSensitiveSettings) {.signal.}
proc getNotificationSoundsEnabled*(self: LocalAccountSensitiveSettings): bool {.slot.} =
getSettingsProp[bool](self, LSS_KEY_NOTIFICATION_SOUNDS_ENABLED, newQVariant(DEFAULT_NOTIFICATION_SOUNDS_ENABLED))
@ -433,19 +447,6 @@ QtObject:
notify = notificationSoundsEnabledChanged
proc useOSNotificationsChanged*(self: LocalAccountSensitiveSettings) {.signal.}
proc getUseOSNotifications*(self: LocalAccountSensitiveSettings): bool {.slot.} =
getSettingsProp[bool](self, LSS_KEY_USE_OS_NOTIFICATIONS, newQVariant(DEFAULT_USE_OS_NOTIFICATIONS))
proc setUseOSNotifications*(self: LocalAccountSensitiveSettings, value: bool) {.slot.} =
setSettingsProp(self, LSS_KEY_USE_OS_NOTIFICATIONS, newQVariant(value)):
self.useOSNotificationsChanged()
QtProperty[bool] useOSNotifications:
read = getUseOSNotifications
write = setUseOSNotifications
notify = useOSNotificationsChanged
proc notificationMessagePreviewSettingChanged*(self: LocalAccountSensitiveSettings) {.signal.}
proc getNotificationMessagePreviewSetting*(self: LocalAccountSensitiveSettings): int {.slot.} =
getSettingsProp[int](self, LSS_KEY_NOTIFICATION_MESSAGE_PREVIEW_SETTING, newQVariant(DEFAULT_NOTIFICATION_MESSAGE_PREVIEW_SETTING))
@ -459,19 +460,6 @@ QtObject:
notify = notificationMessagePreviewSettingChanged
proc notifyOnNewRequestsChanged*(self: LocalAccountSensitiveSettings) {.signal.}
proc getNotifyOnNewRequests*(self: LocalAccountSensitiveSettings): bool {.slot.} =
getSettingsProp[bool](self, LSS_KEY_NOTIFY_ON_NEW_REQUESTS, newQVariant(DEFAULT_NOTIFY_ON_NEW_REQUESTS))
proc setNotifyOnNewRequests*(self: LocalAccountSensitiveSettings, value: bool) {.slot.} =
setSettingsProp(self, LSS_KEY_NOTIFY_ON_NEW_REQUESTS, newQVariant(value)):
self.notifyOnNewRequestsChanged()
QtProperty[bool] notifyOnNewRequests:
read = getNotifyOnNewRequests
write = setNotifyOnNewRequests
notify = notifyOnNewRequestsChanged
proc whitelistedUnfurlingSitesChanged*(self: LocalAccountSensitiveSettings) {.signal.}
proc getWhitelistedUnfurlingSites*(self: LocalAccountSensitiveSettings): QVariant {.slot.} =
getSettingsPropQVariant(self, LSS_KEY_WITHLISTED_UNFURLING_SITES, newQVariant(DEFAULT_WITHLISTED_UNFURLING_SITES))
@ -847,6 +835,117 @@ QtObject:
write = setIs24hTimeFormat
notify = is24hTimeFormatChanged
proc notifSettingAllowNotificationsChanged*(self: LocalAccountSensitiveSettings) {.signal.}
proc getNotifSettingAllowNotifications*(self: LocalAccountSensitiveSettings): bool {.slot.} =
getSettingsProp[bool](self, LSS_KEY_NOTIF_SETTING_ALLOW_NOTIFICATIONS, newQVariant(DEFAULT_NOTIF_SETTING_ALLOW_NOTIFICATIONS))
proc setNotifSettingAllowNotifications*(self: LocalAccountSensitiveSettings, value: bool) {.slot.} =
setSettingsProp(self, LSS_KEY_NOTIF_SETTING_ALLOW_NOTIFICATIONS, newQVariant(value)):
self.notifSettingAllowNotificationsChanged()
QtProperty[bool] notifSettingAllowNotifications:
read = getNotifSettingAllowNotifications
write = setNotifSettingAllowNotifications
notify = notifSettingAllowNotificationsChanged
proc notifSettingOneToOneChatsChanged*(self: LocalAccountSensitiveSettings) {.signal.}
proc getNotifSettingOneToOneChats*(self: LocalAccountSensitiveSettings): string {.slot.} =
getSettingsProp[string](self, LSS_KEY_NOTIF_SETTING_ONE_TO_ONE_CHATS, newQVariant(DEFAULT_NOTIF_SETTING_ONE_TO_ONE_CHATS))
proc setNotifSettingOneToOneChats*(self: LocalAccountSensitiveSettings, value: string) {.slot.} =
setSettingsProp(self, LSS_KEY_NOTIF_SETTING_ONE_TO_ONE_CHATS, newQVariant(value)):
self.notifSettingOneToOneChatsChanged()
QtProperty[string] notifSettingOneToOneChats:
read = getNotifSettingOneToOneChats
write = setNotifSettingOneToOneChats
notify = notifSettingOneToOneChatsChanged
proc notifSettingGroupChatsChanged*(self: LocalAccountSensitiveSettings) {.signal.}
proc getNotifSettingGroupChats*(self: LocalAccountSensitiveSettings): string {.slot.} =
getSettingsProp[string](self, LSS_KEY_NOTIF_SETTING_GROUP_CHATS, newQVariant(DEFAULT_NOTIF_SETTING_GROUP_CHATS))
proc setNotifSettingGroupChats*(self: LocalAccountSensitiveSettings, value: string) {.slot.} =
setSettingsProp(self, LSS_KEY_NOTIF_SETTING_GROUP_CHATS, newQVariant(value)):
self.notifSettingGroupChatsChanged()
QtProperty[string] notifSettingGroupChats:
read = getNotifSettingGroupChats
write = setNotifSettingGroupChats
notify = notifSettingGroupChatsChanged
proc notifSettingPersonalMentionsChanged*(self: LocalAccountSensitiveSettings) {.signal.}
proc getNotifSettingPersonalMentions*(self: LocalAccountSensitiveSettings): string {.slot.} =
getSettingsProp[string](self, LSS_KEY_NOTIF_SETTING_PERSONAL_MENTIONS, newQVariant(DEFAULT_NOTIF_SETTING_PERSONAL_MENTIONS))
proc setNotifSettingPersonalMentions*(self: LocalAccountSensitiveSettings, value: string) {.slot.} =
setSettingsProp(self, LSS_KEY_NOTIF_SETTING_PERSONAL_MENTIONS, newQVariant(value)):
self.notifSettingPersonalMentionsChanged()
QtProperty[string] notifSettingPersonalMentions:
read = getNotifSettingPersonalMentions
write = setNotifSettingPersonalMentions
notify = notifSettingPersonalMentionsChanged
proc notifSettingGlobalMentionsChanged*(self: LocalAccountSensitiveSettings) {.signal.}
proc getNotifSettingGlobalMentions*(self: LocalAccountSensitiveSettings): string {.slot.} =
getSettingsProp[string](self, LSS_KEY_NOTIF_SETTING_GLOBAL_MENTIONS, newQVariant(DEFAULT_NOTIF_SETTING_GLOBAL_MENTIONS))
proc setNotifSettingGlobalMentions*(self: LocalAccountSensitiveSettings, value: string) {.slot.} =
setSettingsProp(self, LSS_KEY_NOTIF_SETTING_GLOBAL_MENTIONS, newQVariant(value)):
self.notifSettingGlobalMentionsChanged()
QtProperty[string] notifSettingGlobalMentions:
read = getNotifSettingGlobalMentions
write = setNotifSettingGlobalMentions
notify = notifSettingGlobalMentionsChanged
proc notifSettingAllMessagesChanged*(self: LocalAccountSensitiveSettings) {.signal.}
proc getNotifSettingAllMessages*(self: LocalAccountSensitiveSettings): string {.slot.} =
getSettingsProp[string](self, LSS_KEY_NOTIF_SETTING_ALL_MESSAGES, newQVariant(DEFAULT_NOTIF_SETTING_ALL_MESSAGES))
proc setNotifSettingAllMessages*(self: LocalAccountSensitiveSettings, value: string) {.slot.} =
setSettingsProp(self, LSS_KEY_NOTIF_SETTING_ALL_MESSAGES, newQVariant(value)):
self.notifSettingAllMessagesChanged()
QtProperty[string] notifSettingAllMessages:
read = getNotifSettingAllMessages
write = setNotifSettingAllMessages
notify = notifSettingAllMessagesChanged
proc notifSettingContactRequestsChanged*(self: LocalAccountSensitiveSettings) {.signal.}
proc getNotifSettingContactRequests*(self: LocalAccountSensitiveSettings): string {.slot.} =
getSettingsProp[string](self, LSS_KEY_NOTIF_SETTING_CONTACT_REQUESTS, newQVariant(DEFAULT_NOTIF_SETTING_CONTACT_REQUESTS))
proc setNotifSettingContactRequests*(self: LocalAccountSensitiveSettings, value: string) {.slot.} =
setSettingsProp(self, LSS_KEY_NOTIF_SETTING_CONTACT_REQUESTS, newQVariant(value)):
self.notifSettingContactRequestsChanged()
QtProperty[string] notifSettingContactRequests:
read = getNotifSettingContactRequests
write = setNotifSettingContactRequests
notify = notifSettingContactRequestsChanged
proc notifSettingIdentityVerificationRequestsChanged*(self: LocalAccountSensitiveSettings) {.signal.}
proc getNotifSettingIdentityVerificationRequests*(self: LocalAccountSensitiveSettings): string {.slot.} =
getSettingsProp[string](self, LSS_KEY_NOTIF_SETTING_IDENTITY_VERIF_REQUESTS, newQVariant(DEFAULT_NOTIF_SETTING_IDENTITY_VERIF_REQUESTS))
proc setNotifSettingIdentityVerificationRequests*(self: LocalAccountSensitiveSettings, value: string) {.slot.} =
setSettingsProp(self, LSS_KEY_NOTIF_SETTING_IDENTITY_VERIF_REQUESTS, newQVariant(value)):
self.notifSettingIdentityVerificationRequestsChanged()
QtProperty[string] notifSettingIdentityVerificationRequests:
read = getNotifSettingIdentityVerificationRequests
write = setNotifSettingIdentityVerificationRequests
notify = notifSettingIdentityVerificationRequestsChanged
proc notifSettingExemptionsChanged*(self: LocalAccountSensitiveSettings) {.signal.}
proc getNotifSettingExemptions*(self: LocalAccountSensitiveSettings): string {.slot.} =
getSettingsProp[string](self, LSS_KEY_NOTIF_SETTING_EXEMPTIONS, newQVariant(DEFAULT_NOTIF_SETTING_EXEMPTIONS))
proc setNotifSettingExemptions*(self: LocalAccountSensitiveSettings, value: string) {.slot.} =
setSettingsProp(self, LSS_KEY_NOTIF_SETTING_EXEMPTIONS, newQVariant(value)):
self.notifSettingExemptionsChanged()
QtProperty[string] notifSettingExemptions:
read = getNotifSettingExemptions
write = setNotifSettingExemptions
notify = notifSettingExemptionsChanged
proc getNotifSettingExemptionsAsJson*(self: LocalAccountSensitiveSettings): JsonNode =
var allExemptions = newJObject()
let exemptions = self.getNotifSettingExemptions()
if(exemptions.len == 0):
return allExemptions
try:
let exemptionsObj = exemptions.parseJson
allExemptions = exemptionsObj
except Exception as e:
error "stored exemptions are corrupted, will be overwritten", msg=e.msg
return allExemptions
proc removeKey*(self: LocalAccountSensitiveSettings, key: string) =
if(self.settings.isNil):
return
@ -873,11 +972,8 @@ QtObject:
of LSS_KEY_HIDDEN_COMMUNITY_CHANNELS_AND_CATEGORIES_BANNERS: self.hiddenCommunityChannelAndCategoriesBannersChanged()
of LSS_KEY_HIDDEN_COMMUNITY_BACKUP_BANNERS: self.hiddenCommunityBackUpBannersChanged()
of LSS_KEY_VOLUME: self.volumeChanged()
of LSS_KEY_NOTIFICATION_SETTING: self.notificationSettingChanged()
of LSS_KEY_NOTIFICATION_SOUNDS_ENABLED: self.notificationSoundsEnabledChanged()
of LSS_KEY_USE_OS_NOTIFICATIONS: self.useOSNotificationsChanged()
of LSS_KEY_NOTIFICATION_MESSAGE_PREVIEW_SETTING: self.notificationMessagePreviewSettingChanged()
of LSS_KEY_NOTIFY_ON_NEW_REQUESTS: self.notifyOnNewRequestsChanged()
of LSS_KEY_WITHLISTED_UNFURLING_SITES: self.whitelistedUnfurlingSitesChanged()
of LSS_KEY_NEVER_ASK_ABOUT_UNFURLING_AGAIN: self.neverAskAboutUnfurlingAgainChanged()
of LSS_KEY_HIDE_CHANNEL_SUGGESTIONS: self.hideChannelSuggestionsChanged()
@ -907,4 +1003,12 @@ QtObject:
of LSS_KEY_STICKERS_ENS_ROPSTEN: self.stickersEnsRopstenChanged()
of LSS_KEY_IS_DDMMYY_DATE_FORMAT: self.isDDMMYYDateFormatChanged()
of LSS_KEY_IS_24H_TIME_FORMAT: self.is24hTimeFormatChanged()
of LSS_KEY_NOTIF_SETTING_ALLOW_NOTIFICATIONS: self.notifSettingAllowNotificationsChanged()
of LSS_KEY_NOTIF_SETTING_ONE_TO_ONE_CHATS: self.notifSettingOneToOneChatsChanged()
of LSS_KEY_NOTIF_SETTING_GROUP_CHATS: self.notifSettingGroupChatsChanged()
of LSS_KEY_NOTIF_SETTING_PERSONAL_MENTIONS: self.notifSettingPersonalMentionsChanged()
of LSS_KEY_NOTIF_SETTING_GLOBAL_MENTIONS: self.notifSettingGlobalMentionsChanged()
of LSS_KEY_NOTIF_SETTING_ALL_MESSAGES: self.notifSettingAllMessagesChanged()
of LSS_KEY_NOTIF_SETTING_CONTACT_REQUESTS: self.notifSettingContactRequestsChanged()
of LSS_KEY_NOTIF_SETTING_IDENTITY_VERIF_REQUESTS: self.notifSettingIdentityVerificationRequestsChanged()
of LSS_KEY_NOTIF_SETTING_EXEMPTIONS: self.notifSettingExemptionsChanged()

View File

@ -63,11 +63,10 @@ proc getActiveChatId*(self: Controller): string =
proc init*(self: Controller) =
self.events.on(SIGNAL_NEW_MESSAGE_RECEIVED) do(e: Args):
let args = MessagesArgs(e)
if(self.isCommunitySection and args.chatType != ChatType.CommunityChat or
not self.isCommunitySection and args.chatType == ChatType.CommunityChat):
return
self.delegate.onNewMessagesReceived(args.chatId, args.unviewedMessagesCount, args.unviewedMentionsCount,
args.messages)
if (self.sectionId != args.sectionId or args.messages.len == 0):
return
self.delegate.onNewMessagesReceived(args.sectionId, args.chatId, args.chatType, args.unviewedMessagesCount,
args.unviewedMentionsCount, args.messages[0])
self.events.on(message_service.SIGNAL_MENTIONED_IN_EDITED_MESSAGE) do(e: Args):
let args = MessageEditedArgs(e)

View File

@ -81,8 +81,8 @@ method addChatIfDontExist*(self: AccessInterface,
setChatAsActive: bool = true) {.base.} =
raise newException(ValueError, "No implementation available")
method onNewMessagesReceived*(self: AccessInterface, chatId: string, unviewedMessagesCount: int,
unviewedMentionsCount: int, messages: seq[MessageDto]) {.base.} =
method onNewMessagesReceived*(self: AccessInterface, sectionIdMsgBelongsTo: string, chatIdMsgBelongsTo: string,
chatTypeMsgBelongsTo: ChatType, unviewedMessagesCount: int, unviewedMentionsCount: int, message: MessageDto) {.base.} =
raise newException(ValueError, "No implementation available")
method onChatMuted*(self: AccessInterface, chatId: string) {.base.} =

View File

@ -12,6 +12,7 @@ import chat_content/module as chat_content_module
import ../../../global/app_sections_config as conf
import ../../../global/global_singleton
import ../../../core/eventemitter
import ../../../core/notifications/details as notification_details
import ../../../../app_service/service/settings/service as settings_service
import ../../../../app_service/service/contacts/service as contact_service
import ../../../../app_service/service/chat/service as chat_service
@ -636,25 +637,29 @@ method onContactDetailsUpdated*(self: Module, publicKey: string) =
let chatImage = contactDetails.icon
self.view.chatsModel().updateItemDetails(publicKey, chatName, chatImage)
method onNewMessagesReceived*(self: Module, chatId: string, unviewedMessagesCount: int, unviewedMentionsCount: int,
messages: seq[MessageDto]) =
if(self.controller.getMySectionId() != self.delegate.getActiveSectionId() or
self.controller.getActiveChatId() != chatId):
method onNewMessagesReceived*(self: Module, sectionIdMsgBelongsTo: string, chatIdMsgBelongsTo: string,
chatTypeMsgBelongsTo: ChatType, unviewedMessagesCount: int, unviewedMentionsCount: int, message: MessageDto) =
let messageBelongsToActiveSection = sectionIdMsgBelongsTo == self.controller.getMySectionId() and
self.controller.getMySectionId() == self.delegate.getActiveSectionId()
let messageBelongsToActiveChat = self.controller.getActiveChatId() == chatIdMsgBelongsTo
if(not messageBelongsToActiveSection or not messageBelongsToActiveChat):
let hasUnreadMessages = unviewedMessagesCount > 0
self.updateBadgeNotifications(chatId, hasUnreadMessages, unviewedMentionsCount)
self.updateBadgeNotifications(chatIdMsgBelongsTo, hasUnreadMessages, unviewedMentionsCount)
# Prepare bubble notification
# Prepare notification
let myPK = singletonInstance.userProfile.getPubKey()
for m in messages:
let contactDetails = self.controller.getContactDetails(m.`from`)
let renderedMessageText = self.controller.getRenderedText(m.parsedText)
let plainText = singletonInstance.utils.plainText(renderedMessageText)
if(m.isUserWithPkMentioned(myPK)):
singletonInstance.globalEvents.showMentionMessageNotification(contactDetails.displayName, plainText,
self.controller.getMySectionId(), chatId, m.id)
else:
singletonInstance.globalEvents.showNormalMessageNotification(contactDetails.displayName, plainText,
self.controller.getMySectionId(), chatId, m.id)
var notificationType = notification_details.NotificationType.NewMessage
if(message.isPersonalMention(myPK)):
notificationType = notification_details.NotificationType.NewMessageWithPersonalMention
elif(message.isGlobalMention()):
notificationType = notification_details.NotificationType.NewMessageWithGlobalMention
let contactDetails = self.controller.getContactDetails(message.`from`)
let renderedMessageText = self.controller.getRenderedText(message.parsedText)
let plainText = singletonInstance.utils.plainText(renderedMessageText)
singletonInstance.globalEvents.showMessageNotification(contactDetails.displayName, plainText, sectionIdMsgBelongsTo,
self.controller.isCommunity(), messageBelongsToActiveSection, chatIdMsgBelongsTo, messageBelongsToActiveChat,
message.id, notificationType.int,
chatTypeMsgBelongsTo == ChatType.OneToOne, chatTypeMsgBelongsTo == ChatType.PrivateGroupChat)
method onMeMentionedInEditedMessage*(self: Module, chatId: string, editedMessage : MessageDto) =
if((editedMessage.communityId.len == 0 and

View File

@ -56,6 +56,8 @@ import ../../core/eventemitter
export io_interface
const COMMUNITY_PERMISSION_ACCESS_ON_REQUEST = 3
type
Module*[T: io_interface.DelegateInterface] = ref object of io_interface.AccessInterface
delegate: T
@ -588,6 +590,12 @@ method communityJoined*[T](
else:
self.view.model().addItem(communitySectionItem)
if(community.permissions.access == COMMUNITY_PERMISSION_ACCESS_ON_REQUEST and
community.requestedToJoinAt > 0 and
community.joined):
singletonInstance.globalEvents.myRequestToJoinCommunityAcccepted("Community Request Accepted",
fmt "Your request to join community {community.name} is accepted", community.id)
if setActive:
self.setActiveSection(communitySectionItem)

View File

@ -23,6 +23,13 @@ QtObject:
new(result, delete)
result.setup
proc countChanged(self: Model) {.signal.}
proc getCount(self: Model): int {.slot.} =
self.items.len
QtProperty[int] count:
read = getCount
notify = countChanged
method rowCount(self: Model, index: QModelIndex = nil): int =
return self.items.len
@ -64,6 +71,7 @@ QtObject:
self.beginInsertRows(parentModelIndex, first, last)
self.items.add(items)
self.endInsertRows()
self.countChanged()
proc addItem*(self: Model, item: Item) =
let parentModelIndex = newQModelIndex()
@ -72,6 +80,7 @@ QtObject:
self.beginInsertRows(parentModelIndex, self.items.len, self.items.len)
self.items.add(item)
self.endInsertRows()
self.countChanged()
proc findIndexByInstallationId(self: Model, installationId: string): int =
for i in 0..<self.items.len:

View File

@ -84,7 +84,7 @@ proc newModule*(delegate: delegate_interface.AccessInterface,
result.advancedModule = advanced_module.newModule(result, events, settingsService, stickersService, nodeConfigurationService)
result.devicesModule = devices_module.newModule(result, events, settingsService, devicesService)
result.syncModule = sync_module.newModule(result, events, settingsService, mailserversService)
result.notificationsModule = notifications_module.newModule(result, events, chatService)
result.notificationsModule = notifications_module.newModule(result, events, chatService, contactsService)
result.ensUsernamesModule = ens_usernames_module.newModule(
result, events, settingsService, ensService, walletAccountService
)

View File

@ -1,8 +1,11 @@
import Tables, chronicles
import io_interface
import ../../../../global/app_signals
import ../../../../core/eventemitter
import ../../../../../app_service/service/chat/service as chat_service
import ../../../../../app_service/service/contacts/service as contact_service
import ../../../../../app_service/service/community/service as community_service
logScope:
topics = "profile-section-notifications-module-controller"
@ -12,42 +15,84 @@ type
delegate: io_interface.AccessInterface
events: EventEmitter
chatService: chat_service.Service
contactService: contact_service.Service
proc newController*(delegate: io_interface.AccessInterface,
events: EventEmitter,
chatService: chat_service.Service): Controller =
chatService: chat_service.Service,
contactService: contact_service.Service): Controller =
result = Controller()
result.delegate = delegate
result.events = events
result.chatService = chatService
result.contactService = contactService
proc delete*(self: Controller) =
discard
proc init*(self: Controller) =
self.events.on(chat_service.SIGNAL_CHAT_MUTED) do(e:Args):
let args = chat_service.ChatArgs(e)
self.delegate.onChatMuted(args.chatId)
self.events.on(TOGGLE_SECTION) do(e:Args):
let args = ToggleSectionArgs(e)
self.delegate.onToggleSection(args.sectionType)
self.events.on(chat_service.SIGNAL_CHAT_UNMUTED) do(e:Args):
self.events.on(SIGNAL_COMMUNITY_JOINED) do(e:Args):
let args = CommunityArgs(e)
if(args.error.len > 0):
return
self.delegate.addCommunity(args.community)
self.events.on(SIGNAL_COMMUNITY_CREATED) do(e:Args):
let args = CommunityArgs(e)
if(args.error.len > 0):
return
self.delegate.addCommunity(args.community)
self.events.on(SIGNAL_COMMUNITY_IMPORTED) do(e:Args):
let args = CommunityArgs(e)
if(args.error.len > 0):
return
self.delegate.addCommunity(args.community)
self.events.on(SIGNAL_COMMUNITY_LEFT) do(e:Args):
let args = CommunityIdArgs(e)
self.delegate.removeItemWithId(args.communityId)
self.events.on(SIGNAL_COMMUNITY_EDITED) do(e:Args):
let args = CommunityArgs(e)
self.delegate.editCommunity(args.community)
self.events.on(SIGNAL_COMMUNITIES_UPDATE) do(e:Args):
let args = CommunitiesArgs(e)
for community in args.communities:
self.delegate.editCommunity(community)
self.events.on(chat_service.SIGNAL_CHAT_ADDED_OR_UPDATED) do(e: Args):
let args = chat_service.ChatArgs(e)
self.delegate.onChatUnmuted(args.chatId)
self.delegate.addChat(args.chatId)
self.events.on(chat_service.SIGNAL_CHAT_LEFT) do(e: Args):
let args = chat_service.ChatArgs(e)
self.delegate.onChatLeft(args.chatId)
self.delegate.removeItemWithId(args.chatId)
## We need to add leave community handler here, once we have appropriate signal in place
self.events.on(SIGNAL_CHAT_UPDATE) do(e: Args):
var args = ChatUpdateArgsNew(e)
for chat in args.chats:
let belongsToCommunity = chat.communityId.len > 0
self.delegate.addChat(chat)
proc getAllChats*(self: Controller): seq[ChatDto] =
return self.chatService.getAllChats()
self.events.on(SIGNAL_CHAT_RENAMED) do(e: Args):
var args = ChatRenameArgs(e)
self.delegate.setName(args.id, args.newName)
self.events.on(SIGNAL_CHAT_SWITCH_TO_OR_CREATE_1_1_CHAT) do(e:Args):
let args = ChatExtArgs(e)
self.delegate.addChat(args.chatId)
proc getChannelGroups*(self: Controller): seq[ChannelGroupDto] =
return self.chatService.getChannelGroups()
proc getChatDetails*(self: Controller, chatId: string): ChatDto =
return self.chatService.getChatById(chatId)
proc getOneToOneChatNameAndImage*(self: Controller, chatId: string):
tuple[name: string, image: string] =
return self.chatService.getOneToOneChatNameAndImage(chatId)
proc unmuteChat*(self: Controller, chatId: string) =
self.chatService.unmuteChat(chatId)
proc getContactDetails*(self: Controller, id: string): ContactDetails =
return self.contactService.getContactDetails(id)

View File

@ -1,4 +1,7 @@
import NimQml
import ../../../../global/app_signals
from ../../../../../app_service/service/community/dto/community import CommunityDto
from ../../../../../app_service/service/chat/dto/chat import ChatDto
type
AccessInterface* {.pure inheritable.} = ref object of RootObj
@ -9,23 +12,39 @@ method delete*(self: AccessInterface) {.base.} =
method load*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method viewDidLoad*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method isLoaded*(self: AccessInterface): bool {.base.} =
raise newException(ValueError, "No implementation available")
method sendTestNotification*(self: AccessInterface, title: string, message: string) {.base.} =
raise newException(ValueError, "No implementation available")
method getModuleAsVariant*(self: AccessInterface): QVariant {.base.} =
raise newException(ValueError, "No implementation available")
method onChatMuted*(self: AccessInterface, chatId: string) {.base.} =
method saveExemptions*(self: AccessInterface, itemId: string, muteAllMessages: bool, personalMentions: string,
globalMentions: string, allMessages: string) {.base.} =
raise newException(ValueError, "No implementation available")
method onChatUnmuted*(self: AccessInterface, chatId: string) {.base.} =
method onToggleSection*(self: AccessInterface, sectionType: SectionType) {.base.} =
raise newException(ValueError, "No implementation available")
method onChatLeft*(self: AccessInterface, chatId: string) {.base.} =
method addCommunity*(self: AccessInterface, communityDto: CommunityDto) {.base.} =
raise newException(ValueError, "No implementation available")
method viewDidLoad*(self: AccessInterface) {.base.} =
method editCommunity*(self: AccessInterface, communityDto: CommunityDto) {.base.} =
raise newException(ValueError, "No implementation available")
method unmuteChat*(self: AccessInterface, chatId: string) {.base.} =
method removeItemWithId*(self: AccessInterface, itemId: string) {.base.} =
raise newException(ValueError, "No implementation available")
method addChat*(self: AccessInterface, chatDto: ChatDto) {.base.} =
raise newException(ValueError, "No implementation available")
method addChat*(self: AccessInterface, itemId: string) {.base.} =
raise newException(ValueError, "No implementation available")
method setName*(self: AccessInterface, itemId: string, name: string) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -1,25 +1,86 @@
import ../../../../global/local_account_sensitive_settings
type
Item* = object
Type* {.pure.} = enum
Community
OneToOneChat
GroupChat
type
Item* = ref object
id: string
name: string
icon: string
image: string
color: string
joinedTimestamp: int64
itemType: Type
muteAllMessages: bool
personalMentions: string
globalMentions: string
otherMessages: string
proc initItem*(id, name, icon: string, color: string): Item =
proc initItem*(id, name, image, color: string, joinedTimestamp: int64, itemType: Type, muteAllMessages = false,
personalMentions = LSS_VALUE_NOTIF_SEND_ALERTS, globalMentions = LSS_VALUE_NOTIF_SEND_ALERTS,
otherMessages = LSS_VALUE_NOTIF_SEND_TURN_OFF): Item =
result = Item()
result.id = id
result.name = name
result.icon = icon
result.image = image
result.color = color
result.joinedTimestamp = joinedTimestamp
result.itemType = itemType
result.muteAllMessages = muteAllMessages
result.personalMentions = personalMentions
result.globalMentions = globalMentions
result.otherMessages = otherMessages
proc id*(self: Item): string =
self.id
return self.id
proc name*(self: Item): string =
self.name
return self.name
proc icon*(self: Item): string =
self.icon
proc `name=`*(self: Item, value: string) =
self.name = value
proc image*(self: Item): string =
return self.image
proc color*(self: Item): string =
self.color
proc joinedTimestamp*(self: Item): int64 =
return self.joinedTimestamp
proc itemType*(self: Item): Type =
return self.itemType
proc customized*(self: Item): bool =
return self.muteAllMessages or
self.personalMentions != LSS_VALUE_NOTIF_SEND_ALERTS or
self.globalMentions != LSS_VALUE_NOTIF_SEND_ALERTS or
self.otherMessages != LSS_VALUE_NOTIF_SEND_TURN_OFF
proc muteAllMessages*(self: Item): bool =
return self.muteAllMessages
proc `muteAllMessages=`*(self: Item, value: bool) =
self.muteAllMessages = value
proc personalMentions*(self: Item): string =
return self.personalMentions
proc `personalMentions=`*(self: Item, value: string) =
self.personalMentions = value
proc globalMentions*(self: Item): string =
return self.globalMentions
proc `globalMentions=`*(self: Item, value: string) =
self.globalMentions = value
proc otherMessages*(self: Item): string =
return self.otherMessages
proc `otherMessages=`*(self: Item, value: string) =
self.otherMessages = value

View File

@ -1,13 +1,20 @@
import NimQml, Tables
import item
import ../../../../global/local_account_sensitive_settings
type
ModelRole {.pure.} = enum
Id = UserRole + 1
Name
Icon
Image
Color
Type
Customized
MuteAllMessages
PersonalMentions
GlobalMentions
OtherMessages
QtObject:
type
@ -26,10 +33,8 @@ QtObject:
result.setup
proc countChanged(self: Model) {.signal.}
proc getCount(self: Model): int {.slot.} =
self.items.len
QtProperty[int] count:
read = getCount
notify = countChanged
@ -41,8 +46,14 @@ QtObject:
{
ModelRole.Id.int:"itemId",
ModelRole.Name.int:"name",
ModelRole.Icon.int:"icon",
ModelRole.Color.int:"color"
ModelRole.Image.int:"image",
ModelRole.Color.int:"color",
ModelRole.Type.int:"type",
ModelRole.Customized.int:"customized",
ModelRole.MuteAllMessages.int:"muteAllMessages",
ModelRole.PersonalMentions.int:"personalMentions",
ModelRole.GlobalMentions.int:"globalMentions",
ModelRole.OtherMessages.int:"otherMessages"
}.toTable
method data(self: Model, index: QModelIndex, role: int): QVariant =
@ -60,39 +71,107 @@ QtObject:
result = newQVariant(item.id)
of ModelRole.Name:
result = newQVariant(item.name)
of ModelRole.Icon:
result = newQVariant(item.icon)
of ModelRole.Image:
result = newQVariant(item.image)
of ModelRole.Color:
result = newQVariant(item.color)
of ModelRole.Type:
result = newQVariant(item.itemType.int)
of ModelRole.Customized:
result = newQVariant(item.customized)
of ModelRole.MuteAllMessages:
result = newQVariant(item.muteAllMessages)
of ModelRole.PersonalMentions:
result = newQVariant(item.personalMentions)
of ModelRole.GlobalMentions:
result = newQVariant(item.globalMentions)
of ModelRole.OtherMessages:
result = newQVariant(item.otherMessages)
proc addItem*(self: Model, item: Item) =
# add most recent item on top
var position = -1
for i in 0 ..< self.items.len:
if(item.joinedTimestamp >= self.items[i].joinedTimestamp):
position = i
break
if(position == -1):
position = self.items.len
let parentModelIndex = newQModelIndex()
defer: parentModelIndex.delete
self.beginInsertRows(parentModelIndex, self.items.len, self.items.len)
self.items.add(item)
self.beginInsertRows(parentModelIndex, position, position)
self.items.insert(item, position)
self.endInsertRows()
self.countChanged()
proc getItemIdxById*(self: Model, id: string): int =
var idx = 0
for it in self.items:
if(it.id == id):
return idx
idx.inc
return -1
proc removeItemById*(self: Model, id: string) =
let idx = self.getItemIdxById(id)
if idx == -1:
proc setItems*(self: Model, items: seq[Item]) =
if(items.len == 0):
return
let parentModelIndex = newQModelIndex()
defer: parentModelIndex.delete
self.beginRemoveRows(parentModelIndex, idx, idx)
self.items.delete(idx)
self.beginInsertRows(parentModelIndex, 0, items.len - 1)
self.items = items
self.endInsertRows()
self.countChanged()
proc findIndexForItemId*(self: Model, id: string): int =
var ind = 0
for it in self.items:
if(it.id == id):
return ind
ind.inc
return -1
proc removeItemById*(self: Model, id: string) =
let ind = self.findIndexForItemId(id)
if(ind == -1):
return
let parentModelIndex = newQModelIndex()
defer: parentModelIndex.delete
self.beginRemoveRows(parentModelIndex, ind, ind)
self.items.delete(ind)
self.endRemoveRows()
self.countChanged()
proc removeItemsByType*(self: Model, itemType: Type) =
let items = self.items
for i in items:
if(i.itemType == itemType):
self.removeItemById(i.id)
iterator modelIterator*(self: Model): Item =
for i in 0 ..< self.items.len:
yield self.items[i]
proc updateExemptions*(self: Model, id: string, muteAllMessages = false, personalMentions = LSS_VALUE_NOTIF_SEND_ALERTS,
globalMentions = LSS_VALUE_NOTIF_SEND_ALERTS, otherMessages = LSS_VALUE_NOTIF_SEND_TURN_OFF) =
let ind = self.findIndexForItemId(id)
if(ind == -1):
return
self.items[ind].muteAllMessages = muteAllMessages
self.items[ind].personalMentions = personalMentions
self.items[ind].globalMentions = globalMentions
self.items[ind].otherMessages = otherMessages
let index = self.createIndex(ind, 0, nil)
self.dataChanged(index, index, @[ModelRole.MuteAllMessages.int, ModelRole.PersonalMentions.int,
ModelRole.GlobalMentions.int, ModelRole.OtherMessages.int, ModelRole.Customized.int])
proc updateName*(self: Model, id: string, name: string) =
let ind = self.findIndexForItemId(id)
if(ind == -1):
return
self.items[ind].name = name
let index = self.createIndex(ind, 0, nil)
self.dataChanged(index, index, @[ModelRole.Name.int])

View File

@ -1,10 +1,14 @@
import NimQml, chronicles
import NimQml, algorithm, json, chronicles
import io_interface
import ../io_interface as delegate_interface
import view, controller, model, item
import ../../../../global/app_signals
import ../../../../global/global_singleton
import ../../../../core/eventemitter
import ../../../../../app_service/service/chat/service as chat_service
import ../../../../../app_service/service/contacts/service as contact_service
from ../../../../../app_service/service/community/dto/community import CommunityDto
export io_interface
@ -21,12 +25,13 @@ type
proc newModule*(delegate: delegate_interface.AccessInterface,
events: EventEmitter,
chatService: chat_service.Service): Module =
chatService: chat_service.Service,
contactService: contact_service.Service): Module =
result = Module()
result.delegate = delegate
result.view = view.newView(result)
result.viewVariant = newQVariant(result.view)
result.controller = controller.newController(result, events, chatService)
result.controller = controller.newController(result, events, chatService, contactService)
result.moduleLoaded = false
method delete*(self: Module) =
@ -34,6 +39,11 @@ method delete*(self: Module) =
self.viewVariant.delete
self.controller.delete
proc comp[T](x,y: T):int =
if x.joinedTimestamp > y.joinedTimestamp: return 1
elif x.joinedTimestamp < y.joinedTimestamp: return -1
else: return 0
method load*(self: Module) =
self.controller.init()
self.view.load()
@ -41,19 +51,52 @@ method load*(self: Module) =
method isLoaded*(self: Module): bool =
return self.moduleLoaded
proc initModel(self: Module) =
let chats = self.controller.getAllChats()
for c in chats:
if(not c.muted):
continue
proc createItem(self: Module, id, name, image, color: string, joinedTimestamp: int64, itemType: Type): Item =
let allExemptions = singletonInstance.localAccountSensitiveSettings.getNotifSettingExemptionsAsJson()
var item = initItem(id, name, image, color, joinedTimestamp, itemType)
if(allExemptions.contains(id)):
let obj = allExemptions[id]
if(obj.contains(EXEMPTION_KEY_MUTE_ALL_MESSAGES)):
item.muteAllMessages = obj[EXEMPTION_KEY_MUTE_ALL_MESSAGES].getBool
if(obj.contains(EXEMPTION_KEY_PERSONAL_MENTIONS)):
item.personalMentions = obj[EXEMPTION_KEY_PERSONAL_MENTIONS].getStr
if(obj.contains(EXEMPTION_KEY_GLOBAL_MENTIONS)):
item.globalMentions = obj[EXEMPTION_KEY_GLOBAL_MENTIONS].getStr
if(obj.contains(EXEMPTION_KEY_OTHER_MESSAGES)):
item.otherMessages = obj[EXEMPTION_KEY_OTHER_MESSAGES].getStr
return item
if(c.chatType == ChatType.OneToOne):
let (chatName, chatImage) = self.controller.getOneToOneChatNameAndImage(c.id)
let item = initItem(c.id, chatName, chatImage, c.color)
self.view.mutedContactsModel().addItem(item)
else:
let item = initItem(c.id, c.name, c.icon, c.color)
self.view.mutedChatsModel().addItem(item)
proc createChatItem(self: Module, chatDto: ChatDto): Item =
var chatName = chatDto.name
var chatImage = chatDto.icon
var itemType = item.Type.GroupChat
if(chatDto.chatType == ChatType.OneToOne):
let contactDetails = self.controller.getContactDetails(chatDto.id)
chatName = contactDetails.displayName
chatImage = contactDetails.icon
itemType = item.Type.OneToOneChat
return self.createItem(chatDto.id, chatName, chatImage, chatDto.color, chatDto.joined, itemType)
proc initModel(self: Module) =
let channelGroups = self.controller.getChannelGroups()
var items: seq[Item]
for cg in channelGroups:
if cg.channelGroupType == ChannelGroupType.Community:
if(not singletonInstance.localAccountSensitiveSettings.getCommunitiesEnabled()):
continue
let item = self.createItem(cg.id, cg.name, cg.images.thumbnail, cg.color, joinedTimestamp = 0, item.Type.Community)
items.add(item)
elif cg.channelGroupType == ChannelGroupType.Personal:
for c in cg.chats:
if c.chatType != ChatType.OneToOne and c.chatType != ChatType.PrivateGroupChat:
continue
let item = self.createChatItem(c)
items.add(item)
# Sort to get most recent first
items.sort(comp, SortOrder.Descending)
self.view.exemptionsModel().setItems(items)
method viewDidLoad*(self: Module) =
self.initModel()
@ -63,23 +106,72 @@ method viewDidLoad*(self: Module) =
method getModuleAsVariant*(self: Module): QVariant =
return self.viewVariant
method unmuteChat*(self: Module, chatId: string) =
self.controller.unmuteChat(chatId)
method sendTestNotification*(self: Module, title: string, message: string) =
singletonInstance.globalEvents.showTestNotification(title, message)
method onChatMuted*(self: Module, chatId: string) =
let chat = self.controller.getChatDetails(chatId)
if(chat.chatType == ChatType.OneToOne):
let (chatName, chatImage) = self.controller.getOneToOneChatNameAndImage(chat.id)
let item = initItem(chat.id, chatName, chatImage, chat.color)
self.view.mutedContactsModel().addItem(item)
method saveExemptions*(self: Module, itemId: string, muteAllMessages: bool, personalMentions: string,
globalMentions: string, otherMessages: string) =
var allExemptions = singletonInstance.localAccountSensitiveSettings.getNotifSettingExemptionsAsJson()
allExemptions[itemId] = %* {
EXEMPTION_KEY_MUTE_ALL_MESSAGES: muteAllMessages,
EXEMPTION_KEY_PERSONAL_MENTIONS: personalMentions,
EXEMPTION_KEY_GLOBAL_MENTIONS: globalMentions,
EXEMPTION_KEY_OTHER_MESSAGES: otherMessages
}
self.view.exemptionsModel().updateExemptions(itemId, muteAllMessages, personalMentions, globalMentions, otherMessages)
singletonInstance.localAccountSensitiveSettings.setNotifSettingExemptions($allExemptions)
method onToggleSection*(self: Module, sectionType: SectionType) =
if(sectionType != SectionType.Community):
return
if(singletonInstance.localAccountSensitiveSettings.getCommunitiesEnabled()):
let channelGroups = self.controller.getChannelGroups()
for cg in channelGroups:
if cg.channelGroupType == ChannelGroupType.Community:
let item = self.createItem(cg.id, cg.name, cg.images.thumbnail, cg.color, joinedTimestamp = 0, item.Type.Community)
self.view.exemptionsModel().addItem(item)
else:
let item = initItem(chat.id, chat.name, chat.icon, chat.color)
self.view.mutedChatsModel().addItem(item)
let allExemptions = singletonInstance.localAccountSensitiveSettings.getNotifSettingExemptionsAsJson()
for item in self.view.exemptionsModel().modelIterator():
if(allExemptions.contains(item.id)):
allExemptions.delete(item.id)
singletonInstance.localAccountSensitiveSettings.setNotifSettingExemptions($allExemptions)
self.view.exemptionsModel().removeItemsByType(item.Type.Community)
method addCommunity*(self: Module, communityDto: CommunityDto) =
let item = self.createItem(communityDto.id, communityDto.name, communityDto.images.thumbnail, communityDto.color,
joinedTimestamp = 0, item.Type.Community)
self.view.exemptionsModel().addItem(item)
method onChatUnmuted*(self: Module, chatId: string) =
self.view.mutedContactsModel().removeItemById(chatId)
self.view.mutedChatsModel().removeItemById(chatId)
method editCommunity*(self: Module, communityDto: CommunityDto) =
self.view.exemptionsModel().removeItemById(communityDto.id)
let item = self.createItem(communityDto.id, communityDto.name, communityDto.images.thumbnail, communityDto.color,
joinedTimestamp = 0, item.Type.Community)
self.view.exemptionsModel().addItem(item)
method onChatLeft*(self: Module, chatId: string) =
self.view.mutedContactsModel().removeItemById(chatId)
self.view.mutedChatsModel().removeItemById(chatId)
method removeItemWithId*(self: Module, itemId: string) =
var allExemptions = singletonInstance.localAccountSensitiveSettings.getNotifSettingExemptionsAsJson()
if(allExemptions.contains(itemId)):
allExemptions.delete(itemId)
singletonInstance.localAccountSensitiveSettings.setNotifSettingExemptions($allExemptions)
self.view.exemptionsModel().removeItemById(itemId)
method addChat*(self: Module, chatDto: ChatDto) =
let ind = self.view.exemptionsModel().findIndexForItemId(chatDto.id)
if(ind != -1):
return
let item = self.createChatItem(chatDto)
self.view.exemptionsModel().addItem(item)
method addChat*(self: Module, itemId: string) =
let ind = self.view.exemptionsModel().findIndexForItemId(itemId)
if(ind != -1):
return
let chatDto = self.controller.getChatDetails(itemId)
self.addChat(chatDto)
method setName*(self: Module, itemId: string, name: string) =
self.view.exemptionsModel().updateName(itemId, name)

View File

@ -5,49 +5,37 @@ QtObject:
type
View* = ref object of QObject
delegate: io_interface.AccessInterface
mutedContactsModel: Model
mutedContactsModelVariant: QVariant
mutedChatsModel: Model
mutedChatsModelVariant: QVariant
exemptionsModel: Model
exemptionsModelVariant: QVariant
proc delete*(self: View) =
self.mutedContactsModel.delete
self.mutedContactsModelVariant.delete
self.mutedChatsModel.delete
self.mutedChatsModelVariant.delete
self.exemptionsModel.delete
self.exemptionsModelVariant.delete
self.QObject.delete
proc newView*(delegate: io_interface.AccessInterface): View =
new(result, delete)
result.QObject.setup
result.delegate = delegate
result.mutedContactsModel = newModel()
result.mutedContactsModelVariant = newQVariant(result.mutedContactsModel)
result.mutedChatsModel = newModel()
result.mutedChatsModelVariant = newQVariant(result.mutedChatsModel)
result.exemptionsModel = newModel()
result.exemptionsModelVariant = newQVariant(result.exemptionsModel)
proc load*(self: View) =
self.delegate.viewDidLoad()
proc mutedContactsModel*(self: View): Model =
return self.mutedContactsModel
proc sendTestNotification*(self: View, title: string, message: string) {.slot.} =
self.delegate.sendTestNotification(title, message)
proc mutedContactsModelChanged*(self: View) {.signal.}
proc getMutedContactsModel(self: View): QVariant {.slot.} =
return self.mutedContactsModelVariant
QtProperty[QVariant] mutedContactsModel:
read = getMutedContactsModel
notify = mutedContactsModelChanged
proc exemptionsModel*(self: View): Model =
return self.exemptionsModel
proc mutedChatsModel*(self: View): Model =
return self.mutedChatsModel
proc exemptionsModelChanged*(self: View) {.signal.}
proc getExemptionsModel(self: View): QVariant {.slot.} =
return self.exemptionsModelVariant
QtProperty[QVariant] exemptionsModel:
read = getExemptionsModel
notify = exemptionsModelChanged
proc mutedChatsModelChanged*(self: View) {.signal.}
proc getMutedChatsModel(self: View): QVariant {.slot.} =
return self.mutedChatsModelVariant
QtProperty[QVariant] mutedChatsModel:
read = getMutedChatsModel
notify = mutedChatsModelChanged
proc unmuteChat*(self: View, chatId: string) {.slot.} =
self.delegate.unmuteChat(chatId)
proc saveExemptions*(self: View, itemId: string, muteAllMessages: bool, personalMentions: string,
globalMentions: string, otherMessages: string) {.slot.} =
self.delegate.saveExemptions(itemId, muteAllMessages, personalMentions, globalMentions, otherMessages)

View File

@ -1,4 +1,4 @@
import json, sequtils, strutils, uuids, os
import json, sequtils, strutils, uuids
import json_serialization, chronicles
import ./dto/accounts as dto_accounts

View File

@ -85,6 +85,7 @@ const SIGNAL_CHAT_MEMBERS_ADDED* = "chatMemberAdded"
const SIGNAL_CHAT_MEMBER_REMOVED* = "chatMemberRemoved"
const SIGNAL_CHAT_MEMBER_UPDATED* = "chatMemberUpdated"
const SIGNAL_CHAT_SWITCH_TO_OR_CREATE_1_1_CHAT* = "switchToOrCreateOneToOneChat"
const SIGNAL_CHAT_ADDED_OR_UPDATED* = "chatAddedOrUpdated"
QtObject:
type Service* = ref object of QObject
@ -166,6 +167,7 @@ QtObject:
proc updateOrAddChat*(self: Service, chat: ChatDto) =
self.chats[chat.id] = chat
self.events.emit(SIGNAL_CHAT_ADDED_OR_UPDATED, ChatArgs(communityId: chat.communityId, chatId: chat.id))
var channelGroupId = chat.communityId
if (channelGroupId == ""):

View File

@ -174,13 +174,17 @@ proc containsContactMentions*(self: MessageDto): bool =
return true
return false
proc isUserWithPkMentioned*(self: MessageDto, publicKey: string): bool =
proc isPersonalMention*(self: MessageDto, publicKey: string): bool =
for pText in self.parsedText:
for child in pText.children:
if (child.type == PARSED_TEXT_CHILD_TYPE_MENTION and child.literal.contains(publicKey)):
return true
return false
proc isGlobalMention*(self: MessageDto): bool =
# TODO: we should check here if message contains global mention.
return false
proc mentionedUsersPks*(self: MessageDto): seq[string] =
for pText in self.parsedText:
for child in pText.children:

View File

@ -56,6 +56,7 @@ include async_tasks
type
MessagesArgs* = ref object of Args
sectionId*: string
chatId*: string
chatType*: ChatType
unviewedMessagesCount*: int
@ -157,6 +158,7 @@ QtObject:
# if (not chats[0].active):
# return
let sectionId = if chats[0].communityId.len > 0: chats[0].communityId else: singletonInstance.userProfile.getPubKey()
let chatId = chats[0].id
let chatType = chats[0].chatType
let unviewedMessagesCount = chats[0].unviewedMessagesCount
@ -187,6 +189,7 @@ QtObject:
removeMessageWithId(messages, msgId)
let data = MessagesArgs(
sectionId: sectionId,
chatId: chatId,
chatType: chatType,
unviewedMessagesCount: unviewedMessagesCount,

View File

@ -106,7 +106,6 @@ StatusAppTwoPanelLayout {
EnsView {
// TODO: we need to align structure for the entire this part using `SettingsContentBase` as root component
// TODO: handle structure for this subsection to match style used in onther sections
// using `SettingsContentBase` component as base.
id: ensContainer
@ -158,14 +157,6 @@ StatusAppTwoPanelLayout {
systemPalette: profileView.systemPalette
}
SoundsView {
Layout.fillWidth: true
Layout.fillHeight: true
sectionTitle: profileView.store.getNameForSubsection(Constants.settingsSubsection.sound)
contentWidth: d.contentWidth
}
LanguageView {
Layout.fillWidth: true
Layout.fillHeight: true
@ -181,6 +172,7 @@ StatusAppTwoPanelLayout {
Layout.fillHeight: true
notificationsStore: profileView.store.notificationsStore
devicesStore: profileView.store.devicesStore
sectionTitle: profileView.store.getNameForSubsection(Constants.settingsSubsection.notifications)
contentWidth: d.contentWidth
}

View File

@ -0,0 +1,71 @@
import QtQuick 2.13
import QtQuick.Controls 2.13
import StatusQ.Controls 0.1
import StatusQ.Popups 0.1
import utils 1.0
Item {
id: root
signal sendAlertsClicked()
signal deliverQuietlyClicked()
signal turnOffClicked()
property string selected: Constants.settingsSection.notifications.sendAlertsValue
implicitWidth: button.width
implicitHeight: button.height
QtObject {
id: d
readonly property string sendAlertsText: qsTr("Send Alerts")
readonly property string deliverQuietlyText: qsTr("Deliver Quietly")
readonly property string turnOffText: qsTr("Turn Off")
}
StatusButton {
id: button
text: root.selected === Constants.settingsSection.notifications.turnOffValue? d.turnOffText :
root.selected === Constants.settingsSection.notifications.deliverQuietlyValue? d.deliverQuietlyText :
d.sendAlertsText
icon.name: "chevron-down"
onClicked: {
if (selectMenu.opened) {
selectMenu.close()
} else {
selectMenu.popup(button.x, button.y + button.height + 8)
}
}
}
StatusPopupMenu {
id: selectMenu
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent
width: parent.width
clip: true
StatusMenuItem {
text: d.sendAlertsText
onTriggered: {
root.sendAlertsClicked()
}
}
StatusMenuItem {
text: d.deliverQuietlyText
onTriggered: {
root.deliverQuietlyClicked()
}
}
StatusMenuItem {
text: d.turnOffText
onTriggered: {
root.turnOffClicked()
}
}
}
}

View File

@ -0,0 +1,159 @@
import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.14
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
import StatusQ.Components 0.1
import StatusQ.Popups 0.1
import utils 1.0
import shared.panels 1.0
import "../controls"
StatusModal {
id: root
property var notificationsStore
property var item: ({
name: "",
image: "",
color: "",
customized: false,
type: Constants.settingsSection.exemptions.community,
muteAllMessages: false,
personalMentions: Constants.settingsSection.notifications.sendAlertsValue,
globalMentions: Constants.settingsSection.notifications.sendAlertsValue,
otherMessages: Constants.settingsSection.notifications.turnOffValue
})
header.title: qsTr("%1 exemption").arg(root.item.name)
header.image.source: root.item.image
header.icon: StatusIconSettings {
// Once we introduce StatusSmartIdenticon in popup header, we should use the folowing
// color: root.item.type === Constants.settingsSection.exemptions.oneToOneChat?
// Theme.palette.userCustomizationColors[Utils.colorIdForPubkey(root.item.itemId)] :
// root.item.color
// until then the following is used
background.color: root.item.type === Constants.settingsSection.exemptions.oneToOneChat?
Theme.palette.userCustomizationColors[Utils.colorIdForPubkey(root.item.itemId)] :
root.item.color
charactersLen: root.item.type === Constants.settingsSection.exemptions.oneToOneChat? 2 : 1
isLetterIdenticon: root.item.image === ""
height: isLetterIdenticon ? 40 : 20
width: isLetterIdenticon ? 40 : 20
}
QtObject {
id: d
readonly property bool isOneToOneChat: root.item.type === Constants.settingsSection.exemptions.oneToOneChat
readonly property int contentSpacing: 0
property bool muteAllMessages: root.item.muteAllMessages
property string personalMentions: root.item.personalMentions
property string globalMentions: root.item.globalMentions
property string otherMessages: root.item.otherMessages
property bool customized: d.muteAllMessages ||
d.personalMentions !== Constants.settingsSection.notifications.sendAlertsValue ||
d.globalMentions !== Constants.settingsSection.notifications.sendAlertsValue ||
d.otherMessages !== Constants.settingsSection.notifications.turnOffValue
}
contentItem: Column {
width: root.width
spacing: d.contentSpacing
StatusListItem {
width: parent.width
title: qsTr("Mute all messages")
enabled: false
components: [
StatusSwitch {
id: muteAllMessagesSwitch
checked: d.muteAllMessages
onClicked: {
d.muteAllMessages = !d.muteAllMessages
}
}
]
sensor.onClicked: {
muteAllMessagesSwitch.clicked()
}
}
Separator {
visible: !d.isOneToOneChat
}
StatusListItem {
width: parent.width
title: qsTr("Personal @ Mentions")
enabled: false
visible: !d.isOneToOneChat
components: [
NotificationSelect {
selected: d.personalMentions
onSendAlertsClicked: d.personalMentions = Constants.settingsSection.notifications.sendAlertsValue
onDeliverQuietlyClicked: d.personalMentions = Constants.settingsSection.notifications.deliverQuietlyValue
onTurnOffClicked: d.personalMentions = Constants.settingsSection.notifications.turnOffValue
}
]
}
StatusListItem {
width: parent.width
title: qsTr("Global @ Mentions")
enabled: false
visible: !d.isOneToOneChat
components: [
NotificationSelect {
selected: d.globalMentions
onSendAlertsClicked: d.globalMentions = Constants.settingsSection.notifications.sendAlertsValue
onDeliverQuietlyClicked: d.globalMentions = Constants.settingsSection.notifications.deliverQuietlyValue
onTurnOffClicked: d.globalMentions = Constants.settingsSection.notifications.turnOffValue
}
]
}
StatusListItem {
width: parent.width
title: qsTr("Other Messages")
enabled: false
visible: !d.isOneToOneChat
components: [
NotificationSelect {
selected: d.otherMessages
onSendAlertsClicked: d.otherMessages = Constants.settingsSection.notifications.sendAlertsValue
onDeliverQuietlyClicked: d.otherMessages = Constants.settingsSection.notifications.deliverQuietlyValue
onTurnOffClicked: d.otherMessages = Constants.settingsSection.notifications.turnOffValue
}
]
}
}
rightButtons: [
StatusFlatButton {
text: qsTr("Clear Exemptions")
enabled: d.customized
onClicked: {
d.muteAllMessages = false
d.personalMentions = Constants.settingsSection.notifications.sendAlertsValue
d.globalMentions = Constants.settingsSection.notifications.sendAlertsValue
d.otherMessages = Constants.settingsSection.notifications.turnOffValue
}
},
StatusButton {
id: btnCreateEdit
text: qsTr("Done")
onClicked: {
root.notificationsStore.saveExemptions(root.item.itemId,
d.muteAllMessages,
d.personalMentions,
d.globalMentions,
d.otherMessages)
root.close()
}
}
]
}

View File

@ -6,10 +6,13 @@ QtObject {
property var notificationsModule
property var mutedContactsModel: notificationsModule.mutedContactsModel
property var mutedChatsModel: notificationsModule.mutedChatsModel
property var exemptionsModel: notificationsModule.exemptionsModel
function unmuteChat(chatId) {
return root.notificationsModule.unmuteChat(chatId)
function sendTestNotification(title, message) {
root.notificationsModule.sendTestNotification(title, message)
}
function saveExemptions(itemId, muteAllMessages, personalMentions, globalMentions, allMessages) {
root.notificationsModule.saveExemptions(itemId, muteAllMessages, personalMentions, globalMentions, allMessages)
}
}

View File

@ -96,14 +96,11 @@ QtObject {
append({subsection: Constants.settingsSubsection.appearance,
text: qsTr("Appearance"),
icon: "appearance"})
append({subsection: Constants.settingsSubsection.sound,
text: qsTr("Sound"),
icon: "sound"})
append({subsection: Constants.settingsSubsection.language,
text: qsTr("Language & Currency"),
icon: "language"})
append({subsection: Constants.settingsSubsection.notifications,
text: qsTr("Notifications"),
text: qsTr("Notifications & Sounds"),
icon: "notification"})
append({subsection: Constants.settingsSubsection.devicesSettings,
text: qsTr("Devices settings"),

View File

@ -1,406 +1,551 @@
import QtQuick 2.13
import QtQuick.Controls 2.13
import QtGraphicalEffects 1.13
import QtQuick.Layouts 1.13
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
import StatusQ.Components 0.1
import StatusQ.Popups 0.1
import utils 1.0
import shared.panels 1.0
import shared.status 1.0
import shared.controls 1.0
import "../stores"
import "../popups"
import "../controls"
import "../panels"
import "./"
import "../popups"
SettingsContentBase {
id: root
property NotificationsStore notificationsStore
property DevicesStore devicesStore
Item {
id: notificationsContainer
width: root.contentWidth
height: this.childrenRect.height + 100
ColumnLayout {
id: contentColumn
spacing: Constants.settingsSection.itemSpacing
property Component mutedChatsModalComponent: MutedChatsModal {}
ButtonGroup {
id: messageSetting
}
Loader {
id: exemptionNotificationsModal
active: false
ButtonGroup {
id: notificationSetting
}
function open(item) {
active = true
exemptionNotificationsModal.item.item = item
exemptionNotificationsModal.item.open()
}
function close() {
active = false
}
ButtonGroup {
id: soundSetting
}
sourceComponent: ExemptionNotificationsModal {
anchors.centerIn: parent
notificationsStore: root.notificationsStore
ButtonGroup {
id: messageSetting
}
Column {
id: column
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
RadioButtonSelector {
anchors.leftMargin: 0
anchors.rightMargin: 0
//% "All messages"
title: qsTrId("all-messages")
buttonGroup: notificationSetting
checked: localAccountSensitiveSettings.notificationSetting === Constants.notifyAllMessages
onCheckedChanged: {
if (checked) {
localAccountSensitiveSettings.notificationSetting = Constants.notifyAllMessages
onClosed: {
exemptionNotificationsModal.close();
}
}
}
RadioButtonSelector {
anchors.leftMargin: 0
anchors.rightMargin: 0
//% "Just @mentions"
title: qsTrId("just--mentions")
buttonGroup: notificationSetting
checked: localAccountSensitiveSettings.notificationSetting === Constants.notifyJustMentions
onCheckedChanged: {
if (checked) {
localAccountSensitiveSettings.notificationSetting = Constants.notifyJustMentions
}
}
}
Component {
id: exemptionDelegateComponent
StatusListItem {
property string lowerCaseSearchString: searchBox.text.toLowerCase()
RadioButtonSelector {
anchors.leftMargin: 0
anchors.rightMargin: 0
//% "Nothing"
title: qsTrId("nothing")
buttonGroup: notificationSetting
checked: localAccountSensitiveSettings.notificationSetting === Constants.notifyNone
onCheckedChanged: {
if (checked) {
localAccountSensitiveSettings.notificationSetting = Constants.notifyNone
}
}
}
}
Separator {
id: separator
anchors.top: column.bottom
anchors.topMargin: Style.current.bigPadding
anchors.left: parent.left
anchors.right: parent.right
}
StatusSectionHeadline {
id: sectionHeadlineSound
//% "Appearance"
text: qsTrId("appearance")
anchors.top: separator.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: Style.current.padding
anchors.rightMargin: Style.current.padding
}
Column {
id: column2
anchors.top: sectionHeadlineSound.bottom
anchors.topMargin: Style.current.smallPadding
anchors.left: parent.left
anchors.right: parent.right
width: parent.width
// TODO: replace with StatusListItem
StatusSettingsLineButton {
anchors.leftMargin: 0
anchors.rightMargin: 0
//% "Play a sound when receiving a notification"
text: qsTrId("play-a-sound-when-receiving-a-notification")
isSwitch: true
switchChecked: localAccountSensitiveSettings.notificationSoundsEnabled
onClicked: {
localAccountSensitiveSettings.notificationSoundsEnabled = checked
}
}
// TODO: replace with StatusListItem
StatusSettingsLineButton {
anchors.leftMargin: 0
anchors.rightMargin: 0
//% "Use your operating system's notifications"
text: qsTrId("use-your-operating-system-s-notifications")
isSwitch: true
switchChecked: localAccountSensitiveSettings.useOSNotifications
onClicked: {
localAccountSensitiveSettings.useOSNotifications = checked
}
StatusBaseText {
id: detailText
//% "Setting this to false will instead use Status' notification style as seen below"
text: qsTrId("setting-this-to-false-will-instead-use-status--notification-style-as-seen-below")
color: Theme.palette.baseColor1
width: parent.width
font.pixelSize: 12
wrapMode: Text.WordWrap
anchors.left: parent.left
anchors.leftMargin: Style.current.padding
anchors.bottom: parent.bottom
anchors.topMargin: 2
height: visible ? implicitHeight : 0
visible: lowerCaseSearchString === "" ||
model.itemId.toLowerCase().includes(lowerCaseSearchString) ||
model.name.toLowerCase().includes(lowerCaseSearchString)
title: model.name
subTitle: {
if(model.type === Constants.settingsSection.exemptions.community)
return qsTr("Community")
else if(model.type === Constants.settingsSection.exemptions.oneToOneChat)
return qsTr("1:1 Chat")
else if(model.type === Constants.settingsSection.exemptions.groupChat)
return qsTr("Group Chat")
else
return ""
}
label: {
if(!model.customized)
return ""
let l = ""
if(model.muteAllMessages)
l += qsTr("Muted")
else {
let nbOfChanges = 0
if(model.personalMentions !== Constants.settingsSection.notifications.sendAlertsValue)
{
nbOfChanges++
let valueText = model.personalMentions === Constants.settingsSection.notifications.turnOffValue?
qsTr("Off") :
qsTr("Quiet")
l = qsTr("Personal @ Mentions %1").arg(valueText)
}
if(model.globalMentions !== Constants.settingsSection.notifications.sendAlertsValue)
{
nbOfChanges++
let valueText = model.globalMentions === Constants.settingsSection.notifications.turnOffValue?
qsTr("Off") :
qsTr("Quiet")
l = qsTr("Global @ Mentions %1").arg(valueText)
}
if(model.otherMessages !== Constants.settingsSection.notifications.turnOffValue)
{
nbOfChanges++
let valueText = model.otherMessages === Constants.settingsSection.notifications.sendAlertsValue?
qsTr("Alerts") :
qsTr("Quiet")
l = qsTr("Other Messages %1").arg(valueText)
}
if(nbOfChanges > 1)
l = qsTr("Multiple Exemptions")
}
return l
}
// Maybe we need to redo `StatusListItem` to display identicon ring, but that's not in Figma design for now.
image.source: model.image
ringSettings.ringSpecModel: Utils.getColorHashAsJson(model.itemId)
icon: StatusIconSettings {
color: model.type === Constants.settingsSection.exemptions.oneToOneChat?
Theme.palette.userCustomizationColors[Utils.colorIdForPubkey(model.itemId)] :
model.color
charactersLen: model.type === Constants.settingsSection.exemptions.oneToOneChat? 2 : 1
isLetterIdenticon: model.image === ""
height: isLetterIdenticon ? 40 : 20
width: isLetterIdenticon ? 40 : 20
}
components: [
StatusIcon {
visible: model.customized
icon: "chevron-down"
rotation: 270
color: Theme.palette.baseColor1
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: {
exemptionNotificationsModal.open(model)
}
}
},
StatusIcon {
visible: !model.customized
icon: "add"
rotation: 270
color: Theme.palette.primaryColor1
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: {
exemptionNotificationsModal.open(model)
}
}
}]
}
}
}
Column {
id: column3
spacing: Style.current.bigPadding
anchors.top: column2.bottom
anchors.topMargin: Style.current.padding*2
anchors.left: parent.left
anchors.right: parent.right
Rectangle {
Layout.preferredWidth: root.contentWidth
implicitHeight: col1.height + 2 * Style.current.padding
visible: Qt.platform.os == "osx"
radius: Constants.settingsSection.radius
color: Theme.palette.primaryColor3
StatusBaseText {
//% "Message preview"
text: qsTrId("message-preview")
font.pixelSize: 15
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: Style.current.padding
anchors.rightMargin: Style.current.padding
color: Theme.palette.directColor1
}
ColumnLayout {
id: col1
anchors.margins: Style.current.padding
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
spacing: Constants.settingsSection.infoSpacing
Column {
anchors.left: parent.left
anchors.right: parent.right
spacing: 10
StatusBaseText {
Layout.preferredWidth: parent.width
text: qsTr("Enable Notifications in macOS Settings")
font.pixelSize: Constants.settingsSection.infoFontSize
lineHeight: Constants.settingsSection.infoLineHeight
lineHeightMode: Text.FixedHeight
color: Theme.palette.primaryColor1
NotificationAppearancePreviewPanel {
//% "Anonymous"
name: qsTrId("anonymous")
notificationTitle: "Status"
//% "You have a new message"
notificationMessage: qsTrId("you-have-a-new-message")
buttonGroup: messageSetting
checked: localAccountSensitiveSettings.notificationMessagePreviewSetting === Constants.notificationPreviewAnonymous
onRadioCheckedChanged: {
if (checked) {
localAccountSensitiveSettings.notificationMessagePreviewSetting = Constants.notificationPreviewAnonymous
}
StatusBaseText {
Layout.preferredWidth: parent.width
text: qsTr("To receive Status notifications, make sure you've enabled them in" +
" your computer's settings under <b>System Preferences > Notifications</b>")
font.pixelSize: Constants.settingsSection.infoFontSize
lineHeight: Constants.settingsSection.infoLineHeight
lineHeightMode: Text.FixedHeight
color: Theme.palette.baseColor1
wrapMode: Text.WordWrap
}
}
}
}
NotificationAppearancePreviewPanel {
//% "Name only"
name: qsTrId("name-only")
notificationTitle: "Vitalik Buterin"
//% "You have a new message"
notificationMessage: qsTrId("you-have-a-new-message")
buttonGroup: messageSetting
checked: localAccountSensitiveSettings.notificationMessagePreviewSetting === Constants.notificationPreviewNameOnly
onRadioCheckedChanged: {
if (checked) {
localAccountSensitiveSettings.notificationMessagePreviewSetting = Constants.notificationPreviewNameOnly
Rectangle {
Layout.preferredWidth: root.contentWidth
implicitHeight: row1.height + 2 * Style.current.padding
radius: Constants.settingsSection.radius
color: Theme.palette.pinColor2
RowLayout {
id: row1
anchors.margins: Style.current.padding
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
visible: root.devicesStore.devicesModel.count > 0
StatusBaseText {
Layout.fillWidth: true
text: qsTr("Sync your devices to share notifications preferences")
font.pixelSize: Constants.settingsSection.infoFontSize
lineHeight: Constants.settingsSection.infoLineHeight
lineHeightMode: Text.FixedHeight
color: Theme.palette.pinColor1
}
StatusBaseText {
text: qsTr("Syncing >")
font.pixelSize: Constants.settingsSection.infoFontSize
lineHeight: Constants.settingsSection.infoLineHeight
lineHeightMode: Text.FixedHeight
color: Theme.palette.pinColor1
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: {
root.devicesStore.syncAll()
}
}
}
}
}
}
NotificationAppearancePreviewPanel {
//% "Name & Message"
name: qsTrId("name---message")
notificationTitle: "Vitalik Buterin"
//% "Hi there! Yes, no problem, let me know if I can help."
notificationMessage: qsTrId("hi-there--yes--no-problem--let-me-know-if-i-can-help-")
buttonGroup: messageSetting
checked: localAccountSensitiveSettings.notificationMessagePreviewSetting === Constants.notificationPreviewNameAndMessage
onRadioCheckedChanged: {
if (checked) {
localAccountSensitiveSettings.notificationMessagePreviewSetting = Constants.notificationPreviewNameAndMessage
StatusListItem {
Layout.preferredWidth: root.contentWidth
title: qsTr("Allow Notifications")
components: [
StatusSwitch {
id: allowNotifSwitch
checked: localAccountSensitiveSettings.notifSettingAllowNotifications
onClicked: {
localAccountSensitiveSettings.notifSettingAllowNotifications = !localAccountSensitiveSettings.notifSettingAllowNotifications
}
}
]
sensor.onClicked: {
allowNotifSwitch.clicked()
}
}
}
}
StatusBaseText {
//% "No preview or Advanced? Go to Notification Center"
text: qsTrId("no-preview-or-advanced--go-to-notification-center")
font.pixelSize: 15
anchors.left: parent.left
anchors.leftMargin: Style.current.padding
anchors.rightMargin: Style.current.padding
color: Theme.palette.directColor1
}
}
Separator {
id: separator2
anchors.top: column3.bottom
anchors.topMargin: Style.current.bigPadding
anchors.left: parent.left
anchors.right: parent.right
}
StatusSectionHeadline {
id: sectionHeadlineContacts
//% "Contacts & Users"
text: qsTrId("contacts---users")
anchors.top: separator2.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: Style.current.padding
anchors.rightMargin: Style.current.padding
}
Column {
id: column4
anchors.top: sectionHeadlineContacts.bottom
anchors.topMargin: Style.current.smallPadding
anchors.left: parent.left
anchors.right: parent.right
width: parent.width
// TODO: replace with StatusListItem
StatusSettingsLineButton {
anchors.leftMargin: 0
anchors.rightMargin: 0
//% "Notify on new requests"
text: qsTrId("notify-on-new-requests")
isSwitch: true
switchChecked: localAccountSensitiveSettings.notifyOnNewRequests
onClicked: {
localAccountSensitiveSettings.notifyOnNewRequests = checked
}
}
// TODO: replace with StatusListItem
StatusSettingsLineButton {
anchors.leftMargin: 0
anchors.rightMargin: 0
//% "Muted users"
text: qsTrId("muted-users")
currentValue: root.notificationsStore.mutedContactsModel.count > 0 ?
//% "None"
root.notificationsStore.mutedContactsModel.count : qsTrId("none")
isSwitch: false
onClicked: {
const mutedChatsModal = notificationsContainer.mutedChatsModalComponent.createObject(notificationsContainer)
mutedChatsModal.model = root.notificationsStore.notificationsModule.mutedContactsModel
//% "Muted contacts"
mutedChatsModal.title = qsTrId("muted-contacts");
//% "Muted contacts will appear here"
mutedChatsModal.noContentText = qsTrId("muted-contacts-will-appear-here");
mutedChatsModal.unmuteChat.connect(function(chatId){
root.notificationsStore.unmuteChat(chatId)
})
mutedChatsModal.open();
}
}
// TODO: replace with StatusListItem
StatusSettingsLineButton {
anchors.leftMargin: 0
anchors.rightMargin: 0
//% "Muted chats"
text: qsTrId("muted-chats")
currentValue: root.notificationsStore.mutedChatsModel.count > 0 ?
//% "None"
root.notificationsStore.mutedChatsModel.count : qsTrId("none")
isSwitch: false
onClicked: {
const mutedChatsModal = notificationsContainer.mutedChatsModalComponent.createObject(notificationsContainer)
mutedChatsModal.model = root.notificationsStore.notificationsModule.mutedChatsModel
//% "Muted chats"
mutedChatsModal.title = qsTrId("muted-chats");
//% "Muted chats will appear here"
mutedChatsModal.noContentText = qsTrId("muted-chats-will-appear-here");
mutedChatsModal.unmuteChat.connect(function(chatId){
root.notificationsStore.unmuteChat(chatId)
})
mutedChatsModal.open();
}
StatusBaseText {
//% "You can limit what gets shown in notifications"
text: qsTrId("you-can-limit-what-gets-shown-in-notifications")
color: Theme.palette.baseColor1
width: parent.width
font.pixelSize: 12
wrapMode: Text.WordWrap
anchors.left: parent.left
anchors.leftMargin: Style.current.padding
anchors.bottom: parent.bottom
anchors.topMargin: 2
}
}
}
Separator {
id: separator3
anchors.top: column4.bottom
anchors.topMargin: Style.current.bigPadding
anchors.left: parent.left
anchors.right: parent.right
}
Column {
id: column5
spacing: Style.current.smallPadding
anchors.top: separator3.bottom
anchors.topMargin: Style.current.bigPadding
anchors.left: parent.left
anchors.right: parent.right
width: parent.width
StatusBaseText {
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: Style.current.padding
anchors.rightMargin: Style.current.padding
//% "Reset notification settings"
text: qsTrId("reset-notification-settings")
font.pixelSize: 15
color: Theme.palette.dangerColor1
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
hoverEnabled: true
onEntered: {
parent.font.underline = true
StatusBaseText {
Layout.preferredWidth: root.contentWidth
Layout.leftMargin: Style.current.padding
text: qsTr("Messages")
font.pixelSize: Constants.settingsSection.subHeaderFontSize
color: Theme.palette.baseColor1
}
onExited: {
parent.font.underline = false
StatusListItem {
Layout.preferredWidth: root.contentWidth
title: qsTr("1:1 Chats")
components: [
NotificationSelect {
selected: localAccountSensitiveSettings.notifSettingOneToOneChats
onSendAlertsClicked: localAccountSensitiveSettings.notifSettingOneToOneChats = Constants.settingsSection.notifications.sendAlertsValue
onDeliverQuietlyClicked: localAccountSensitiveSettings.notifSettingOneToOneChats = Constants.settingsSection.notifications.deliverQuietlyValue
onTurnOffClicked: localAccountSensitiveSettings.notifSettingOneToOneChats = Constants.settingsSection.notifications.turnOffValue
}
]
}
onClicked: {
localAccountSensitiveSettings.notificationSetting = Constants.notifyAllMessages
localAccountSensitiveSettings.notificationSoundsEnabled = true
localAccountSensitiveSettings.notificationMessagePreviewSetting = Constants.notificationPreviewNameAndMessage
localAccountSensitiveSettings.allowNotificationsFromNonContacts = false
StatusListItem {
Layout.preferredWidth: root.contentWidth
title: qsTr("Group Chats")
components: [
NotificationSelect {
selected: localAccountSensitiveSettings.notifSettingGroupChats
onSendAlertsClicked: localAccountSensitiveSettings.notifSettingGroupChats = Constants.settingsSection.notifications.sendAlertsValue
onDeliverQuietlyClicked: localAccountSensitiveSettings.notifSettingGroupChats = Constants.settingsSection.notifications.deliverQuietlyValue
onTurnOffClicked: localAccountSensitiveSettings.notifSettingGroupChats = Constants.settingsSection.notifications.turnOffValue
}
]
}
StatusListItem {
Layout.preferredWidth: root.contentWidth
title: qsTr("Personal @ Mentions")
tertiaryTitle: qsTr("Messages containing @%1").arg(userProfile.name)
components: [
NotificationSelect {
selected: localAccountSensitiveSettings.notifSettingPersonalMentions
onSendAlertsClicked: localAccountSensitiveSettings.notifSettingPersonalMentions = Constants.settingsSection.notifications.sendAlertsValue
onDeliverQuietlyClicked: localAccountSensitiveSettings.notifSettingPersonalMentions = Constants.settingsSection.notifications.deliverQuietlyValue
onTurnOffClicked: localAccountSensitiveSettings.notifSettingPersonalMentions = Constants.settingsSection.notifications.turnOffValue
}
]
}
StatusListItem {
Layout.preferredWidth: root.contentWidth
title: qsTr("Global @ Mentions")
tertiaryTitle: qsTr("Messages containing @here and @channel")
components: [
NotificationSelect {
selected: localAccountSensitiveSettings.notifSettingGlobalMentions
onSendAlertsClicked: localAccountSensitiveSettings.notifSettingGlobalMentions = Constants.settingsSection.notifications.sendAlertsValue
onDeliverQuietlyClicked: localAccountSensitiveSettings.notifSettingGlobalMentions = Constants.settingsSection.notifications.deliverQuietlyValue
onTurnOffClicked: localAccountSensitiveSettings.notifSettingGlobalMentions = Constants.settingsSection.notifications.turnOffValue
}
]
}
StatusListItem {
Layout.preferredWidth: root.contentWidth
title: qsTr("All Messages")
components: [
NotificationSelect {
selected: localAccountSensitiveSettings.notifSettingAllMessages
onSendAlertsClicked: localAccountSensitiveSettings.notifSettingAllMessages = Constants.settingsSection.notifications.sendAlertsValue
onDeliverQuietlyClicked: localAccountSensitiveSettings.notifSettingAllMessages = Constants.settingsSection.notifications.deliverQuietlyValue
onTurnOffClicked: localAccountSensitiveSettings.notifSettingAllMessages = Constants.settingsSection.notifications.turnOffValue
}
]
}
StatusBaseText {
Layout.preferredWidth: root.contentWidth
Layout.leftMargin: Style.current.padding
text: qsTr("Others")
font.pixelSize: Constants.settingsSection.subHeaderFontSize
color: Theme.palette.baseColor1
}
StatusListItem {
Layout.preferredWidth: root.contentWidth
title: qsTr("Contact Requests")
components: [
NotificationSelect {
selected: localAccountSensitiveSettings.notifSettingContactRequests
onSendAlertsClicked: localAccountSensitiveSettings.notifSettingContactRequests = Constants.settingsSection.notifications.sendAlertsValue
onDeliverQuietlyClicked: localAccountSensitiveSettings.notifSettingContactRequests = Constants.settingsSection.notifications.deliverQuietlyValue
onTurnOffClicked: localAccountSensitiveSettings.notifSettingContactRequests = Constants.settingsSection.notifications.turnOffValue
}
]
}
StatusListItem {
Layout.preferredWidth: root.contentWidth
title: qsTr("Identity Verification Requests")
components: [
NotificationSelect {
selected: localAccountSensitiveSettings.notifSettingIdentityVerificationRequests
onSendAlertsClicked: localAccountSensitiveSettings.notifSettingIdentityVerificationRequests = Constants.settingsSection.notifications.sendAlertsValue
onDeliverQuietlyClicked: localAccountSensitiveSettings.notifSettingIdentityVerificationRequests = Constants.settingsSection.notifications.deliverQuietlyValue
onTurnOffClicked: localAccountSensitiveSettings.notifSettingIdentityVerificationRequests = Constants.settingsSection.notifications.turnOffValue
}
]
}
Separator {
Layout.preferredWidth: root.contentWidth
Layout.preferredHeight: Style.current.bigPadding
}
StatusBaseText {
Layout.preferredWidth: root.contentWidth
Layout.leftMargin: Style.current.padding
text: qsTr("Notification Content")
font.pixelSize: Constants.settingsSection.subHeaderFontSize
color: Theme.palette.directColor1
}
NotificationAppearancePreviewPanel {
id: notifNameAndMsg
Layout.preferredWidth: root.contentWidth
Layout.leftMargin: Style.current.padding
name: qsTr("Show Name and Message")
notificationTitle: "Vitalik Buterin"
notificationMessage: qsTr("Hi there! So EIP-1559 will defini...")
buttonGroup: messageSetting
checked: localAccountSensitiveSettings.notificationMessagePreviewSetting === Constants.settingsSection.notificationsBubble.previewNameAndMessage
onRadioCheckedChanged: {
if (checked) {
localAccountSensitiveSettings.notificationMessagePreviewSetting = Constants.settingsSection.notificationsBubble.previewNameAndMessage
}
}
}
NotificationAppearancePreviewPanel {
Layout.preferredWidth: root.contentWidth
Layout.leftMargin: Style.current.padding
name: qsTr("Name Only")
notificationTitle: "Vitalik Buterin"
notificationMessage: qsTr("You have a new message")
buttonGroup: messageSetting
checked: localAccountSensitiveSettings.notificationMessagePreviewSetting === Constants.settingsSection.notificationsBubble.previewNameOnly
onRadioCheckedChanged: {
if (checked) {
localAccountSensitiveSettings.notificationMessagePreviewSetting = Constants.settingsSection.notificationsBubble.previewNameOnly
}
}
}
NotificationAppearancePreviewPanel {
Layout.preferredWidth: root.contentWidth
Layout.leftMargin: Style.current.padding
name: qsTr("Anonymous")
notificationTitle: "Status"
notificationMessage: qsTr("You have a new message")
buttonGroup: messageSetting
checked: localAccountSensitiveSettings.notificationMessagePreviewSetting === Constants.settingsSection.notificationsBubble.previewAnonymous
onRadioCheckedChanged: {
if (checked) {
localAccountSensitiveSettings.notificationMessagePreviewSetting = Constants.settingsSection.notificationsBubble.previewAnonymous
}
}
}
StatusListItem {
Layout.preferredWidth: root.contentWidth
title: qsTr("Play a Sound When Receiving a Notification")
components: [
StatusSwitch {
id: soundSwitch
checked: localAccountSensitiveSettings.notificationSoundsEnabled
onClicked: {
localAccountSensitiveSettings.notificationSoundsEnabled = !localAccountSensitiveSettings.notificationSoundsEnabled
}
}
]
sensor.onClicked: {
soundSwitch.clicked()
}
}
StatusBaseText {
Layout.preferredWidth: root.contentWidth
Layout.leftMargin: Style.current.padding
text: qsTr("Volume")
font.pixelSize: Constants.settingsSection.subHeaderFontSize
color: Theme.palette.directColor1
}
Item {
Layout.preferredWidth: root.contentWidth
Layout.preferredHeight: Constants.settingsSection.itemHeight + Style.current.padding
StatusSlider {
id: volumeSlider
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: Style.current.bigPadding
anchors.leftMargin: Style.current.padding
anchors.rightMargin: Style.current.padding
from: 0
to: 100
stepSize: 1
onValueChanged: {
localAccountSensitiveSettings.volume = value
}
Component.onCompleted: {
value = localAccountSensitiveSettings.volume
}
}
RowLayout {
anchors.top: volumeSlider.bottom
anchors.left: volumeSlider.left
anchors.topMargin: Style.current.halfPadding
width: volumeSlider.width
StatusBaseText {
font.pixelSize: 15
text: volumeSlider.from
Layout.preferredWidth: volumeSlider.width/2
color: Theme.palette.baseColor1
}
StatusBaseText {
font.pixelSize: 15
text: volumeSlider.to
Layout.alignment: Qt.AlignRight
color: Theme.palette.baseColor1
}
}
}
StatusButton {
Layout.leftMargin: Style.current.padding
text: qsTr("Send a Test Notification")
onClicked: {
root.notificationsStore.sendTestNotification(notifNameAndMsg.notificationTitle,
notifNameAndMsg.notificationMessage)
}
}
Separator {
Layout.preferredWidth: root.contentWidth
Layout.preferredHeight: Style.current.bigPadding
}
StatusBaseText {
Layout.preferredWidth: root.contentWidth
Layout.leftMargin: Style.current.padding
text: qsTr("Exemptions")
font.pixelSize: Constants.settingsSection.subHeaderFontSize
color: Theme.palette.directColor1
}
SearchBox {
id: searchBox
Layout.preferredWidth: root.contentWidth - 2 * Style.current.padding
Layout.leftMargin: Style.current.padding
Layout.rightMargin: Style.current.padding
input.implicitHeight: 44
input.placeholderText: qsTr("Search Communities, Group Chats and 1:1 Chats")
}
StatusBaseText {
Layout.preferredWidth: root.contentWidth
Layout.leftMargin: Style.current.padding
text: qsTr("Most recent")
font.pixelSize: Constants.settingsSection.subHeaderFontSize
color: Theme.palette.baseColor1
}
ListView {
Layout.preferredWidth: root.contentWidth
Layout.preferredHeight: 400
visible: root.notificationsStore.exemptionsModel.count > 0
clip: true
model: root.notificationsStore.exemptionsModel
delegate: exemptionDelegateComponent
}
}
}
StatusBaseText {
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: Style.current.padding
anchors.rightMargin: Style.current.padding
//% "Restore default notification settings and unmute all chats and users"
text: qsTrId("restore-default-notification-settings-and-unmute-all-chats-and-users")
font.pixelSize: 15
color: Theme.palette.baseColor1
}
}
}
//}
// }
//}
}

View File

@ -1,46 +0,0 @@
import QtQuick 2.13
import QtQuick.Controls 2.13
import QtQuick.Layouts 1.13
import utils 1.0
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
SettingsContentBase {
id: root
ColumnLayout {
spacing: Constants.settingsSection.itemSpacing
width: root.contentWidth
StatusBaseText {
id: labelVolume
Layout.fillWidth: true
Layout.leftMargin: Style.current.padding
Layout.rightMargin: Style.current.padding
//% "Sound volume"
text: qsTrId("sound-volume") + " " + volume.value.toPrecision(1)
font.pixelSize: 15
color: Theme.palette.directColor1
}
StatusSlider {
id: volume
Layout.fillWidth: true
Layout.leftMargin: Style.current.padding
Layout.rightMargin: Style.current.padding
from: 0.0
to: 1.0
stepSize: 0.1
onValueChanged: {
localAccountSensitiveSettings.volume = volume.value * 10
}
Component.onCompleted: {
value = localAccountSensitiveSettings.volume * 0.1
}
}
}
}

View File

@ -47,7 +47,7 @@ QtObject {
// property MessageStore messageStore: MessageStore { }
property real volume: !!localAccountSensitiveSettings ? localAccountSensitiveSettings.volume * 0.1 : 0.2
property real volume: !!localAccountSensitiveSettings ? localAccountSensitiveSettings.volume * 0.01 : 0.5
property bool notificationSoundsEnabled: !!localAccountSensitiveSettings ? localAccountSensitiveSettings.notificationSoundsEnabled : false
property var walletSectionTransactionsInst: walletSectionTransactions

View File

@ -26,7 +26,7 @@ Rectangle {
Loader {
id: identicon
sourceComponent: localAccountSensitiveSettings.notificationMessagePreviewSetting === Constants.notificationPreviewAnonymous ? statusIdenticon : userOrChannelIdenticon
sourceComponent: localAccountSensitiveSettings.notificationMessagePreviewSetting === Constants.settingsSection.notificationsBubble.previewAnonymous ? statusIdenticon : userOrChannelIdenticon
anchors.left: parent.left
anchors.leftMargin: Style.current.padding
anchors.verticalCenter: parent.verticalCenter

View File

@ -37,15 +37,14 @@ QtObject {
property int wallet: 4
property int privacyAndSecurity: 5
property int appearance: 6
property int sound: 7
property int language: 8
property int notifications: 9
property int devicesSettings: 10
property int browserSettings: 11
property int advanced: 12
property int needHelp: 13
property int about: 14
property int signout: 15
property int language: 7
property int notifications: 8
property int devicesSettings: 9
property int browserSettings: 10
property int advanced: 11
property int needHelp: 12
property int about: 13
property int signout: 14
}
readonly property QtObject userStatus: QtObject{
@ -151,7 +150,35 @@ QtObject {
readonly property QtObject settingsSection: QtObject {
readonly property int itemSpacing: 10
readonly property int radius: 8
readonly property int mainHeaderFontSize: 28
readonly property int subHeaderFontSize: 15
readonly property int infoFontSize: 15
readonly property int infoLineHeight: 22
readonly property int infoSpacing: 5
readonly property int itemHeight: 64
readonly property int leftMargin: 64
readonly property int rightMargin: 64
readonly property int topMargin: 64
readonly property int bottomMargin: 64
readonly property QtObject notificationsBubble: QtObject {
readonly property int previewAnonymous: 0
readonly property int previewNameOnly: 1
readonly property int previewNameAndMessage: 2
}
readonly property QtObject notifications: QtObject {
readonly property string sendAlertsValue: "sendAlerts"
readonly property string deliverQuietlyValue: "deliverQuietly"
readonly property string turnOffValue: "turnOff"
}
readonly property QtObject exemptions: QtObject {
readonly property int community: 0
readonly property int oneToOneChat: 1
readonly property int groupChat: 2
}
}
readonly property int communityImported: 0
@ -194,9 +221,7 @@ QtObject {
readonly property int notifyAllMessages: 0
readonly property int notifyJustMentions: 1
readonly property int notifyNone: 2
readonly property int notificationPreviewAnonymous: 0
readonly property int notificationPreviewNameOnly: 1
readonly property int notificationPreviewNameAndMessage: 2
readonly property string watchWalletType: "watch"
readonly property string keyWalletType: "key"