feat(new-links): Parse url data and display

Fixes: #10852
This commit is contained in:
Boris Melnik 2023-07-27 14:21:25 +03:00
parent b9fbb7c50c
commit 43a5d7eeeb
18 changed files with 416 additions and 26 deletions

View File

@ -33,6 +33,7 @@ import ../../app_service/service/gif/service as gif_service
import ../../app_service/service/ens/service as ens_service
import ../../app_service/service/community_tokens/service as tokens_service
import ../../app_service/service/network_connection/service as network_connection_service
import ../../app_service/service/shared_urls/service as shared_urls_service
import ../modules/shared_modules/keycard_popup/module as keycard_shared_module
import ../modules/startup/module as startup_module
@ -99,6 +100,7 @@ type
ensService: ens_service.Service
tokensService: tokens_service.Service
networkConnectionService: network_connection_service.Service
sharedUrlsService: shared_urls_service.Service
# Modules
startupModule: startup_module.AccessInterface
@ -228,7 +230,7 @@ proc newAppController*(statusFoundation: StatusFoundation): AppController =
result.transactionService, result.tokenService, result.settingsService, result.walletAccountService)
result.providerService = provider_service.newService(statusFoundation.events, statusFoundation.threadpool, result.ensService)
result.networkConnectionService = network_connection_service.newService(statusFoundation.events, result.walletAccountService, result.networkService, result.nodeService)
result.sharedUrlsService = shared_urls_service.newService(statusFoundation.events, statusFoundation.threadpool)
# Modules
result.startupModule = startup_module.newModule[AppController](
result,
@ -277,7 +279,8 @@ proc newAppController*(statusFoundation: StatusFoundation): AppController =
result.networkService,
result.generalService,
result.keycardService,
result.networkConnectionService
result.networkConnectionService,
result.sharedUrlsService
)
# Do connections

View File

