feature: support url unfurling settings (#12441)

This commit is contained in:
Igor Sirotin 2023-10-16 17:05:55 +01:00 committed by GitHub
parent cefafbccc6
commit 22ce35cf9c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 222 additions and 35 deletions

View File

@ -92,7 +92,8 @@ const DEFAULT_STICKERS_ENS_ROPSTEN = false
const LSS_KEY_USER_DECLINED_BACKUP_BANNER* = "userDeclinedBackupBanner"
const DEFAULT_USER_DECLINED_BACKUP_BANNER = false
const DEFAULT_IS_DISCORD_IMPORT_TOOL_ENABLED = false
const LSS_KEY_GIF_UNFURLING_ENABLED* = "gifUnfurlingEnabled"
const DEFAULT_GIF_UNFURLING_ENABLED* = false
logScope:
topics = "la-sensitive-settings"
@ -727,6 +728,18 @@ QtObject:
write = setUserDeclinedBackupBanner
notify = userDeclinedBackupBannerChanged
proc gifUnfurlingEnabledChanged*(self: LocalAccountSensitiveSettings) {.signal.}
proc getGifUnfurlingEnabled*(self: LocalAccountSensitiveSettings): bool {.slot.} =
getSettingsProp[bool](self, LSS_KEY_GIF_UNFURLING_ENABLED, newQVariant(DEFAULT_GIF_UNFURLING_ENABLED))
proc setGifUnfurlingEnabled*(self: LocalAccountSensitiveSettings, value: bool) {.slot.} =
setSettingsProp(self, LSS_KEY_GIF_UNFURLING_ENABLED, newQVariant(value)):
self.gifUnfurlingEnabledChanged()
QtProperty[bool] gifUnfurlingEnabled:
read = getGifUnfurlingEnabled
write = setGifUnfurlingEnabled
notify = gifUnfurlingEnabledChanged
proc removeKey*(self: LocalAccountSensitiveSettings, key: string) =
if(self.settings.isNil):
return
@ -776,3 +789,4 @@ QtObject:
of LSS_KEY_COMPATIBILITY_MODE: self.compatibilityModeChanged()
of LSS_KEY_STICKERS_ENS_ROPSTEN: self.stickersEnsRopstenChanged()
of LSS_KEY_USER_DECLINED_BACKUP_BANNER: self.userDeclinedBackupBannerChanged()
of LSS_KEY_GIF_UNFURLING_ENABLED: self.gifUnfurlingEnabledChanged()

View File

@ -1,21 +1,18 @@
import io_interface, chronicles, tables, sequtils
import ../../../../../../app_service/service/settings/service as settings_service
import ../../../../../../app_service/service/message/service as message_service
import ../../../../../../app_service/service/community/service as community_service
import ../../../../../../app_service/service/chat/service as chat_service
import ../../../../../../app_service/service/gif/service as gif_service
import ../../../../../../app_service/service/gif/dto
import ../../../../../../app_service/service/message/dto/link_preview
import ../../../../../../app_service/service/settings/dto/settings
import ../../../../../core/eventemitter
import ../../../../../core/unique_event_emitter
import ./link_preview_cache
type
LinkPreviewSetting* {.pure.} = enum
AlwaysAsk
Enabled
Disabled
type
Controller* = ref object of RootObj
delegate: io_interface.AccessInterface
@ -27,9 +24,10 @@ type
chatService: chat_service.Service
gifService: gif_service.Service
messageService: message_service.Service
settingsService: settings_service.Service
linkPreviewCache: LinkPreviewCache
linkPreviewPersistentSetting: LinkPreviewSetting
linkPreviewCurrentMessageSetting: LinkPreviewSetting
linkPreviewPersistentSetting: UrlUnfurlingMode
linkPreviewCurrentMessageSetting: UrlUnfurlingMode
proc newController*(
delegate: io_interface.AccessInterface,
@ -40,7 +38,8 @@ proc newController*(
chatService: chat_service.Service,
communityService: community_service.Service,
gifService: gif_service.Service,
messageService: message_service.Service
messageService: message_service.Service,
settingsService: settings_service.Service
): Controller =
result = Controller()
result.delegate = delegate
@ -52,11 +51,13 @@ proc newController*(
result.communityService = communityService
result.gifService = gifService
result.messageService = messageService
result.settingsService = settingsService
result.linkPreviewCache = newLinkPreiewCache()
result.linkPreviewPersistentSetting = LinkPreviewSetting.AlwaysAsk
result.linkPreviewCurrentMessageSetting = LinkPreviewSetting.AlwaysAsk
result.linkPreviewPersistentSetting = UrlUnfurlingMode.AlwaysAsk
result.linkPreviewCurrentMessageSetting = UrlUnfurlingMode.AlwaysAsk
proc onUrlsUnfurled(self: Controller, args: LinkPreviewV2DataArgs)
proc clearLinkPreviewCache*(self: Controller)
proc delete*(self: Controller) =
self.events.disconnect()
@ -101,13 +102,13 @@ proc belongsToCommunity*(self: Controller): bool =
return self.belongsToCommunity
proc setLinkPreviewEnabledForThisMessage*(self: Controller, enabled: bool) =
self.linkPreviewCurrentMessageSetting = if enabled: LinkPreviewSetting.Enabled else: LinkPreviewSetting.Disabled
self.linkPreviewCurrentMessageSetting = if enabled: UrlUnfurlingMode.Enabled else: UrlUnfurlingMode.Disabled
self.delegate.setAskToEnableLinkPreview(false)
proc resetLinkPreviews(self: Controller) =
self.delegate.setUrls(@[])
self.linkPreviewCache.clear()
self.linkPreviewCurrentMessageSetting = LinkPreviewSetting.AlwaysAsk
self.linkPreviewCurrentMessageSetting = UrlUnfurlingMode.AlwaysAsk
self.delegate.setAskToEnableLinkPreview(false)
proc sendImages*(self: Controller,
@ -187,10 +188,10 @@ proc isFavorite*(self: Controller, item: GifDto): bool =
return self.gifService.isFavorite(item)
proc getLinkPreviewEnabled*(self: Controller): bool =
return self.linkPreviewPersistentSetting == LinkPreviewSetting.Enabled or self.linkPreviewCurrentMessageSetting == LinkPreviewSetting.Enabled
return self.linkPreviewPersistentSetting == UrlUnfurlingMode.Enabled or self.linkPreviewCurrentMessageSetting == UrlUnfurlingMode.Enabled
proc canAskToEnableLinkPreview(self: Controller): bool =
return self.linkPreviewPersistentSetting == LinkPreviewSetting.AlwaysAsk and self.linkPreviewCurrentMessageSetting == LinkPreviewSetting.AlwaysAsk
return self.linkPreviewPersistentSetting == UrlUnfurlingMode.AlwaysAsk and self.linkPreviewCurrentMessageSetting == UrlUnfurlingMode.AlwaysAsk
proc setText*(self: Controller, text: string, unfurlNewUrls: bool) =
if text == "":
@ -229,10 +230,10 @@ proc loadLinkPreviews*(self: Controller, urls: seq[string]) =
proc setLinkPreviewEnabled*(self: Controller, enabled: bool) =
if(enabled):
self.linkPreviewPersistentSetting = LinkPreviewSetting.Enabled
self.linkPreviewCurrentMessageSetting = LinkPreviewSetting.Enabled
self.linkPreviewPersistentSetting = UrlUnfurlingMode.Enabled
self.linkPreviewCurrentMessageSetting = UrlUnfurlingMode.Enabled
else:
self.linkPreviewPersistentSetting = LinkPreviewSetting.Disabled
self.linkPreviewCurrentMessageSetting = LinkPreviewSetting.Disabled
self.linkPreviewPersistentSetting = UrlUnfurlingMode.Disabled
self.linkPreviewCurrentMessageSetting = UrlUnfurlingMode.Disabled
self.delegate.setAskToEnableLinkPreview(false)

View File

@ -5,6 +5,7 @@ import view, controller
import ../../../../../global/global_singleton
import ../../../../../core/eventemitter
import ../../../../../../app_service/service/settings/service as settings_service
import ../../../../../../app_service/service/message/service as message_service
import ../../../../../../app_service/service/message/dto/link_preview
import ../../../../../../app_service/service/chat/service as chat_service
@ -31,14 +32,15 @@ proc newModule*(
chatService: chat_service.Service,
communityService: community_service.Service,
gifService: gif_service.Service,
messageService: message_service.Service
messageService: message_service.Service,
settingsService: settings_service.Service
):
Module =
result = Module()
result.delegate = delegate
result.view = view.newView(result)
result.viewVariant = newQVariant(result.view)
result.controller = controller.newController(result, events, sectionId, chatId, belongsToCommunity, chatService, communityService, gifService, messageService)
result.controller = controller.newController(result, events, sectionId, chatId, belongsToCommunity, chatService, communityService, gifService, messageService, settingsService)
result.moduleLoaded = false
method delete*(self: Module) =

View File

@ -56,7 +56,7 @@ proc newModule*(delegate: delegate_interface.AccessInterface, events: EventEmitt
result.moduleLoaded = false
result.inputAreaModule = input_area_module.newModule(result, events, sectionId, chatId, belongsToCommunity,
chatService, communityService, gifService, messageService)
chatService, communityService, gifService, messageService, settingsService)
result.messagesModule = messages_module.newModule(result, events, sectionId, chatId, belongsToCommunity,
contactService, communityService, chatService, messageService, mailserversService)
result.usersModule = users_module.newModule(events, sectionId, chatId, belongsToCommunity,

View File

@ -1,5 +1,5 @@
import io_interface
import uuids
import uuids, chronicles
import ../../../../../constants as main_constants
import ../../../../global/global_singleton
@ -94,6 +94,14 @@ proc getMessagesFromContactsOnly*(self: Controller): bool =
proc setMessagesFromContactsOnly*(self: Controller, value: bool): bool =
return self.settingsService.saveMessagesFromContactsOnly(value)
method urlUnfurlingMode*(self: Controller): int {.base.} =
return int(self.settingsService.urlUnfurlingMode())
method setUrlUnfurlingMode*(self: Controller, value: int) {.base.} =
let mode = toUrlUnfurlingMode(value)
if not self.settingsService.saveUrlUnfurlingMode(mode):
error "failed to save url unfurling mode setting", value
proc validatePassword*(self: Controller, password: string): bool =
return self.privacyService.validatePassword(password)
@ -129,4 +137,4 @@ proc authenticateLoggedInUser*(self: Controller) =
self.events.emit(SIGNAL_SHARED_KEYCARD_MODULE_AUTHENTICATE_USER, data)
proc backupData*(self: Controller): int64 =
return self.generalService.backupData()
return self.generalService.backupData()

View File

@ -53,6 +53,12 @@ method getMessagesFromContactsOnly*(self: AccessInterface): bool {.base.} =
method setMessagesFromContactsOnly*(self: AccessInterface, value: bool) {.base.} =
raise newException(ValueError, "No implementation available")
method urlUnfurlingMode*(self: AccessInterface): int {.base.} =
raise newException(ValueError, "No implementation available")
method setUrlUnfurlingMode*(self: AccessInterface, value: int) {.base.} =
raise newException(ValueError, "No implementation available")
method validatePassword*(self: AccessInterface, password: string): bool {.base.} =
raise newException(ValueError, "No implementation available")
@ -75,4 +81,4 @@ method onUserAuthenticated*(self: AccessInterface, pin: string, password: string
raise newException(ValueError, "No implementation available")
method backupData*(self: AccessInterface): int64 {.base.} =
raise newException(ValueError, "No implementation available")
raise newException(ValueError, "No implementation available")

View File

@ -88,6 +88,12 @@ method setMessagesFromContactsOnly*(self: Module, value: bool) =
if(not self.controller.setMessagesFromContactsOnly(value)):
error "an error occurred while saving messages from contacts only flag"
method urlUnfurlingMode*(self: Module): int =
return self.controller.urlUnfurlingMode()
method setUrlUnfurlingMode*(self: Module, value: int) =
self.controller.setUrlUnfurlingMode(value)
method validatePassword*(self: Module, password: string): bool =
self.controller.validatePassword(password)
@ -120,4 +126,4 @@ method onUserAuthenticated*(self: Module, pin: string, password: string, keyUid:
self.controller.storeToKeychain(password)
method backupData*(self: Module): int64 =
return self.controller.backupData()
return self.controller.backupData()

View File

@ -51,6 +51,8 @@ QtObject:
proc getMessagesFromContactsOnly(self: View): bool {.slot.} =
return self.delegate.getMessagesFromContactsOnly()
proc setMessagesFromContactsOnly(self: View, value: bool) {.slot.} =
if self.getMessagesFromContactsOnly() == value:
return
self.delegate.setMessagesFromContactsOnly(value)
self.messagesFromContactsOnlyChanged()
QtProperty[bool] messagesFromContactsOnly:
@ -58,6 +60,19 @@ QtObject:
write = setMessagesFromContactsOnly
notify = messagesFromContactsOnlyChanged
proc urlUnfurlingModeChanged(self: View) {.signal.}
proc getUrlUnfurlingMode(self: View): int {.slot.} =
return self.delegate.urlUnfurlingMode()
proc setUrlUnfurlingMode(self: View, value: int) {.slot.} =
if self.getUrlUnfurlingMode() == value:
return
self.delegate.setUrlUnfurlingMode(value)
self.urlUnfurlingModeChanged()
QtProperty[int] urlUnfurlingMode:
read = getUrlUnfurlingMode
write = setUrlUnfurlingMode
notify = urlUnfurlingModeChanged
proc validatePassword*(self: View, password: string): bool {.slot.} =
self.delegate.validatePassword(password)
@ -79,4 +94,4 @@ QtObject:
self.delegate.tryRemoveFromKeyChain()
proc backupData*(self: View): int {.slot.} =
return self.delegate.backupData().int
return self.delegate.backupData().int

View File

@ -293,7 +293,8 @@ QtObject:
"text": ""
},
"profile-pictures-show-to": settings.PROFILE_PICTURES_SHOW_TO_EVERYONE,
"profile-pictures-visibility": settings.PROFILE_PICTURES_VISIBILITY_EVERYONE
"profile-pictures-visibility": settings.PROFILE_PICTURES_VISIBILITY_EVERYONE,
"url-unfurling-mode": int(settings.UrlUnfurlingMode.AlwaysAsk),
}
proc getAccountSettings(self: Service, accountId: string,

View File

@ -46,6 +46,7 @@ const KEY_BIO* = "bio"
const KEY_TEST_NETWORKS_ENABLED* = "test-networks-enabled?"
const KEY_IS_SEPOLIA_ENABLED* = "is-sepolia-enabled?"
const PROFILE_MIGRATION_NEEDED* = "profile-migration-needed"
const KEY_URL_UNFURLING_MODE* = "url-unfurling-mode"
# Notifications Settings Values
const VALUE_NOTIF_SEND_ALERTS* = "SendAlerts"
@ -60,6 +61,17 @@ const PROFILE_PICTURES_SHOW_TO_CONTACTS_ONLY* = 1
const PROFILE_PICTURES_SHOW_TO_EVERYONE* = 2
const PROFILE_PICTURES_SHOW_TO_NO_ONE* = 3
type UrlUnfurlingMode* {.pure.} = enum
AlwaysAsk = 1,
Enabled = 2,
Disabled = 3,
proc toUrlUnfurlingMode*(value: int): UrlUnfurlingMode =
try:
return UrlUnfurlingMode(value)
except RangeDefect:
return AlwaysAsk # this is the default value
type NotificationsExemptions* = object
muteAllMessages*: bool
personalMentions*: string
@ -139,6 +151,8 @@ type
notificationsMessagePreview*: int
profileMigrationNeeded*: bool
isSepoliaEnabled*: bool
urlUnfurlingMode*: UrlUnfurlingMode
proc toPinnedMailserver*(jsonObj: JsonNode): PinnedMailserver =
# we maintain pinned mailserver per fleet
@ -195,6 +209,10 @@ proc toSettingsDto*(jsonObj: JsonNode): SettingsDto =
discard jsonObj.getProp(KEY_IS_SEPOLIA_ENABLED, result.isSepoliaEnabled)
discard jsonObj.getProp(PROFILE_MIGRATION_NEEDED, result.profileMigrationNeeded)
var urlUnfurlingMode: int
discard jsonObj.getProp(KEY_URL_UNFURLING_MODE, urlUnfurlingMode)
result.urlUnfurlingMode = toUrlUnfurlingMode(urlUnfurlingMode)
var pinnedMailserverObj: JsonNode
if(jsonObj.getProp(KEY_PINNED_MAILSERVERS, pinnedMailserverObj)):
result.pinnedMailserver = toPinnedMailserver(pinnedMailserverObj)

View File

@ -28,6 +28,7 @@ const SIGNAL_MNEMONIC_REMOVED* = "mnemonicRemoved"
const SIGNAL_SOCIAL_LINKS_UPDATED* = "socialLinksUpdated"
const SIGNAL_CURRENT_USER_STATUS_UPDATED* = "currentUserStatusUpdated"
const SIGNAL_PROFILE_MIGRATION_NEEDED_UPDATED* = "profileMigrationNeededUpdated"
const SIGNAL_URL_UNFURLING_MODEL_UPDATED* = "urlUnfurlingModeUpdated"
logScope:
topics = "settings-service"
@ -44,12 +45,12 @@ type
socialLinks*: SocialLinks
error*: string
SettingProfilePictureArgs* = ref object of Args
value*: int
SettingsBoolValueArgs* = ref object of Args
value*: bool
UrlUnfurlingModeArgs* = ref object of Args
value*: UrlUnfurlingMode
QtObject:
type Service* = ref object of QObject
events: EventEmitter
@ -116,6 +117,9 @@ QtObject:
if settingsField.name == PROFILE_MIGRATION_NEEDED:
self.settings.profileMigrationNeeded = settingsField.value.getBool
self.events.emit(SIGNAL_PROFILE_MIGRATION_NEEDED_UPDATED, SettingsBoolValueArgs(value: self.settings.profileMigrationNeeded))
if settingsField.name == KEY_URL_UNFURLING_MODE:
self.settings.urlUnfurlingMode = toUrlUnfurlingMode(settingsField.value.getInt)
self.events.emit(SIGNAL_URL_UNFURLING_MODEL_UPDATED, UrlUnfurlingModeArgs(value: self.settings.urlUnfurlingMode))
if receivedData.socialLinksInfo.links.len > 0 or
receivedData.socialLinksInfo.removed:
@ -490,6 +494,16 @@ QtObject:
return true
return false
proc urlUnfurlingMode*(self: Service): UrlUnfurlingMode =
return self.settings.urlUnfurlingMode
proc saveUrlUnfurlingMode*(self: Service, value: UrlUnfurlingMode): bool =
if not self.saveSetting(KEY_URL_UNFURLING_MODE, int(value)):
return false
self.settings.urlUnfurlingMode = value
self.events.emit(SIGNAL_URL_UNFURLING_MODEL_UPDATED, UrlUnfurlingModeArgs(value: self.settings.urlUnfurlingMode))
return true
proc notifSettingAllowNotificationsChanged*(self: Service) {.signal.}
proc getNotifSettingAllowNotifications*(self: Service): bool {.slot.} =
if self.initialized:

View File

@ -90,6 +90,8 @@ QtObject {
property var advancedModule: profileSectionModule.advancedModule
property var privacyModule: profileSectionModule.privacyModule
readonly property bool permissionsCheckOngoing: chatCommunitySectionModule.permissionsCheckOngoing
signal importingCommunityStateChanged(string communityId, int state, string errorMsg)

View File

@ -146,6 +146,8 @@ Item {
d.restoreInputAttachments()
}
signal updateLinkPreviewsRequested
readonly property var updateLinkPreviews: {
return Backpressure.debounce(this, 250, () => {
const messageText = root.rootStore.cleanMessageText(chatInput.textInput.text)
@ -165,6 +167,14 @@ Item {
}
}
Connections {
enabled: !root.rootStore.privacyModule.urlUnfurlingMode === Constants.UrlUnfurlingModeDisableAll
target: d
function onUpdateLinkPreviewsRequested() {
d.updateLinkPreviews()
}
}
EmptyChatPanel {
anchors.fill: parent
visible: root.activeChatId === "" || root.chatsCount == 0
@ -277,7 +287,7 @@ Item {
textInput.onTextChanged: {
if (!!d.activeChatContentModule) {
d.activeChatContentModule.inputAreaModule.preservedProperties.text = textInput.text
d.updateLinkPreviews()
d.updateLinkPreviewsRequested()
}
}

View File

@ -161,6 +161,85 @@ SettingsContentBase {
Layout.fillWidth: true
}
// GIF LINK PREVIEWS
StatusSectionHeadline {
Layout.fillWidth: true
Layout.leftMargin: Style.current.padding
Layout.rightMargin: Style.current.padding
text: qsTr("GIF link previews")
}
StatusListItem {
Layout.fillWidth: true
title: qsTr("Allow show GIF previews")
components: [
StatusSwitch {
id: showGifPreviewsSwitch
checked: localAccountSensitiveSettings.gifUnfurlingEnabled
onClicked: {
localAccountSensitiveSettings.gifUnfurlingEnabled = !localAccountSensitiveSettings.gifUnfurlingEnabled
}
}
]
onClicked: {
showGifPreviewsSwitch.clicked()
}
}
Separator {
Layout.fillWidth: true
}
// URL UNFRULING
StatusSectionHeadline {
Layout.fillWidth: true
Layout.leftMargin: Style.current.padding
Layout.rightMargin: Style.current.padding
text: qsTr("Website link previews")
}
ButtonGroup {
id: urlUnfurlingGroup
}
SettingsRadioButton {
Layout.fillWidth: true
Layout.leftMargin: Style.current.padding
Layout.rightMargin: Style.current.padding
label: qsTr("Always ask")
group: urlUnfurlingGroup
checked: root.messagingStore.privacyModule.urlUnfurlingMode === Constants.UrlUnfurlingModeAlwaysAsk
onClicked: {
root.messagingStore.privacyModule.urlUnfurlingMode = Constants.UrlUnfurlingModeAlwaysAsk
}
}
SettingsRadioButton {
Layout.topMargin: Constants.settingsSection.itemSpacing / 2
Layout.fillWidth: true
Layout.leftMargin: Style.current.padding
Layout.rightMargin: Style.current.padding
label: qsTr("Always show previews")
group: urlUnfurlingGroup
checked: root.messagingStore.privacyModule.urlUnfurlingMode === Constants.UrlUnfurlingModeEnableAll
onClicked: {
root.messagingStore.privacyModule.urlUnfurlingMode = Constants.UrlUnfurlingModeEnableAll
}
}
SettingsRadioButton {
Layout.topMargin: Constants.settingsSection.itemSpacing / 2
Layout.fillWidth: true
Layout.leftMargin: Style.current.padding
Layout.rightMargin: Style.current.padding
label: qsTr("Never show previews")
group: urlUnfurlingGroup
checked: root.messagingStore.privacyModule.urlUnfurlingMode === Constants.UrlUnfurlingModeDisableAll
onClicked: {
root.messagingStore.privacyModule.urlUnfurlingMode = Constants.UrlUnfurlingModeDisableAll
}
}
// MESSAGE LINK PREVIEWS
StatusListItem {
Layout.fillWidth: true

View File

@ -71,7 +71,12 @@ Loader {
return []
const separator = " "
const arr = links.split(separator)
const filtered = arr.filter(v => v.toLowerCase().endsWith('.gif'))
const filtered = arr.filter(value => {
const v = value.toLowerCase()
return localAccountSensitiveSettings.gifUnfurlingEnabled && value.endsWith('.gif')
})
const out = filtered.join(separator)
return out
}

View File

@ -1231,4 +1231,10 @@ QtObject {
enum HoldingType {
Unknown, Asset, Collectible
}
enum UrlUnfurlingMode {
UrlUnfurlingModeAlwaysAsk = 1,
UrlUnfurlingModeEnableAll = 2,
UrlUnfurlingModeDisableAll = 3
}
}

2
vendor/status-go vendored

@ -1 +1 @@
Subproject commit aded258ccb68f88dc995e22f8b4e06157bb642db
Subproject commit 176bdd297deb32b3f7a4e86aa8127f13e56dd50e