summaryrefslogtreecommitdiff
path: root/eventsview-plugins/eventsview-plugin-fediverse/fediverse-delegate.qml
diff options
context:
space:
mode:
Diffstat (limited to 'eventsview-plugins/eventsview-plugin-fediverse/fediverse-delegate.qml')
-rw-r--r--eventsview-plugins/eventsview-plugin-fediverse/fediverse-delegate.qml185
1 files changed, 185 insertions, 0 deletions
diff --git a/eventsview-plugins/eventsview-plugin-fediverse/fediverse-delegate.qml b/eventsview-plugins/eventsview-plugin-fediverse/fediverse-delegate.qml
new file mode 100644
index 0000000..f954db4
--- /dev/null
+++ b/eventsview-plugins/eventsview-plugin-fediverse/fediverse-delegate.qml
@@ -0,0 +1,185 @@
+/*
+ * SPDX-FileCopyrightText: 2013 - 2026 Jolla Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+import QtQuick 2.0
+import Sailfish.Silica 1.0
+import org.nemomobile.socialcache 1.0
+import com.jolla.eventsview.fediverse 1.0
+import QtQml.Models 2.1
+import "shared"
+
+SocialMediaAccountDelegate {
+ id: delegateItem
+ property string instanceHomeUrl: ""
+ property string instanceIconPath: ""
+
+ //: Fediverse posts
+ //% "Posts"
+ headerText: qsTrId("lipstick-jolla-home-la-fediverse_posts")
+ headerIcon: delegateItem.instanceIconPath.length > 0 ? delegateItem.instanceIconPath : "image://theme/icon-l-fediverse"
+ showRemainingCount: false
+
+ services: ["Posts"]
+ socialNetwork: SocialSync.Fediverse
+ dataType: SocialSync.Posts
+ providerName: "fediverse"
+ periodicSyncLoopEnabled: true
+
+ FediversePostActions {
+ id: fediversePostActions
+ }
+
+ model: FediversePostsModel {}
+
+ delegate: FediverseFeedItem {
+ downloader: delegateItem.downloader
+ imageList: model.images
+ avatarSource: model.icon
+ fallbackAvatarSource: model.icon
+ resolvedStatusUrl: delegateItem.authorizeInteractionUrl(model)
+ postId: model.fediverseId
+ postActions: fediversePostActions
+ accountId: delegateItem.firstAccountId(model, -1)
+
+ onTriggered: {
+ if (resolvedStatusUrl.length > 0) {
+ Qt.openUrlExternally(resolvedStatusUrl)
+ }
+ }
+
+ Component.onCompleted: {
+ delegateItem.instanceHomeUrl = statusUrl({instanceUrl: model.instanceUrl})
+ if (model.instanceIconPath && model.instanceIconPath.length > 0) {
+ delegateItem.instanceIconPath = model.instanceIconPath
+ }
+ refreshTimeCount = Qt.binding(function() { return delegateItem.refreshTimeCount })
+ connectedToNetwork = Qt.binding(function() { return delegateItem.connectedToNetwork })
+ eventsColumnMaxWidth = Qt.binding(function() { return delegateItem.eventsColumnMaxWidth })
+ }
+ }
+ //% "Show more in Fediverse"
+ expandedLabel: qsTrId("lipstick-jolla-home-la-show-more-in-fediverse")
+
+ onHeaderClicked: {
+ if (delegateItem.instanceHomeUrl.length > 0) {
+ Qt.openUrlExternally(delegateItem.instanceHomeUrl)
+ }
+ }
+ onExpandedClicked: {
+ if (delegateItem.instanceHomeUrl.length > 0) {
+ Qt.openUrlExternally(delegateItem.instanceHomeUrl)
+ }
+ }
+
+ onViewVisibleChanged: {
+ if (viewVisible) {
+ delegateItem.resetHasSyncableAccounts()
+ delegateItem.model.refresh()
+ if (delegateItem.hasSyncableAccounts) {
+ delegateItem.startPeriodicSyncLoop()
+ }
+ } else {
+ delegateItem.stopPeriodicSyncLoop()
+ }
+ }
+
+ onConnectedToNetworkChanged: {
+ if (viewVisible) {
+ delegateItem.startPeriodicSyncLoop()
+ }
+ }
+
+ Connections {
+ target: delegateItem.model
+
+ onCountChanged: {
+ if (target.count === 0) {
+ delegateItem.instanceHomeUrl = ""
+ delegateItem.instanceIconPath = ""
+ }
+ }
+ }
+
+ function statusUrl(modelData) {
+ var directUrl = modelData && modelData.url ? modelData.url.toString() : ""
+ if (directUrl.length > 0) {
+ return directUrl
+ }
+
+ var instanceUrl = modelData && modelData.instanceUrl ? modelData.instanceUrl.toString() : ""
+ instanceUrl = stripTrailingSlashes(instanceUrl)
+ if (instanceUrl.length === 0) {
+ return ""
+ }
+
+ var accountName = modelData && modelData.accountName ? modelData.accountName.toString() : ""
+ var statusId = modelData && modelData.fediverseId ? modelData.fediverseId.toString() : ""
+ if (accountName.length > 0 && statusId.length > 0) {
+ accountName = trimLeadingCharacter(accountName, "@")
+ return instanceUrl + "/@" + accountName + "/" + statusId
+ }
+
+ return instanceUrl + "/explore"
+ }
+
+ function authorizeInteractionUrl(modelData) {
+ var targetUrl = statusUrl(modelData)
+ if (targetUrl.length === 0) {
+ return targetUrl
+ }
+
+ var instanceUrl = modelData && modelData.instanceUrl ? modelData.instanceUrl.toString() : ""
+ if (instanceUrl.length === 0) {
+ return targetUrl
+ }
+ instanceUrl = stripTrailingSlashes(instanceUrl)
+
+ // Links on the user's own instance should open directly.
+ var sameServer = /^([a-z][a-z0-9+.-]*):\/\/([^\/?#]+)/i
+ var targetMatch = targetUrl.match(sameServer)
+ var instanceMatch = instanceUrl.match(sameServer)
+ if (targetMatch && instanceMatch
+ && targetMatch.length > 2
+ && instanceMatch.length > 2
+ && targetMatch[1].toLowerCase() === instanceMatch[1].toLowerCase()
+ && targetMatch[2].toLowerCase() === instanceMatch[2].toLowerCase()) {
+ return targetUrl
+ }
+
+ return instanceUrl + "/authorize_interaction?uri=" + encodeURIComponent(targetUrl)
+ }
+
+ function firstAccountId(modelData, defaultValue) {
+ var fallback = typeof defaultValue === "undefined" ? -1 : Number(defaultValue)
+ var accounts = modelData ? modelData.accounts : undefined
+ if (!accounts || accounts.length <= 0) {
+ return fallback
+ }
+
+ var accountId = Number(accounts[0])
+ return isNaN(accountId) ? fallback : accountId
+ }
+
+ function stripTrailingSlashes(value) {
+ value = String(value || "")
+ while (value.length > 0 && value.charAt(value.length - 1) === "/") {
+ value = value.slice(0, value.length - 1)
+ }
+ return value
+ }
+
+ function trimLeadingCharacter(value, character) {
+ value = String(value || "")
+ if (!character || character.length === 0) {
+ return value
+ }
+
+ while (value.length > 0 && value.charAt(0) === character) {
+ value = value.substring(1)
+ }
+ return value
+ }
+}