@ -25,6 +25,8 @@ import communities/module as communities_module
import node_section/module as node_section_module
import communities/tokens/models/token_item
import network_connection/module as network_connection_module
import shared_urls/module as shared_urls_module
import ../../../app_service/service/contacts/dto/contacts
import ../../../app_service/service/keychain/service as keychain_service
@ -59,6 +61,7 @@ import ../../../app_service/service/community_tokens/service as community_tokens
import ../../../app_service/service/network/service as network_service
import ../../../app_service/service/general/service as general_service
import ../../../app_service/service/keycard/service as keycard_service
import ../../../app_service/service/shared_urls/service as urls_service
import ../../../app_service/service/network_connection/service as network_connection_service
import ../../../app_service/common/types
import ../../../app_service/common/social_links
@ -102,6 +105,7 @@ type
keycardSharedModule: keycard_shared_module.AccessInterface
keycardSharedModuleKeycardSyncPurpose: keycard_shared_module.AccessInterface
networkConnectionModule: network_connection_module.AccessInterface
sharedUrlsModule: shared_urls_module.AccessInterface
moduleLoaded: bool
chatsLoaded: bool
communityDataLoaded: bool
@ -147,7 +151,8 @@ proc newModule*[T](
networkService: network_service.Service,
generalService: general_service.Service,
keycardService: keycard_service.Service,
networkConnectionService: network_connection_service.Service
networkConnectionService: network_connection_service.Service,
sharedUrlsService: urls_service.Service
): Module[T] =
result = Module[T]()
result.delegate = delegate
@ -214,6 +219,7 @@ proc newModule*[T](
messageService)
result.nodeSectionModule = node_section_module.newModule(result, events, settingsService, nodeService, nodeConfigurationService)
result.networkConnectionModule = network_connection_module.newModule(result, events, networkConnectionService)
result.sharedUrlsModule = shared_urls_module.newModule(result, events, sharedUrlsService)
method delete*[T](self: Module[T]) =
self.controller.delete
@ -233,6 +239,7 @@ method delete*[T](self: Module[T]) =
if not self.keycardSharedModuleKeycardSyncPurpose.isNil:
self.keycardSharedModuleKeycardSyncPurpose.delete
self.networkConnectionModule.delete
self.sharedUrlsModule.delete
self.view.delete
self.viewVariant.delete
@ -521,6 +528,7 @@ method load*[T](
# Load wallet last as it triggers events that are listened by other modules
self.walletSectionModule.load()
self.networkConnectionModule.load()
self.sharedUrlsModule.load()
# Set active section on app start
# If section is empty or profile then open the loading section until chats are loaded
@ -1250,6 +1258,16 @@ method onDisplayKeycardSharedModuleFlow*[T](self: Module[T]) =
self.view.emitDisplayKeycardSharedModuleFlow()
method activateStatusDeepLink*[T](self: Module[T], statusDeepLink: string) =
let urlData = self.sharedUrlsModule.parseSharedUrl(statusDeepLink)
if urlData.community.communityId != "":
self.onStatusUrlRequested(StatusUrlAction.OpenCommunity, urlData.community.communityId, "", "", "")
return
if urlData.contact.publicKey != "":
self.onStatusUrlRequested(StatusUrlAction.DisplayUserProfile, "", "", "", urlData.contact.publicKey)
return
if urlData.channel.uuid != "":
self.onStatusUrlRequested(StatusUrlAction.OpenCommunityChannel, "", urlData.channel.uuid, "", "")
return
let linkToActivate = self.urlsManager.convertExternalLinkToInternal(statusDeepLink)
self.urlsManager.onUrlActivated(linkToActivate)
@ -1262,3 +1280,4 @@ method windowActivated*[T](self: Module[T]) =
method windowDeactivated*[T](self: Module[T]) =
self.controller.speedupArchivesImport()

View File

@ -0,0 +1,40 @@
import stint
import ./io_interface
import ../../../core/signals/types
import ../../../core/eventemitter
import ../../../../app_service/service/shared_urls/service as urls_service
type
Controller* = ref object of RootObj
delegate: io_interface.AccessInterface
events: EventEmitter
sharedUrlsService: urls_service.Service
proc newController*(
delegate: io_interface.AccessInterface,
events: EventEmitter,
sharedUrlsService: urls_service.Service,
): Controller =
result = Controller()
result.delegate = delegate
result.events = events
result.sharedUrlsService = sharedUrlsService
proc delete*(self: Controller) =
discard
proc parseCommunitySharedUrl*(self: Controller, url: string): CommunityUrlDataDto =
let data = self.sharedUrlsService.parseSharedUrl(url)
return data.community
proc parseCommunityChannelSharedUrl*(self: Controller, url: string): CommunityChannelUrlDataDto =
let data = self.sharedUrlsService.parseSharedUrl(url)
return data.channel
proc parseContactSharedUrl*(self: Controller, url: string): ContactUrlDataDto =
let data = self.sharedUrlsService.parseSharedUrl(url)
return data.contact
proc parseSharedUrl*(self: Controller, url: string): UrlDataDto =
return self.sharedUrlsService.parseSharedUrl(url)

View File

@ -0,0 +1,32 @@
import NimQml, stint
import ../../../../app_service/service/shared_urls/service as urls_service
type
AccessInterface* {.pure inheritable.} = ref object of RootObj
method delete*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method load*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method viewDidLoad*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method parseCommunitySharedUrl*(self: AccessInterface, url: string): string {.base.} =
raise newException(ValueError, "No implementation available")
method parseCommunityChannelSharedUrl*(self: AccessInterface, url: string): string {.base.} =
raise newException(ValueError, "No implementation available")
method parseContactSharedUrl*(self: AccessInterface, url: string): string {.base.} =
raise newException(ValueError, "No implementation available")
method parseSharedUrl*(self: AccessInterface, url: string): UrlDataDto {.base.} =
raise newException(ValueError, "No implementation available")
# This way (using concepts) is used only for the modules managed by AppController
type
DelegateInterface* = concept c
c.mainDidLoad()

View File

@ -0,0 +1,65 @@
import NimQml, sequtils, stint
import io_interface, view, controller
import ../io_interface as delegate_interface
import ../../../../app_service/service/shared_urls/service as urls_service
import ../../../global/global_singleton
import ../../../core/eventemitter
export io_interface
type
Module* = ref object of io_interface.AccessInterface
delegate: delegate_interface.AccessInterface
controller: Controller
view: View
viewVariant: QVariant
moduleLoaded: bool
proc newModule*(
delegate: delegate_interface.AccessInterface,
events: EventEmitter,
sharedUrlsService: urls_service.Service,
): Module =
result = Module()
result.delegate = delegate
result.view = newView(result)
result.viewVariant = newQVariant(result.view)
result.controller = controller.newController(
result,
events,
sharedUrlsService,
)
result.moduleLoaded = false
method delete*(self: Module) =
self.view.delete
self.viewVariant.delete
self.controller.delete
method load*(self: Module) =
singletonInstance.engine.setRootContextProperty("sharedUrlsModule", self.viewVariant)
self.view.load()
method isLoaded*(self: Module): bool =
return self.moduleLoaded
method viewDidLoad*(self: Module) =
self.moduleLoaded = true
method parseSharedUrl*(self: Module, url: string): UrlDataDto =
return self.controller.parseSharedUrl(url)
method parseCommunitySharedUrl*(self: Module, url: string): string =
let communityData = self.controller.parseCommunitySharedUrl(url)
return $communityData
method parseCommunityChannelSharedUrl*(self: Module, url: string): string =
let channelData = self.controller.parseCommunityChannelSharedUrl(url)
return $channelData
method parseContactSharedUrl*(self: Module, url: string): string =
let contactData = self.controller.parseContactSharedUrl(url)
return $contactData

View File

@ -0,0 +1,28 @@
import NimQml, json, strutils, sequtils
import ./io_interface
QtObject:
type
View* = ref object of QObject
delegate: io_interface.AccessInterface
proc delete*(self: View) =
self.QObject.delete
proc newView*(delegate: io_interface.AccessInterface): View =
new(result, delete)
result.QObject.setup
result.delegate = delegate
proc load*(self: View) =
self.delegate.viewDidLoad()
proc parseCommunitySharedUrl*(self: View, url: string): string {.slot.} =
return self.delegate.parseCommunitySharedUrl(url)
proc parseCommunityChannelSharedUrl*(self: View, url: string): string {.slot.} =
return self.delegate.parseCommunityChannelSharedUrl(url)
proc parseContactSharedUrl*(self: View, url: string): string {.slot.} =
return self.delegate.parseContactSharedUrl(url)

View File

@ -273,4 +273,4 @@ QtObject:
## Signals for in app (ephemeral) notifications
proc showToastAccountAdded*(self: View, name: string) {.signal.}
proc showToastKeypairRenamed*(self: View, oldName: string, newName: string) {.signal.}
proc showToastKeypairRenamed*(self: View, oldName: string, newName: string) {.signal.}

View File

@ -0,0 +1,97 @@
{.used.}
import json, strformat, strutils
include ../../../common/json_utils
type CommunityUrlDataDto* = object
displayName*: string
description*: string
membersCount*: int
color*: string
tagIndices*: seq[int]
communityId*: string
type CommunityChannelUrlDataDto* = object
emoji*: string
displayName*: string
description*: string
color*: string
uuid*: string
type ContactUrlDataDto* = object
displayName*: string
description*: string
publicKey*: string
type UrlDataDto* = object
community*: CommunityUrlDataDto
channel*: CommunityChannelUrlDataDto
contact*: ContactUrlDataDto
proc toCommunityUrlDataDto*(jsonObj: JsonNode): CommunityUrlDataDto =
result = CommunityUrlDataDto()
discard jsonObj.getProp("displayName", result.displayName)
discard jsonObj.getProp("description", result.description)
discard jsonObj.getProp("membersCount", result.membersCount)
discard jsonObj.getProp("color", result.color)
var tagIndicesObj: JsonNode
if (jsonObj.getProp("tagIndices", tagIndicesObj) and tagIndicesObj.kind == JArray):
for tagIndex in tagIndicesObj:
result.tagIndices.add(tagIndex.getInt)
discard jsonObj.getProp("communityId", result.communityId)
proc toCommunityChannelUrlDataDto*(jsonObj: JsonNode): CommunityChannelUrlDataDto =
result = CommunityChannelUrlDataDto()
discard jsonObj.getProp("displayName", result.displayName)
discard jsonObj.getProp("description", result.description)
discard jsonObj.getProp("emoji", result.emoji)
discard jsonObj.getProp("color", result.color)
discard jsonObj.getProp("uuid", result.uuid)
proc toContactUrlDataDto*(jsonObj: JsonNode): ContactUrlDataDto =
result = ContactUrlDataDto()
discard jsonObj.getProp("displayName", result.displayName)
discard jsonObj.getProp("description", result.description)
discard jsonObj.getProp("publicKey", result.publicKey)
proc toUrlDataDto*(jsonObj: JsonNode): UrlDataDto =
result = UrlDataDto()
var communityObj: JsonNode
if (jsonObj.getProp("community", communityObj)):
result.community = communityObj.toCommunityUrlDataDto()
var communityChannelObj: JsonNode
if (jsonObj.getProp("channel", communityChannelObj)):
result.channel = communityChannelObj.toCommunityChannelUrlDataDto()
var contactObj: JsonNode
if (jsonObj.getProp("contact", contactObj)):
result.contact = contactObj.toContactUrlDataDto()
proc `$`*(communityUrlDataDto: CommunityUrlDataDto): string =
var jsonObj = newJObject()
jsonObj["displayName"] = %* communityUrlDataDto.displayName
jsonObj["description"] = %* communityUrlDataDto.description
jsonObj["membersCount"] = %* communityUrlDataDto.membersCount
jsonObj["color"] = %* communityUrlDataDto.color
jsonObj["communityId"] = %* communityUrlDataDto.communityId
return $jsonObj
proc `$`*(communityChannelUrlDataDto: CommunityChannelUrlDataDto): string =
var jsonObj = newJObject()
jsonObj["displayName"] = %* communityChannelUrlDataDto.displayName
jsonObj["description"] = %* communityChannelUrlDataDto.description
jsonObj["emoji"] = %* communityChannelUrlDataDto.emoji
jsonObj["color"] = %* communityChannelUrlDataDto.color
jsonObj["uuid"] = %* communityChannelUrlDataDto.uuid
return $jsonObj
proc `$`*(contactUrlDataDto: ContactUrlDataDto): string =
var jsonObj = newJObject()
jsonObj["displayName"] = %* contactUrlDataDto.displayName
jsonObj["description"] = %* contactUrlDataDto.description
jsonObj["publicKey"] = %* contactUrlDataDto.publicKey
return $jsonObj

View File

@ -0,0 +1,34 @@
import NimQml, os, json, chronicles
import ../../../backend/general as status_general
import ../../../constants as app_constants
import ../../../app/core/eventemitter
import ../../../app/core/tasks/[qt, threadpool]
import ./dto/url_data as url_data_dto
export url_data_dto
logScope:
topics = "shared-urls-app-service"
QtObject:
type Service* = ref object of QObject
events: EventEmitter
threadpool: ThreadPool
proc newService*(events: EventEmitter, threadpool: ThreadPool): Service =
result = Service()
result.QObject.setup
result.events = events
proc parseSharedUrl*(self: Service, url: string): UrlDataDto =
try:
let response = status_general.parseSharedUrl(url)
if(response.result.contains("error")):
let errMsg = response.result["error"].getStr()
error "error while pasring shared url: ", errDesription = errMsg
return
return response.result.toUrlDataDto()
except Exception as e:
error "error while parsing shared url: ", msg = e.msg

View File

@ -81,4 +81,7 @@ proc initKeystore*(keystoreDir: string): RpcResponse[JsonNode] {.raises: [Except
proc backupData*(): RpcResponse[JsonNode] {.raises: [Exception].} =
let payload = %* []
result = callPrivateRPC("backupData".prefix, payload)
result = callPrivateRPC("backupData".prefix, payload)
proc parseSharedUrl*(url: string): RpcResponse[JsonNode] {.raises: [Exception].} =
result = callPrivateRPC("parseSharedURL".prefix, %*[url])

View File

@ -439,7 +439,7 @@ QtObject {
title: "Status",
callback: null,
fetching: true,
communityId: ""
communityData: null
}
// User profile
@ -455,26 +455,28 @@ QtObject {
}*/
// Community
result.communityId = Utils.getCommunityIdFromShareLink(link)
if(!result.communityId) return result
result.communityData = Utils.getCommunityDataFromSharedLink(link)
if(!result.communityData) return result
const communityName = getSectionNameById(result.communityId)
const communityName = getSectionNameById(result.communityData.communityId)
if (!communityName) {
// Unknown community, fetch the info if possible
root.requestCommunityInfo(result.communityId)
root.requestCommunityInfo(result.communityData.communityId)
result.title = qsTr("Join the %1 community").arg(result.communityData.displayName)
return result
}
result.title = qsTr("Join the %1 community").arg(communityName)
result.fetching = false
result.callback = function () {
const isUserMemberOfCommunity = isUserMemberOfCommunity(result.communityId)
const isUserMemberOfCommunity = isUserMemberOfCommunity(result.communityData.communityId)
if (isUserMemberOfCommunity) {
setActiveCommunity(result.communityId)
setActiveCommunity(result.communityData.communityId)
return
}
const userCanJoin = userCanJoin(result.communityId)
const userCanJoin = userCanJoin(result.communityData.communityId)
// TODO find what to do when you can't join
if (userCanJoin) {
requestToJoinCommunityWithAuthentication(userProfileInst.preferredName) // FIXME what addresses to share?
@ -493,7 +495,7 @@ QtObject {
return {
site: Constants.externalStatusLinkWithHttps,
title: result.title,
communityId: result.communityId,
communityData: result.communityData,
fetching: result.fetching,
thumbnailUrl: Style.png("status"),
contentType: "",

View File

@ -63,10 +63,17 @@ MembersSelectorBase {
property ListModel selectedMembers: ListModel {}
function lookupContact(value) {
let contactObj = Utils.parseContactUrl(value)
if (contactObj) {
processContact(contactObj)
return
}
value = Utils.dropUserLinkPrefix(value.trim())
if (Utils.isChatKey(value)) {
processContact(value)
processContact({publicKey: value})
return
}
@ -78,12 +85,19 @@ MembersSelectorBase {
root.suggestionsDialog.forceHide = false
}
function processContact(publicKey) {
const contactDetails = Utils.getContactDetailsAsJson(publicKey, false)
function processContact(contactData) {
// Open contact request if we have data from url
if (contactData.publicKey !== "" && contactData.displayName !== "") {
Global.openContactRequestPopupWithContactData(contactData,
popup => popup.closed.connect(root.rejected))
return
}
const contactDetails = Utils.getContactDetailsAsJson(contactData.publicKey, false)
if (contactDetails.publicKey === "") {
// not a valid key given
root.suggestionsDialog.forceHide = false
return
}

View File

@ -35,6 +35,7 @@ QtObject {
Global.openIncomingIDRequestPopup.connect(openIncomingIDRequestPopup)
Global.openInviteFriendsToCommunityPopup.connect(openInviteFriendsToCommunityPopup)
Global.openContactRequestPopup.connect(openContactRequestPopup)
Global.openContactRequestPopupWithContactData.connect(openContactRequestPopupWithContactData)
Global.openChooseBrowserPopup.connect(openChooseBrowserPopup)
Global.openDownloadModalRequested.connect(openDownloadModal)
Global.openImagePopup.connect(openImagePopup)
@ -195,6 +196,14 @@ QtObject {
openPopup(sendContactRequestPopupComponent, popupProperties, cb)
}
function openContactRequestPopupWithContactData(contactData, cb) {
const popupProperties = {
userPublicKey: contactData.publicKey,
userDisplayName: contactData.displayName
}
openPopup(sendContactRequestPopupComponent, popupProperties, cb)
}
function openPinnedMessagesPopup(store, messageStore, pinnedMessagesModel, messageToPin, chatId) {
openPopup(pinnedMessagesPopup, {
store: store,

View File

@ -35,6 +35,14 @@ StatusModal {
onAboutToShow: {
messageInput.input.edit.forceActiveFocus()
if (userDisplayName !== "" && userPublicKey !== "") {
d.updateContactDetails({
displayName: userDisplayName,
largeImage: "",
userIsEnsVerified: false
})
}
const contactDetails = Utils.getContactDetailsAsJson(userPublicKey, false)
if (contactDetails.displayName !== "") {

View File

@ -21,17 +21,18 @@ Control {
property var store
property string communityId
property bool loading: false
property var communityData
QtObject {
id: d
property var invitedCommunity
readonly property string communityName: !!d.invitedCommunity ? d.invitedCommunity.name : ""
readonly property string communityDescription: !!d.invitedCommunity ? d.invitedCommunity.description : ""
readonly property string communityName: !!d.invitedCommunity ? d.invitedCommunity.name : (communityData ? communityData.displayName : "")
readonly property string communityDescription: !!d.invitedCommunity ? d.invitedCommunity.description : (communityData ? communityData.description : "")
readonly property string communityImage: !!d.invitedCommunity ? d.invitedCommunity.image : ""
readonly property string communityColor: !!d.invitedCommunity ? d.invitedCommunity.color : ""
readonly property int communityNbMembers: !!d.invitedCommunity ? d.invitedCommunity.nbMembers : 0
readonly property string communityColor: !!d.invitedCommunity ? d.invitedCommunity.color : (communityData ? communityData.color : "")
readonly property int communityNbMembers: !!d.invitedCommunity ? d.invitedCommunity.nbMembers : (communityData ? communityData.membersCount : 0)
readonly property bool communityVerified: false //!!d.invitedCommunity ? d.invitedCommunity.verified : false TODO: add this to the community object if we should support verified communities
readonly property bool communityJoined: !!d.invitedCommunity ? d.invitedCommunity.joined : false
readonly property bool communitySpectated: !!d.invitedCommunity ? d.invitedCommunity.spectated : false
@ -135,7 +136,7 @@ Control {
isImage: true
}
visible: !root.loading
visible: d.communityColor && d.communityName
}
ColumnLayout {
@ -144,7 +145,7 @@ Control {
StatusBaseText {
Layout.fillWidth: true
text: root.loading ? qsTr("Community data not loaded yet.") : d.communityName
text: d.communityName
font.weight: Font.Bold
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
font.pixelSize: 17
@ -154,7 +155,7 @@ Control {
StatusBaseText {
Layout.fillWidth: true
text: root.loading ? qsTr("Please wait for the unfurl to show") : d.communityDescription
text: d.communityDescription
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
color: Theme.palette.directColor1
}
@ -162,7 +163,7 @@ Control {
StatusBaseText {
Layout.fillWidth: true
text: root.loading ? "" : qsTr("%n member(s)", "", d.communityNbMembers)
text: qsTr("%n member(s)", "", d.communityNbMembers)
font.pixelSize: 13
font.weight: Font.Medium
color: Theme.palette.baseColor1
@ -193,6 +194,7 @@ Control {
StatusBaseText {
anchors.centerIn: parent
anchors.verticalCenterOffset: d.radius/2
visible: !joinBtn.loading
font: joinBtn.font
color: joinBtn.enabled ? joinBtn.textColor : joinBtn.disabledTextColor
text: qsTr("Go to Community")

View File

@ -143,7 +143,8 @@ ColumnLayout {
property var invitationData: root.store.getLinkDataForStatusLinks(link)
store: root.store
communityId: invitationData ? invitationData.communityId : ""
communityId: invitationData && invitationData.communityData ? invitationData.communityData.communityId : ""
communityData: invitationData && invitationData.communityData ? invitationData.communityData : null
anchors.left: parent.left
visible: !!invitationData
loading: invitationData.fetching

View File

@ -39,6 +39,7 @@ QtObject {
signal openActivityCenterPopupRequested()
signal openSendIDRequestPopup(string publicKey, var cb)
signal openContactRequestPopup(string publicKey, var cb)
signal openContactRequestPopupWithContactData(var contactData, var cb)
signal removeContactRequested(string displayName, string publicKey)
signal openInviteFriendsToCommunityPopup(var community, var communitySectionModule, var cb)
signal openIncomingIDRequestPopup(string publicKey, var cb)

View File

@ -10,6 +10,7 @@ import StatusQ.Core.Utils 0.1 as StatusQUtils
QtObject {
property var mainModuleInst: typeof mainModule !== "undefined" ? mainModule : null
property var sharedUrlsModuleInst: typeof sharedUrlsModule !== "undefined" ? sharedUrlsModule : null
property var globalUtilsInst: typeof globalUtils !== "undefined" ? globalUtils : null
property var communitiesModuleInst: typeof communitiesModule !== "undefined" ? communitiesModule : null
@ -515,6 +516,22 @@ QtObject {
return communityKey
}
function getCommunityDataFromSharedLink(link) {
let index = link.lastIndexOf("/c/")
if (index === -1) {
return null
}
let communityDataString = sharedUrlsModuleInst.parseCommunitySharedUrl(link)
try {
let communityData = JSON.parse(communityDataString)
return communityData
} catch (e) {
console.warn("Error while parsing community data from url:", e.message)
return null
}
}
function changeCommunityKeyCompression(communityKey) {
return globalUtilsInst.changeCommunityKeyCompression(communityKey)
@ -669,6 +686,21 @@ QtObject {
return text
}
function parseContactUrl(link) {
let index = link.lastIndexOf("/u/")
if (index === -1) {
return null
}
let contactDataString = sharedUrlsModuleInst.parseContactSharedUrl(link)
try {
let contactObj = JSON.parse(contactDataString)
return contactObj
} catch (e) {
return null
}
}
function dropCommunityLinkPrefix(text) {
if (text.startsWith(Constants.communityLinkPrefix))
text = text.slice(Constants.communityLinkPrefix.length)