feat(desktop/general): app support for status-im:// URIs - mac
Fixes #3375
This commit is contained in:
parent
7c74a0942d
commit
698374b91c
|
@ -16,6 +16,19 @@
|
|||
<string>StatusDev</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>status.im.customurl</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>status-im</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0.0</string>
|
||||
<key>IFMajorVersion</key>
|
||||
|
|
13
Info.plist
13
Info.plist
|
@ -16,6 +16,19 @@
|
|||
<string>Status</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>status.im.customurl</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>status-im</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0.0</string>
|
||||
<key>IFMajorVersion</key>
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
// To Do: Currently this gets added to eahc file that its imported into need to create as enums in calss when some works on this potentially
|
||||
#include <QString>
|
||||
|
||||
const QString CHAT_SECTION_ID = "chat";
|
||||
const QString CHAT_SECTION_NAME = "Chat";
|
||||
const QString CHAT_SECTION_ICON = "chat";
|
||||
|
||||
|
|
|
@ -0,0 +1,132 @@
|
|||
import NimQml, strutils, chronicles
|
||||
import ../eventemitter
|
||||
|
||||
import ../../global/app_signals
|
||||
|
||||
logScope:
|
||||
topics = "urls-manager"
|
||||
|
||||
const UriFormatBrowserShort = "status-im://b/"
|
||||
const UriFormatBrowserLong = "status-im://browser/"
|
||||
|
||||
const UriFormatUserProfileShort = "status-im://u/"
|
||||
const UriFormatUserProfileLong = "status-im://user/"
|
||||
|
||||
const UriFormatPrivateChatShort = "status-im://pm/"
|
||||
const UriFormatPrivateChatLong = "status-im://private-message/"
|
||||
|
||||
const UriFormatPublicChatShort = "status-im://p/"
|
||||
const UriFormatPublicChatLong = "status-im://public/"
|
||||
|
||||
const UriFormatGroupChatShort = "status-im://g/"
|
||||
const UriFormatGroupChatLong = "status-im://group/"
|
||||
|
||||
const UriFormatCommunityRequestsShort = "status-im://cr/"
|
||||
const UriFormatCommunityRequestsLong = "status-im://community-requests/"
|
||||
|
||||
const UriFormatCommunityShort = "status-im://c/"
|
||||
const UriFormatCommunityLong = "status-im://community/"
|
||||
|
||||
const UriFormatCommunityChannelShort = "status-im://cc/"
|
||||
const UriFormatCommunityChannelLong = "status-im://community-channel/"
|
||||
|
||||
QtObject:
|
||||
type UrlsManager* = ref object of QObject
|
||||
events: EventEmitter
|
||||
|
||||
proc setup(self: UrlsManager, urlSchemeEvent: StatusEvent) =
|
||||
self.QObject.setup
|
||||
signalConnect(urlSchemeEvent, "urlActivated(QString)", self, "onUrlActivated(QString)", 2)
|
||||
|
||||
proc delete*(self: UrlsManager) =
|
||||
self.QObject.delete
|
||||
|
||||
proc newUrlsManager*(events: EventEmitter, urlSchemeEvent: StatusEvent): UrlsManager =
|
||||
new(result)
|
||||
result.setup(urlSchemeEvent)
|
||||
result.events = events
|
||||
|
||||
proc prepareGroupChatDetails(self: UrlsManager, urlQuery: string, data: var StatusUrlArgs) =
|
||||
var urlParams = rsplit(urlQuery, "/u/")
|
||||
if(urlParams.len > 0):
|
||||
data.groupName = urlParams[0]
|
||||
urlParams.delete(0)
|
||||
data.listOfUserIds = urlParams
|
||||
else:
|
||||
info "wrong url format for group chat"
|
||||
|
||||
proc onUrlActivated*(self: UrlsManager, url: string) {.slot.} =
|
||||
var data = StatusUrlArgs()
|
||||
|
||||
# Open `url` in the app's browser
|
||||
if url.startsWith(UriFormatBrowserShort):
|
||||
data.action = StatusUrlAction.OpenLinkInBrowser
|
||||
data.url = url[UriFormatBrowserShort.len .. url.len-1]
|
||||
elif url.startsWith(UriFormatBrowserLong):
|
||||
data.action = StatusUrlAction.OpenLinkInBrowser
|
||||
data.url = url[UriFormatBrowserLong.len .. url.len-1]
|
||||
|
||||
# Display user profile popup for user with `user_pk` or `ens_name`
|
||||
elif url.startsWith(UriFormatUserProfileShort):
|
||||
data.action = StatusUrlAction.DisplayUserProfile
|
||||
data.userId = url[UriFormatUserProfileShort.len .. url.len-1]
|
||||
elif url.startsWith(UriFormatUserProfileLong):
|
||||
data.action = StatusUrlAction.DisplayUserProfile
|
||||
data.userId = url[UriFormatUserProfileLong.len .. url.len-1]
|
||||
|
||||
# Open or create 1:1 chat with user with `user_pk` or `ens_name`
|
||||
elif url.startsWith(UriFormatPrivateChatShort):
|
||||
data.action = StatusUrlAction.OpenOrCreatePrivateChat
|
||||
data.chatId = url[UriFormatPrivateChatShort.len .. url.len-1]
|
||||
elif url.startsWith(UriFormatPrivateChatLong):
|
||||
data.action = StatusUrlAction.OpenOrCreatePrivateChat
|
||||
data.chatId = url[UriFormatPrivateChatLong.len .. url.len-1]
|
||||
|
||||
# Open public chat with `chat_key`
|
||||
elif url.startsWith(UriFormatPublicChatShort):
|
||||
data.action = StatusUrlAction.OpenOrJoinPublicChat
|
||||
data.chatId = url[UriFormatPublicChatShort.len .. url.len-1]
|
||||
elif url.startsWith(UriFormatPublicChatLong):
|
||||
data.action = StatusUrlAction.OpenOrJoinPublicChat
|
||||
data.chatId = url[UriFormatPublicChatLong.len .. url.len-1]
|
||||
|
||||
# Open a group chat with named `group_name`, adding up to 19 participants with their `user_pk` or `ens_name`.
|
||||
# Group chat may have up to 20 participants including the admin of a group
|
||||
elif url.startsWith(UriFormatGroupChatShort):
|
||||
data.action = StatusUrlAction.OpenOrCreateGroupChat
|
||||
let urlQuery = url[UriFormatGroupChatShort.len .. url.len-1]
|
||||
self.prepareGroupChatDetails(urlQuery, data)
|
||||
elif url.startsWith(UriFormatGroupChatLong):
|
||||
data.action = StatusUrlAction.OpenOrCreateGroupChat
|
||||
let urlQuery = url[UriFormatGroupChatLong.len .. url.len-1]
|
||||
self.prepareGroupChatDetails(urlQuery, data)
|
||||
|
||||
# Send a join community request to a community with `community_key`
|
||||
elif url.startsWith(UriFormatCommunityRequestsShort):
|
||||
data.action = StatusUrlAction.RequestToJoinCommunity
|
||||
data.communityId = url[UriFormatCommunityRequestsShort.len .. url.len-1]
|
||||
elif url.startsWith(UriFormatCommunityRequestsLong):
|
||||
data.action = StatusUrlAction.RequestToJoinCommunity
|
||||
data.communityId = url[UriFormatCommunityRequestsLong.len .. url.len-1]
|
||||
|
||||
# Open community with `community_key`
|
||||
elif url.startsWith(UriFormatCommunityShort):
|
||||
data.action = StatusUrlAction.OpenCommunity
|
||||
data.communityId = url[UriFormatCommunityShort.len .. url.len-1]
|
||||
elif url.startsWith(UriFormatCommunityLong):
|
||||
data.action = StatusUrlAction.OpenCommunity
|
||||
data.communityId = url[UriFormatCommunityLong.len .. url.len-1]
|
||||
|
||||
# Open community which has a channel with `channel_key` and makes that channel active
|
||||
elif url.startsWith(UriFormatCommunityChannelShort):
|
||||
data.action = StatusUrlAction.OpenCommunityChannel
|
||||
data.chatId = url[UriFormatCommunityChannelShort.len .. url.len-1]
|
||||
elif url.startsWith(UriFormatCommunityChannelLong):
|
||||
data.action = StatusUrlAction.OpenCommunityChannel
|
||||
data.chatId = url[UriFormatCommunityChannelLong.len .. url.len-1]
|
||||
|
||||
else:
|
||||
info "Unsupported deep link structure: ", url
|
||||
return
|
||||
|
||||
self.events.emit(SIGNAL_STATUS_URL_REQUESTED, data)
|
|
@ -1,10 +1,11 @@
|
|||
import task_runner
|
||||
import NimQml, task_runner
|
||||
import
|
||||
eventemitter,
|
||||
./fleets/fleet_configuration,
|
||||
./tasks/marathon,
|
||||
./tasks/threadpool,
|
||||
./signals/signals_manager
|
||||
./signals/signals_manager,
|
||||
./custom_urls/urls_manager
|
||||
|
||||
export eventemitter
|
||||
export marathon, task_runner, signals_manager, fleet_configuration
|
||||
|
@ -14,6 +15,7 @@ type StatusFoundation* = ref object
|
|||
fleetConfiguration*: FleetConfiguration
|
||||
threadpool*: ThreadPool
|
||||
signalsManager*: SignalsManager
|
||||
urlsManager: UrlsManager
|
||||
|
||||
proc newStatusFoundation*(fleetConfig: string): StatusFoundation =
|
||||
result = StatusFoundation()
|
||||
|
@ -25,4 +27,8 @@ proc newStatusFoundation*(fleetConfig: string): StatusFoundation =
|
|||
proc delete*(self: StatusFoundation) =
|
||||
self.threadpool.teardown()
|
||||
self.fleetConfiguration.delete()
|
||||
self.signalsManager.delete()
|
||||
self.signalsManager.delete()
|
||||
self.urlsManager.delete()
|
||||
|
||||
proc initUrlSchemeManager*(self: StatusFoundation, urlSchemeEvent: StatusEvent) =
|
||||
self.urlsManager = newUrlsManager(self.events, urlSchemeEvent)
|
|
@ -21,4 +21,28 @@ type
|
|||
const SIGNAL_MAKE_SECTION_CHAT_ACTIVE* = "makeSectionChatActive"
|
||||
## Emmiting this signal will switch the app to passed `sectionId`, after that if `chatId` is set
|
||||
## it will make that chat an active one and at the end if `messageId` is set it will point to
|
||||
## that message.
|
||||
## that message.
|
||||
|
||||
|
||||
type
|
||||
StatusUrlAction* {.pure.} = enum
|
||||
OpenLinkInBrowser = 0
|
||||
DisplayUserProfile,
|
||||
OpenOrCreatePrivateChat,
|
||||
OpenOrJoinPublicChat,
|
||||
OpenOrCreateGroupChat,
|
||||
RequestToJoinCommunity,
|
||||
OpenCommunity,
|
||||
OpenCommunityChannel
|
||||
|
||||
type
|
||||
StatusUrlArgs* = ref object of Args
|
||||
action*: StatusUrlAction
|
||||
communityId*:string
|
||||
chatId*: string
|
||||
url*: string
|
||||
userId*: string # can be public key or ens name
|
||||
groupName*: string
|
||||
listOfUserIds*: seq[string] # used for creating group chat
|
||||
|
||||
const SIGNAL_STATUS_URL_REQUESTED* = "statusUrlRequested"
|
|
@ -20,4 +20,7 @@ method providerDidLoad*(self: AccessInterface) {.base.} =
|
|||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method viewDidLoad*(self: AccessInterface) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method openUrl*(self: AccessInterface, url: string) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
|
@ -92,3 +92,6 @@ method dappsDidLoad*(self: Module) =
|
|||
|
||||
method viewDidLoad*(self: Module) =
|
||||
self.checkIfModuleDidLoad()
|
||||
|
||||
method openUrl*(self: Module, url: string) =
|
||||
self.view.sendOpenUrlSignal(url)
|
|
@ -19,3 +19,7 @@ QtObject:
|
|||
|
||||
proc load*(self: View) =
|
||||
self.delegate.viewDidLoad()
|
||||
|
||||
proc openUrl*(self: View, url: string) {.signal.}
|
||||
proc sendOpenUrlSignal*(self: View, url: string) =
|
||||
self.openUrl(url)
|
|
@ -14,6 +14,7 @@ type
|
|||
value: string
|
||||
uuid: string
|
||||
chainId: int
|
||||
reason: string
|
||||
|
||||
const lookupContactTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
|
||||
let arg = decode[LookupContactTaskArg](argEncoded)
|
||||
|
@ -35,7 +36,8 @@ const lookupContactTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
|
|||
let output = %*{
|
||||
"id": pubkey,
|
||||
"address": address,
|
||||
"uuid": arg.uuid
|
||||
"uuid": arg.uuid,
|
||||
"reason": arg.reason
|
||||
}
|
||||
arg.finish(output)
|
||||
|
||||
|
|
|
@ -107,6 +107,9 @@ proc mainProc() =
|
|||
# Register events objects
|
||||
let dockShowAppEvent = newStatusDockShowAppEventObject(singletonInstance.engine)
|
||||
let osThemeEvent = newStatusOSThemeEventObject(singletonInstance.engine)
|
||||
let urlSchemeEvent = newStatusUrlSchemeEventObject()
|
||||
|
||||
statusFoundation.initUrlSchemeManager(urlSchemeEvent)
|
||||
|
||||
if not defined(macosx):
|
||||
app.icon(app.applicationDirPath & statusAppIconPath)
|
||||
|
@ -125,6 +128,7 @@ proc mainProc() =
|
|||
|
||||
app.installEventFilter(dockShowAppEvent)
|
||||
app.installEventFilter(osThemeEvent)
|
||||
app.installEventFilter(urlSchemeEvent)
|
||||
|
||||
defer:
|
||||
info "shutting down..."
|
||||
|
|
Loading…
Reference in New Issue