fix(LinkPreviews): Fixing gif hyperlink detection in StatusChatInput

The link preview model can be filtered, but the hyperlink detection needs an unfiltered model to properly highlight all URLs. This brought in the need to separate the urls model and the link previews model.
This commit is contained in:
Alex Jbanca 2023-10-23 19:21:35 +03:00 committed by Alex Jbanca
parent b9867c2463
commit 8ac6eb8916
8 changed files with 136 additions and 11 deletions

View File

@ -111,7 +111,7 @@ proc setLinkPreviewEnabledForThisMessage*(self: Controller, enabled: bool) =
self.delegate.setAskToEnableLinkPreview(false)
proc resetLinkPreviews(self: Controller) =
self.delegate.setUrls(@[])
self.delegate.setLinkPreviewUrls(@[])
self.linkPreviewCache.clear()
self.linkPreviewCurrentMessageSetting = self.linkPreviewPersistentSetting
self.delegate.setAskToEnableLinkPreview(false)
@ -201,12 +201,15 @@ proc canAskToEnableLinkPreview(self: Controller): bool =
proc setText*(self: Controller, text: string, unfurlNewUrls: bool) =
if text == "":
self.resetLinkPreviews()
self.delegate.setUrls(@[])
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)
self.delegate.setLinkPreviewUrls(supportedUrls)
let newUrls = self.linkPreviewCache.unknownUrls(supportedUrls)
let askToEnableLinkPreview = len(newUrls) > 0 and self.canAskToEnableLinkPreview()
self.delegate.setAskToEnableLinkPreview(askToEnableLinkPreview)

View File

@ -102,7 +102,7 @@ method setText*(self: AccessInterface, text: string, unfurlUrls: bool) {.base.}
method getPlainText*(self: AccessInterface): string =
raise newException(ValueError, "No implementation available")
method setUrls*(self: AccessInterface, urls: seq[string]) {.base.} =
method setLinkPreviewUrls*(self: AccessInterface, urls: seq[string]) {.base.} =
raise newException(ValueError, "No implementation available")
method updateLinkPreviewsFromCache*(self: AccessInterface, urls: seq[string]) {.base.} =
@ -128,3 +128,6 @@ method setAskToEnableLinkPreview*(self: AccessInterface, value: bool) =
method setLinkPreviewEnabledForThisMessage*(self: AccessInterface, enabled: bool) =
raise newException(ValueError, "No implementation available")
method setUrls*(self: AccessInterface, urls: seq[string]) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -166,8 +166,8 @@ method clearLinkPreviewCache*(self: Module) {.slot.} =
method updateLinkPreviewsFromCache*(self: Module, urls: seq[string]) =
self.view.updateLinkPreviewsFromCache(urls)
method setUrls*(self: Module, urls: seq[string]) =
self.view.setUrls(urls)
method setLinkPreviewUrls*(self: Module, urls: seq[string]) =
self.view.setLinkPreviewUrls(urls)
method linkPreviewsFromCache*(self: Module, urls: seq[string]): Table[string, LinkPreview] =
return self.controller.linkPreviewsFromCache(urls)
@ -186,3 +186,6 @@ method setAskToEnableLinkPreview*(self: Module, value: bool) =
method setLinkPreviewEnabledForThisMessage*(self: Module, value: bool) =
self.controller.setLinkPreviewEnabledForThisMessage(value)
method setUrls*(self: Module, urls: seq[string]) =
self.view.setUrls(urls)

View File

@ -0,0 +1,94 @@
import NimQml, tables, sequtils
type
ModelRole {.pure.} = enum
Url = UserRole + 1
QtObject:
type
Model* = ref object of QAbstractListModel
items: seq[string]
proc delete*(self: Model) =
self.items = @[]
self.QAbstractListModel.delete
proc setup(self: Model) =
self.QAbstractListModel.setup
proc newUrlsModel*(): Model =
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
method roleNames(self: Model): Table[int, string] =
{
ModelRole.Url.int:"url"
}.toTable
method data(self: Model, index: QModelIndex, role: int): QVariant =
if (not index.isValid):
return
if (index.row < 0 or index.row >= self.items.len):
return
let enumRole = role.ModelRole
case enumRole:
of ModelRole.Url:
let item = self.items[index.row]
result = newQVariant(item)
else:
result = newQVariant()
proc removeItemWithIndex(self: Model, ind: int) =
if(ind < 0 or ind >= self.items.len):
return
let parentModelIndex = newQModelIndex()
defer: parentModelIndex.delete
self.beginRemoveRows(parentModelIndex, ind, ind)
self.items.delete(ind)
self.endRemoveRows()
proc setUrls*(self: Model, urls: seq[string]) =
var itemsToInsert: seq[string]
var indexesToRemove: seq[int]
#remove
for i in 0 ..< self.items.len:
if not urls.anyIt(it == self.items[i]):
indexesToRemove.add(i)
while indexesToRemove.len > 0:
let index = pop(indexesToRemove)
self.removeItemWithIndex(index)
# Move or insert
for i in 0 ..< urls.len:
if self.items.anyIt(it == urls[i]):
continue
itemsToInsert.add(urls[i])
if itemsToInsert.len > 0:
let parentModelIndex = newQModelIndex()
defer: parentModelIndex.delete
self.beginInsertRows(parentModelIndex, self.items.len, self.items.len + itemsToInsert.len - 1)
self.items = self.items & itemsToInsert
self.endInsertRows()
self.countChanged()

