diff options
Diffstat (limited to 'eventsview-plugins/eventsview-plugin-fediverse/fediverse-delegate.qml')
| -rw-r--r-- | eventsview-plugins/eventsview-plugin-fediverse/fediverse-delegate.qml | 185 |
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 + } +} |
