fix: messaging settings and url unfurling fixes (#12457)

* remove browser selection setting
* remove main whitelist settings. replace tenorGif setting with gifUnfurlingEnabled
* remove old unfurling
* move history nodes section
* disable outdated e2e tests step
* remove isGifWidgetEnabled setting
* fix: StatusMessage height when gif unfurling disabled

---------

Co-authored-by: Anastasiya Semenkevich <anastasija.ig@gmail.com>
This commit is contained in:
Igor Sirotin 2023-10-18 10:03:32 +01:00 committed by GitHub
parent e1149c9227
commit e5b68e8823
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 126 additions and 784 deletions

View File

@ -18,13 +18,7 @@ const LSS_KEY_SHOW_ONLINE_USERS* = "showOnlineUsers"
const DEFAULT_SHOW_ONLINE_USERS = true
const LSS_KEY_EXPAND_USERS_LIST* = "expandUsersList"
const DEFAULT_EXPAND_USERS_LIST = true
const LSS_KEY_IS_GIF_WIDGET_ENABLED* = "isGifWidgetEnabled"
const DEFAULT_IS_GIF_WIDGET_ENABLED = true
const DEFAULT_IS_MULTI_NETWORK_ENABLED = false
const LSS_KEY_IS_TENOR_WARNING_ACCEPTED* = "isTenorWarningAccepted"
const DEFAULT_IS_TENOR_WARNING_ACCEPTED = false
const LSS_KEY_DISPLAY_CHAT_IMAGES* = "displayChatImages"
const DEFAULT_DISPLAY_CHAT_IMAGES = false
const LSS_KEY_RECENT_EMOJIS* = "recentEmojis"
const DEFAULT_RECENT_EMOJIS = ""
const LSS_KEY_HIDDEN_COMMUNITY_WELCOME_BANNERS* = "hiddenCommunityWelcomeBanners"
@ -33,8 +27,6 @@ const LSS_KEY_HIDDEN_COMMUNITY_CHANNELS_AND_CATEGORIES_BANNERS* = "hiddenCommuni
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_WITHLISTED_UNFURLING_SITES* = "whitelistedUnfurlingSites"
const DEFAULT_WITHLISTED_UNFURLING_SITES = ""
const LSS_KEY_NEVER_ASK_ABOUT_UNFURLING_AGAIN* = "neverAskAboutUnfurlingAgain"
const DEFAULT_NEVER_ASK_ABOUT_UNFURLING_AGAIN = false
const LSS_KEY_HIDE_CHANNEL_SUGGESTIONS* = "hideChannelSuggestions"
@ -277,44 +269,6 @@ QtObject:
notify = expandUsersListChanged
proc isGifWidgetEnabledChanged*(self: LocalAccountSensitiveSettings) {.signal.}
proc getIsGifWidgetEnabled*(self: LocalAccountSensitiveSettings): bool {.slot.} =
getSettingsProp[bool](self, LSS_KEY_IS_GIF_WIDGET_ENABLED, newQVariant(DEFAULT_IS_GIF_WIDGET_ENABLED))
proc setIsGifWidgetEnabled*(self: LocalAccountSensitiveSettings, value: bool) {.slot.} =
setSettingsProp(self, LSS_KEY_IS_GIF_WIDGET_ENABLED, newQVariant(value)):
self.isGifWidgetEnabledChanged()
QtProperty[bool] isGifWidgetEnabled:
read = getIsGifWidgetEnabled
write = setIsGifWidgetEnabled
notify = isGifWidgetEnabledChanged
proc isTenorWarningAcceptedChanged*(self: LocalAccountSensitiveSettings) {.signal.}
proc getIsTenorWarningAccepted*(self: LocalAccountSensitiveSettings): bool {.slot.} =
getSettingsProp[bool](self, LSS_KEY_IS_TENOR_WARNING_ACCEPTED, newQVariant(DEFAULT_IS_TENOR_WARNING_ACCEPTED))
proc setIsTenorWarningAccepted*(self: LocalAccountSensitiveSettings, value: bool) {.slot.} =
setSettingsProp(self, LSS_KEY_IS_TENOR_WARNING_ACCEPTED, newQVariant(value)):
self.isTenorWarningAcceptedChanged()
QtProperty[bool] isTenorWarningAccepted:
read = getIsTenorWarningAccepted
write = setIsTenorWarningAccepted
notify = isTenorWarningAcceptedChanged
proc displayChatImagesChanged*(self: LocalAccountSensitiveSettings) {.signal.}
proc getDisplayChatImages*(self: LocalAccountSensitiveSettings): bool {.slot.} =
getSettingsProp[bool](self, LSS_KEY_DISPLAY_CHAT_IMAGES, newQVariant(DEFAULT_DISPLAY_CHAT_IMAGES))
proc setDisplayChatImages*(self: LocalAccountSensitiveSettings, value: bool) {.slot.} =
setSettingsProp(self, LSS_KEY_DISPLAY_CHAT_IMAGES, newQVariant(value)):
self.displayChatImagesChanged()
QtProperty[bool] displayChatImages:
read = getDisplayChatImages
write = setDisplayChatImages
notify = displayChatImagesChanged
proc recentEmojisChanged*(self: LocalAccountSensitiveSettings) {.signal.}
proc getRecentEmojis*(self: LocalAccountSensitiveSettings): QVariant {.slot.} =
getSettingsPropQVariant(self, LSS_KEY_RECENT_EMOJIS, newQVariant(DEFAULT_RECENT_EMOJIS))
@ -364,20 +318,6 @@ QtObject:
write = setHiddenCommunityBackUpBanners
notify = hiddenCommunityBackUpBannersChanged
proc whitelistedUnfurlingSitesChanged*(self: LocalAccountSensitiveSettings) {.signal.}
proc getWhitelistedUnfurlingSites*(self: LocalAccountSensitiveSettings): QVariant {.slot.} =
getSettingsPropQVariant(self, LSS_KEY_WITHLISTED_UNFURLING_SITES, newQVariant(DEFAULT_WITHLISTED_UNFURLING_SITES))
proc setWhitelistedUnfurlingSites*(self: LocalAccountSensitiveSettings, value: QVariant) {.slot.} =
setSettingsProp(self, LSS_KEY_WITHLISTED_UNFURLING_SITES, value):
self.whitelistedUnfurlingSitesChanged()
QtProperty[QVariant] whitelistedUnfurlingSites:
read = getWhitelistedUnfurlingSites
write = setWhitelistedUnfurlingSites
notify = whitelistedUnfurlingSitesChanged
proc neverAskAboutUnfurlingAgainChanged*(self: LocalAccountSensitiveSettings) {.signal.}
proc getNeverAskAboutUnfurlingAgain*(self: LocalAccountSensitiveSettings): bool {.slot.} =
getSettingsProp[bool](self, LSS_KEY_NEVER_ASK_ABOUT_UNFURLING_AGAIN, newQVariant(DEFAULT_NEVER_ASK_ABOUT_UNFURLING_AGAIN))
@ -754,14 +694,10 @@ QtObject:
of LSS_KEY_IS_BROWSER_ENABLED: self.isBrowserEnabledChanged()
of LSS_KEY_SHOW_ONLINE_USERS: self.showOnlineUsersChanged()
of LSS_KEY_EXPAND_USERS_LIST: self.expandUsersListChanged()
of LSS_KEY_IS_GIF_WIDGET_ENABLED: self.isGifWidgetEnabledChanged()
of LSS_KEY_IS_TENOR_WARNING_ACCEPTED: self.isTenorWarningAcceptedChanged()
of LSS_KEY_DISPLAY_CHAT_IMAGES: self.displayChatImagesChanged()
of LSS_KEY_RECENT_EMOJIS: self.recentEmojisChanged()
of LSS_KEY_HIDDEN_COMMUNITY_WELCOME_BANNERS: self.hiddenCommunityWelcomeBannersChanged()
of LSS_KEY_HIDDEN_COMMUNITY_CHANNELS_AND_CATEGORIES_BANNERS: self.hiddenCommunityChannelAndCategoriesBannersChanged()
of LSS_KEY_HIDDEN_COMMUNITY_BACKUP_BANNERS: self.hiddenCommunityBackUpBannersChanged()
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()
of LSS_KEY_FONT_SIZE: self.fontSizeChanged()

View File

@ -1,4 +1,4 @@
import io_interface, chronicles, tables, sequtils
import io_interface, chronicles, tables, sequtils, strutils, sugar
import ../../../../../../app_service/service/settings/service as settings_service
@ -199,7 +199,8 @@ proc setText*(self: Controller, text: string, unfurlNewUrls: bool) =
return
let urls = self.messageService.getTextUrls(text)
self.delegate.setUrls(urls)
let supportedUrls = urls.filter(x => not x.endsWith(".gif")) # GIFs are currently unfurled by receiver
self.delegate.setUrls(supportedUrls)
let newUrls = self.linkPreviewCache.unknownUrls(urls)
let askToEnableLinkPreview = len(newUrls) > 0 and self.canAskToEnableLinkPreview()

View File

@ -192,10 +192,6 @@ proc init*(self: Controller) =
return
self.delegate.onHistoryCleared()
self.events.on(SIGNAL_MESSAGE_LINK_PREVIEW_DATA_LOADED) do(e: Args):
let args = LinkPreviewDataArgs(e)
self.delegate.onPreviewDataLoaded($(args.response), args.uuid)
self.events.on(SIGNAL_MAKE_SECTION_CHAT_ACTIVE) do(e: Args):
let args = ActiveSectionChatArgs(e)
if(self.sectionId != args.sectionId or self.chatId != args.chatId):
@ -279,9 +275,6 @@ proc deleteMessage*(self: Controller, messageId: string) =
proc editMessage*(self: Controller, messageId: string, contentType: int, updatedMsg: string) =
self.messageService.editMessage(messageId, contentType, updatedMsg)
proc getLinkPreviewData*(self: Controller, link: string, uuid: string, whiteListedSites: string, whiteListedImgExtensions: string, unfurlImages: bool): string =
self.messageService.asyncGetLinkPreviewData(link, uuid, whiteListedSites, whiteListedImgExtensions, unfurlImages)
proc getSearchedMessageId*(self: Controller): string =
return self.searchedMessageId

View File

@ -126,12 +126,6 @@ method editMessage*(self: AccessInterface, messageId: string, contentType: int,
method onHistoryCleared*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method getLinkPreviewData*(self: AccessInterface, link: string, uuid: string, whiteListedSites: string, whiteListedImgExtensions: string, unfurlImages: bool): string {.base.} =
raise newException(ValueError, "No implementation available")
method onPreviewDataLoaded*(self: AccessInterface, previewData: string, uuid: string) {.base.} =
raise newException(ValueError, "No implementation available")
method requestMoreMessages*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -644,12 +644,6 @@ method updateChatFetchMoreMessages*(self: Module) =
if (self.controller.getChatDetails().hasMoreMessagesToRequest()):
self.view.model().insertItemBasedOnClock(self.createFetchMoreMessagesItem())
method getLinkPreviewData*(self: Module, link: string, uuid: string, whiteListedSites: string, whiteListedImgExtensions: string, unfurlImages: bool): string =
return self.controller.getLinkPreviewData(link, uuid, whiteListedSites, whiteListedImgExtensions, unfurlImages)
method onPreviewDataLoaded*(self: Module, previewData: string, uuid: string) =
self.view.onPreviewDataLoaded(previewData, uuid)
proc switchToMessage*(self: Module, messageId: string) =
let index = self.view.model().findIndexForMessageId(messageId)
if(index != -1):

View File

@ -102,14 +102,6 @@ QtObject:
proc editMessage*(self: View, messageId: string, contentType: int, updatedMsg: string) {.slot.} =
self.delegate.editMessage(messageId, contentType, updatedMsg)
proc getLinkPreviewData*(self: View, link: string, uuid: string, whiteListedSites: string, whiteListedImgExtensions: string, unfurlImages: bool): string {.slot.} =
return self.delegate.getLinkPreviewData(link, uuid, whiteListedSites, whiteListedImgExtensions, unfurlImages)
proc linkPreviewDataWasReceived*(self: View, previewData: string, uuid: string) {.signal.}
proc onPreviewDataLoaded*(self: View, previewData: string, uuid: string) {.slot.} =
self.linkPreviewDataWasReceived(previewData, uuid)
proc switchToMessage(self: View, messageIndex: int) {.signal.}
proc emitSwitchToMessageSignal*(self: View, messageIndex: int) =
self.switchToMessage(messageIndex)

View File

@ -73,9 +73,6 @@ proc init*(self: Controller) =
proc isMnemonicBackedUp*(self: Controller): bool =
return self.privacyService.isMnemonicBackedUp()
proc getLinkPreviewWhitelist*(self: Controller): string =
return self.privacyService.getLinkPreviewWhitelist()
proc changePassword*(self: Controller, password: string, newPassword: string) =
self.privacyService.changePassword(password, newPassword)

View File

@ -25,9 +25,6 @@ method viewDidLoad*(self: AccessInterface) {.base.} =
method isMnemonicBackedUp*(self: AccessInterface): bool {.base.} =
raise newException(ValueError, "No implementation available")
method getLinkPreviewWhitelist*(self: AccessInterface): string {.base.} =
raise newException(ValueError, "No implementation available")
method changePassword*(self: AccessInterface, password: string, newPassword: string) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -57,9 +57,6 @@ method viewDidLoad*(self: Module) =
method getModuleAsVariant*(self: Module): QVariant =
return self.viewVariant
method getLinkPreviewWhitelist*(self: Module): string =
return self.controller.getLinkPreviewWhitelist()
method changePassword*(self: Module, password: string, newPassword: string) =
self.controller.changePassword(password, newPassword)

View File

@ -18,9 +18,6 @@ QtObject:
proc load*(self: View) =
self.delegate.viewDidLoad()
proc getLinkPreviewWhitelist*(self: View): string {.slot.} =
return self.delegate.getLinkPreviewWhitelist()
proc changePassword*(self: View, password: string, newPassword: string) {.slot.} =
self.delegate.changePassword(password, newPassword)

View File

@ -162,96 +162,7 @@ const asyncMarkCertainMessagesReadTask: Task = proc(argEncoded: string) {.gcsafe
"error": error
}
arg.finish(responseJson)
#################################################
#################################################
# Async GetLinkPreviewData
#################################################
type
AsyncGetLinkPreviewDataTaskArg = ref object of QObjectTaskArg
links: string
uuid: string
whiteListedUrls: string
whiteListedImgExtensions: string
unfurlImages: bool
const asyncGetLinkPreviewDataTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
let arg = decode[AsyncGetLinkPreviewDataTaskArg](argEncoded)
var previewData = %* {
"links": %*[]
}
if arg.links == "":
arg.finish(previewData)
return
let parsedWhiteListUrls = parseJson(arg.whiteListedUrls)
let parsedWhiteListImgExtensions = arg.whiteListedImgExtensions.split(",")
for link in arg.links.split(" "):
if link == "":
continue
let uri = parseUri(link)
let path = uri.path
let domain = uri.hostname.toLower()
let isSupportedImage = any(parsedWhiteListImgExtensions, proc (extenstion: string): bool = path.endsWith(extenstion))
let isListed = parsedWhiteListUrls.hasKey(domain)
let isProfileLink = path.startsWith(profileLinkPrefix)
let processUrl = isListed or isSupportedImage
if domain == "" or processUrl == false:
continue
let canUnfurl = parsedWhiteListUrls{domain}.getBool() or (isSupportedImage and arg.unfurlImages)
let responseJson = %*{
"link": link,
"success": true,
"unfurl": canUnfurl,
"isStatusDeepLink": false,
"result": %*{}
}
if canUnfurl == false:
previewData["links"].add(responseJson)
continue
#1. if it's an image, we use httpclient to validate the url
if isSupportedImage:
#TODO: validate image url using HEAD request
responseJson["result"] = %*{
"site": domain,
"thumbnailUrl": link,
"contentType": "image/" & path.split(".")[^1]
}
previewData["links"].add(responseJson)
continue
#2. Process whitelisted url
#status deep links are handled internally
if domain == StatusInternalLink or domain == StatusExternalLink:
responseJson["success"] = %true
responseJson["isStatusDeepLink"] = %true
responseJson["result"] = %*{
"site": domain,
"contentType": "text/html"
}
previewData["links"].add(responseJson)
continue
#other links are handled by status-go
try:
let response = status_go_chat.getLinkPreviewData(link)
responseJson["result"] = response.result
responseJson["success"] = %true
except:
responseJson["success"] = %false
previewData["links"].add(responseJson)
let tpl: tuple[previewData: JsonNode, uuid: string] = (previewData, arg.uuid)
arg.finish(tpl)
#################################################
# Async get first unseen message id

View File

@ -58,7 +58,6 @@ const SIGNAL_MESSAGE_DELIVERED* = "messageDelivered"
const SIGNAL_MESSAGE_EDITED* = "messageEdited"
const SIGNAL_ENVELOPE_SENT* = "envelopeSent"
const SIGNAL_ENVELOPE_EXPIRED* = "envelopeExpired"
const SIGNAL_MESSAGE_LINK_PREVIEW_DATA_LOADED* = "messageLinkPreviewDataLoaded"
const SIGNAL_RELOAD_MESSAGES* = "reloadMessages"
const SIGNAL_URLS_UNFURLED* = "urlsUnfurled"
const SIGNAL_GET_MESSAGE_FINISHED* = "getMessageFinished"
@ -121,10 +120,6 @@ type
chatId*: string
message*: MessageDto
LinkPreviewDataArgs* = ref object of Args
response*: JsonNode
uuid*: string
LinkPreviewV2DataArgs* = ref object of Args
linkPreviews*: Table[string, LinkPreview]
@ -810,32 +805,6 @@ QtObject:
except Exception as e:
error "error: ", procName="onGetFirstUnseenMessageIdFor", errName = e.name, errDesription = e.msg
proc onAsyncGetLinkPreviewData*(self: Service, response: string) {.slot.} =
let responseObj = response.parseJson
if (responseObj.kind != JObject):
info "expected response is not a json object", methodName="onAsyncGetLinkPreviewData"
return
let args = LinkPreviewDataArgs(
response: responseObj["previewData"],
uuid: responseObj["uuid"].getStr()
)
self.events.emit(SIGNAL_MESSAGE_LINK_PREVIEW_DATA_LOADED, args)
proc asyncGetLinkPreviewData*(self: Service, links: string, uuid: string, whiteListedSites: string, whiteListedImgExtensions: string, unfurlImages: bool): string =
let arg = AsyncGetLinkPreviewDataTaskArg(
tptr: cast[ByteAddress](asyncGetLinkPreviewDataTask),
vptr: cast[ByteAddress](self.vptr),
slot: "onAsyncGetLinkPreviewData",
links: links,
whiteListedUrls: whiteListedSites,
whiteListedImgExtensions: whiteListedImgExtensions,
unfurlImages: unfurlImages,
uuid: uuid
)
self.threadpool.start(arg)
return $genOid()
proc getTextUrls*(self: Service, text: string): seq[string] =
try:
let response = status_go.getTextUrls(text)

View File

@ -42,21 +42,6 @@ QtObject:
proc init*(self: Service) =
discard
proc getLinkPreviewWhitelist*(self: Service): string =
try:
let response = status_privacy.getLinkPreviewWhitelist()
if(response.result.kind != JArray):
var errMsg = "response is not an array"
if(response.result.contains("error")):
errMsg = response.result["error"].getStr
error "error: ", procName="getLinkPreviewWhitelist", errDesription = errMsg
return
return $(response.result)
except Exception as e:
error "error: ", procName="getLinkPreviewWhitelist", errName = e.name, errDesription = e.msg
proc getDefaultAccount(self: Service): string =
try:
let response = status_eth.getAccounts()

View File

@ -149,9 +149,6 @@ proc createGroupChatFromInvitation*(groupName: string, chatId: string, adminPK:
let payload = %* [groupName, chatId, adminPK]
result = callPrivateRPC("createGroupChatFromInvitation".prefix, payload)
proc getLinkPreviewData*(link: string): RpcResponse[JsonNode] {.raises: [Exception].} =
result = callPrivateRPC("getLinkPreviewData".prefix, %* [link])
proc getMembers*(communityId, chatId: string): RpcResponse[JsonNode] {.raises: [Exception].} =
result = callPrivateRPC("chat_getMembers", %* [communityId, chatId])

View File

@ -17,7 +17,3 @@ proc changeDatabasePassword*(keyUID: string, oldHashedPassword: string, newHashe
except RpcException as e:
error "error", methodName = "changeDatabasePassword", exception=e.msg
raise newException(RpcException, e.msg)
proc getLinkPreviewWhitelist*(): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* []
result = callPrivateRPC("getLinkPreviewWhitelist".prefix, payload)

View File

@ -1,7 +1,9 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import shared.views.chat 1.0
import shared.stores 1.0
SplitView {
@ -14,20 +16,10 @@ SplitView {
"unfurled": true,
"immutable": false,
"empty": false,
"url": "https://www.youtube.com/watch?v=9bZkp7q19f0",
"url": "",
"previewType": 1,
"standardPreview": {
"hostname": "www.youtube.com",
"title": "PSY - GANGNAM STYLE(강남스타일) M/V",
"description": "PSY - I LUV IT M/V @ https://youtu.be/Xvjnoagk6GU PSY - New Face M/V @https://youtu.be/OwJPPaEyqhI PSY - 8TH ALBUM '4X2=8' on iTunes @ https://smarturl.it/PSY_8thAlbum PSY - GANGNAM STYLE(강남스타일) on iTunes @ http://smarturl.it/PsyGangnam #PSY #싸이 #GANGNAMSTYLE #강남스타일 More about PSY@ http://www.psyp...",
"linkType": 0,
},
"standardPreviewThumbnail": {
"width": 480,
"height": 360,
"url": "https://i.ytimg.com/vi/9bZkp7q19f0/hqdefault.jpg",
"dataUri": "https://i.ytimg.com/vi/9bZkp7q19f0/hqdefault.jpg",
},
"standardPreview": {},
"standardPreviewThumbnail": {},
"statusContactPreview": {},
"statusContactPreviewThumbnail": {},
"statusCommunityPreview": {},
@ -47,7 +39,7 @@ SplitView {
preview1.standardPreview.hostname = "www.youtube.com"
preview1.standardPreview.title = "PSY - GANGNAM STYLE(강남스타일) M/V"
preview1.standardPreview.description = "PSY - I LUV IT M/V @ https://youtu.be/Xvjnoagk6GU PSY - New Face M/V @https://youtu.be/OwJPPaEyqhI PSY - 8TH ALBUM '4X2=8' on iTunes @ https://smarturl.it/PSY_8thAlbum PSY - GANGNAM STYLE(강남스타일) on iTunes @ http://smarturl.it/PsyGangnam #PSY #싸이 #GANGNAMSTYLE #강남스타일 More about PSY@ http://www.psyp..."
preview1.standardPreview.standardLinkType = 0
preview1.standardPreview.linkType = 0
preview1.standardPreviewThumbnail.width = 480
preview1.standardPreviewThumbnail.height = 360
preview1.standardPreviewThumbnail.url = "https://i.ytimg.com/vi/9bZkp7q19f0/hqdefault.jpg"
@ -127,7 +119,7 @@ SplitView {
store: {}
messageStore: {}
linkPreviewModel: mockedLinkPreviewModel
localUnfurlLinks: {}
gifLinks: [ "https://media.tenor.com/qN_ytiwLh24AAAAC/cold.gif" ]
isCurrentUser: true
onImageClicked: {
@ -151,6 +143,23 @@ SplitView {
checked: linksMessageView.isCurrentUser
onToggled: linksMessageView.isCurrentUser = !linksMessageView.isCurrentUser
}
Label {
text: qsTr("GIF unfuring settings")
}
CheckBox {
text: qsTr("Enabled")
checked: RootStore.gifUnfurlingEnabled
onToggled: RootStore.gifUnfurlingEnabled = !RootStore.gifUnfurlingEnabled
}
CheckBox {
text: qsTr("Never ask about GIF unfurling again")
checked: RootStore.neverAskAboutUnfurlingAgain
onClicked: RootStore.neverAskAboutUnfurlingAgain = !RootStore.neverAskAboutUnfurlingAgain
}
Button {
text: qsTr("Reset local `askAboutUnfurling` setting")
onClicked: linksMessageView.resetLocalAskAboutUnfurling()
}
}
}
}

View File

@ -62,9 +62,8 @@ SplitView {
}
Component.onCompleted: {
RootStore.isGifWidgetEnabled = true
RootStore.isWalletEnabled = true
RootStore.isTenorWarningAccepted = true
RootStore.gifUnfurlingEnabled = true
RootStore.getSelectedTextWithFormationChars = rootStoreMock.getSelectedTextWithFormationChars
RootStore.gifColumnA = rootStoreMock.gifColumnA
rootStoreMock.ready = true

View File

@ -702,7 +702,7 @@ Item {
property ListModel gifColumnA: ListModel {}
readonly property var formationChars: (["*", "`", "~"])
property bool isTenorWarningAccepted: true
property bool gifUnfurlingEnabled: true
function getSelectedTextWithFormationChars(messageInputField) {
let i = 1
let text = ""
@ -723,9 +723,8 @@ Item {
}
Component.onCompleted: {
RootStore.isGifWidgetEnabled = true
RootStore.isWalletEnabled = true
RootStore.isTenorWarningAccepted = rootStoreMock.isTenorWarningAccepted
RootStore.gifUnfurlingEnabled = rootStoreMock.gifUnfurlingEnabled
RootStore.getSelectedTextWithFormationChars = rootStoreMock.getSelectedTextWithFormationChars
RootStore.gifColumnA = rootStoreMock.gifColumnA

View File

@ -4,12 +4,12 @@ import QtQuick 2.14
QtObject {
property var userProfileInst
property bool isTenorWarningAccepted
property bool isGifWidgetEnabled
property bool gifUnfurlingEnabled
property bool isWalletEnabled
property var getSelectedTextWithFormationChars
property var gifColumnA
property var currentCurrency
property bool neverAskAboutUnfurlingAgain: false
property var currencyStore
property var history
@ -32,4 +32,9 @@ QtObject {
function copyToClipboard(text) {
console.warn("STUB: copyToClipboard:", text)
}
function setNeverAskAboutUnfurlingAgain(value) {
console.log("STUB: setNeverAskAboutUnfurlingAgain:", value)
neverAskAboutUnfurlingAgain = value
}
}

View File

@ -112,7 +112,7 @@ generatedAccounts_ListView = {"container": statusDesktop_mainWindow, "objectName
displayMessageLinkPreviewItem = {"container": statusDesktop_mainWindow, "objectName": "displayMessageLinkPreviewsItem", "type": "StatusListItem"}
linkPreviewSwitch = {"container": statusDesktop_mainWindow, "objectName": "MessagingView_showMessageLinksSwitch", "type": "StatusSwitch", "visible": True}
imageUnfurlingItem = {"container": statusDesktop_mainWindow, "objectName": "imageUnfurlingItem", "type": "StatusListItem"}
tenorGifsPreviewSwitchItem = {"container": statusDesktop_mainWindow, "objectName": "MessagingView_sitesListView_StatusListItem_tenor_gifs_subdomain", "type": "StatusListItem"}
showGifPreviewsSwitch = {"container": settingsContentBase_ScrollView, "id": "showGifPreviewsSwitch", "type": "StatusSwitch", "unnamed": 1, "visible": True}
contacts_listItem_btn = {"container": statusDesktop_mainWindow, "objectName": "MessagingView_ContactsListItem_btn", "type": "StatusContactRequestsIndicatorListItem"}
settingsContentBaseScrollView_StatusScrollBar = {"container": settingsContentBase_ScrollView, "occurrence": 3, "type": "StatusScrollBar", "unnamed": 1, "visible": True}

View File

@ -95,12 +95,13 @@ Feature: Status Desktop community messages
And the user sends a chat message "history"
When the user clears chat history
Then the chat is cleared
@mayfail
Scenario: The user can send a GIF
Given the user opens app settings screen
And the user opens the messaging settings
When the user activates the link preview if it is deactivated
And the user activates tenor GIFs preview
#When the user activates the link preview if it is deactivated
When the user activates tenor GIFs preview
And the user opens the community named "test_community"
Then the user lands on the community named "test_community"
When the user sends a GIF message

View File

@ -40,7 +40,7 @@ Control {
property string messageAttachments: ""
property var reactionIcons: []
property var linkPreviewModel
property var localUnfurlLinks
property var gifLinks
property string messageId: ""
property bool editMode: false
@ -357,10 +357,11 @@ Control {
Loader {
id: linksLoader
Layout.fillWidth: true
Layout.preferredHeight: implicitHeight
active: !root.editMode &&
((!!root.linkPreviewModel && root.linkPreviewModel.count > 0)
|| (!!root.localUnfurlLinks && root.localUnfurlLinks.length > 0))
visible: active
|| (!!root.gifLinks && root.gifLinks.length > 0))
visible: active
}
Loader {
id: transactionBubbleLoader

View File

@ -166,12 +166,6 @@ QtObject {
return msg
}
function getLinkPreviewData(url, uuid) {
if(!messageModule)
return
return messageModule.getLinkPreviewData(url, uuid)
}
function requestMoreMessages() {
if(!messageModule)
return

View File

@ -168,7 +168,7 @@ Item {
}
Connections {
enabled: !root.rootStore.privacyModule.urlUnfurlingMode === Constants.UrlUnfurlingModeDisableAll
enabled: root.rootStore.privacyModule.urlUnfurlingMode !== Constants.UrlUnfurlingModeDisableAll
target: d
function onUpdateLinkPreviewsRequested() {
d.updateLinkPreviews()

View File

@ -34,7 +34,6 @@ QtObject {
readonly property string activityCenter: "activityCenter"
readonly property string nodeManagement: "nodeManagement"
readonly property string onlineUsers: "onlineUsers"
readonly property string gifWidget: "gifWidget"
readonly property string communitiesPortal: "communitiesPortal"
readonly property string communityPermissions: "communityPermissions"
readonly property string discordImportTool: "discordImportTool"
@ -144,9 +143,6 @@ QtObject {
else if (feature === experimentalFeatures.onlineUsers) {
localAccountSensitiveSettings.showOnlineUsers = !localAccountSensitiveSettings.showOnlineUsers
}
else if (feature === experimentalFeatures.gifWidget) {
localAccountSensitiveSettings.isGifWidgetEnabled = !localAccountSensitiveSettings.isGifWidgetEnabled
}
}
function toggleFakeLoadingScreen() {

View File

@ -43,8 +43,4 @@ QtObject {
}
root.syncModule.enableAutomaticSelection(checked)
}
function getLinkPreviewWhitelist() {
return root.privacyModule.getLinkPreviewWhitelist()
}
}

View File

@ -342,6 +342,32 @@ SettingsContentBase {
}
}
// SYNC WAKU SECTION
StatusListItem {
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: Style.current.padding
anchors.rightMargin: Style.current.padding
title: qsTr("History nodes")
label: root.messagingStore.getMailserverNameForNodeAddress(root.messagingStore.activeMailserver)
components: [
StatusIcon {
icon: "next"
color: Theme.palette.baseColor1
}
]
onClicked: Global.openPopup(wakuStoreModalComponent)
}
Component {
id: wakuStoreModalComponent
WakuStoreModal {
messagingStore: root.messagingStore
advancedStore: root.advancedStore
}
}
StatusSectionHeadline {
anchors.left: parent.left
anchors.right: parent.right

View File

@ -33,39 +33,6 @@ SettingsContentBase {
spacing: 2 * Constants.settingsSection.itemSpacing
width: root.contentWidth
function switchOffPreviewableSites() {
//update all models
localAccountSensitiveSettings.displayChatImages = false
for (let i = 0; i < previewableSites.count; i++) {
let item = previewableSites.get(i)
RootStore.updateWhitelistedUnfurlingSites(item.address, false)
}
}
function buildPreviewablesSitesJSON() {
let whitelistAsString = root.messagingStore.getLinkPreviewWhitelist()
if(whitelistAsString == "")
return
if (!localAccountSensitiveSettings.whitelistedUnfurlingSites) {
localAccountSensitiveSettings.whitelistedUnfurlingSites = {}
}
let anyWhitelisted = false
let whitelist = JSON.parse(whitelistAsString)
whitelist.forEach(entry => {
entry.isWhitelisted = !!localAccountSensitiveSettings.whitelistedUnfurlingSites[entry.address]
if(entry.isWhitelisted) anyWhitelisted = true
})
return [anyWhitelisted, whitelist]
}
function populatePreviewableSites() {
const [anyWhitelisted, whitelist] = buildPreviewablesSitesJSON()
previewableSites.populateModel(whitelist)
previewableSites.anyWhitelisted = anyWhitelisted
}
ButtonGroup {
id: showProfilePictureToGroup
}
@ -104,45 +71,7 @@ SettingsContentBase {
}
}
// Open Message Links With
StatusBaseText {
Layout.topMargin: Constants.settingsSection.itemSpacing
Layout.fillWidth: true
Layout.leftMargin: Style.current.padding
Layout.rightMargin: Style.current.padding
text: qsTr("Open Message Links With")
font.pixelSize: 15
color: Theme.palette.directColor1
}
SettingsRadioButton {
Layout.fillWidth: true
Layout.leftMargin: Style.current.padding
Layout.rightMargin: Style.current.padding
label: qsTr("Status Browser")
group: browserGroup
checked: localAccountSensitiveSettings.openLinksInStatus
onClicked: {
localAccountSensitiveSettings.openLinksInStatus = true
}
}
SettingsRadioButton {
Layout.topMargin: Constants.settingsSection.itemSpacing / 2
Layout.fillWidth: true
Layout.leftMargin: Style.current.padding
Layout.rightMargin: Style.current.padding
label: qsTr("System Default Browser")
group: browserGroup
checked: !localAccountSensitiveSettings.openLinksInStatus
onClicked: {
localAccountSensitiveSettings.openLinksInStatus = false
}
}
Separator {
id: separator1
Layout.topMargin: Constants.settingsSection.itemSpacing
Layout.fillWidth: true
}
@ -239,194 +168,5 @@ SettingsContentBase {
root.messagingStore.privacyModule.urlUnfurlingMode = Constants.UrlUnfurlingModeDisableAll
}
}
// MESSAGE LINK PREVIEWS
StatusListItem {
Layout.fillWidth: true
objectName: "displayMessageLinkPreviewsItem"
title: qsTr("Display Message Link Previews")
implicitHeight: 64
components: [
StatusSwitch {
id: showMessageLinksSwitch
objectName: "MessagingView_showMessageLinksSwitch"
checked: previewableSites.anyWhitelisted || localAccountSensitiveSettings.displayChatImages
onToggled: {
if (!checked) {
generalColumn.switchOffPreviewableSites()
}
}
}
]
onClicked: {
showMessageLinksSwitch.toggle()
if (!showMessageLinksSwitch.checked) {
generalColumn.switchOffPreviewableSites()
}
}
}
Component.onCompleted: {
populatePreviewableSites()
}
StatusSectionHeadline {
id: labelWebsites
visible: showMessageLinksSwitch.checked
Layout.fillWidth: true
Layout.leftMargin: Style.current.padding
Layout.rightMargin: Style.current.padding
text: qsTr("Fine tune which sites to allow link previews")
}
Column {
id: siteColumn
visible: showMessageLinksSwitch.checked
Layout.fillWidth: true
ListModel {
id: previewableSites
function populateModel(jsonModel) {
// add/update rows
Object.entries(jsonModel)
.forEach(([index, newRow]) => {
var existingRow = previewableSites.get(index)
let isRowIdentical = existingRow != undefined && Object.entries(newRow)
.every(([key, value]) => value == existingRow[key])
if(!isRowIdentical) {
previewableSites.set(index, newRow)
}
})
// remove rows that are not in the new model
if(previewableSites.count > jsonModel.length) {
let rowsToDelete = previewableSites.count - jsonModel.length
previewableSites.remove(jsonModel.length - 1, rowsToDelete)
}
}
property bool anyWhitelisted: false
}
Connections {
target: Global
function onSettingsLoaded() {
generalColumn.populatePreviewableSites()
}
}
Connections {
target: localAccountSensitiveSettings
function onWhitelistedUnfurlingSitesChanged() {
generalColumn.populatePreviewableSites()
}
}
// Manually add switch for the image unfurling
StatusListItem {
objectName: "imageUnfurlingItem"
width: parent.width
implicitHeight: 64
title: qsTr("Image unfurling")
subTitle: qsTr("All images (links that contain an image extension) will be downloaded and displayed")
// TODO find a better icon for this
asset.name: Style.svg('globe')
asset.isImage: true
components: [
StatusSwitch {
id: imageSwitch
checked: localAccountSensitiveSettings.displayChatImages
onToggled: {
localAccountSensitiveSettings.displayChatImages = !localAccountSensitiveSettings.displayChatImages
}
}
]
onClicked: {
localAccountSensitiveSettings.displayChatImages = !localAccountSensitiveSettings.displayChatImages
}
}
Repeater {
id: sitesListView
model: previewableSites
delegate: Component {
StatusListItem {
objectName: "MessagingView_sitesListView_StatusListItem_" + model.title.replace(/ /g, "_").toLowerCase()
width: parent.width
implicitHeight: 64
title: model.title
subTitle: model.address
asset.name: {
let filename;
switch (model.title.toLowerCase()) {
case "youtube":
case "youtube shortener":
filename = "youtube"; break;
case "github":
filename = "github"; break;
case "medium":
filename = "medium"; break;
case "tenor gifs subdomain":
filename = "tenor"; break;
case "giphy gifs":
case "giphy gifs shortener":
case "giphy gifs subdomain":
filename = "giphy"; break;
case "github":
filename = "github"; break;
case "status":
filename = "status"; break;
// TODO get a good default icon
default: filename = "../globe"
}
return Style.svg(`linkPreviewThumbnails/${filename}`)
}
asset.isImage: true
components: [
StatusSwitch {
id: siteSwitch
checked: !!model.isWhitelisted
onToggled: {
RootStore.updateWhitelistedUnfurlingSites(model.address, checked)
}
}
]
onClicked: {
RootStore.updateWhitelistedUnfurlingSites(model.address, !model.isWhitelisted)
}
}
}
}
} // Site Column
Separator {
id: separator3
visible: siteColumn.visible
Layout.fillWidth: true
}
// SYNC WAKU SECTION
StatusListItem {
Layout.fillWidth: true
title: qsTr("History nodes")
label: root.messagingStore.getMailserverNameForNodeAddress(root.messagingStore.activeMailserver)
components: [
StatusIcon {
icon: "next"
color: Theme.palette.baseColor1
}
]
onClicked: Global.openPopup(wakuStoreModalComponent)
}
Component {
id: wakuStoreModalComponent
WakuStoreModal {
messagingStore: root.messagingStore
advancedStore: root.advancedStore
}
}
}
}

View File

@ -163,7 +163,7 @@ QtObject {
property var savedAddressesModel: walletSectionSavedAddresses.model
readonly property bool showBrowserSelector: localAccountSensitiveSettings.showBrowserSelector
readonly property bool openLinksInStatus: localAccountSensitiveSettings.openLinksInStatus
readonly property bool openLinksInStatus: false
property var allNetworks: networksModule.all

View File

@ -271,7 +271,7 @@ Item {
}
function onOpenLinkWithConfirmation(link: string, domain: string) {
if (appMainLocalSettings.whitelistedUnfurledDomains.includes(domain) || !!localAccountSensitiveSettings.whitelistedUnfurlingSites[domain])
if (appMainLocalSettings.whitelistedUnfurledDomains.includes(domain))
globalConns.onOpenLink(link)
else
popups.openConfirmExternalLinkPopup(link, domain)
@ -1597,55 +1597,6 @@ Item {
}
}
Component.onCompleted: {
const whitelist = appMain.rootStore.messagingStore.getLinkPreviewWhitelist()
try {
const whiteListedSites = JSON.parse(whitelist)
let settingsUpdated = false
// Add Status links to whitelist
whiteListedSites.push({title: "Status", address: Constants.deepLinkPrefix, imageSite: false})
whiteListedSites.push({title: "Status", address: Constants.externalStatusLink, imageSite: false})
let settings = localAccountSensitiveSettings.whitelistedUnfurlingSites
if (!settings) {
settings = {}
}
// Set Status links as true. We intercept those URLs so it is privacy-safe
if (!settings[Constants.deepLinkPrefix] || !settings[Constants.externalStatusLink]) {
settings[Constants.deepLinkPrefix] = true
settings[Constants.externalStatusLink] = true
settingsUpdated = true
}
const whitelistedHostnames = []
// Add whitelisted sites in to app settings that are not already there
whiteListedSites.forEach(site => {
if (!settings.hasOwnProperty(site.address)) {
settings[site.address] = false
settingsUpdated = true
}
whitelistedHostnames.push(site.address)
})
// Remove any whitelisted sites from app settings that don't exist in the
// whitelist from status-go
Object.keys(settings).forEach(settingsHostname => {
if (!whitelistedHostnames.includes(settingsHostname)) {
delete settings[settingsHostname]
settingsUpdated = true
}
})
if (settingsUpdated) {
localAccountSensitiveSettings.whitelistedUnfurlingSites = settings
}
} catch (e) {
console.error('Could not parse the whitelist for sites', e)
}
Global.settingsLoaded()
}
Loader {
id: keycardPopupForAuthentication
active: false

View File

@ -1472,7 +1472,7 @@ Rectangle {
objectName: "gifPopupButton"
implicitHeight: 32
implicitWidth: 32
visible: !isEdit && RootStore.isGifWidgetEnabled
visible: !isEdit
icon.name: "gif"
icon.color: (hovered || highlighted) ? Theme.palette.primaryColor1
: Theme.palette.baseColor1

View File

@ -61,7 +61,7 @@ Popup {
onAboutToShow: {
searchBox.text = ""
searchBox.input.edit.forceActiveFocus()
if (RootStore.isTenorWarningAccepted) {
if (RootStore.gifUnfurlingEnabled) {
RootStore.getTrendingsGifs()
}
}
@ -94,7 +94,7 @@ Popup {
SearchBox {
id: searchBox
placeholderText: qsTr("Search")
enabled: RootStore.isTenorWarningAccepted
enabled: RootStore.gifUnfurlingEnabled
anchors.right: parent.right
anchors.rightMargin: gifHeader.headerMargin
anchors.top: parent.top
@ -136,7 +136,7 @@ Popup {
Loader {
id: gifsLoader
active: root.opened && RootStore.isTenorWarningAccepted
active: root.opened && RootStore.gifUnfurlingEnabled
Layout.fillWidth: true
Layout.alignment: Qt.AlignTop | Qt.AlignLeft
Layout.preferredHeight: {
@ -160,7 +160,7 @@ Popup {
onClicked: {
toggleCategory(GifPopupDefinitions.Category.Trending)
}
enabled: RootStore.isTenorWarningAccepted
enabled: RootStore.gifUnfurlingEnabled
}
StatusTabBarIconButton {
@ -169,7 +169,7 @@ Popup {
onClicked: {
toggleCategory(GifPopupDefinitions.Category.Recent)
}
enabled: RootStore.isTenorWarningAccepted
enabled: RootStore.gifUnfurlingEnabled
}
StatusTabBarIconButton {
@ -178,7 +178,7 @@ Popup {
onClicked: {
toggleCategory(GifPopupDefinitions.Category.Favorite)
}
enabled: RootStore.isTenorWarningAccepted
enabled: RootStore.gifUnfurlingEnabled
}
}
}
@ -200,7 +200,7 @@ Popup {
sourceComponent: ConfirmationPopup {
visible: true
}
active: !RootStore.isTenorWarningAccepted
active: !RootStore.gifUnfurlingEnabled
}
Component {

View File

@ -79,8 +79,7 @@ Popup {
size: StatusBaseButton.Size.Small
onClicked: {
RootStore.setIsTenorWarningAccepted(true)
RootStore.updateWhitelistedUnfurlingSites("media.tenor.com", true)
RootStore.setGifUnfurlingEnabled(true)
RootStore.getTrendingsGifs()
root.close()
}

View File

@ -17,9 +17,7 @@ QtObject {
property bool notificationSoundsEnabled: !!appSettingsInst ? appSettingsInst.notificationSoundsEnabled : true
property bool neverAskAboutUnfurlingAgain: !!accountSensitiveSettings ? accountSensitiveSettings.neverAskAboutUnfurlingAgain : false
property bool isGifWidgetEnabled: !!accountSensitiveSettings ? accountSensitiveSettings.isGifWidgetEnabled : false
property bool isTenorWarningAccepted: !!accountSensitiveSettings ? accountSensitiveSettings.isTenorWarningAccepted : false
property bool displayChatImages: !!accountSensitiveSettings ? accountSensitiveSettings.displayChatImages : false
property bool gifUnfurlingEnabled: !!accountSensitiveSettings ? accountSensitiveSettings.gifUnfurlingEnabled : false
property CurrenciesStore currencyStore: CurrenciesStore {}
property string currentCurrency: Global.appIsReady? walletSectionInst.currentCurrency : ""
@ -93,8 +91,8 @@ QtObject {
localAccountSensitiveSettings.neverAskAboutUnfurlingAgain = value;
}
function setIsTenorWarningAccepted(value) {
localAccountSensitiveSettings.isTenorWarningAccepted = value;
function setGifUnfurlingEnabled(value) {
localAccountSensitiveSettings.gifUnfurlingEnabled = value
}
function copyToClipboard(text) {
@ -122,22 +120,6 @@ QtObject {
chatSectionChatContentInputAreaInst.getTrendingsGifs()
}
function updateWhitelistedUnfurlingSites(hostname, whitelisted) {
// no way to send update notification for individual array entries
let settings = localAccountSensitiveSettings.whitelistedUnfurlingSites
if (!settings)
settings = {}
if (settings[hostname] === whitelisted)
return
settings[hostname] = whitelisted
localAccountSensitiveSettings.whitelistedUnfurlingSites = settings
if(hostname === "media.tenor.com" && whitelisted === false)
RootStore.setIsTenorWarningAccepted(false)
}
function getRecentsGifs() {
if (chatSectionChatContentInputAreaInst)
chatSectionChatContentInputAreaInst.getRecentsGifs()

View File

@ -20,7 +20,7 @@ Flow {
required property var messageStore
required property var linkPreviewModel
required property var localUnfurlLinks
required property var gifLinks
required property bool isCurrentUser
@ -29,57 +29,31 @@ Flow {
signal imageClicked(var image, var mouse, var imageSource, string url)
function resetLocalAskAboutUnfurling() {
d.localAskAboutUnfurling = true
}
spacing: 12
//TODO: remove once GIF previews are unfurled sender side
Repeater {
QtObject {
id: d
property bool localAskAboutUnfurling: true
}
Loader {
visible: active
active: root.gifLinks && root.gifLinks.length > 0
&& !RootStore.gifUnfurlingEnabled
&& d.localAskAboutUnfurling && !RootStore.neverAskAboutUnfurlingAgain
sourceComponent: enableLinkComponent
}
Repeater {
id: tempRepeater
visible: !RootStore.neverAskAboutUnfurlingAgain
model: linksModel
delegate: Loader {
id: tempLoader
required property var result
required property string link
required property int index
required property bool unfurl
required property bool success
required property bool isStatusDeepLink
readonly property bool isImage: result.contentType && result.contentType.startsWith("image/") ? true : false
readonly property bool isUserProfileLink: link.toLowerCase().startsWith(Constants.userLinkPrefix.toLowerCase())
readonly property string thumbnailUrl: result && result.thumbnailUrl ? result.thumbnailUrl : ""
readonly property string title: result && result.title ? result.title : ""
readonly property string hostname: result && result.site ? result.site : ""
readonly property bool animated: isImage && result.contentType === "image/gif" // TODO support more types of animated images?
StateGroup {
//Using StateGroup as a warkardound for https://bugreports.qt.io/browse/QTBUG-47796
id: linkPreviewLoaderState
states: [
State {
name: "askToEnableUnfurling"
when: !tempLoader.unfurl
PropertyChanges { target: tempLoader; sourceComponent: enableLinkComponent }
},
State {
name: "loadImage"
when: tempLoader.unfurl && tempLoader.isImage
PropertyChanges { target: tempLoader; sourceComponent: unfurledImageComponent }
},
State {
name: "userProfileLink"
when: unfurl && isUserProfileLink && isStatusDeepLink
PropertyChanges { target: tempLoader; sourceComponent: unfurledProfileLinkComponent }
}
// State {
// name: "statusInvitation"
// when: unfurl && isStatusDeepLink
// PropertyChanges { target: tempLoader; sourceComponent: invitationBubble }
// }
]
}
}
model: RootStore.gifUnfurlingEnabled ? gifLinks : []
delegate: gifComponent
}
Repeater {
@ -117,7 +91,6 @@ Flow {
readonly property int thumbnailHeight: standardPreviewThumbnail ? standardPreviewThumbnail.height : ""
readonly property string thumbnailUrl: standardPreviewThumbnail ? standardPreviewThumbnail.url : ""
readonly property string thumbnailDataUri: standardPreviewThumbnail ? standardPreviewThumbnail.dataUri : ""
property bool animated: false
asynchronous: true
active: unfurled && !empty
@ -180,7 +153,7 @@ Flow {
//TODO: Remove this once we have gif support in new unfurling flow
Component {
id: unfurledImageComponent
id: gifComponent
CalloutCard {
implicitWidth: linkImage.width
implicitHeight: linkImage.height
@ -188,19 +161,19 @@ Flow {
StatusChatImageLoader {
id: linkImage
readonly property bool globalAnimationEnabled: root.messageStore.playAnimation
readonly property string urlLink: link
readonly property string urlLink: modelData
property bool localAnimationEnabled: true
objectName: "LinksMessageView_unfurledImageComponent_linkImage"
anchors.centerIn: parent
source: thumbnailUrl
source: urlLink
imageWidth: 300
isCurrentUser: root.isCurrentUser
playing: globalAnimationEnabled && localAnimationEnabled
isOnline: root.store.mainModuleInst.isOnline
asynchronous: true
isAnimated: animated
isAnimated: true
onClicked: {
if (isAnimated && !playing)
if (!playing)
localAnimationEnabled = true
else
root.imageClicked(linkImage.imageAlias, mouse, source, urlLink)
@ -239,86 +212,19 @@ Flow {
}
}
}
// Code below can be dropped when New unfurling flow suppports GIFs.
Component {
id: invitationBubble
InvitationBubbleView {
property var invitationData: root.store.getLinkDataForStatusLinks(link)
store: root.store
communityId: invitationData && invitationData.communityData ? invitationData.communityData.communityId : ""
communityData: invitationData && invitationData.communityData ? invitationData.communityData : null
anchors.left: parent.left
visible: !!invitationData
loading: invitationData.fetching
onInvitationDataChanged: {
if (!invitationData)
linksModel.remove(index)
}
Connections {
enabled: !!invitationData && invitationData.fetching
target: root.store.communitiesModuleInst
function onCommunityAdded(communityId: string) {
if (communityId !== invitationData.communityId) return
invitationData = root.store.getLinkDataForStatusLinks(link)
}
}
}
}
QtObject {
id: d
readonly property string uuid: Utils.uuid()
readonly property string whiteListedImgExtensions: Constants.acceptedImageExtensions.toString()
readonly property string whiteListedUrls: JSON.stringify(localAccountSensitiveSettings.whitelistedUnfurlingSites)
readonly property string getLinkPreviewDataId: {
if (root.localUnfurlLinks === "")
return ""
return root.messageStore.messageModule.getLinkPreviewData(root.localUnfurlLinks,
d.uuid,
whiteListedUrls,
whiteListedImgExtensions,
localAccountSensitiveSettings.displayChatImages)
}
onGetLinkPreviewDataIdChanged: {
linkFetchConnections.enabled = root.localUnfurlLinks !== ""
}
}
Connections {
id: linkFetchConnections
enabled: false
target: root.messageStore.messageModule
function onLinkPreviewDataWasReceived(previewData, uuid) {
if (d.uuid !== uuid)
return
linkFetchConnections.enabled = false
try {
linksModel.rawData = JSON.parse(previewData)
}
catch(e) {
console.warn("error parsing link preview data", previewData)
}
}
}
ListModel {
id: linksModel
property var rawData
onRawDataChanged: {
linksModel.clear()
rawData.links.forEach((link) => {
linksModel.append(link)
})
}
}
Component {
id: enableLinkComponent
Rectangle {
id: enableLinkRoot
width: 300
height: childrenRect.height + Style.current.smallPadding
implicitWidth: 300
implicitHeight: childrenRect.height + Style.current.smallPadding
radius: 16
border.width: 1
border.color: Style.current.border
color: Style.current.background
StatusFlatRoundButton {
anchors.top: parent.top
anchors.topMargin: Style.current.smallPadding
@ -327,7 +233,7 @@ Flow {
icon.width: 20
icon.height: 20
icon.name: "close-circle"
onClicked: linksModel.remove(index)
onClicked: d.localAskAboutUnfurling = false
}
Image {
id: unfurlingImage
@ -340,8 +246,7 @@ Flow {
}
StatusBaseText {
id: enableText
text: isImage ? qsTr("Enable automatic image unfurling") :
qsTr("Enable link previews in chat?")
text: qsTr("Enable automatic GIF unfurling")
horizontalAlignment: Text.AlignHCenter
width: parent.width
wrapMode: Text.WordWrap
@ -398,7 +303,7 @@ Flow {
anchors.centerIn: parent
anchors.verticalCenterOffset: Style.current.halfPadding
font: dontAskBtn.font
color: dontAskBtn.enabled ? dontAskBtn.textColor : dontAskBtn.disabledTextColor
color: dontAskBtn.textColor
text: qsTr("Don't ask me again")
}
}

View File

@ -66,19 +66,11 @@ Loader {
// These 2 properties can be dropped when the new unfurling flow supports GIFs
property var links
readonly property var localUnfurlLinks: {
readonly property var gifLinks: {
if (!links)
return []
const separator = " "
const arr = links.split(separator)
const filtered = arr.filter(value => {
const v = value.toLowerCase()
return localAccountSensitiveSettings.gifUnfurlingEnabled && value.endsWith('.gif')
})
const out = filtered.join(separator)
return out
const arr = links.split(" ")
return arr.filter(value => value.toLowerCase().endsWith('.gif'))
}
property string responseToMessageWithId: ""
@ -535,7 +527,7 @@ Loader {
resendError: root.resendError
reactionsModel: root.reactionsModel
linkPreviewModel: root.linkPreviewModel
localUnfurlLinks: root.localUnfurlLinks
gifLinks: root.gifLinks
showHeader: root.shouldRepeatHeader || dateGroupLabel.visible || isAReply ||
root.prevMessageContentType === Constants.messageContentType.systemMessagePrivateGroupType ||
@ -762,7 +754,7 @@ Loader {
LinksMessageView {
id: linksMessageView
linkPreviewModel: root.linkPreviewModel
localUnfurlLinks: root.localUnfurlLinks
gifLinks: root.gifLinks
messageStore: root.messageStore
store: root.rootStore
isCurrentUser: root.amISender

View File

@ -943,7 +943,6 @@ QtObject {
readonly property int maxNumberOfPins: 3
readonly property string dataImagePrefix: "data:image"
readonly property var acceptedImageExtensions: [".png", ".jpg", ".jpeg", ".svg", ".gif"]
readonly property var acceptedDragNDropImageExtensions: [".png", ".jpg", ".jpeg", ".heif", ".tif", ".tiff"]
readonly property string mentionSpanTag: `<span style="background-color: ${Style.current.mentionBgColor};"><a style="color:${Style.current.mentionColor};text-decoration:none" href='http://'>`

View File

@ -18,7 +18,6 @@ QtObject {
signal openLinkInBrowser(string link)
signal openChooseBrowserPopup(string link)
signal settingsLoaded()
signal openCreateChatView()
signal closeCreateChatView()

View File

@ -322,10 +322,6 @@ QtObject {
return link.includes(Constants.deepLinkPrefix) || link.includes(Constants.externalStatusLink)
}
function hasImageExtension(url) {
return Constants.acceptedImageExtensions.some(ext => url.toLowerCase().includes(ext))
}
function removeGifUrls(message) {
return message.replace(/(?:https?|ftp):\/\/[\n\S]*(\.gif)+/gm, '');
}

View File

@ -204,9 +204,6 @@ StatusWindow {
if(localAccountSensitiveSettings.recentEmojis === "") {
localAccountSensitiveSettings.recentEmojis = [];
}
if (localAccountSensitiveSettings.whitelistedUnfurlingSites === "") {
localAccountSensitiveSettings.whitelistedUnfurlingSites = {};
}
if (localAccountSensitiveSettings.hiddenCommunityWelcomeBanners === "") {
localAccountSensitiveSettings.hiddenCommunityWelcomeBanners = [];
}