View File

@ -2,6 +2,7 @@ import NimQml
import ./io_interface
import ./gif_column_model
import ./preserved_properties
import ./urls_model
import ../../../../../../app/modules/shared_models/link_preview_model as link_preview_model
import ../../../../../../app_service/service/gif/dto
@ -17,6 +18,8 @@ QtObject:
preservedPropertiesVariant: QVariant
linkPreviewModel: link_preview_model.Model
linkPreviewModelVariant: QVariant
urlsModel: urls_model.Model
urlsModelVariant: QVariant
askToEnableLinkPreview: bool
proc delete*(self: View) =
@ -24,10 +27,12 @@ QtObject:
self.gifColumnAModel.delete
self.gifColumnBModel.delete
self.gifColumnCModel.delete
self.preservedProperties.delete
self.preservedPropertiesVariant.delete
self.linkPreviewModel.delete
self.preservedProperties.delete
self.linkPreviewModelVariant.delete
self.linkPreviewModel.delete
self.urlsModelVariant.delete
self.urlsModel.delete
proc newView*(delegate: io_interface.AccessInterface): View =
new(result, delete)
@ -41,6 +46,8 @@ QtObject:
result.preservedPropertiesVariant = newQVariant(result.preservedProperties)
result.linkPreviewModel = newLinkPreviewModel()
result.linkPreviewModelVariant = newQVariant(result.linkPreviewModel)
result.urlsModel = newUrlsModel()
result.urlsModelVariant = newQVariant(result.urlsModel)
result.askToEnableLinkPreview = false
proc load*(self: View) =
@ -223,7 +230,7 @@ QtObject:
let linkPreviews = self.delegate.linkPreviewsFromCache(urls)
self.linkPreviewModel.updateLinkPreviews(linkPreviews)
proc setUrls*(self: View, urls: seq[string]) =
proc setLinkPreviewUrls*(self: View, urls: seq[string]) =
self.linkPreviewModel.setUrls(urls)
if(self.delegate.getLinkPreviewEnabled()):
self.updateLinkPreviewsFromCache(urls)
@ -253,8 +260,19 @@ QtObject:
self.delegate.setLinkPreviewEnabledForThisMessage(enabled)
let links = self.linkPreviewModel.getLinks()
self.linkPreviewModel.clearItems()
self.setUrls(links)
self.setLinkPreviewUrls(links)
self.loadLinkPreviews(links)
proc removeLinkPreviewData*(self: View, index: int) {.slot.} =
self.linkPreviewModel.removePreviewData(index)
proc urlsModelChanged(self: View) {.signal.}
proc getUrlsModel*(self: View): QVariant {.slot.} =
return self.urlsModelVariant
proc setUrls*(self: View, urls: seq[string]) =
self.urlsModel.setUrls(urls)
QtProperty[QVariant] urlsModel:
read = getUrlsModel
notify = urlsModelChanged

View File

@ -112,6 +112,7 @@ SplitView {
enabled: enabledCheckBox.checked
linkPreviewModel: fakeLinksModel
urlsModel: fakeLinksModel
askToEnableLinkPreview: askToEnableLinkPreviewSwitch.checked
onAskToEnableLinkPreviewChanged: {
if(askToEnableLinkPreview) {

View File

@ -255,6 +255,7 @@ Item {
store: root.rootStore
usersStore: d.activeUsersStore
linkPreviewModel: d.activeChatContentModule.inputAreaModule.linkPreviewModel
urlsModel: d.activeChatContentModule.inputAreaModule.urlsModel
askToEnableLinkPreview: {
if(!d.activeChatContentModule || !d.activeChatContentModule.inputAreaModule || !d.activeChatContentModule.inputAreaModule.preservedProperties)
return false

View File

@ -65,6 +65,8 @@ Rectangle {
property var linkPreviewModel: null
property var urlsModel: null
property bool askToEnableLinkPreview: false
property var imageErrorMessageLocation: StatusChatInput.ImageErrorMessageLocation.Top // TODO: Remove this property?
@ -1366,7 +1368,7 @@ Rectangle {
TextEditHyperlinksFormatter {
id: hyperlinksFormatter
textEdit: messageInputField
urlModel: control.linkPreviewModel
urlModel: control.urlsModel
highlightUrl: linkPreviewArea.hoveredUrl
enabled: messageInputField.enabled && messageInputField.textFormat == TextEdit.RichText
}